From fcd13fd5d22219d8ed69b88e9cc1138b96b9a16d Mon Sep 17 00:00:00 2001 From: Wilhem Barbier Date: Wed, 28 Jun 2017 12:56:04 +0200 Subject: [PATCH] Add some functions to generate images Namely: - GenImageHorizontalV - GenImageHorizontalH - GenImageChecked - GenImageWhiteNoise - GenImageCellular The gradient implementation may be a bit naive, for example it doesn't do any gamma correction. --- examples/textures/textures_image_generation.c | 57 +++++++ src/raylib.h | 7 + src/textures.c | 144 +++++++++++++++++- 3 files changed, 207 insertions(+), 1 deletion(-) create mode 100644 examples/textures/textures_image_generation.c diff --git a/examples/textures/textures_image_generation.c b/examples/textures/textures_image_generation.c new file mode 100644 index 00000000..9db64ef7 --- /dev/null +++ b/examples/textures/textures_image_generation.c @@ -0,0 +1,57 @@ +/******************************************************************************************* +* +* raylib [textures] example - Procedural images generation +* +* This example has been created using raylib 1.7 (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* +* Copyright (c) 2O17 Ramon Santamaria (@raysan5) +* +********************************************************************************************/ + +#include "raylib.h" + +#define TEXTURES_NUM 5 // for now we have 5 generation algorithms + +int main() +{ + int screenWidth = 800; + int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [textures] example - procedural images generation"); + + Image verticalGradient = GenImageGradientV(screenWidth, screenHeight, RED, BLUE); + Image horizontalGradient = GenImageGradientH(screenWidth, screenHeight, RED, BLUE); + Image checked = GenImageChecked(screenWidth, screenHeight, 32, 32, RED, BLUE); + Image whiteNoise = GenImageWhiteNoise(screenWidth, screenHeight, 0.5f); + Image cellular = GenImageCellular(screenWidth, screenHeight, 32); + + Texture2D textures[TEXTURES_NUM]; + textures[0] = LoadTextureFromImage(verticalGradient); + textures[1] = LoadTextureFromImage(horizontalGradient); + textures[2] = LoadTextureFromImage(checked); + textures[3] = LoadTextureFromImage(whiteNoise); + textures[4] = LoadTextureFromImage(cellular); + + int currentTexture = 0; + + while (!WindowShouldClose()) + { + if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) + { + currentTexture = (currentTexture + 1) % TEXTURES_NUM; // cycle between the 5 textures + } + + BeginDrawing(); + ClearBackground(RAYWHITE); + DrawTexture(textures[currentTexture], 0, 0, WHITE); + EndDrawing(); + } + + for (int i = 0; i < TEXTURES_NUM; i++) // unload the textures + { + UnloadTexture(textures[i]); + } + + CloseWindow(); +} diff --git a/src/raylib.h b/src/raylib.h index 6d597fef..29cc5728 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -873,6 +873,13 @@ RLAPI void ImageColorGrayscale(Image *image); RLAPI void ImageColorContrast(Image *image, float contrast); // Modify image color: contrast (-100 to 100) RLAPI void ImageColorBrightness(Image *image, int brightness); // Modify image color: brightness (-255 to 255) +// Image generation functions +RLAPI Image GenImageGradientV(int width, int height, Color top, Color bottom); // Generate image: vertical gradient +RLAPI Image GenImageGradientH(int width, int height, Color left, Color right); // Generate image: horizontal gradient +RLAPI Image GenImageChecked(int width, int height, int checksX, int checksY, Color col1, Color col2); // Generate image: checked +RLAPI Image GenImageWhiteNoise(int width, int height, float factor); // Generate image: white noise +RLAPI Image GenImageCellular(int width, int height, int tileSize); // Generate image: cellular algorithm. Bigger tileSize means bigger cells + // Texture2D configuration functions RLAPI void GenTextureMipmaps(Texture2D *texture); // Generate GPU mipmaps for a texture RLAPI void SetTextureFilter(Texture2D texture, int filterMode); // Set texture scaling filter mode diff --git a/src/textures.c b/src/textures.c index d249d2be..99392516 100644 --- a/src/textures.c +++ b/src/textures.c @@ -1431,6 +1431,148 @@ void ImageColorBrightness(Image *image, int brightness) } #endif // SUPPORT_IMAGE_MANIPULATION +// Generate image: vertical gradient +Image GenImageGradientV(int width, int height, Color top, Color bottom) +{ + Color *pixels = (Color *)malloc(width*height*sizeof(Color)); + + for (int j = 0; j < height; j++) + { + float factor = (float)j / (float)height; + for (int i = 0; i < width; i++) + { + pixels[j*width + i].r = (int)((float)bottom.r * factor + (float)top.r * (1.f - factor)); + pixels[j*width + i].g = (int)((float)bottom.g * factor + (float)top.g * (1.f - factor)); + pixels[j*width + i].b = (int)((float)bottom.b * factor + (float)top.b * (1.f - factor)); + pixels[j*width + i].a = (int)((float)bottom.a * factor + (float)top.a * (1.f - factor)); + } + } + + Image image = LoadImageEx(pixels, width, height); + free(pixels); + + return image; +} + +// Generate image: horizontal gradient +Image GenImageGradientH(int width, int height, Color left, Color right) +{ + Color *pixels = (Color *)malloc(width*height*sizeof(Color)); + + for (int i = 0; i < width; i++) + { + float factor = (float)i / (float)width; + for (int j = 0; j < height; j++) + { + pixels[j*width + i].r = (int)((float)right.r * factor + (float)left.r * (1.f - factor)); + pixels[j*width + i].g = (int)((float)right.g * factor + (float)left.g * (1.f - factor)); + pixels[j*width + i].b = (int)((float)right.b * factor + (float)left.b * (1.f - factor)); + pixels[j*width + i].a = (int)((float)right.a * factor + (float)left.a * (1.f - factor)); + } + } + + Image image = LoadImageEx(pixels, width, height); + free(pixels); + + return image; +} + +// Generate image: checked +Image GenImageChecked(int width, int height, int checksX, int checksY, Color col1, Color col2) +{ + Color *pixels = (Color *)malloc(width*height*sizeof(Color)); + + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + if ((x/checksX + y/checksY) % 2 == 0) pixels[y*width + x] = col1; + else pixels[y*width + x] = col2; + } + } + + Image image = LoadImageEx(pixels, width, height); + free(pixels); + + return image; +} + +// Generate image: white noise +Image GenImageWhiteNoise(int width, int height, float factor) +{ + Color *pixels = (Color *)malloc(width*height*sizeof(Color)); + + for (int i = 0; i < width*height; i++) + { + if (GetRandomValue(0, 99) < (int)(factor * 100.f)) pixels[i] = WHITE; + else pixels[i] = BLACK; + } + + Image image = LoadImageEx(pixels, width, height); + free(pixels); + + return image; +} + +// Generate image: cellular algorithm. Bigger tileSize means bigger cells +Image GenImageCellular(int width, int height, int tileSize) +{ + Color *pixels = (Color*)malloc(width*height*sizeof(Color)); + + int seeds_per_row = width / tileSize; + int seeds_per_col = height / tileSize; + int seeds_count = seeds_per_row * seeds_per_col; + + Vector2* seeds = (Vector2*)malloc(seeds_count * sizeof(Vector2)); + + for (int i = 0; i < seeds_count; i++) + { + int y = (i / seeds_per_row) * tileSize + GetRandomValue(0, tileSize-1); + int x = (i % seeds_per_row) * tileSize + GetRandomValue(0, tileSize-1); + seeds[i] = (Vector2){x, y}; + } + + for (int y = 0; y < height; y++) + { + int tile_y = y / tileSize; + for (int x = 0; x < width; x++) + { + int tile_x = x / tileSize; + + float min_distance = strtod("Inf", NULL); + + // Check all adjacent tiles + for (int i = -1; i < 2; i++) + { + if (tile_x + i < 0 || tile_x + i >= seeds_per_row) continue; + + for (int j = -1; j < 2; j++) + { + if (tile_y + j < 0 || tile_y + j >= seeds_per_col) continue; + + Vector2 neighbor_seed = seeds[(tile_y+j) * seeds_per_row + tile_x+i]; + + float dist = hypot(x - (int)neighbor_seed.x, y - (int)neighbor_seed.y); + min_distance = fmin(min_distance, dist); + } + } + + // I made this up but it seems to give good results at all tile sizes + int intensity = (int)(min_distance * 256.f / tileSize); + if (intensity > 255) intensity = 255; + + Color c = {intensity, intensity, intensity, 255}; + pixels[y*width + x] = c; + } + } + free(seeds); + + Image image = LoadImageEx(pixels, width, height); + free(pixels); + + return image; +} + // Generate GPU mipmaps for a texture void GenTextureMipmaps(Texture2D *texture) { @@ -2250,4 +2392,4 @@ static Image LoadASTC(const char *fileName) return image; } -#endif \ No newline at end of file +#endif