diff options
-rw-r--r-- | effect-pad.c | 157 |
1 files changed, 121 insertions, 36 deletions
diff --git a/effect-pad.c b/effect-pad.c index dae1a02..0911701 100644 --- a/effect-pad.c +++ b/effect-pad.c @@ -1,12 +1,15 @@ #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <assert.h> #include <SDL.h> #include <SDL_image.h> +//#define EFFECT_FIRE_COLORKEYED + #define NARRAY(ARRAY) \ - (sizeof(ARRAY) / sizeof(ARRAY[0])) + (sizeof(ARRAY) / sizeof((ARRAY)[0])) #define SDL_MAYBE_LOCK(SURFACE) do { \ if (SDL_MUSTLOCK(SURFACE)) \ @@ -33,61 +36,140 @@ static SDL_Surface *screen; +static SDL_Color colors[256]; + +#define FIRE_DECAY(C) \ + ((C) > 0 ? (C) - 1 : 0) + static inline SDL_Surface * effect_fire_init(void) { + Uint32 flags = SDL_HWSURFACE; SDL_Surface *surface; - static SDL_Color colors[256]; - surface = SDL_CreateRGBSurface(SDL_HWSURFACE | SDL_SRCCOLORKEY, - screen->w, screen->h, 8, 0, 0, 0, 0); +#ifdef EFFECT_FIRE_COLORKEYED + surface = SDL_CreateRGBSurface(flags, screen->w, screen->h, 8, + 0, 0, 0, 0); +#else + flags |= SDL_SRCALPHA; + surface = SDL_CreateRGBSurface(flags, screen->w, screen->h, 32, + 0x000000FF, 0x0000FF00, + 0x00FF0000, 0xFF000000); +#endif if (surface == NULL) { SDL_ERROR("SDL_CreateRGBSurface"); exit(EXIT_FAILURE); } +#ifdef EFFECT_FIRE_COLORKEYED if (SDL_SetColorKey(surface, SDL_SRCCOLORKEY, 0)) { SDL_ERROR("SDL_SetColorKey"); SDL_FreeSurface(surface); exit(EXIT_FAILURE); } +#endif + + memset(colors, 0, sizeof(colors)); for (int i = 0; i < 32; i++) { +#ifdef EFFECT_FIRE_COLORKEYED /* black to blue, 32 values */ colors[i].b = i << 1; +#else + /* transparent to blue, 32 values */ + colors[i].b = 255; + colors[i].unused = i << 3; +#endif /* blue to red, 32 values */ colors[i + 32].r = i << 3; - colors[i + 32].b = 64 - (i << 1); + colors[i + 32].b = 64 - (i << 1); + colors[i + 32].unused = SDL_ALPHA_OPAQUE; /*red to yellow, 32 values */ colors[i + 64].r = 255; colors[i + 64].g = i << 3; + colors[i + 64].unused = SDL_ALPHA_OPAQUE; /* yellow to white, 162 */ colors[i + 96].r = 255; colors[i + 96].g = 255; colors[i + 96].b = i << 2; + colors[i + 96].unused = SDL_ALPHA_OPAQUE; colors[i + 128].r = 255; colors[i + 128].g = 255; colors[i + 128].b = 64 + (i << 2); + colors[i + 128].unused = SDL_ALPHA_OPAQUE; colors[i + 160].r = 255; colors[i + 160].g = 255; colors[i + 160].b = 128 + (i << 2); + colors[i + 160].unused = SDL_ALPHA_OPAQUE; colors[i + 192].r = 255; colors[i + 192].g = 255; colors[i + 192].b = 192 + i; + colors[i + 192].unused = SDL_ALPHA_OPAQUE; colors[i + 224].r = 255; colors[i + 224].g = 255; colors[i + 224].b = 224 + i; + colors[i + 224].unused = SDL_ALPHA_OPAQUE; } +#ifdef EFFECT_FIRE_COLORKEYED SDL_SetPalette(surface, SDL_LOGPAL | SDL_PHYSPAL, colors, - 0, NARRAY(colors)); + 0, NARRAY(colors)); +#else + SDL_FillRect(surface, NULL, + SDL_MapRGBA(surface->format, + colors[0].r, colors[0].g, + colors[0].b, colors[0].unused)); +#endif return surface; } +#ifdef EFFECT_FIRE_COLORKEYED + +static inline Uint8 +effect_fire_get_color(SDL_Surface *surface, int x, int y) +{ + return ((Uint8 *)surface->pixels)[surface->w*y + x]; +} + +static inline void +effect_fire_set_color(SDL_Surface *surface, int x, int y, Uint8 color) +{ + ((Uint8 *)surface->pixels)[surface->w*y + x] = color; +} + +#else + +static inline Uint8 +effect_fire_get_color(SDL_Surface *surface, int x, int y) +{ + SDL_Color color; + + /* alpha-channel surface */ + SDL_GetRGBA(((Uint32 *)surface->pixels)[surface->w*y + x], + surface->format, &color.r, &color.g, &color.b, &color.unused); + for (Uint8 i = 0; i < NARRAY(colors); i++) + if (!memcmp(colors + i, &color, sizeof(color))) + return i; + + /* shouldn't be reached */ + return 0; +} + +static inline void +effect_fire_set_color(SDL_Surface *surface, int x, int y, Uint8 color) +{ + ((Uint32 *)surface->pixels)[surface->w*y + x] = + SDL_MapRGBA(surface->format, + colors[color].r, colors[color].g, + colors[color].b, colors[color].unused); +} + +#endif + static inline void effect_fire_update(SDL_Surface *surface) { @@ -95,38 +177,41 @@ effect_fire_update(SDL_Surface *surface) SDL_MAYBE_LOCK(surface); - if (SDL_GetMouseState(&mouse_x, &mouse_y) & SDL_BUTTON(1)) { - Uint8 *p = (Uint8 *)surface->pixels; - float r = (float)rand()/RAND_MAX; - - p[mouse_y*surface->pitch + mouse_x] = r > .3 ? 255 : 0; - } - - for (Uint8 *p = (Uint8 *)surface->pixels + surface->pitch*surface->h - 1; - p >= (Uint8 *)surface->pixels + surface->pitch; - p--) { - Uint16 acc; - - if (!((p - (Uint8 *)surface->pixels) % surface->pitch)) { - /* left edge */ - acc = (Uint16)p[0] + p[1]; - if (acc/2 > p[-surface->pitch]) - p[-surface->pitch] = (acc + p[-surface->pitch])/3; - } else if (!((p - (Uint8 *)surface->pixels + 1) % surface->pitch)) { - /* right edge */ - acc = (Uint16)p[-1] + p[0]; - if (acc/2 > p[-surface->pitch]) - p[-surface->pitch] = (acc + p[-surface->pitch])/3; - } else { - /* somewhere inbetween */ - acc = (Uint16)p[-1] + p[0] + p[1]; - if (acc/3 > p[-surface->pitch]) - p[-surface->pitch] = (acc + p[-surface->pitch])/4; + if (SDL_GetMouseState(&mouse_x, &mouse_y) & SDL_BUTTON(1)) + effect_fire_set_color(surface, mouse_x, mouse_y, + (float)rand()/RAND_MAX > .3 ? 255 : 0); + + for (int y = surface->h - 1; y > 0; y--) { + Uint16 acc; + Uint8 color; + + /* right edge */ + acc = (Uint16)effect_fire_get_color(surface, surface->w - 2, y) + + effect_fire_get_color(surface, surface->w - 1, y); + color = effect_fire_get_color(surface, surface->w - 1, y - 1); + if (acc/2 > color) + color = (Uint8)((acc + color)/3); + effect_fire_set_color(surface, surface->w - 1, y - 1, + FIRE_DECAY(color)); + + /* center */ + for (int x = surface->w - 2; x > 0; x--) { + acc = (Uint16)effect_fire_get_color(surface, x - 1, y) + + effect_fire_get_color(surface, x, y) + + effect_fire_get_color(surface, x + 1, y); + color = effect_fire_get_color(surface, x, y - 1); + if (acc/3 > color) + color = (Uint8)((acc + color)/4); + effect_fire_set_color(surface, x, y - 1, FIRE_DECAY(color)); } - /* decay */ - if (p[-surface->pitch] > 0) - p[-surface->pitch]--; + /* left edge */ + acc = (Uint16)effect_fire_get_color(surface, 0, y) + + effect_fire_get_color(surface, 1, y); + color = effect_fire_get_color(surface, 0, y - 1); + if (acc/2 > color) + color = (Uint8)((acc + color)/3); + effect_fire_set_color(surface, 0, y - 1, FIRE_DECAY(color)); } SDL_MAYBE_UNLOCK(surface); |