aboutsummaryrefslogtreecommitdiff
path: root/effect-pad.c
diff options
context:
space:
mode:
authorRobin Haberkorn <robin.haberkorn@googlemail.com>2012-08-14 17:14:20 +0200
committerRobin Haberkorn <robin.haberkorn@googlemail.com>2012-08-14 17:14:20 +0200
commit9be84de9fb224a3e069eb8577baf02f3dcf81a0f (patch)
treef54c103c79a0dd988a7c84dd8a82c2c7b49d762a /effect-pad.c
parent34c25eab5d1258d8b51e2c7963fdab03408b8eb2 (diff)
downloadosc-graphics-9be84de9fb224a3e069eb8577baf02f3dcf81a0f.tar.gz
support fire effect with alpha blending
main algorithm has been revised
Diffstat (limited to 'effect-pad.c')
-rw-r--r--effect-pad.c157
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);