1+ /*******************************************************************************************
2+ *
3+ * raylib [textures] example - screen buffer / update Image as screen buffer and display with texture
4+ *
5+ * Example complexity rating: [★★☆☆] 2/4
6+ *
7+ * Example originally created with raylib 5.5, last time updated with raylib 5.6
8+ *
9+ * Example contributed by Agnis Aldiņš (@nezvers) and reviewed by Ramon Santamaria (@raysan5)
10+ *
11+ * Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
12+ * BSD-like license that allows static linking with closed source software
13+ *
14+ * Copyright (c) 2025 Agnis Aldiņš (@nezvers)
15+ *
16+ ********************************************************************************************/
17+
18+ #include "raylib.h"
19+
20+ #define MAX_COLORS 256
21+ #define SCREEN_WIDTH 800
22+ #define SCREEN_HEIGHT 450
23+ #define SCALE_FACTOR 2
24+ // buffer size at least for screenImage pixel count
25+ #define INDEX_BUFFER_SIZE ((SCREEN_WIDTH * SCREEN_HEIGHT) / SCALE_FACTOR)
26+ #define FLAME_WIDTH (SCREEN_WIDTH / SCALE_FACTOR)
27+
28+ static void GeneretePalette (Color * palette );
29+ static void ClearIndexBuffer (unsigned char * buffer , int count );
30+
31+ //------------------------------------------------------------------------------------
32+ // Program main entry point
33+ //------------------------------------------------------------------------------------
34+ int main (void )
35+ {
36+ // Initialization
37+ //--------------------------------------------------------------------------------------
38+ const int screenWidth = SCREEN_WIDTH ;
39+ const int screenHeight = SCREEN_HEIGHT ;
40+ const int pixelScale = SCALE_FACTOR ;
41+ const int imageWidth = screenWidth / pixelScale ;
42+ const int imageHeight = screenHeight / pixelScale ;
43+ InitWindow (screenWidth , screenHeight , "raylib [<module>] example - <name>" );
44+
45+ Color palette [MAX_COLORS ] = {0 };
46+ unsigned char indexBuffer [INDEX_BUFFER_SIZE ] = {0 };
47+ unsigned char flameRootBuffer [FLAME_WIDTH ] = {0 };
48+
49+ Image screenImage = GenImageColor (imageWidth , imageHeight , BLACK );
50+ Texture screenTexture = LoadTextureFromImage (screenImage );
51+ GeneretePalette (palette );
52+ ClearIndexBuffer (indexBuffer , INDEX_BUFFER_SIZE );
53+ ClearIndexBuffer (flameRootBuffer , FLAME_WIDTH );
54+
55+ SetTargetFPS (60 );
56+ //--------------------------------------------------------------------------------------
57+
58+ // Main game loop
59+ while (!WindowShouldClose ()) // Detect window close button or ESC key
60+ {
61+ // Grow flameRoot
62+ for (int x = 2 ; x < FLAME_WIDTH ; ++ x )
63+ {
64+ unsigned short flame = flameRootBuffer [x ];
65+ if (flame == 255 ) continue ;
66+ flame += GetRandomValue (0 , 2 );
67+ if (flame > 255 ) flame = 255 ;
68+ flameRootBuffer [x ] = flame ;
69+ }
70+
71+ // transfer flameRoot to indexBuffer
72+ for (int x = 0 ; x < FLAME_WIDTH ; ++ x )
73+ {
74+ int i = x + (imageHeight - 1 ) * imageWidth ;
75+ indexBuffer [i ] = flameRootBuffer [x ];
76+ }
77+
78+ // Clear top row, because it can't move any higher
79+ for (int x = 0 ; x < imageWidth ; ++ x )
80+ {
81+ if (indexBuffer [x ] == 0 ) continue ;
82+ indexBuffer [x ] = 0 ;
83+ }
84+
85+ // Skip top row, it is already cleared
86+ for (int y = 1 ; y < imageHeight ; ++ y )
87+ {
88+ for (int x = 0 ; x < imageWidth ; ++ x )
89+ {
90+ unsigned i = x + y * imageWidth ;
91+ unsigned char colorIndex = indexBuffer [i ];
92+ if (colorIndex == 0 ) continue ;
93+
94+ // Move pixel a row above
95+ indexBuffer [i ] = 0 ;
96+ int moveX = GetRandomValue (0 , 2 ) - 1 ;
97+ int newX = x + moveX ;
98+ if (newX < 0 || newX >= imageWidth ) continue ;
99+
100+ unsigned i_above = i - imageWidth + moveX ;
101+ int decay = GetRandomValue (0 , 3 );
102+ colorIndex -= (decay < colorIndex ) ? decay : colorIndex ;
103+ indexBuffer [i_above ] = colorIndex ;
104+ }
105+ }
106+
107+ // Update screenImage with palette colors
108+ for (int y = 1 ; y < imageHeight ; ++ y )
109+ {
110+ for (int x = 0 ; x < imageWidth ; ++ x )
111+ {
112+ unsigned i = x + y * imageWidth ;
113+ unsigned char colorIndex = indexBuffer [i ];
114+ Color col = palette [colorIndex ];
115+ ImageDrawPixel (& screenImage , x , y , col );
116+ }
117+ }
118+
119+ UpdateTexture (screenTexture , screenImage .data );
120+ // Draw
121+ //----------------------------------------------------------------------------------
122+ BeginDrawing ();
123+ const Vector2 origin = (Vector2 ){0 , 0 };
124+ const float rotation = 0.f ;
125+ DrawTextureEx (screenTexture , origin , rotation , pixelScale , WHITE );
126+ EndDrawing ();
127+ //----------------------------------------------------------------------------------
128+ }
129+
130+ // De-Initialization
131+ //--------------------------------------------------------------------------------------
132+
133+ UnloadTexture (screenTexture );
134+ UnloadImage (screenImage );
135+
136+ CloseWindow (); // Close window and OpenGL context
137+ //--------------------------------------------------------------------------------------
138+
139+ return 0 ;
140+ }
141+
142+ static void GeneretePalette (Color * palette )
143+ {
144+ for (int i = 0 ; i < MAX_COLORS ; ++ i )
145+ {
146+ float t = (float )i /(float )(MAX_COLORS - 1 );
147+ float hue = t * t ;
148+ float saturation = t ;
149+ float value = t ;
150+ palette [i ] = ColorFromHSV (250.f + 150.f * hue , saturation , value );
151+ }
152+ }
153+
154+ static void ClearIndexBuffer (unsigned char * buffer , int count )
155+ {
156+ // Use memset to set to ZERO, but for demonstration a plain for loop is used
157+ for (int i = 0 ; i < count ; ++ i )
158+ {
159+ buffer [i ] = 0 ;
160+ }
161+ }
0 commit comments