summaryrefslogtreecommitdiffstats
path: root/mufhd0/water.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'mufhd0/water.cpp')
-rw-r--r--mufhd0/water.cpp615
1 files changed, 615 insertions, 0 deletions
diff --git a/mufhd0/water.cpp b/mufhd0/water.cpp
new file mode 100644
index 0000000..763bd27
--- /dev/null
+++ b/mufhd0/water.cpp
@@ -0,0 +1,615 @@
+/*
+ Water lib 0.1
+ (C)2000 Denis Roio - aka jaromil
+
+ Thanks go to Federico 'pix' Feroldi for the original
+ water algorithm idea...
+ Some optimizations added by Jason Hood.
+ Some other optimizations by Scott Scriven.
+ Further optimizations followed...
+*/
+
+#include <iostream>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <SDL/SDL.h>
+#include "datatype.h"
+#include "fixsin.h"
+
+using namespace std;
+
+#define MAXWATERWIDTH 768
+#define MAXWATERHEIGHT 768
+
+/* water physics */
+#define WATER 1
+#define JELLY 2
+#define SLUDGE 3
+#define SUPER_SLUDGE 4
+
+/* The Height field... Two pages, so that the filter will work correctly */
+int Height[2][MAXWATERHEIGHT * MAXWATERHEIGHT];
+
+/* Yes, I've got three copies of the background, all next to each other.
+ Press 's' a bunch of times to see why...
+ */
+
+static byte BkGdImagePre[MAXWATERWIDTH * MAXWATERHEIGHT];
+static byte BkGdImage[MAXWATERWIDTH * MAXWATERHEIGHT];
+static byte BkGdImagePost[MAXWATERWIDTH * MAXWATERHEIGHT];
+
+byte *bufptr;
+int waterwidth;
+int waterheight;
+
+// water effect variables
+int Hpage = 0;
+int xang, yang;
+int swirlangle;
+int x, y, ox = 80, oy = 60;
+int done = 0;
+int mode=0x4000;
+
+/* density: water density (step 1)
+ pheight: splash height (step 40)
+ radius: waterdrop radius (step 1)
+ light: light level (step 1)
+*/
+int density = 4, pheight = 600, radius = 30;
+int movement=1;
+int light=0;
+int offset;
+
+int water_surfacesize;
+int calc_optimization;
+
+/* *** clear:
+ memset(Height[0], 0, sizeof(int)*waterwidth*waterheight);
+ memset(Height[1], 0, sizeof(int)*waterwidth*waterheight);
+ *** distort /exaggerate water:
+ memset(Height[Hpage], 0, sizeof(int)*waterwidth*waterheight);
+ *** water physics
+ mode |= 0x40000;
+ density=4; light=1; pheight=600;
+ *** jelly physics
+ mode &= 0xBFFF;
+ density=3; pheight=400;
+ *** sludge physics
+ mode &= 0xBFFF;
+ density=8; pheight=400;
+ *** super sludge physics
+ mode &= 0xBFFF;
+ density=8; pheight=400;
+*/
+
+void DrawWaterNoLight(int page);
+void DrawWaterWithLight(int page, int LightModifier);
+void CalcWater(int npage, int density);
+void SmoothWater(int npage);
+
+void HeightBlob(int x, int y, int radius, int height, int page);
+void HeightBox (int x, int y, int radius, int height, int page);
+
+void WarpBlob(int x, int y, int radius, int height, int page);
+void SineBlob(int x, int y, int radius, int height, int page);
+
+SDL_Surface *water_init(char *imagefile, SDL_Surface *screen) {
+ SDL_Palette *palette;
+ SDL_Surface *image;
+
+ randomize();
+ image = SDL_LoadBMP(imagefile);
+ if (image == NULL) {
+ cout << "! Error loading water imagefile\n";
+ cout << "!!! Sorry, exiting.\n";
+ exit(1);
+ }
+
+ palette = image->format->palette;
+
+ if ((image->format->BitsPerPixel != 8) || (palette == NULL))
+ {
+ cout << "! Water imagefile must have 8bit depth and have a palette\n";
+ cout << "!!! Sorry, exiting.\n";
+ exit(1);
+ }
+
+ if ((image->format->BitsPerPixel != 8) || (image->format->palette == NULL))
+ {
+ cout << "! Screen for water effect must have 8 bit depth and have a palette\n";
+ cout << "!!! Sorry, exiting.\n";
+ exit(1);
+ }
+
+ waterwidth = image->w;
+ waterheight = image->h;
+
+ FCreateSines();
+
+ // misc optimization variables
+ water_surfacesize = sizeof(int)*waterwidth*waterheight;
+ calc_optimization = (waterheight-1)*waterwidth;
+
+ /* Fill the extra palette entries with white and set the display palette */
+ {
+ int nwhite;
+
+ nwhite = 256-palette->ncolors;
+ memset(&palette->colors[palette->ncolors], 255, nwhite*sizeof(SDL_Color));
+ SDL_SetColors(screen, palette->colors, 0, 256);
+ }
+
+ xang = rand()%2048;
+ yang = rand()%2048;
+ swirlangle = rand()%2048;
+
+ memset(Height[0], 0, water_surfacesize);
+ memset(Height[1], 0, water_surfacesize);
+
+ bufptr = (unsigned char*)image->pixels;
+ memcpy(BkGdImagePre, bufptr, waterwidth*waterheight);
+ memcpy(BkGdImage, bufptr, waterwidth*waterheight);
+ memcpy(BkGdImagePost, bufptr, waterwidth*waterheight);
+
+ return(image);
+}
+
+void water_clear() {
+ memset(Height[0], 0, water_surfacesize);
+ memset(Height[1], 0, water_surfacesize);
+}
+
+void water_distort() {
+ if(movement)
+ memset(Height[Hpage], 0, water_surfacesize);
+ else
+ SmoothWater(Hpage);
+}
+
+void water_setphysics(int physics) {
+ switch(physics) {
+ case WATER:
+ mode |= 0x4000;
+ density=4;
+ light=1;
+ pheight=600;
+ break;
+ case JELLY:
+ mode &= 0xBFFF;
+ density=3;
+ pheight=400;
+ break;
+ case SLUDGE:
+ mode &= 0xBFFF;
+ density=6;
+ pheight=400;
+ break;
+ case SUPER_SLUDGE:
+ mode &=0xBFFF;
+ density=8;
+ pheight=400;
+ break;
+ }
+}
+
+void water_update() {
+ if(light)
+ DrawWaterWithLight(Hpage, light-1);
+ else
+ DrawWaterNoLight(Hpage);
+
+ CalcWater(Hpage^1, density);
+ Hpage ^=1 ;
+}
+
+void water_drop(int x, int y) {
+ Height[Hpage][y*waterwidth + x] = rand()%(pheight<<2);
+}
+
+void water_bigsplash(int x, int y) {
+ if(mode & 0x4000)
+ HeightBlob(x, y, (radius>>1), pheight, Hpage);
+ else
+ SineBlob(x, y, radius, -pheight*6, Hpage);
+}
+
+void water_surfer() {
+ x = (waterwidth>>1)
+ + ((
+ (
+ (FSin( (xang* 65) >>8) >>8) *
+ (FSin( (xang*349) >>8) >>8)
+ ) * ((waterwidth-8)>>1)
+ ) >> 16);
+ y = (waterheight>>1)
+ + ((
+ (
+ (FSin( (yang*377) >>8) >>8) *
+ (FSin( (yang* 84) >>8) >>8)
+ ) * ((waterheight-8)>>1)
+ ) >> 16);
+ xang += 13;
+ yang += 12;
+
+ if(mode & 0x4000)
+ {
+ offset = (oy+y)/2*waterwidth + ((ox+x)>>1);
+ Height[Hpage][offset] = pheight;
+ Height[Hpage][offset + 1] =
+ Height[Hpage][offset - 1] =
+ Height[Hpage][offset + waterwidth] =
+ Height[Hpage][offset - waterwidth] = pheight >> 1;
+
+ offset = y*waterwidth + x;
+ Height[Hpage][offset] = pheight<<1;
+ Height[Hpage][offset + 1] =
+ Height[Hpage][offset - 1] =
+ Height[Hpage][offset + waterwidth] =
+ Height[Hpage][offset - waterwidth] = pheight;
+ }
+ else
+ {
+ SineBlob(((ox+x)>>1), ((oy+y)>>1), 3, -1200, Hpage);
+ SineBlob(x, y, 4, -2000, Hpage);
+ }
+
+ ox = x;
+ oy = y;
+}
+
+void water_swirl() {
+ x = (waterwidth>>1)
+ + ((
+ (FCos(swirlangle)) * (25)
+ ) >> 16);
+ y = (waterheight>>1)
+ + ((
+ (FSin(swirlangle)) * (25)
+ ) >> 16);
+ swirlangle += 50;
+ if(mode & 0x4000)
+ HeightBlob(x,y, radius>>2, pheight, Hpage);
+ else
+ WarpBlob(x, y, radius, pheight, Hpage);
+}
+
+void DrawWaterNoLight(int page)
+{
+
+ int dx, dy;
+ int x, y;
+ int c;
+
+ int offset=waterwidth + 1;
+
+ int *ptr = &Height[page][0];
+
+ for (y = calc_optimization; offset < y; offset += 2)
+ {
+ for (x = offset+waterwidth-2; offset < x; offset++)
+ {
+ dx = ptr[offset] - ptr[offset+1];
+ dy = ptr[offset] - ptr[offset+waterwidth];
+ c = BkGdImage[offset + waterwidth*(dy>>3) + (dx>>3)];
+
+ /* If anyone knows a better/faster way to do this, please tell me... */
+ bufptr[offset] = (c < 0) ? 0 : (c > 255) ? 255 : c;
+
+ offset++;
+ dx = ptr[offset] - ptr[offset+1];
+ dy = ptr[offset] - ptr[offset+waterwidth];
+ c = BkGdImage[offset + waterwidth*(dy>>3) + (dx>>3)];
+ bufptr[offset] = (c < 0) ? 0 : (c > 255) ? 255 : c;
+
+ }
+ }
+}
+
+void DrawWaterWithLight(int page, int LightModifier)
+{
+
+ int dx, dy;
+ int x, y;
+ int c;
+
+ int offset=waterwidth + 1;
+
+ int *ptr = &Height[page][0];
+
+
+ for (y = calc_optimization; offset < y; offset += 2)
+ {
+ for (x = offset+waterwidth-2; offset < x; offset++)
+ {
+ dx = ptr[offset] - ptr[offset+1];
+ dy = ptr[offset] - ptr[offset+waterwidth];
+
+ c = BkGdImage[offset + waterwidth*(dy>>3) + (dx>>3)] - (dx>>LightModifier);
+
+ /* If anyone knows a better/faster way to do this, please tell me... */
+ bufptr[offset] = (c < 0) ? 0 : (c > 255) ? 255 : c;
+
+ offset++;
+ dx = ptr[offset] - ptr[offset+1];
+ dy = ptr[offset] - ptr[offset+waterwidth];
+ c = BkGdImage[offset + waterwidth*(dy>>3) + (dx>>3)] - (dx>>LightModifier);
+ bufptr[offset] = (c < 0) ? 0 : (c > 255) ? 255 : c;
+
+ }
+ }
+}
+
+void CalcWater(int npage, int density)
+{
+ int newh;
+ int count = waterwidth + 1;
+
+ int *newptr = &Height[npage][0];
+ int *oldptr = &Height[npage^1][0];
+
+ int x, y;
+
+ /* Sorry, this function might not be as readable as I'd like, because
+ I optimized it somewhat. (enough to make me feel satisfied with it)
+ */
+ for (y = calc_optimization; count < y; count += 2)
+ {
+ for (x = count+waterwidth-2; count < x; count++)
+ {
+/* This does the eight-pixel method. It looks much better. */
+
+ newh = ((oldptr[count + waterwidth]
+ + oldptr[count - waterwidth]
+ + oldptr[count + 1]
+ + oldptr[count - 1]
+ + oldptr[count - waterwidth - 1]
+ + oldptr[count - waterwidth + 1]
+ + oldptr[count + waterwidth - 1]
+ + oldptr[count + waterwidth + 1]
+ ) >> 2 )
+ - newptr[count];
+
+
+ newptr[count] = newh - (newh >> density);
+ }
+ }
+}
+
+void SmoothWater(int npage)
+{
+ int newh;
+ int count = waterwidth + 1;
+
+ int *newptr = &Height[npage][0];
+ int *oldptr = &Height[npage^1][0];
+
+ int x, y;
+
+ /* Sorry, this function might not be as readable as I'd like, because
+ I optimized it somewhat. (enough to make me feel satisfied with it)
+ */
+
+ for(y=1; y<waterheight-1; y++)
+ {
+ for(x=1; x<waterwidth-1; x++)
+ {
+/* This does the eight-pixel method. It looks much better. */
+
+ newh = ((oldptr[count + waterwidth]
+ + oldptr[count - waterwidth]
+ + oldptr[count + 1]
+ + oldptr[count - 1]
+ + oldptr[count - waterwidth - 1]
+ + oldptr[count - waterwidth + 1]
+ + oldptr[count + waterwidth - 1]
+ + oldptr[count + waterwidth + 1]
+ ) >> 3 )
+ + newptr[count];
+
+
+ newptr[count] = newh>>1;
+ count++;
+ }
+ count += 2;
+ }
+}
+
+void CalcWaterBigFilter(int npage, int density)
+{
+ int newh;
+ int count = (waterwidth<<1) + 2;
+
+ int *newptr = &Height[npage][0];
+ int *oldptr = &Height[npage^1][0];
+
+ int x, y;
+
+ /* Sorry, this function might not be as readable as I'd like, because
+ I optimized it somewhat. (enough to make me feel satisfied with it)
+ */
+
+ for(y=2; y<waterheight-2; y++)
+ {
+ for(x=2; x<waterwidth-2; x++)
+ {
+/* This does the 25-pixel method. It looks much okay. */
+
+ newh = (
+ (
+ (
+ (oldptr[count + waterwidth]
+ + oldptr[count - waterwidth]
+ + oldptr[count + 1]
+ + oldptr[count - 1]
+ )<<1)
+ + ((oldptr[count - waterwidth - 1]
+ + oldptr[count - waterwidth + 1]
+ + oldptr[count + waterwidth - 1]
+ + oldptr[count + waterwidth + 1]))
+ + ( (
+ oldptr[count - (waterwidth<<1)]
+ + oldptr[count + (waterwidth<<1)]
+ + oldptr[count - 2]
+ + oldptr[count + 2]
+ ) >> 1 )
+ + ( (
+ oldptr[count - (waterwidth<<1) - 1]
+ + oldptr[count - (waterwidth<<1) + 1]
+ + oldptr[count + (waterwidth<<1) - 1]
+ + oldptr[count + (waterwidth<<1) + 1]
+ + oldptr[count - 2 - waterwidth]
+ + oldptr[count - 2 + waterwidth]
+ + oldptr[count + 2 - waterwidth]
+ + oldptr[count + 2 + waterwidth]
+ ) >> 2 )
+ )
+ >> 3)
+ - (newptr[count]);
+
+
+ newptr[count] = newh - (newh >> density);
+ count++;
+ }
+ count += 4;
+ }
+}
+
+void HeightBlob(int x, int y, int radius, int height, int page)
+{
+ int rquad;
+ int cx, cy, cyq;
+ int left, top, right, bottom;
+
+
+ rquad = radius * radius;
+
+ /* Make a randomly-placed blob... */
+ if(x<0) x = 1+radius+ rand()%(waterwidth-2*radius-1);
+ if(y<0) y = 1+radius+ rand()%(waterheight-2*radius-1);
+
+ left=-radius; right = radius;
+ top=-radius; bottom = radius;
+
+ /* Perform edge clipping... */
+ if(x - radius < 1) left -= (x-radius-1);
+ if(y - radius < 1) top -= (y-radius-1);
+ if(x + radius > waterwidth-1) right -= (x+radius-waterwidth+1);
+ if(y + radius > waterheight-1) bottom-= (y+radius-waterheight+1);
+
+
+ for(cy = top; cy < bottom; cy++)
+ {
+ cyq = cy*cy;
+ for(cx = left; cx < right; cx++)
+ {
+ if(cx*cx + cyq < rquad)
+ Height[page][waterwidth*(cy+y) + (cx+x)] += height;
+ }
+ }
+}
+
+
+void HeightBox (int x, int y, int radius, int height, int page)
+{
+ int cx, cy;
+ int left, top, right, bottom;
+
+
+ if(x<0) x = 1+radius+ rand()%(waterwidth-2*radius-1);
+ if(y<0) y = 1+radius+ rand()%(waterheight-2*radius-1);
+
+ left=-radius; right = radius;
+ top=-radius; bottom = radius;
+
+ /* Perform edge clipping... */
+ if(x - radius < 1) left -= (x-radius-1);
+ if(y - radius < 1) top -= (y-radius-1);
+ if(x + radius > waterwidth-1) right -= (x+radius-waterwidth+1);
+ if(y + radius > waterheight-1) bottom-= (y+radius-waterheight+1);
+
+ for(cy = top; cy < bottom; cy++)
+ {
+ for(cx = left; cx < right; cx++)
+ {
+ Height[page][waterwidth*(cy+y) + (cx+x)] = height;
+ }
+ }
+
+}
+
+void WarpBlob(int x, int y, int radius, int height, int page)
+{
+ int cx, cy;
+ int left,top,right,bottom;
+ int square;
+ int radsquare = radius * radius;
+
+ radsquare = (radius*radius);
+
+ height = height>>5;
+
+ left=-radius; right = radius;
+ top=-radius; bottom = radius;
+
+ /* Perform edge clipping... */
+ if(x - radius < 1) left -= (x-radius-1);
+ if(y - radius < 1) top -= (y-radius-1);
+ if(x + radius > waterwidth-1) right -= (x+radius-waterwidth+1);
+ if(y + radius > waterheight-1) bottom-= (y+radius-waterheight+1);
+
+ for(cy = top; cy < bottom; cy++)
+ {
+ for(cx = left; cx < right; cx++)
+ {
+ square = cy*cy + cx*cx;
+ if(square < radsquare)
+ {
+ Height[page][waterwidth*(cy+y) + cx+x]
+ += (int)((radius-sqrt(square))*(float)(height));
+ }
+ }
+ }
+}
+
+void SineBlob(int x, int y, int radius, int height, int page)
+{
+ int cx, cy;
+ int left,top,right,bottom;
+ int square, dist;
+ int radsquare = radius * radius;
+ float length = (1024.0/(float)radius)*(1024.0/(float)radius);
+
+ if(x<0) x = 1+radius+ rand()%(waterwidth-2*radius-1);
+ if(y<0) y = 1+radius+ rand()%(waterheight-2*radius-1);
+
+
+ radsquare = (radius*radius);
+
+
+ left=-radius; right = radius;
+ top=-radius; bottom = radius;
+
+
+ /* Perform edge clipping... */
+ if(x - radius < 1) left -= (x-radius-1);
+ if(y - radius < 1) top -= (y-radius-1);
+ if(x + radius > waterwidth-1) right -= (x+radius-waterwidth+1);
+ if(y + radius > waterheight-1) bottom-= (y+radius-waterheight+1);
+
+ for(cy = top; cy < bottom; cy++)
+ {
+ for(cx = left; cx < right; cx++)
+ {
+ square = cy*cy + cx*cx;
+ if(square < radsquare)
+ {
+ dist = (int)(sqrt(square*length));
+ Height[page][waterwidth*(cy+y) + cx+x]
+ += (int)((FCos(dist)+0xffff)*(height)) >> 19;
+ }
+ }
+ }
+}
+