diff --git a/examples/shaders/resources/game_of_life/acorn.png b/examples/shaders/resources/game_of_life/acorn.png new file mode 100644 index 000000000..58ea0b4d1 Binary files /dev/null and b/examples/shaders/resources/game_of_life/acorn.png differ diff --git a/examples/shaders/resources/game_of_life/breeder.png b/examples/shaders/resources/game_of_life/breeder.png new file mode 100644 index 000000000..88aa073d3 Binary files /dev/null and b/examples/shaders/resources/game_of_life/breeder.png differ diff --git a/examples/shaders/resources/game_of_life/glider.png b/examples/shaders/resources/game_of_life/glider.png new file mode 100644 index 000000000..921adb8ed Binary files /dev/null and b/examples/shaders/resources/game_of_life/glider.png differ diff --git a/examples/shaders/resources/game_of_life/glider_gun.png b/examples/shaders/resources/game_of_life/glider_gun.png new file mode 100644 index 000000000..29b65d3de Binary files /dev/null and b/examples/shaders/resources/game_of_life/glider_gun.png differ diff --git a/examples/shaders/resources/game_of_life/oscillators.png b/examples/shaders/resources/game_of_life/oscillators.png new file mode 100644 index 000000000..badd6a92d Binary files /dev/null and b/examples/shaders/resources/game_of_life/oscillators.png differ diff --git a/examples/shaders/resources/game_of_life/puffer_train.png b/examples/shaders/resources/game_of_life/puffer_train.png new file mode 100644 index 000000000..8d77219b0 Binary files /dev/null and b/examples/shaders/resources/game_of_life/puffer_train.png differ diff --git a/examples/shaders/resources/game_of_life/r_pentomino.png b/examples/shaders/resources/game_of_life/r_pentomino.png new file mode 100644 index 000000000..1707f3c12 Binary files /dev/null and b/examples/shaders/resources/game_of_life/r_pentomino.png differ diff --git a/examples/shaders/resources/game_of_life/spaceships.png b/examples/shaders/resources/game_of_life/spaceships.png new file mode 100644 index 000000000..867f6fea3 Binary files /dev/null and b/examples/shaders/resources/game_of_life/spaceships.png differ diff --git a/examples/shaders/resources/game_of_life/still_lifes.png b/examples/shaders/resources/game_of_life/still_lifes.png new file mode 100644 index 000000000..ac184ac49 Binary files /dev/null and b/examples/shaders/resources/game_of_life/still_lifes.png differ diff --git a/examples/shaders/resources/shaders/glsl100/game_of_life.fs b/examples/shaders/resources/shaders/glsl100/game_of_life.fs new file mode 100644 index 000000000..70c12ac2c --- /dev/null +++ b/examples/shaders/resources/shaders/glsl100/game_of_life.fs @@ -0,0 +1,44 @@ +#version 100 + +precision highp float; + +// Input vertex attributes (from vertex shader) +varying vec2 fragTexCoord; +varying vec4 fragColor; + +// Input uniform values +uniform sampler2D texture0; +uniform vec4 colDiffuse; + +// Input size in pixels of the textures +uniform vec2 resolution; + +void main() +{ + // Size of one pixel in texture coordinates (from 0.0 to 1.0) + float x = 1.0/resolution.x; + float y = 1.0/resolution.y; + + // Status of the current cell (1 = alive, 0 = dead) + int origValue = (texture2D(texture0, fragTexCoord).r < 0.1)? 1 : 0; + + // Sum of alive neighbors + int sumValue = (texture2D(texture0, vec2(fragTexCoord.x - x, fragTexCoord.y - y)).r < 0.1)? 1 : 0; // Top-left + sumValue += (texture2D(texture0, vec2(fragTexCoord.x - x, fragTexCoord.y )).r < 0.1)? 1 : 0; // Top + sumValue += (texture2D(texture0, vec2(fragTexCoord.x - x, fragTexCoord.y + y)).r < 0.1)? 1 : 0; // Top-right + + sumValue += (texture2D(texture0, vec2(fragTexCoord.x, fragTexCoord.y - y)).r < 0.1)? 1 : 0; // Left + sumValue += (texture2D(texture0, vec2(fragTexCoord.x, fragTexCoord.y + y)).r < 0.1)? 1 : 0; // Right + + sumValue += (texture2D(texture0, vec2(fragTexCoord.x + x, fragTexCoord.y - y)).r < 0.1)? 1 : 0; // Bottom-left + sumValue += (texture2D(texture0, vec2(fragTexCoord.x + x, fragTexCoord.y )).r < 0.1)? 1 : 0; // Bottom + sumValue += (texture2D(texture0, vec2(fragTexCoord.x + x, fragTexCoord.y + y)).r < 0.1)? 1 : 0; // Bottom-right + + // Game of life rules: + // Current cell remains alive when 2 or 3 neighbors are alive, dies otherwise + // Current cell goes from dead to alive when exactly 3 neighbors are alive + if ((origValue == 1 && sumValue == 2) || sumValue == 3) + gl_FragColor = vec4(0.0, 0.0, 0.0, 255.0); // Alive: draw the pixel black + else + gl_FragColor = fragColor; // Dead: draw the pixel with the background color, RAYWHITE +} diff --git a/examples/shaders/resources/shaders/glsl120/game_of_life.fs b/examples/shaders/resources/shaders/glsl120/game_of_life.fs new file mode 100644 index 000000000..611f961bc --- /dev/null +++ b/examples/shaders/resources/shaders/glsl120/game_of_life.fs @@ -0,0 +1,42 @@ +#version 120 + +// Input vertex attributes (from vertex shader) +varying vec2 fragTexCoord; +varying vec4 fragColor; + +// Input uniform values +uniform sampler2D texture0; +uniform vec4 colDiffuse; + +// Input size in pixels of the textures +uniform vec2 resolution; + +void main() +{ + // Size of one pixel in texture coordinates (from 0.0 to 1.0) + float x = 1.0/resolution.x; + float y = 1.0/resolution.y; + + // Status of the current cell (1 = alive, 0 = dead) + int origValue = (texture2D(texture0, fragTexCoord).r < 0.1)? 1 : 0; + + // Sum of alive neighbors + int sumValue = (texture2D(texture0, vec2(fragTexCoord.x - x, fragTexCoord.y - y)).r < 0.1)? 1 : 0; // Top-left + sumValue += (texture2D(texture0, vec2(fragTexCoord.x - x, fragTexCoord.y )).r < 0.1)? 1 : 0; // Top + sumValue += (texture2D(texture0, vec2(fragTexCoord.x - x, fragTexCoord.y + y)).r < 0.1)? 1 : 0; // Top-right + + sumValue += (texture2D(texture0, vec2(fragTexCoord.x, fragTexCoord.y - y)).r < 0.1)? 1 : 0; // Left + sumValue += (texture2D(texture0, vec2(fragTexCoord.x, fragTexCoord.y + y)).r < 0.1)? 1 : 0; // Right + + sumValue += (texture2D(texture0, vec2(fragTexCoord.x + x, fragTexCoord.y - y)).r < 0.1)? 1 : 0; // Bottom-left + sumValue += (texture2D(texture0, vec2(fragTexCoord.x + x, fragTexCoord.y )).r < 0.1)? 1 : 0; // Bottom + sumValue += (texture2D(texture0, vec2(fragTexCoord.x + x, fragTexCoord.y + y)).r < 0.1)? 1 : 0; // Bottom-right + + // Game of life rules: + // Current cell remains alive when 2 or 3 neighbors are alive, dies otherwise + // Current cell goes from dead to alive when exactly 3 neighbors are alive + if (((origValue == 1) && (sumValue == 2)) || sumValue == 3) + gl_FragColor = vec4(0.0, 0.0, 0.0, 255.0); // Alive: draw the pixel black + else + gl_FragColor = fragColor; // Dead: draw the pixel with the background color, RAYWHITE +} diff --git a/examples/shaders/resources/shaders/glsl330/game_of_life.fs b/examples/shaders/resources/shaders/glsl330/game_of_life.fs new file mode 100644 index 000000000..cc80861d6 --- /dev/null +++ b/examples/shaders/resources/shaders/glsl330/game_of_life.fs @@ -0,0 +1,45 @@ +#version 330 + +// Input vertex attributes (from vertex shader) +in vec2 fragTexCoord; +in vec4 fragColor; + +// Input uniform values +uniform sampler2D texture0; +uniform vec4 colDiffuse; + +// Output fragment color +out vec4 finalColor; + +// Input size in pixels of the textures +uniform vec2 resolution; + +void main() +{ + // Size of one pixel in texture coordinates (from 0.0 to 1.0) + float x = 1.0/resolution.x; + float y = 1.0/resolution.y; + + // Status of the current cell (1 = alive, 0 = dead) + int origValue = (texture(texture0, fragTexCoord).r < 0.1)? 1 : 0; + + // Sum of alive neighbors + int sumValue = (texture(texture0, vec2(fragTexCoord.x - x, fragTexCoord.y - y)).r < 0.1)? 1 : 0; // Top-left + sumValue += (texture(texture0, vec2(fragTexCoord.x - x, fragTexCoord.y )).r < 0.1)? 1 : 0; // Top + sumValue += (texture(texture0, vec2(fragTexCoord.x - x, fragTexCoord.y + y)).r < 0.1)? 1 : 0; // Top-right + + sumValue += (texture(texture0, vec2(fragTexCoord.x, fragTexCoord.y - y)).r < 0.1)? 1 : 0; // Left + sumValue += (texture(texture0, vec2(fragTexCoord.x, fragTexCoord.y + y)).r < 0.1)? 1 : 0; // Right + + sumValue += (texture(texture0, vec2(fragTexCoord.x + x, fragTexCoord.y - y)).r < 0.1)? 1 : 0; // Bottom-left + sumValue += (texture(texture0, vec2(fragTexCoord.x + x, fragTexCoord.y )).r < 0.1)? 1 : 0; // Bottom + sumValue += (texture(texture0, vec2(fragTexCoord.x + x, fragTexCoord.y + y)).r < 0.1)? 1 : 0; // Bottom-right + + // Game of life rules: + // Current cell remains alive when 2 or 3 neighbors are alive, dies otherwise + // Current cell goes from dead to alive when exactly 3 neighbors are alive + if (((origValue == 1) && (sumValue == 2)) || sumValue == 3) + finalColor = vec4(0.0, 0.0, 0.0, 255.0); // Alive: draw the pixel black + else + finalColor = fragColor; // Dead: draw the pixel with the background color, RAYWHITE +} diff --git a/examples/shaders/shaders_game_of_life.c b/examples/shaders/shaders_game_of_life.c new file mode 100644 index 000000000..daeb4d789 --- /dev/null +++ b/examples/shaders/shaders_game_of_life.c @@ -0,0 +1,350 @@ +/******************************************************************************************* +* +* raylib [shaders] example - Conway's Game of Life with shaders +* +* Example complexity rating: [★★★☆] 3/4 +* +* NOTE: This example requires raylib OpenGL 3.3 or ES2 versions for shaders support, +* OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version +* +* Example originally created with raylib 5.6, last time updated with raylib 5.6 +* +* Example contributed by Jordi Santonja (@JordSant) and reviewed by Ramon Santamaria (@raysan5) +* +* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, +* BSD-like license that allows static linking with closed source software +* +* Copyright (c) 2025 Jordi Santonja (@JordSant) +* +********************************************************************************************/ + +#include "raylib.h" + +#define RAYGUI_IMPLEMENTATION +#include "raygui.h" // Required for GUI controls + +#if defined(PLATFORM_DESKTOP) + #define GLSL_VERSION 330 +#else // PLATFORM_ANDROID, PLATFORM_WEB + #define GLSL_VERSION 100 +#endif + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- +// Interaction mode +typedef enum { + MODE_RUN = 0, + MODE_PAUSE, + MODE_DRAW, +} InteractionMode; + +// Struct to store example preset patterns +typedef struct { + char *name; + char *fileName; + Vector2 position; +} PresetPattern; + +//---------------------------------------------------------------------------------- +// Functions declaration +//---------------------------------------------------------------------------------- +void FreeImageToDraw(Image **imageToDraw); + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + const int menuWidth = 100; + const int windowWidth = screenWidth - menuWidth; + const int windowHeight = screenHeight; + + const int worldWidth = 2048; + const int worldHeight = 2048; + + const int randomTiles = 8; // Random preset: divide the world to compute random points in each tile + + const Rectangle worldRectSource = { 0, 0, (float)worldWidth, (float)-worldHeight }; + const Rectangle worldRectDest = { 0, 0, (float)worldWidth, (float)worldHeight }; + const Rectangle textureOnScreen = { 0, 0, (float)windowWidth, (float)windowHeight }; + + const PresetPattern presetPatterns[] = { + { "Glider", "glider", { 0.5f, 0.5f } }, { "R-pentomino", "r_pentomino", { 0.5f, 0.5f } }, { "Acorn", "acorn", { 0.5f,0.5f } }, + { "Spaceships", "spaceships", { 0.1f, 0.5f } }, { "Still lifes", "still_lifes", { 0.5f, 0.5f } }, { "Oscillators", "oscillators", { 0.5f, 0.5f } }, + { "Puffer train", "puffer_train", { 0.1f, 0.5f } }, { "Glider Gun", "glider_gun", { 0.2f, 0.2f } }, { "Breeder", "breeder", { 0.1f, 0.5f } }, + { "Random", "", { 0.5f, 0.5f } } + }; + const int numberOfPresets = sizeof(presetPatterns) / sizeof(presetPatterns[0]); + + // Variable declaration + //-------------------------------------------------------------------------------------- + int zoom = 1; + float offsetX = (worldWidth - windowWidth)/2.0f; // Centered on window + float offsetY = (worldHeight - windowHeight)/2.0f; // Centered on window + int framesPerStep = 1; + int frame = 0; + + int preset = -1; // No button pressed for preset + int mode = MODE_RUN; // Starting mode: running + bool buttonZoomIn = false; // Button states: false not pressed + bool buttonZomOut = false; + bool buttonFaster = false; + bool buttonSlower = false; + + InitWindow(screenWidth, screenHeight, "raylib [shaders] example - conway's game of life"); + + // Load shader + Shader shdrGameOfLife = LoadShader(0, TextFormat("resources/shaders/glsl%i/game_of_life.fs", GLSL_VERSION)); + + // Set shader uniform size of the world + int resolutionLoc = GetShaderLocation(shdrGameOfLife, "resolution"); + const float resolution[2] = { (float)worldWidth, (float)worldHeight }; + SetShaderValue(shdrGameOfLife, resolutionLoc, resolution, SHADER_UNIFORM_VEC2); + + // Define two textures: the current world and the previous world + RenderTexture2D world1 = LoadRenderTexture(worldWidth, worldHeight); + RenderTexture2D world2 = LoadRenderTexture(worldWidth, worldHeight); + BeginTextureMode(world2); + ClearBackground(RAYWHITE); + EndTextureMode(); + + Image startPattern = LoadImage("resources/game_of_life/r_pentomino.png"); + UpdateTextureRec(world2.texture, (Rectangle) { worldWidth / 2.0f, worldHeight / 2.0f, (float)(startPattern.width), (float)(startPattern.height) }, startPattern.data); + UnloadImage(startPattern); + + // Pointers to the two textures, to be swapped + RenderTexture2D *currentWorld = &world2; + RenderTexture2D *previousWorld = &world1; + + // Image to be used in DRAW mode, to be changed with mouse input + Image *imageToDraw = NULL; + + SetTargetFPS(60); // Set at 60 frames-per-second + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + frame++; + + // Change zoom: both by buttons or by mouse wheel + float mouseWheelMove = GetMouseWheelMove(); + if (buttonZoomIn || (buttonZomOut && (zoom > 1)) || (mouseWheelMove != 0.0f)) + { + FreeImageToDraw(&imageToDraw); // Zoom change: free the image to draw to be recreated again + + const float centerX = offsetX + (windowWidth/2.0f)/zoom; + const float centerY = offsetY + (windowHeight/2.0f)/zoom; + if (buttonZoomIn || (mouseWheelMove > 0.0f)) + zoom *= 2; + if ((buttonZomOut || (mouseWheelMove < 0.0f)) && (zoom > 1)) + zoom /= 2; + offsetX = centerX - (windowWidth/2.0f)/zoom; + offsetY = centerY - (windowHeight/2.0f)/zoom; + } + + // Change speed: number of frames per step + if (buttonFaster && framesPerStep > 1) framesPerStep--; + if (buttonSlower) framesPerStep++; + + // Mouse management + //---------------------------------------------------------------------------------- + if ((mode == MODE_RUN) || (mode == MODE_PAUSE)) + { + FreeImageToDraw(&imageToDraw); // Free the image to draw: no longer needed in these modes + + // Pan with mouse left button + static Vector2 previousMousePosition = { 0.0f, 0.0f }; + const Vector2 mousePosition = GetMousePosition(); + if (IsMouseButtonDown(MOUSE_BUTTON_LEFT) && (mousePosition.x < windowWidth)) + { + offsetX -= (mousePosition.x - previousMousePosition.x)/zoom; + offsetY -= (mousePosition.y - previousMousePosition.y)/zoom; + } + previousMousePosition = mousePosition; + } + else // MODE_DRAW + { + const float offsetDecimalX = offsetX - floorf(offsetX); + const float offsetDecimalY = offsetY - floorf(offsetY); + int sizeInWorldX = (int)(ceilf((float)(windowWidth + offsetDecimalX*zoom)/zoom)); + int sizeInWorldY = (int)(ceilf((float)(windowHeight + offsetDecimalY*zoom)/zoom)); + if (offsetX + sizeInWorldX >= worldWidth) + sizeInWorldX = worldWidth - (int)floorf(offsetX); + if (offsetY + sizeInWorldY >= worldHeight) + sizeInWorldY = worldHeight - (int)floorf(offsetY); + + // Create image to draw if not created yet + if (imageToDraw == NULL) + { + RenderTexture2D worldOnScreen = LoadRenderTexture(sizeInWorldX, sizeInWorldY); + BeginTextureMode(worldOnScreen); + DrawTexturePro(currentWorld->texture, (Rectangle) { floorf(offsetX), floorf(offsetY), (float)(sizeInWorldX), -(float)(sizeInWorldY) }, + (Rectangle) { 0, 0, (float)(sizeInWorldX), (float)(sizeInWorldY) }, (Vector2) { 0, 0 }, 0.0f, WHITE); + EndTextureMode(); + imageToDraw = (Image*)RL_MALLOC(sizeof(Image)); + *imageToDraw = LoadImageFromTexture(worldOnScreen.texture); + UnloadRenderTexture(worldOnScreen); + } + + const Vector2 mousePosition = GetMousePosition(); + static int firstColor = -1; + if (IsMouseButtonDown(MOUSE_BUTTON_LEFT) && (mousePosition.x < windowWidth)) + { + int mouseX = (int)(mousePosition.x + offsetDecimalX*zoom)/zoom; + int mouseY = (int)(mousePosition.y + offsetDecimalY*zoom)/zoom; + if (mouseX >= sizeInWorldX) + mouseX = sizeInWorldX - 1; + if (mouseY >= sizeInWorldY) + mouseY = sizeInWorldY - 1; + if (firstColor == -1) + firstColor = (GetImageColor(*imageToDraw, mouseX, mouseY).r < 5)? 0 : 1; + const int prevColor = (GetImageColor(*imageToDraw, mouseX, mouseY).r < 5)? 0 : 1; + ImageDrawPixel(imageToDraw, mouseX, mouseY, (firstColor) ? BLACK : RAYWHITE); + if (prevColor != firstColor) + UpdateTextureRec(currentWorld->texture, (Rectangle){ floorf(offsetX), floorf(offsetY), (float)(sizeInWorldX), (float)(sizeInWorldY) }, imageToDraw->data); + } + else + firstColor = -1; + } + + // Load selected preset + //---------------------------------------------------------------------------------- + if (preset >= 0) + { + Image pattern; + if (preset < numberOfPresets - 1) // Preset with pattern image lo load + { + pattern = LoadImage(TextFormat("resources/game_of_life/%s.png", presetPatterns[preset].fileName)); + BeginTextureMode(*currentWorld); + ClearBackground(RAYWHITE); + EndTextureMode(); + UpdateTextureRec(currentWorld->texture, (Rectangle){ worldWidth*presetPatterns[preset].position.x - pattern.width/2.0f, + worldHeight*presetPatterns[preset].position.y - pattern.height/2.0f, + (float)(pattern.width), (float)(pattern.height) }, pattern.data); + } + else // Last preset: Random values + { + pattern = GenImageColor(worldWidth/randomTiles, worldHeight/randomTiles, RAYWHITE); + for (int i = 0; i < randomTiles; i++) + { + for (int j = 0; j < randomTiles; j++) + { + ImageClearBackground(&pattern, RAYWHITE); + for (int x = 0; x < pattern.width; x++) + for (int y = 0; y < pattern.height; y++) + if (GetRandomValue(0, 100) < 15) + ImageDrawPixel(&pattern, x, y, BLACK); + UpdateTextureRec(currentWorld->texture, + (Rectangle){ (float)(pattern.width*i), (float)(pattern.height*j), + (float)(pattern.width), (float)(pattern.height) }, pattern.data); + } + } + } + + UnloadImage(pattern); + mode = MODE_PAUSE; + offsetX = worldWidth * presetPatterns[preset].position.x - windowWidth/zoom/2.0f; + offsetY = worldHeight * presetPatterns[preset].position.y - windowHeight/zoom/2.0f; + } + + // Check window draw inside world limits + if (offsetX < 0) offsetX = 0; + if (offsetY < 0) offsetY = 0; + if (offsetX > worldWidth - (float)(windowWidth)/zoom) + offsetX = worldWidth - (float)(windowWidth)/zoom; + if (offsetY > worldHeight - (float)(windowHeight)/zoom) + offsetY = worldHeight - (float)(windowHeight)/zoom; + + // Rectangles for drawing texture portion to screen + //---------------------------------------------------------------------------------- + const Rectangle textureSourceToScreen = { offsetX, offsetY, (float)windowWidth/zoom, (float)windowHeight/zoom }; + + // Draw to texture + //---------------------------------------------------------------------------------- + if ((mode == MODE_RUN) && ((frame % framesPerStep) == 0)) + { + // Swap worlds + RenderTexture2D *tempWorld = currentWorld; + currentWorld = previousWorld; + previousWorld = tempWorld; + + // Draw to texture + BeginTextureMode(*currentWorld); + BeginShaderMode(shdrGameOfLife); + DrawTexturePro(previousWorld->texture, worldRectSource, worldRectDest, (Vector2){ 0, 0 }, 0.0f, RAYWHITE); + EndShaderMode(); + EndTextureMode(); + } + + // Draw to screen + //---------------------------------------------------------------------------------- + BeginDrawing(); + DrawTexturePro(currentWorld->texture, textureSourceToScreen, textureOnScreen, (Vector2){ 0, 0 }, 0.0f, WHITE); + + DrawLine(windowWidth, 0, windowWidth, screenHeight, (Color){ 218, 218, 218, 255 }); + DrawRectangle(windowWidth, 0, screenWidth - windowWidth, screenHeight, (Color){ 232, 232, 232, 255 }); + + DrawText("Conway's", 704, 4, 20, DARKBLUE); + DrawText(" game of", 704, 19, 20, DARKBLUE); + DrawText(" life", 708, 34, 20, DARKBLUE); + DrawText("in raylib", 757, 42, 6, BLACK); + + DrawText("Presets", 710, 58, 8, GRAY); + preset = -1; + for (int i = 0; i < numberOfPresets; i++) + if (GuiButton((Rectangle){ 710.0f, 70.0f + 18*i, 80.0f, 16.0f }, presetPatterns[i].name)) + preset = i; + + GuiToggleGroup((Rectangle){ 710, 258, 80, 16 }, "Run\nPause\nDraw", &mode); + + DrawText(TextFormat("Zoom: %ix", zoom), 710, 316, 8, GRAY); + buttonZoomIn = GuiButton((Rectangle){ 710, 328, 80, 16 }, "Zoom in"); + buttonZomOut = GuiButton((Rectangle){ 710, 346, 80, 16 }, "Zoom out"); + + DrawText(TextFormat("Speed: %i frame%s", framesPerStep, (framesPerStep > 1)? "s" : ""), 710, 370, 8, GRAY); + buttonFaster = GuiButton((Rectangle){ 710, 382, 80, 16 }, "Faster"); + buttonSlower = GuiButton((Rectangle){ 710, 400, 80, 16 }, "Slower"); + + //------------------------------------------------------------------------------ + + DrawFPS(712, 426); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + UnloadShader(shdrGameOfLife); + UnloadRenderTexture(world1); + UnloadRenderTexture(world2); + + FreeImageToDraw(&imageToDraw); + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} + +//---------------------------------------------------------------------------------- +// Functions definition +//---------------------------------------------------------------------------------- +void FreeImageToDraw(Image **imageToDraw) +{ + if (*imageToDraw != NULL) + { + UnloadImage(**imageToDraw); + RL_FREE(*imageToDraw); + *imageToDraw = NULL; + } +} diff --git a/examples/shaders/shaders_game_of_life.png b/examples/shaders/shaders_game_of_life.png new file mode 100644 index 000000000..8ebc2c12e Binary files /dev/null and b/examples/shaders/shaders_game_of_life.png differ diff --git a/projects/VS2022/examples/shaders_game_of_life.vcxproj b/projects/VS2022/examples/shaders_game_of_life.vcxproj new file mode 100644 index 000000000..0ede87cda --- /dev/null +++ b/projects/VS2022/examples/shaders_game_of_life.vcxproj @@ -0,0 +1,569 @@ + + + + + Debug.DLL + ARM64 + + + Debug.DLL + Win32 + + + Debug.DLL + x64 + + + Debug + ARM64 + + + Debug + Win32 + + + Debug + x64 + + + Release.DLL + ARM64 + + + Release.DLL + Win32 + + + Release.DLL + x64 + + + Release + ARM64 + + + Release + Win32 + + + Release + x64 + + + + {071E64F3-1396-4A97-97CA-98CAC059B168} + Win32Proj + shaders_game_of_life + 10.0 + shaders_game_of_life + + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + $(SolutionDir)..\..\examples\shaders + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shaders + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shaders + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shaders + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shaders + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shaders + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shaders + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shaders + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shaders + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shaders + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shaders + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shaders + WindowsLocalDebugger + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + /FS %(AdditionalOptions) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + /FS %(AdditionalOptions) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + Copy Debug DLL to output directory + + + + + + + Level3 + Disabled + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + Copy Debug DLL to output directory + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + Copy Debug DLL to output directory + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + + + Level3 + + + MaxSpeed + true + true + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + + + Copy Release DLL to output directory + + + + + Level3 + + + MaxSpeed + true + true + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + + + Copy Release DLL to output directory + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + + + Copy Release DLL to output directory + + + + + + + + + + + {e89d61ac-55de-4482-afd4-df7242ebc859} + + + + + + \ No newline at end of file