Skip to content

Commit e55b215

Browse files
committed
Add burning logos to first screen
Classic fire effect from https://lodev.org/cgtutor/fire.html Signed-off-by: Joachim Wiberg <[email protected]>
1 parent c4d864e commit e55b215

File tree

5 files changed

+255
-2
lines changed

5 files changed

+255
-2
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22
demo
33
font_data.h
44
image_data.h
5+
infix_data.h
56
logo_data.h
67
music_data.h
8+
wires_data.h
79
AppDir/
810
appimagetool
911
InfixDemo-x86_64.AppImage

Makefile

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ DEBUGFLAGS = -g -O0 -DDEBUG
77

88
TARGET = demo
99
SOURCE = demo.c
10-
HEADERS = font_data.h image_data.h logo_data.h
10+
HEADERS = font_data.h image_data.h logo_data.h infix_data.h wires_data.h
1111

1212
# Check if music file exists and add to build
1313
ifneq ($(wildcard music.mod),)
@@ -29,6 +29,14 @@ image_data.h: jack.png
2929
logo_data.h: logo.png
3030
xxd -i logo.png > logo_data.h
3131

32+
# Generate embedded infix data from infix.png
33+
infix_data.h: infix.png
34+
xxd -i infix.png > infix_data.h
35+
36+
# Generate embedded wires data from wires.png
37+
wires_data.h: wires.png
38+
xxd -i wires.png > wires_data.h
39+
3240
# Generate embedded music data from music.mod (if present)
3341
music_data.h: music.mod
3442
xxd -i music.mod > music_data.h
@@ -43,7 +51,7 @@ run: $(TARGET)
4351
./$(TARGET)
4452

4553
clean:
46-
rm -f $(TARGET) font_data.h image_data.h logo_data.h music_data.h
54+
rm -f $(TARGET) font_data.h image_data.h logo_data.h infix_data.h wires_data.h music_data.h
4755
rm -rf AppDir appimagetool InfixDemo-x86_64.AppImage
4856

4957
docker-build:

demo.c

Lines changed: 243 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
#include "font_data.h"
2020
#include "image_data.h"
2121
#include "logo_data.h"
22+
#include "infix_data.h"
23+
#include "wires_data.h"
2224

2325
/* Music data will be included when available */
2426
#ifdef HAVE_MUSIC
@@ -65,6 +67,10 @@ typedef struct {
6567
SDL_Texture *jack_texture;
6668
SDL_Surface *logo_surface;
6769
SDL_Texture *logo_texture;
70+
SDL_Surface *infix_surface;
71+
SDL_Texture *infix_texture;
72+
SDL_Surface *wires_surface;
73+
SDL_Texture *wires_texture;
6874
int current_scene;
6975
int current_scene_index; /* Index into scene_list */
7076
int fixed_scene;
@@ -288,6 +294,207 @@ void render_starfield(DemoContext *ctx)
288294
}
289295
}
290296

297+
/* Burning Infix logo in upper left corner */
298+
if (ctx->infix_texture && ctx->infix_surface) {
299+
/* Scale logo to 40% */
300+
int orig_w = ctx->infix_surface->w;
301+
int orig_h = ctx->infix_surface->h;
302+
int logo_w = (int)(orig_w * 0.4f);
303+
int logo_h = (int)(orig_h * 0.4f);
304+
int logo_x = 20; /* Upper left corner */
305+
int logo_y = 20;
306+
307+
/* Create fire effect buffer matching logo dimensions */
308+
static Uint32 fire_buffer[512 * 256]; /* Fire buffer */
309+
static int fire_frame_skip = 0;
310+
int fire_w = logo_w;
311+
int fire_h = logo_h;
312+
313+
/* Update fire every 5th frame to slow it down */
314+
fire_frame_skip++;
315+
if (fire_frame_skip >= 5) {
316+
fire_frame_skip = 0;
317+
318+
/* Randomize bottom row each frame to create fire source */
319+
for (int x = 0; x < fire_w; x++) {
320+
fire_buffer[(fire_h - 1) * fire_w + x] = rand() % 256;
321+
}
322+
323+
/* Fire propagation - lodev.org algorithm */
324+
for (int y = 0; y < fire_h - 1; y++) {
325+
for (int x = 0; x < fire_w; x++) {
326+
/* Calculate indices with wrapping */
327+
int y1 = (y + 1) % fire_h;
328+
int y2 = (y + 2) % fire_h;
329+
int x_left = (x - 1 + fire_w) % fire_w;
330+
int x_right = (x + 1) % fire_w;
331+
332+
/* Average 4 neighboring pixels with exact formula */
333+
int sum = fire_buffer[y1 * fire_w + x_left]; /* Below-left */
334+
sum += fire_buffer[y1 * fire_w + x]; /* Below */
335+
sum += fire_buffer[y1 * fire_w + x_right]; /* Below-right */
336+
sum += fire_buffer[y2 * fire_w + x]; /* Two rows below */
337+
338+
/* Apply decay: (sum * 32) / 129 */
339+
fire_buffer[y * fire_w + x] = (sum * 32) / 129;
340+
}
341+
}
342+
}
343+
344+
/* Render fire masked by logo - only visible through the letters */
345+
float palette_shift = ctx->global_time * 80.0f;
346+
347+
for (int y = 0; y < fire_h; y++) {
348+
for (int x = 0; x < fire_w; x++) {
349+
/* Sample logo to see if we should show fire here (logo acts as mask) */
350+
int sample_x = (x * orig_w) / logo_w;
351+
int sample_y = (y * orig_h) / logo_h;
352+
if (sample_x >= orig_w) sample_x = orig_w - 1;
353+
if (sample_y >= orig_h) sample_y = orig_h - 1;
354+
355+
Uint8 *pixel = (Uint8*)ctx->infix_surface->pixels + sample_y * ctx->infix_surface->pitch +
356+
sample_x * ctx->infix_surface->format->BytesPerPixel;
357+
Uint32 color;
358+
memcpy(&color, pixel, ctx->infix_surface->format->BytesPerPixel);
359+
Uint8 r, g, b, a;
360+
SDL_GetRGBA(color, ctx->infix_surface->format, &r, &g, &b, &a);
361+
362+
/* Only render fire where logo has pixels (logo is the window) */
363+
if (a > 128) {
364+
int heat = fire_buffer[y * fire_w + x];
365+
if (heat > 10) { /* Skip very dim pixels */
366+
/* Simple fire palette: dark red -> bright red -> orange -> yellow */
367+
int shifted_heat = ((int)(heat + palette_shift)) % 200; /* Cycle through lower range */
368+
369+
int fire_r, fire_g, fire_b;
370+
if (shifted_heat < 100) {
371+
/* Dark red to bright red */
372+
fire_r = 128 + (shifted_heat * 127) / 100;
373+
fire_g = 0;
374+
fire_b = 0;
375+
} else {
376+
/* Bright red to yellow */
377+
fire_r = 255;
378+
fire_g = ((shifted_heat - 100) * 255) / 100;
379+
fire_b = 0;
380+
}
381+
382+
SDL_Rect pixel_rect = {logo_x + x, logo_y + y, 2, 2};
383+
384+
SDL_SetRenderDrawBlendMode(ctx->renderer, SDL_BLENDMODE_ADD);
385+
SDL_SetRenderDrawColor(ctx->renderer, fire_r, fire_g, fire_b, heat);
386+
SDL_RenderFillRect(ctx->renderer, &pixel_rect);
387+
}
388+
}
389+
}
390+
}
391+
392+
/* Optionally draw logo outline on top for definition (with low alpha) */
393+
SDL_Rect logo_rect = {logo_x, logo_y, logo_w, logo_h};
394+
SDL_SetTextureAlphaMod(ctx->infix_texture, 100);
395+
SDL_RenderCopy(ctx->renderer, ctx->infix_texture, NULL, &logo_rect);
396+
SDL_SetTextureAlphaMod(ctx->infix_texture, 255);
397+
}
398+
399+
/* Burning Wires logo in upper right corner */
400+
if (ctx->wires_texture && ctx->wires_surface) {
401+
/* Scale to 50% size for wires logo to fit in window */
402+
int orig_w = ctx->wires_surface->w;
403+
int orig_h = ctx->wires_surface->h;
404+
int logo_w = (int)(orig_w * 0.50f);
405+
int logo_h = (int)(orig_h * 0.50f);
406+
int logo_x = WIDTH - logo_w - 20; /* Upper right corner */
407+
int logo_y = 20;
408+
409+
/* Create fire effect buffer matching logo dimensions */
410+
static Uint32 wires_fire_buffer[512 * 256]; /* Fire buffer for wires */
411+
static int wires_fire_frame_skip = 0;
412+
int fire_w = logo_w;
413+
int fire_h = logo_h;
414+
415+
/* Update fire every 5th frame to slow it down */
416+
wires_fire_frame_skip++;
417+
if (wires_fire_frame_skip >= 5) {
418+
wires_fire_frame_skip = 0;
419+
420+
/* Randomize bottom row each frame to create fire source */
421+
for (int x = 0; x < fire_w; x++) {
422+
wires_fire_buffer[(fire_h - 1) * fire_w + x] = rand() % 256;
423+
}
424+
425+
/* Fire propagation - lodev.org algorithm */
426+
for (int y = 0; y < fire_h - 1; y++) {
427+
for (int x = 0; x < fire_w; x++) {
428+
/* Calculate indices with wrapping */
429+
int y1 = (y + 1) % fire_h;
430+
int y2 = (y + 2) % fire_h;
431+
int x_left = (x - 1 + fire_w) % fire_w;
432+
int x_right = (x + 1) % fire_w;
433+
434+
/* Average 4 neighboring pixels with exact formula */
435+
int sum = wires_fire_buffer[y1 * fire_w + x_left];
436+
sum += wires_fire_buffer[y1 * fire_w + x];
437+
sum += wires_fire_buffer[y1 * fire_w + x_right];
438+
sum += wires_fire_buffer[y2 * fire_w + x];
439+
440+
/* Apply decay: (sum * 32) / 129 */
441+
wires_fire_buffer[y * fire_w + x] = (sum * 32) / 129;
442+
}
443+
}
444+
}
445+
446+
/* Render fire masked by wires logo */
447+
float palette_shift = ctx->global_time * 80.0f;
448+
449+
for (int y = 0; y < fire_h; y++) {
450+
for (int x = 0; x < fire_w; x++) {
451+
/* Sample logo - scale coordinates back to original dimensions */
452+
int sample_x = (x * orig_w) / logo_w;
453+
int sample_y = (y * orig_h) / logo_h;
454+
if (sample_x >= orig_w) sample_x = orig_w - 1;
455+
if (sample_y >= orig_h) sample_y = orig_h - 1;
456+
457+
Uint8 *pixel = (Uint8*)ctx->wires_surface->pixels + sample_y * ctx->wires_surface->pitch +
458+
sample_x * ctx->wires_surface->format->BytesPerPixel;
459+
Uint32 color;
460+
memcpy(&color, pixel, ctx->wires_surface->format->BytesPerPixel);
461+
Uint8 r, g, b, a;
462+
SDL_GetRGBA(color, ctx->wires_surface->format, &r, &g, &b, &a);
463+
464+
/* Only render fire where logo has pixels */
465+
if (a > 128) {
466+
int heat = wires_fire_buffer[y * fire_w + x];
467+
if (heat > 10) {
468+
int shifted_heat = ((int)(heat + palette_shift)) % 200;
469+
470+
int fire_r, fire_g, fire_b;
471+
if (shifted_heat < 100) {
472+
fire_r = 128 + (shifted_heat * 127) / 100;
473+
fire_g = 0;
474+
fire_b = 0;
475+
} else {
476+
fire_r = 255;
477+
fire_g = ((shifted_heat - 100) * 255) / 100;
478+
fire_b = 0;
479+
}
480+
481+
SDL_Rect pixel_rect = {logo_x + x, logo_y + y, 2, 2};
482+
483+
SDL_SetRenderDrawBlendMode(ctx->renderer, SDL_BLENDMODE_ADD);
484+
SDL_SetRenderDrawColor(ctx->renderer, fire_r, fire_g, fire_b, heat);
485+
SDL_RenderFillRect(ctx->renderer, &pixel_rect);
486+
}
487+
}
488+
}
489+
}
490+
491+
/* Draw logo outline on top */
492+
SDL_Rect logo_rect = {logo_x, logo_y, logo_w, logo_h};
493+
SDL_SetTextureAlphaMod(ctx->wires_texture, 100);
494+
SDL_RenderCopy(ctx->renderer, ctx->wires_texture, NULL, &logo_rect);
495+
SDL_SetTextureAlphaMod(ctx->wires_texture, 255);
496+
}
497+
291498
/* Rotating textured sphere in center with Jack image */
292499
if (!ctx->jack_texture) return;
293500

@@ -2447,6 +2654,42 @@ int main(int argc, char *argv[])
24472654
}
24482655
}
24492656

2657+
/* Load embedded infix.png from memory */
2658+
SDL_RWops *infix_rw = SDL_RWFromConstMem(infix_png, infix_png_len);
2659+
if (!infix_rw) {
2660+
fprintf(stderr, "Warning: Failed to create RWops for infix: %s\n", SDL_GetError());
2661+
ctx.infix_texture = NULL;
2662+
ctx.infix_surface = NULL;
2663+
} else {
2664+
ctx.infix_surface = IMG_Load_RW(infix_rw, 1); /* 1 = automatically close RW */
2665+
if (!ctx.infix_surface) {
2666+
fprintf(stderr, "Warning: Failed to load embedded infix: %s\n", IMG_GetError());
2667+
ctx.infix_texture = NULL;
2668+
} else {
2669+
/* Create and cache the texture */
2670+
ctx.infix_texture = SDL_CreateTextureFromSurface(ctx.renderer, ctx.infix_surface);
2671+
SDL_SetTextureBlendMode(ctx.infix_texture, SDL_BLENDMODE_BLEND);
2672+
}
2673+
}
2674+
2675+
/* Load embedded wires.png from memory */
2676+
SDL_RWops *wires_rw = SDL_RWFromConstMem(wires_png, wires_png_len);
2677+
if (!wires_rw) {
2678+
fprintf(stderr, "Warning: Failed to create RWops for wires: %s\n", SDL_GetError());
2679+
ctx.wires_texture = NULL;
2680+
ctx.wires_surface = NULL;
2681+
} else {
2682+
ctx.wires_surface = IMG_Load_RW(wires_rw, 1); /* 1 = automatically close RW */
2683+
if (!ctx.wires_surface) {
2684+
fprintf(stderr, "Warning: Failed to load embedded wires: %s\n", IMG_GetError());
2685+
ctx.wires_texture = NULL;
2686+
} else {
2687+
/* Create and cache the texture */
2688+
ctx.wires_texture = SDL_CreateTextureFromSurface(ctx.renderer, ctx.wires_surface);
2689+
SDL_SetTextureBlendMode(ctx.wires_texture, SDL_BLENDMODE_BLEND);
2690+
}
2691+
}
2692+
24502693
/* Initialize starfield */
24512694
for (int i = 0; i < NUM_STARS; i++) {
24522695
ctx.stars[i].x = (rand() % 2000 - 1000) / 10.0f;

infix.png

8.98 KB
Loading

wires.png

12.3 KB
Loading

0 commit comments

Comments
 (0)