303 lines
6.5 KiB
C
303 lines
6.5 KiB
C
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
#include <time.h>
|
|
|
|
#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<decay) ||
|
|
(i<=xstart) ||
|
|
(i>=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 (x<minfire) /* Increase by the "burnability"*/
|
|
{
|
|
/*Starting to burn:*/
|
|
if (x>10) 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;
|
|
}
|
|
}
|
|
|