#include #include #include #include #ifndef M_PI #ifndef PI #define M_PI 3.1415926535897932384626433832795 #else #define M_PI PI #endif #endif /* Hi guys, try this, use it in your code, but please credit Frank Jan Sorensen Alias:Frank Patxi (fjs@lab.jt.dk) for the fireroutine. */ /* Hi again, guys! If you use this code, please also credit me, Joachim Fenkes, 'cause I added the following speedups: -Replaced one tiny loop with a faster Move(...) (not much speedup) -Wrote the main display loop in 100% assembler, including a faster random number generator (the RNG is only a more or less optimized version of Borland's generator (see MEGARAND.ASM), but with the advantage of the ultimate crash if you call it normally :-) -Changed version number into 1.10 (this isn't a speedup, but necessary :-) */ /* Bcoz of the knowledge that reading from videocards is much slower than writing to them, I changed some things to write and read from/to a pointer and put the result with 32-Bit moves to the screen Also I added now a much more faster randommer. The result of this change is more than 3 times fast than before Stefan Goehler Please credit me! ... to JF: your bug is fixed! */ /* Oops, silly me, I removed all of the assembly code, so I can let the compiler have at it. Also makes it more portable... even though I am doing this to add to a project that is very non-portable. */ #define BUF_WIDTH 288 #define BUF_HEIGHT 224 const int rootrand = 20; /* Max/Min decrease of the root of the flames */ const int decay = 5; /* How far should the flames go up on the screen? */ /* This MUST be positive - JF */ const int miny = 0; /* Startingline of the flame routine. (should be adjusted along with MinY above) */ const int smooth = 1; /* How descrete can the flames be?*/ const int minfire = 50; /* limit between the "starting to burn" and the "is burning" routines */ const int xstart = 0; /* Startingpos on the screen, should be divideable by 4 without remain!*/ const int xend = 287; /* Guess! */ const int width = 1 + 287; /* +xend-xstart; Well- */ const int maxcolor = 110; /* Constant for the MakePal procedure */ const int fireincrease = 3; /*3 = Wood, 90 = Gazolin*/ typedef struct colorvalue { unsigned char r, g, b; } colorvalue; typedef colorvalue vgapalettetype[256]; void hsi2rgb(double h, double s, double i, struct colorvalue *c) /*Convert (Hue, Saturation, Intensity) -> (RGB)*/ { double t; double rv, gv, bv; t = h; rv = 1 + s * sin(t - 2 * M_PI / 3); gv = 1 + s * sin(t); bv = 1 + s * sin(t + 2 * M_PI / 3); t = 255.999 * i / 2; { c->r = floor(rv * t); c->g = floor(gv * t); c->b = floor(bv * t); } } void genpal() { int i; vgapalettetype pal; memset(pal, 0, 3); for( i=1; i <= maxcolor; i ++) hsi2rgb(4.6-1.5*i/maxcolor,(double)(i)/maxcolor,(double)(i)/maxcolor,&pal[i]); for( i=maxcolor; i <= 255; i ++) { pal[i]=pal[i-1]; { struct colorvalue *with = &pal[i]; if (with->r<255) with->r += 1; if (with->r<255) with->r += 1; if ((~i & 1) && (with->g<215)) with->g += 1; if ((~i & 1) && (with->b<255)) with->b += 1; } } } int started = 0; #if 0 // emulating Turbo Pascal unsigned int randseed; const unsigned modulus = 2147483647; const unsigned factor = 397204094; void Randomize() { randseed = time(NULL); } unsigned int randint(unsigned range) { randseed = randseed * factor % modulus; return range ? randseed % range : 0; } double randreal() { randseed = randseed * factor % modulus; return (double)randseed / modulus; } int rand1(int r) /* Return a random number between -R And R*/ { int result; result=randint(r*2+1)-r; return result; } #else #define Randomize() #define randint(a) (rand() % (a)) #define randreal() (((double)rand()) / ((double)RAND_MAX)) #define rand1(a) ((randint(a*2+1))-a) #endif unsigned char flamearray[BUF_WIDTH]; int morefire; extern unsigned char *vidbuffer; /* damn, this seems like such a waste */ static unsigned char pt[BUF_WIDTH * BUF_HEIGHT]; #if 0 int burn_init() { int i; if (flamearray) return 1; flamearray = (unsigned char *) malloc(BUF_WIDTH); for( i=xstart; i <= xend; i++) flamearray[i]=0; Randomize(); morefire=1; genpal(); return 0; } void burn_shutdown() { if (flamearray) { free(flamearray); flamearray = NULL; } } #endif void DrawBurn() { int i,j; int x,p; int v; if (!started) { started = 1; for( i=xstart; i <= xend; i++) flamearray[i]=0; Randomize(); morefire=1; memset(pt, 0, BUF_HEIGHT * BUF_WIDTH); /* genpal(); */ } /* for (x=0; x < BUF_WIDTH*BUF_HEIGHT; x++) { i = pt[x]; j = vidbuffer[x] << 2; if (i > j) pt[x] = i; else pt[x] = (i + j) >> 1; } */ /* Put the values from FlameArray on the bottom line of the screen */ memcpy(pt+((BUF_HEIGHT-1)*BUF_WIDTH)+xstart,flamearray, width); /* This loop makes the actual flames */ for( i=xstart; i <= xend; i++) for( j=miny; j <= (BUF_HEIGHT-1); j ++) { v = pt[j*BUF_WIDTH + i]; if ((v==0) || (v=xend)) pt[(j-1)*BUF_WIDTH + i] = 0; else pt[((j-1)*BUF_WIDTH) + (i-(randint(3)-1))] = v - randint(decay); } /*Match?*/ if (randint(150)==0) memset(flamearray + xstart + randint(xend-xstart-5),255,5); /*This loop controls the "root" of the flames ie. the values in FlameArray.*/ for( i=xstart; i <= xend; i++) { x=flamearray[i]; if (x10) x += randint(fireincrease); } else /* Otherwise randomize and increase by intensity (is burning)*/ x += rand1(rootrand)+morefire; if (x>255) x=255; /* X Too large ?*/ flamearray[i]=x; } /* Pour a little water on both sides of the fire to make it look nice on the sides*/ /* for( i=1; i <= width / 8; i ++) { x=floor(sqrt(randreal())*width/8); flamearray[xstart+x]=0; flamearray[xend-x]=0; } */ /*Smoothen the values of FrameArray to avoid "descrete" flames*/ p=0; for( i=xstart+smooth; i <= xend-smooth; i++) { x=0; for( j=-smooth; j <= smooth; j++) x += flamearray[i+j]; flamearray[i] = x / ((smooth << 1) + 1); } for (x=0; x < BUF_WIDTH*BUF_HEIGHT; x++) { i = vidbuffer[x]; j = pt[x] >> 3; if (j > i) vidbuffer[x] = j; else vidbuffer[x] = ((i + j) >> 1) + 1; } }