From ea0853d23dcb2d77e948b5cfd7abf2a907c349c9 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Thu, 1 Feb 2024 14:21:32 -0800 Subject: [PATCH] Added an HDR gradient test to testcolorspace --- test/testcolorspace.c | 174 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 173 insertions(+), 1 deletion(-) diff --git a/test/testcolorspace.c b/test/testcolorspace.c index 07ce0d17d..211636408 100644 --- a/test/testcolorspace.c +++ b/test/testcolorspace.c @@ -32,7 +32,7 @@ static SDL_Colorspace colorspace = SDL_COLORSPACE_SRGB; static const char *colorspace_name = "sRGB"; static int renderer_count = 0; static int renderer_index = 0; -static int stage_count = 4; +static int stage_count = 6; static int stage_index = 0; static int done; @@ -144,6 +144,20 @@ static void DrawText(float x, float y, const char *fmt, ...) SDL_free(text); } +static void DrawTextWhite(float x, float y, const char *fmt, ...) +{ + char *text; + + va_list ap; + va_start(ap, fmt); + SDL_vasprintf(&text, fmt, ap); + va_end(ap); + + SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); + SDLTest_DrawString(renderer, x, y, text); + SDL_free(text); +} + static void RenderClearBackground(void) { /* Draw a 50% gray background. @@ -316,6 +330,158 @@ static void RenderBlendTexture(void) SDL_DestroyTexture(b); } +static void DrawGradient(float x, float y, float width, float height, float start, float end) +{ + float xy[8]; + const int xy_stride = 2 * sizeof(float); + SDL_FColor color[4]; + const int color_stride = sizeof(SDL_FColor); + const int num_vertices = 4; + const int indices[6] = { 0, 1, 2, 0, 2, 3 }; + const int num_indices = 6; + const int size_indices = 4; + float minx, miny, maxx, maxy; + SDL_FColor min_color = { start, start, start, 1.0f }; + SDL_FColor max_color = { end, end, end, 1.0f }; + + minx = x; + miny = y; + maxx = minx + width; + maxy = miny + height; + + xy[0] = minx; + xy[1] = miny; + + xy[2] = maxx; + xy[3] = miny; + + xy[4] = maxx; + xy[5] = maxy; + + xy[6] = minx; + xy[7] = maxy; + + color[0] = min_color; + color[1] = max_color; + color[2] = max_color; + color[3] = min_color; + + SDL_RenderGeometryRaw(renderer, NULL, xy, xy_stride, color, color_stride, NULL, 0, num_vertices, indices, num_indices, size_indices); +} + +static void RenderGradientDrawing(void) +{ + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); + SDL_RenderClear(renderer); + + float x = TEXT_START_X; + float y = TEXT_START_Y; + DrawTextWhite(x, y, "%s %s", renderer_name, colorspace_name); + y += TEXT_LINE_ADVANCE; + DrawTextWhite(x, y, "Test: Draw SDR and HDR gradients"); + y += TEXT_LINE_ADVANCE; + + y += TEXT_LINE_ADVANCE; + + DrawTextWhite(x, y, "SDR mathematically linear gradient (%d nits)", 80); + y += TEXT_LINE_ADVANCE; + DrawGradient(x, y, WINDOW_WIDTH - 2 * x, 64.0f, 0.0f, 1.0f); + y += 64.0f; + + y += TEXT_LINE_ADVANCE; + y += TEXT_LINE_ADVANCE; + + DrawTextWhite(x, y, "HDR mathematically linear gradient (%d nits)", 400); + y += TEXT_LINE_ADVANCE; + SDL_SetRenderDrawColorspace(renderer, SDL_COLORSPACE_SCRGB); + DrawGradient(x, y, WINDOW_WIDTH - 2 * x, 64.0f, 0.0f, 5.0f); + SDL_SetRenderDrawColorspace(renderer, SDL_COLORSPACE_SRGB); + y += 64.0f; + + y += TEXT_LINE_ADVANCE; + y += TEXT_LINE_ADVANCE; + + DrawTextWhite(x, y, "HDR mathematically linear gradient (%d nits)", 1000); + y += TEXT_LINE_ADVANCE; + SDL_SetRenderDrawColorspace(renderer, SDL_COLORSPACE_SCRGB); + DrawGradient(x, y, WINDOW_WIDTH - 2 * x, 64.0f, 0.0f, 12.5f); + SDL_SetRenderDrawColorspace(renderer, SDL_COLORSPACE_SRGB); + y += 64.0f; +} + +static SDL_Texture *CreateGradientTexture(int width, float start, float end) +{ + SDL_Texture *texture; + float *pixels; + + texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA128_FLOAT, SDL_TEXTUREACCESS_STATIC, width, 1); + if (!texture) { + return NULL; + } + + pixels = (float *)SDL_malloc(width * sizeof(float) * 4); + if (pixels) { + int i; + float length = (end - start); + + for (i = 0; i < width; ++i) { + /* Use a 2.4 gamma function to create a perceptually linear gradient */ + float v = SDL_powf(start + (length * i) / width, 2.4f); + pixels[i * 4 + 0] = v; + pixels[i * 4 + 1] = v; + pixels[i * 4 + 2] = v; + pixels[i * 4 + 3] = 1.0f; + } + SDL_UpdateTexture(texture, NULL, pixels, width * sizeof(float) * 4); + SDL_free(pixels); + } + return texture; +} + +static void DrawGradientTexture(float x, float y, float width, float height, float start, float end) +{ + SDL_FRect rect = { x, y, width, height }; + SDL_Texture *texture = CreateGradientTexture((int)width, start, end); + SDL_RenderTexture(renderer, texture, NULL, &rect); + SDL_DestroyTexture(texture); +} + +static void RenderGradientTexture(void) +{ + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); + SDL_RenderClear(renderer); + + float x = TEXT_START_X; + float y = TEXT_START_Y; + DrawTextWhite(x, y, "%s %s", renderer_name, colorspace_name); + y += TEXT_LINE_ADVANCE; + DrawTextWhite(x, y, "Test: Draw SDR and HDR gradients"); + y += TEXT_LINE_ADVANCE; + + y += TEXT_LINE_ADVANCE; + + DrawTextWhite(x, y, "SDR perceptually linear gradient (%d nits)", 80); + y += TEXT_LINE_ADVANCE; + DrawGradientTexture(x, y, WINDOW_WIDTH - 2 * x, 64.0f, 0.0f, 1.0f); + y += 64.0f; + + y += TEXT_LINE_ADVANCE; + y += TEXT_LINE_ADVANCE; + + DrawTextWhite(x, y, "HDR perceptually linear gradient (%d nits)", 400); + y += TEXT_LINE_ADVANCE; + DrawGradientTexture(x, y, WINDOW_WIDTH - 2 * x, 64.0f, 0.0f, 5.0f); + y += 64.0f; + + y += TEXT_LINE_ADVANCE; + y += TEXT_LINE_ADVANCE; + + DrawTextWhite(x, y, "HDR perceptually linear gradient (%d nits)", 1000); + y += TEXT_LINE_ADVANCE; + DrawGradientTexture(x, y, WINDOW_WIDTH - 2 * x, 64.0f, 0.0f, 12.5f); + y += 64.0f; +} + static void loop(void) { SDL_Event event; @@ -364,6 +530,12 @@ static void loop(void) case 3: RenderBlendTexture(); break; + case 4: + RenderGradientDrawing(); + break; + case 5: + RenderGradientTexture(); + break; } SDL_RenderPresent(renderer);