#include #include #include #include // Fixed point variables class #include "d:\watcom\h\general\fixpt.h" // Graphics Library #include "d:\watcom\h\graphics\gfx386.h" // These are the vertices that make up the warp grid struct PARTICLE { Fixpt x,y,xv,yv,xint,yint,xacc,yacc,c; }offset[21][13]; // This make it quick to multiply by 320 int Mul320[200]; //This makes it fast to calculate the distance between points in the grid Fixpt norms[3][3] = { Fixpt(0), Fixpt(16), Fixpt(32), Fixpt(16),Fixpt(16*1.414214),Fixpt(16*2.236068), Fixpt(32),Fixpt(16*2.236068),Fixpt(32*1.414214) }; // Images are stored here char Texture1[64000]; char Texture2[64000]; void copymem(long src, long dest, long numchars); #pragma aux copymem=\ " "\ "shr ecx,2 "\ "cld "\ "rep movsd "\ " "\ parm caller [esi] [edi] [ecx]\ modify [esi edi ecx]; // Smooth an image pointed to by ptr1, and stores the result in image pointed // to by ptr2 void smooth(long ptr1, long ptr2, long NumChars); #pragma aux smooth=\ " "\ " "\ " xor eax, eax "\ " xor edx, edx "\ "top: "\ " xor edx, edx "\ " mov al, [esi+ecx] "\ " "\ " add edx, eax "\ " mov al, [esi-1 +ecx] "\ " "\ " add edx, eax "\ " mov al, [esi+320 +ecx] "\ " "\ " add edx, eax "\ " mov al, [esi+1 +ecx] "\ " "\ " add edx, eax "\ " mov al, [esi-320+ecx] "\ " "\ " shr edx, 2 "\ " mov al, [esi+ecx] "\ " "\ " add edx, eax "\ " shr edx,1 "\ "NoOverflow: "\ " mov [edi+ecx], dl "\ " "\ " dec ecx "\ " jnz top "\ " "\ parm caller [esi] [edi] [ecx]\ modify [eax ebx ecx edx esi edi]; // warps a single block inline void TextureBlock(int xo, int yo) { fixpt VLDx, VRDx, HDx; fixpt VLDy, VRDy, HDy; fixpt TX1, TY1, TX2, TY2, tx, ty; int x, y, xi=(xo<<4), yi=(yo<<4); fixpt a,b,c,d; char *Tptr; Tptr = &(Texture1[xi + (yi*320)]); VLDx = (offset[xo] [yo+1].xint - offset[xo] [yo].xint) >> 4; VRDx = (offset[xo+1][yo+1].xint - offset[xo+1][yo].xint) >> 4; VLDy = (offset[xo] [yo+1].yint - offset[xo] [yo].yint) >> 4; VRDy = (offset[xo+1][yo+1].yint - offset[xo+1][yo].yint) >> 4; TX1 = offset[xo] [yo].xint; TY1 = offset[xo] [yo].yint; TX2 = offset[xo+1][yo].xint; TY2 = offset[xo+1][yo].yint; for (y=yi; y < (yi+16); y++) { HDx = (TX2-TX1) >> 4; HDy = ((TY2-TY1) >> 4); tx = TX1; ty = TY1; for (x=xi; x < (xi+16); x++) { *Tptr++ = Texture2[int(tx) + Mul320[int(ty)] ]; tx += HDx; ty += HDy; } Tptr += (320-16); TX1 += VLDx; TY1 += VLDy; TX2 += VRDx; TY2 += VRDy; } } // Calls TextureBlock, warping the entire screen void TextureWarp() { fixpt yf; int x,y; yf = Fixpt(0); for (y=0; y<=11; y++) { for (x=0; x<=19; x++) TextureBlock(x, y); } } // Draws the colourful texture you see at the begining void DrawTexture(int xs, int ys) { fixpt VLDc, VRDc, HDc; fixpt C1, C2, c; int x, y, xi, yi; for (yi=0; yi<12; yi++) for (xi=0; xi<20; xi++) { VLDc = (offset[xi][yi+1].c-offset[xi][yi].c) / Fixpt(ys); VRDc = (offset[xi+1][yi+1].c-offset[xi+1][yi].c) / Fixpt(ys); C1 = offset[xi][yi].c; C2 = offset[xi+1][yi].c; for (y=yi*ys; y<(yi+1)*ys; y++) { HDc = (C2-C1) / Fixpt(xs); c = C1; for (x=xi*xs; x<(xi+1)*xs; x++) { plot(x,y, char(int(c))); c += HDc; } C1 += VLDc; C2 += VRDc; } } copymem(long(&(screen[0])), long(&(Texture2[0])), 64000); } // Load the contents of a file into an array of characters void LoadGFX(char FileName[], char ArrayPtr[], int xsize, int ysize) { ifstream HFile; HFile.open(FileName, ios::in | ios::binary); if (!HFile) { setvidmode(0x03); cout << "let_flow.raw not found" << endl; exit(0); } HFile.read(&(ArrayPtr[0]), xsize*ysize); HFile.close(); } void Initialise() { int i, x, y; Fixpt t, t1, t2, t3, xf, yf; t =Fixpt(0); t1 =Fixpt(0); t2 =Fixpt(0); t3 =Fixpt(0); InitSin(); // Initialise the sine/cos lookup table used to calculate // fixed point sines and cosines InitSQRT(); // Initialise the fixed point Square Root lookup table for (i=0; i<200; i++) Mul320[i] = i*320; // switch to mode 13h setvidmode(0x13); // setup garish palette for (i=0; i<64; i++) { setpalette(i, i, 0, (63-i)); setpalette(i+64, (63-i), i, 0); setpalette(i+128, 0, (63-i), i); setpalette(i+192, i, 0, (63-i)); } // Now initialise the positions of the vertices of the warp grid for (y=0; y<=12; y++) { yf = Fixpt(y); for (x=0; x<=20; x++) { xf = Fixpt(x); t +=Fixpt(0.081); t1+=Fixpt(0.083); t2+=Fixpt(0.085); t3+=Fixpt(0.087); if ((x==0) || (x==20) || (y==0) || (y==12)) { offset[x][y].x = Fixpt(x<<4); offset[x][y].y = Fixpt(y<<4); offset[x][y].xv = 0; offset[x][y].yv = 0; } else { offset[x][y].x = Fixpt(rand()-16384)/Fixpt(2000) + Fixpt(x<<4); offset[x][y].y = Fixpt(rand()-16384)/Fixpt(2000) + Fixpt(y<<4); offset[x][y].xv = 0; offset[x][y].yv = 0; } offset[x][y].xint = offset[x][y].x; offset[x][y].yint = offset[x][y].y; offset[x][y].xacc = 0; offset[x][y].yacc = 0; offset[x][y].c = abs(rand()) >> 7; } } DrawTexture(16, 16); } // Relax the grid void Relax() { int x,y,xi,yi,xh,xl,yh,yl; Fixpt xv,yv,Xspring,Yspring,ext,length,norm,scaler; // firstly calculate the forces on all points for (y=1; y<12; y++) { yh=y+2; yl=y-2; if (yl<0) yl=0; if (yh>12) yh=12; for (x=1; x<20; x++) { xh=x+2; xl=x-2; if (xl<0) xl=0; if (xh>20) xh=20; for (yi=yl; yi<=yh; yi++) { for (xi=xl; xi<=xh; xi++) { if ((xi != x) || (yi != y)) { Xspring = offset[xi][yi].x - offset[x][y].x; Yspring = offset[xi][yi].y - offset[x][y].y; norm = norms[abs(xi-x)][abs(yi-y)]; length = sqrt(Xspring*Xspring + Yspring*Yspring); scaler = (norm-length) * Fixpt(0.00002); Xspring *= scaler; Yspring *= scaler; offset[xi][yi].xv += Xspring; offset[xi][yi].yv += Yspring; } } } } } // now adjust the positions and velocities of the points for (y=1; y<12; y++) for (x=1; x<20; x++) { if (!((x==0) || (x==20) || (y==0) || (y==12))) { offset[x][y].x += offset[x][y].xv; offset[x][y].y += offset[x][y].yv; offset[x][y].xv *= Fixpt(.9999); offset[x][y].yv *= Fixpt(.9999); } offset[x][y].xint = trunc(offset[x][y].x); offset[x][y].yint = trunc(offset[x][y].y); // this bit allows it to handle non-integer values of points on the // grid offset[x][y].xacc += fracof2(offset[x][y].x); if (offset[x][y].xacc > Fixpt(1)) { offset[x][y].xacc -= Fixpt(1); offset[x][y].xint += Fixpt(1); } if (offset[x][y].xacc < Fixpt(0)) { offset[x][y].xacc += Fixpt(1); offset[x][y].xint -= Fixpt(1); } offset[x][y].yacc += fracof2(offset[x][y].y); if (offset[x][y].yacc > Fixpt(1)) { offset[x][y].yacc -= Fixpt(1); offset[x][y].yint += Fixpt(1); } if (offset[x][y].yacc < Fixpt(0)) { offset[x][y].yacc += Fixpt(1); offset[x][y].yint -= Fixpt(1); } } // Make sure points on the grid never stray outside the screen, causing a crash for (x=0; x<=20; x++) { if (offset[x][1].yint < Fixpt(0)) offset[x][1].yint = Fixpt(0); if (offset[x][11].yint > Fixpt(199)) offset[x][11].yint = Fixpt(199); } for (y=0; y<=12; y++) { if (offset[1][y].xint < Fixpt(0)) offset[1][y].xint = Fixpt(0); if (offset[19][y].xint > Fixpt(319)) offset[19][y].xint = Fixpt(319); } } void main() { int i, up, down, s=4, x, y; Fixpt scaler; Initialise(); setpalette(255,63,63,63); getch(); while(!kbhit()) { // relax the warp grid Relax(); // warp the texture TextureWarp(); // smooth the texture. except the top and bottom rows smooth(long(&(Texture1[320])), long(&(Texture2[320])),64000-640); // just copy the top and bottom rows copymem(long(&(Texture1[0])), long(&(Texture2[0])),320); copymem(long(&(Texture1[64000-320])), long(&(Texture2[64000-320])),320); // synchronise waitvsync(); // update screen copymem(long(&(Texture1[0])), long(&(screen[0])), 64000); } // same as above but with fade out for (scaler=fixpt(1); scaler>fixpt(0); scaler-=fixpt(.05)) { for (i=0; i<64; i++) { up = int(fixpt(i)*scaler); down = int(fixpt(63-i)*scaler); setpalette(i, up, 0, down); setpalette(i+64, down, up, 0); setpalette(i+128, 0, down, up); setpalette(i+192, up, 0, down); } Relax(); TextureWarp(); smooth(long(&(Texture1[320])), long(&(Texture2[320])),64000-640); copymem(long(&(Texture1[0])), long(&(Texture2[0])),320); copymem(long(&(Texture1[64000-320])), long(&(Texture2[64000-320])),320); copymem(long(&(Texture1[0])), long(&(screen[0])), 64000); } getch(); setvidmode(0x03); setpalette(7,0,0,0); cout <