/*
* Make with:
*
* gcc -Wall -o sdl-fire sdl-fire.c -lSDL
*
*/
#include <math.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#if defined(_MSC_VER)
#include "SDL.h"
#else
#include "SDL/SDL.h"
#endif
#include "palette.h"
#define WIDTH 320
//#define HEIGHT 150
#define HEIGHT 100
#define RADIUS 50
SDL_Surface *screen;
int flamebuf[WIDTH][HEIGHT];
void do_fire(int buf[WIDTH][HEIGHT]) {
int x, y;
/*
* Set a random bottom row.
*/
for (x = 0; x < WIDTH; x++) {
buf[x][0] =
(random() % 256);
}
for (y = HEIGHT - 1; y > 0; y--) {
for (x = 0; x < WIDTH; x++) {
buf[x][y] =
(buf[(x + WIDTH) % WIDTH][(y - 2) % HEIGHT] +
buf[(x + WIDTH) % WIDTH][y - 1] +
buf[(x - 1 + WIDTH) % WIDTH][y - 1] +
buf[(x + 1 + WIDTH) % WIDTH][y - 1]) * 32 / 129;
}
}
}
void setpix(long x, long y, long newval)
{
long yofs = screen->pitch/4;
uint32_t *pixadr = ((uint32_t *)screen->pixels) + x + y*yofs ;
*pixadr = newval;
}
void blendpix(long x, long y, long inval)
{
long yofs = screen->pitch/4;
uint32_t *pixadr = ((uint32_t *)screen->pixels) + x + y*yofs ;
uint8_t srcval[4],dstval[4],newval[4];
int i;
/* Yes, I know, so shoot me. */
*(uint32_t *)srcval = inval; /* incoming RGBA */
*(uint32_t *)dstval = *pixadr; /* current RGBA */
for (i=0;i<4;i++) {
newval[i] = srcval[i]/2 + dstval[i]/2;
}
*pixadr = *( (uint32_t *)&newval);
}
void dopix(long x, long y, long newval)
{
setpix(x,y,newval);
blendpix(x+1,y+1,newval);
blendpix(x-1,y+1,newval);
blendpix(x+1,y-1,newval);
blendpix(x-1,y-1,newval);
}
void mappoint(long cx, long cy, long x, long y, long radius)
{
uint32_t newval = palette[flamebuf[x % WIDTH][radius]];
if (x == 0) {
dopix(cx, cy+y ,newval);
dopix(cx, cy-y ,newval);
dopix(cx+y, cy ,newval);
dopix(cx-y, cy ,newval);
} else if (x == y) {
dopix(cx+x, cy+y, newval);
dopix(cx-x, cy+y, newval);
dopix(cx+x, cy-y, newval);
dopix(cx-x, cy-y, newval);
} else if (x < y) {
dopix(cx+x, cy+y, newval);
dopix(cx-x, cy+y, newval);
dopix(cx+x, cy-y, newval);
dopix(cx-x, cy-y, newval);
dopix(cx+y, cy+x, newval);
dopix(cx-y, cy+x, newval);
dopix(cx+y, cy-x, newval);
dopix(cx-y, cy-x, newval);
}
}
void firetocircle(long xcenter, long ycenter, long radius)
{
long x = 0;
long y = radius;
long p = (5 - radius * 4) / 4;
mappoint(xcenter, ycenter, x, y, radius - RADIUS);
while (x < y) {
x++;
if (p < 0) {
p += 2 * x + 1;
} else {
y--;
p += 2 * (x - y) + 1;
}
mappoint(xcenter, ycenter, x, y, radius - RADIUS);
}
}
void render()
{
/*
* Lock surface if needed.
*/
if (SDL_MUSTLOCK(screen))
if (SDL_LockSurface(screen) < 0)
return;
int i;
for (i = RADIUS; i < (HEIGHT + RADIUS); i++) {
firetocircle(screen->w / 2, screen->h / 2, i);
}
/*
* Unlock if needed.
*/
if (SDL_MUSTLOCK(screen))
SDL_UnlockSurface(screen);
/*
* Tell SDL to update the whole screen.
*/
SDL_UpdateRect(screen, 0, 0, screen->w, screen->h);
}
// Entry point
int main(int argc, char *argv[])
{
// Initialize SDL's subsystems - in this case, only video.
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
fprintf(stderr
, "Unable to init SDL: %s\n",
SDL_GetError());
}
// Register SDL_Quit to be called at exit; makes sure things are
// cleaned up when we quit.
// Attempt to create a WIDTHxHEIGHT window with 32bit pixels.
// screen = SDL_SetVideoMode(WIDTH, HEIGHT, 32, SDL_SWSURFACE);
screen = SDL_SetVideoMode(1024,768, 32, SDL_SWSURFACE);
// If we fail, return error.
if (screen == NULL) {
fprintf(stderr
, "Unable to set 640x480 video: %s\n",
SDL_GetError());
}
// Main loop: loop forever.
while (1) {
// Update our fire.
do_fire(flamebuf);
// Render stuff
render();
// Poll for events, and handle the ones we care about.
SDL_Event event;
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_KEYDOWN:
break;
case SDL_KEYUP:
// If escape is pressed, return (and thus, quit)
if (event.key.keysym.sym == SDLK_ESCAPE)
return 0;
break;
case SDL_QUIT:
return (0);
}
}
usleep(50000);
}
return 0;
}