2024-01-30 10:32:27 +08:00
|
|
|
/*
|
|
|
|
Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
|
|
|
|
|
|
|
|
This software is provided 'as-is', without any express or implied
|
|
|
|
warranty. In no event will the authors be held liable for any damages
|
|
|
|
arising from the use of this software.
|
|
|
|
|
|
|
|
Permission is granted to anyone to use this software for any purpose,
|
|
|
|
including commercial applications, and to alter it and redistribute it
|
|
|
|
freely.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <SDL3/SDL.h>
|
|
|
|
#include <SDL3/SDL_test.h>
|
|
|
|
#include <SDL3/SDL_main.h>
|
|
|
|
|
|
|
|
#ifdef SDL_PLATFORM_EMSCRIPTEN
|
|
|
|
#include <emscripten/emscripten.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define WINDOW_WIDTH 640
|
|
|
|
#define WINDOW_HEIGHT 480
|
|
|
|
|
|
|
|
#define TEXT_START_X 6.0f
|
|
|
|
#define TEXT_START_Y 6.0f
|
|
|
|
#define TEXT_LINE_ADVANCE FONT_CHARACTER_SIZE * 2
|
|
|
|
|
|
|
|
static SDL_Window *window;
|
|
|
|
static SDL_Renderer *renderer;
|
|
|
|
static const char *renderer_name;
|
2024-02-01 09:25:25 +08:00
|
|
|
static SDL_Colorspace colorspace = SDL_COLORSPACE_SRGB;
|
|
|
|
static const char *colorspace_name = "sRGB";
|
2024-01-30 10:32:27 +08:00
|
|
|
static int renderer_count = 0;
|
|
|
|
static int renderer_index = 0;
|
|
|
|
static int stage_index = 0;
|
|
|
|
static int done;
|
2024-02-20 00:45:02 +08:00
|
|
|
static float HDR_headroom = 1.0f;
|
2024-02-06 17:53:03 +08:00
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
StageClearBackground,
|
|
|
|
StageDrawBackground,
|
2024-09-12 03:54:07 +08:00
|
|
|
StageTextureBackground,
|
|
|
|
StageTargetBackground,
|
2024-02-06 17:53:03 +08:00
|
|
|
StageBlendDrawing,
|
|
|
|
StageBlendTexture,
|
|
|
|
StageGradientDrawing,
|
|
|
|
StageGradientTexture,
|
|
|
|
StageCount
|
|
|
|
};
|
2024-01-30 10:32:27 +08:00
|
|
|
|
|
|
|
static void FreeRenderer(void)
|
|
|
|
{
|
|
|
|
SDLTest_CleanupTextDrawing();
|
|
|
|
SDL_DestroyRenderer(renderer);
|
|
|
|
renderer = NULL;
|
|
|
|
}
|
|
|
|
|
2024-02-17 09:36:11 +08:00
|
|
|
static void UpdateHDRState(void)
|
|
|
|
{
|
|
|
|
SDL_PropertiesID props;
|
2024-09-18 22:52:28 +08:00
|
|
|
bool HDR_enabled;
|
2024-02-17 09:36:11 +08:00
|
|
|
|
2024-06-18 07:23:10 +08:00
|
|
|
props = SDL_GetWindowProperties(window);
|
2024-09-18 22:52:28 +08:00
|
|
|
HDR_enabled = SDL_GetBooleanProperty(props, SDL_PROP_WINDOW_HDR_ENABLED_BOOLEAN, false);
|
2024-02-17 09:36:11 +08:00
|
|
|
|
|
|
|
SDL_Log("HDR %s\n", HDR_enabled ? "enabled" : "disabled");
|
|
|
|
|
|
|
|
if (HDR_enabled) {
|
|
|
|
props = SDL_GetRendererProperties(renderer);
|
2024-02-20 00:45:02 +08:00
|
|
|
if (SDL_GetNumberProperty(props, SDL_PROP_RENDERER_OUTPUT_COLORSPACE_NUMBER, SDL_COLORSPACE_SRGB) != SDL_COLORSPACE_SRGB_LINEAR) {
|
|
|
|
SDL_Log("Run with --colorspace linear to display HDR colors\n");
|
2024-02-17 09:36:11 +08:00
|
|
|
}
|
2024-02-20 00:45:02 +08:00
|
|
|
HDR_headroom = SDL_GetFloatProperty(props, SDL_PROP_RENDERER_HDR_HEADROOM_FLOAT, 1.0f);
|
2024-02-17 09:36:11 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-30 10:32:27 +08:00
|
|
|
static void CreateRenderer(void)
|
|
|
|
{
|
|
|
|
SDL_PropertiesID props;
|
|
|
|
|
|
|
|
props = SDL_CreateProperties();
|
2024-07-13 00:39:58 +08:00
|
|
|
SDL_SetPointerProperty(props, SDL_PROP_RENDERER_CREATE_WINDOW_POINTER, window);
|
2024-01-30 10:32:27 +08:00
|
|
|
SDL_SetStringProperty(props, SDL_PROP_RENDERER_CREATE_NAME_STRING, SDL_GetRenderDriver(renderer_index));
|
2024-02-01 09:25:25 +08:00
|
|
|
SDL_SetNumberProperty(props, SDL_PROP_RENDERER_CREATE_OUTPUT_COLORSPACE_NUMBER, colorspace);
|
2024-01-30 10:32:27 +08:00
|
|
|
renderer = SDL_CreateRendererWithProperties(props);
|
|
|
|
SDL_DestroyProperties(props);
|
|
|
|
if (!renderer) {
|
|
|
|
SDL_Log("Couldn't create renderer: %s\n", SDL_GetError());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-06-04 10:26:43 +08:00
|
|
|
renderer_name = SDL_GetRendererName(renderer);
|
|
|
|
SDL_Log("Created renderer %s\n", renderer_name);
|
2024-02-06 15:20:43 +08:00
|
|
|
|
2024-02-17 09:36:11 +08:00
|
|
|
UpdateHDRState();
|
2024-01-30 10:32:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void NextRenderer( void )
|
|
|
|
{
|
|
|
|
if (renderer_count <= 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
++renderer_index;
|
|
|
|
if (renderer_index == renderer_count) {
|
|
|
|
renderer_index = 0;
|
|
|
|
}
|
|
|
|
FreeRenderer();
|
|
|
|
CreateRenderer();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void PrevRenderer(void)
|
|
|
|
{
|
|
|
|
if (renderer_count <= 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
--renderer_index;
|
|
|
|
if (renderer_index == -1) {
|
|
|
|
renderer_index += renderer_count;
|
|
|
|
}
|
|
|
|
FreeRenderer();
|
|
|
|
CreateRenderer();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void NextStage(void)
|
|
|
|
{
|
|
|
|
++stage_index;
|
2024-02-06 17:53:03 +08:00
|
|
|
if (stage_index == StageCount) {
|
2024-01-30 10:32:27 +08:00
|
|
|
stage_index = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void PrevStage(void)
|
|
|
|
{
|
|
|
|
--stage_index;
|
|
|
|
if (stage_index == -1) {
|
2024-02-06 17:53:03 +08:00
|
|
|
stage_index += StageCount;
|
2024-01-30 10:32:27 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-18 22:52:28 +08:00
|
|
|
static bool ReadPixel(int x, int y, SDL_Color *c)
|
2024-01-30 10:32:27 +08:00
|
|
|
{
|
2024-02-04 02:18:12 +08:00
|
|
|
SDL_Surface *surface;
|
2024-01-30 10:32:27 +08:00
|
|
|
SDL_Rect r;
|
2024-09-18 22:52:28 +08:00
|
|
|
bool result = false;
|
2024-02-04 02:18:12 +08:00
|
|
|
|
2024-01-30 10:32:27 +08:00
|
|
|
r.x = x;
|
|
|
|
r.y = y;
|
|
|
|
r.w = 1;
|
|
|
|
r.h = 1;
|
2024-02-04 02:18:12 +08:00
|
|
|
|
|
|
|
surface = SDL_RenderReadPixels(renderer, &r);
|
|
|
|
if (surface) {
|
2024-09-12 04:25:00 +08:00
|
|
|
/* Don't tonemap back to SDR, our source content was SDR */
|
|
|
|
SDL_SetStringProperty(SDL_GetSurfaceProperties(surface), SDL_PROP_SURFACE_TONEMAP_OPERATOR_STRING, "*=1");
|
|
|
|
|
2024-08-23 08:33:49 +08:00
|
|
|
if (SDL_ReadSurfacePixel(surface, 0, 0, &c->r, &c->g, &c->b, &c->a)) {
|
2024-09-18 22:52:28 +08:00
|
|
|
result = true;
|
2024-02-04 02:18:12 +08:00
|
|
|
} else {
|
|
|
|
SDL_Log("Couldn't read pixel: %s\n", SDL_GetError());
|
|
|
|
}
|
|
|
|
SDL_DestroySurface(surface);
|
|
|
|
} else {
|
2024-01-30 10:32:27 +08:00
|
|
|
SDL_Log("Couldn't read back pixels: %s\n", SDL_GetError());
|
|
|
|
}
|
2024-02-04 02:18:12 +08:00
|
|
|
return result;
|
2024-01-30 10:32:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void DrawText(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 + 1.0f, y + 1.0f, text);
|
|
|
|
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
|
|
|
|
SDLTest_DrawString(renderer, x, y, text);
|
|
|
|
SDL_free(text);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void RenderClearBackground(void)
|
|
|
|
{
|
|
|
|
/* Draw a 50% gray background.
|
|
|
|
* This will be darker when using sRGB colors and lighter using linear colors
|
|
|
|
*/
|
|
|
|
SDL_SetRenderDrawColor(renderer, 128, 128, 128, 255);
|
|
|
|
SDL_RenderClear(renderer);
|
|
|
|
|
|
|
|
/* Check the renderered pixels */
|
|
|
|
SDL_Color c;
|
|
|
|
if (!ReadPixel(0, 0, &c)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
float x = TEXT_START_X;
|
|
|
|
float y = TEXT_START_Y;
|
2024-02-01 09:25:25 +08:00
|
|
|
DrawText(x, y, "%s %s", renderer_name, colorspace_name);
|
2024-01-30 10:32:27 +08:00
|
|
|
y += TEXT_LINE_ADVANCE;
|
|
|
|
DrawText(x, y, "Test: Clear 50%% Gray Background");
|
|
|
|
y += TEXT_LINE_ADVANCE;
|
|
|
|
DrawText(x, y, "Background color written: 0x808080, read: 0x%.2x%.2x%.2x", c.r, c.g, c.b);
|
|
|
|
y += TEXT_LINE_ADVANCE;
|
|
|
|
if (c.r != 128) {
|
|
|
|
DrawText(x, y, "Incorrect background color, unknown reason");
|
|
|
|
y += TEXT_LINE_ADVANCE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void RenderDrawBackground(void)
|
|
|
|
{
|
|
|
|
/* Draw a 50% gray background.
|
|
|
|
* This will be darker when using sRGB colors and lighter using linear colors
|
|
|
|
*/
|
|
|
|
SDL_SetRenderDrawColor(renderer, 128, 128, 128, 255);
|
|
|
|
SDL_RenderFillRect(renderer, NULL);
|
|
|
|
|
|
|
|
/* Check the renderered pixels */
|
|
|
|
SDL_Color c;
|
|
|
|
if (!ReadPixel(0, 0, &c)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
float x = TEXT_START_X;
|
|
|
|
float y = TEXT_START_Y;
|
2024-02-01 09:25:25 +08:00
|
|
|
DrawText(x, y, "%s %s", renderer_name, colorspace_name);
|
2024-01-30 10:32:27 +08:00
|
|
|
y += TEXT_LINE_ADVANCE;
|
|
|
|
DrawText(x, y, "Test: Draw 50%% Gray Background");
|
|
|
|
y += TEXT_LINE_ADVANCE;
|
|
|
|
DrawText(x, y, "Background color written: 0x808080, read: 0x%.2x%.2x%.2x", c.r, c.g, c.b);
|
|
|
|
y += TEXT_LINE_ADVANCE;
|
|
|
|
if (c.r != 128) {
|
|
|
|
DrawText(x, y, "Incorrect background color, unknown reason");
|
|
|
|
y += TEXT_LINE_ADVANCE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-12 03:54:07 +08:00
|
|
|
static SDL_Texture *CreateGrayTexture(void)
|
|
|
|
{
|
|
|
|
SDL_Texture *texture;
|
|
|
|
Uint8 pixels[4];
|
|
|
|
|
|
|
|
/* Floating point textures are in the linear colorspace by default */
|
|
|
|
texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_STATIC, 1, 1);
|
|
|
|
if (!texture) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
pixels[0] = 128;
|
|
|
|
pixels[1] = 128;
|
|
|
|
pixels[2] = 128;
|
|
|
|
pixels[3] = 255;
|
|
|
|
SDL_UpdateTexture(texture, NULL, pixels, sizeof(pixels));
|
|
|
|
|
|
|
|
return texture;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void RenderTextureBackground(void)
|
|
|
|
{
|
|
|
|
/* Fill the background with a 50% gray texture.
|
|
|
|
* This will be darker when using sRGB colors and lighter using linear colors
|
|
|
|
*/
|
|
|
|
SDL_Texture *texture = CreateGrayTexture();
|
|
|
|
SDL_RenderTexture(renderer, texture, NULL, NULL);
|
|
|
|
SDL_DestroyTexture(texture);
|
|
|
|
|
|
|
|
/* Check the renderered pixels */
|
|
|
|
SDL_Color c;
|
|
|
|
if (!ReadPixel(0, 0, &c)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
float x = TEXT_START_X;
|
|
|
|
float y = TEXT_START_Y;
|
|
|
|
DrawText(x, y, "%s %s", renderer_name, colorspace_name);
|
|
|
|
y += TEXT_LINE_ADVANCE;
|
|
|
|
DrawText(x, y, "Test: Fill 50%% Gray Texture");
|
|
|
|
y += TEXT_LINE_ADVANCE;
|
|
|
|
DrawText(x, y, "Background color written: 0x808080, read: 0x%.2x%.2x%.2x", c.r, c.g, c.b);
|
|
|
|
y += TEXT_LINE_ADVANCE;
|
|
|
|
if (c.r != 128) {
|
|
|
|
DrawText(x, y, "Incorrect background color, unknown reason");
|
|
|
|
y += TEXT_LINE_ADVANCE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void RenderTargetBackground(void)
|
|
|
|
{
|
|
|
|
/* Fill the background with a 50% gray texture.
|
|
|
|
* This will be darker when using sRGB colors and lighter using linear colors
|
|
|
|
*/
|
|
|
|
SDL_Texture *target = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_TARGET, 1, 1);
|
|
|
|
SDL_Texture *texture = CreateGrayTexture();
|
|
|
|
|
|
|
|
/* Fill the render target with the gray texture */
|
|
|
|
SDL_SetRenderTarget(renderer, target);
|
|
|
|
SDL_RenderTexture(renderer, texture, NULL, NULL);
|
|
|
|
SDL_DestroyTexture(texture);
|
|
|
|
|
|
|
|
/* Fill the output with the render target */
|
|
|
|
SDL_SetRenderTarget(renderer, NULL);
|
|
|
|
SDL_RenderTexture(renderer, target, NULL, NULL);
|
|
|
|
SDL_DestroyTexture(target);
|
|
|
|
|
|
|
|
/* Check the renderered pixels */
|
|
|
|
SDL_Color c;
|
|
|
|
if (!ReadPixel(0, 0, &c)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
float x = TEXT_START_X;
|
|
|
|
float y = TEXT_START_Y;
|
|
|
|
DrawText(x, y, "%s %s", renderer_name, colorspace_name);
|
|
|
|
y += TEXT_LINE_ADVANCE;
|
|
|
|
DrawText(x, y, "Test: Fill 50%% Gray Render Target");
|
|
|
|
y += TEXT_LINE_ADVANCE;
|
|
|
|
DrawText(x, y, "Background color written: 0x808080, read: 0x%.2x%.2x%.2x", c.r, c.g, c.b);
|
|
|
|
y += TEXT_LINE_ADVANCE;
|
|
|
|
if (c.r != 128) {
|
|
|
|
DrawText(x, y, "Incorrect background color, unknown reason");
|
|
|
|
y += TEXT_LINE_ADVANCE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-30 10:32:27 +08:00
|
|
|
static void RenderBlendDrawing(void)
|
|
|
|
{
|
|
|
|
SDL_Color a = { 238, 70, 166, 255 }; /* red square */
|
|
|
|
SDL_Color b = { 147, 255, 0, 255 }; /* green square */
|
|
|
|
SDL_FRect rect;
|
|
|
|
|
|
|
|
/* Draw a green square blended over a red square
|
|
|
|
* This will have different effects based on whether sRGB colorspaces and sRGB vs linear blending is used.
|
|
|
|
*/
|
|
|
|
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
|
|
|
|
SDL_RenderClear(renderer);
|
|
|
|
rect.x = WINDOW_WIDTH / 3;
|
|
|
|
rect.y = 0;
|
|
|
|
rect.w = WINDOW_WIDTH / 3;
|
|
|
|
rect.h = WINDOW_HEIGHT;
|
|
|
|
SDL_SetRenderDrawColor(renderer, a.r, a.g, a.b, a.a);
|
|
|
|
SDL_RenderFillRect(renderer, &rect);
|
|
|
|
|
|
|
|
rect.x = 0;
|
|
|
|
rect.y = WINDOW_HEIGHT / 3;
|
|
|
|
rect.w = WINDOW_WIDTH;
|
|
|
|
rect.h = WINDOW_HEIGHT / 6;
|
|
|
|
SDL_SetRenderDrawColor(renderer, b.r, b.g, b.b, b.a);
|
|
|
|
SDL_RenderFillRect(renderer, &rect);
|
|
|
|
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
|
|
|
|
SDL_SetRenderDrawColor(renderer, b.r, b.g, b.b, 128);
|
|
|
|
rect.y += WINDOW_HEIGHT / 6;
|
|
|
|
SDL_RenderFillRect(renderer, &rect);
|
|
|
|
|
|
|
|
SDL_Color ar, br, cr;
|
|
|
|
if (!ReadPixel(WINDOW_WIDTH / 2, 0, &ar) ||
|
|
|
|
!ReadPixel(WINDOW_WIDTH / 2, WINDOW_HEIGHT / 3, &br) ||
|
|
|
|
!ReadPixel(WINDOW_WIDTH / 2, WINDOW_HEIGHT / 2, &cr)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
float x = TEXT_START_X;
|
|
|
|
float y = TEXT_START_Y;
|
2024-02-01 09:25:25 +08:00
|
|
|
DrawText(x, y, "%s %s", renderer_name, colorspace_name);
|
2024-01-30 10:32:27 +08:00
|
|
|
y += TEXT_LINE_ADVANCE;
|
2024-02-03 04:09:37 +08:00
|
|
|
DrawText(x, y, "Test: Draw Blending");
|
2024-01-30 10:32:27 +08:00
|
|
|
y += TEXT_LINE_ADVANCE;
|
|
|
|
if (cr.r == 199 && cr.g == 193 && cr.b == 121) {
|
2024-02-03 04:09:37 +08:00
|
|
|
DrawText(x, y, "Correct blend color, blending in linear space");
|
2024-01-30 10:32:27 +08:00
|
|
|
} else if ((cr.r == 192 && cr.g == 163 && cr.b == 83) ||
|
|
|
|
(cr.r == 191 && cr.g == 162 && cr.b == 82)) {
|
2024-02-03 04:09:37 +08:00
|
|
|
DrawText(x, y, "Correct blend color, blending in sRGB space");
|
2024-02-01 23:53:19 +08:00
|
|
|
} else if (cr.r == 214 && cr.g == 156 && cr.b == 113) {
|
|
|
|
DrawText(x, y, "Incorrect blend color, blending in PQ space");
|
2024-01-30 10:32:27 +08:00
|
|
|
} else {
|
|
|
|
DrawText(x, y, "Incorrect blend color, unknown reason");
|
|
|
|
}
|
|
|
|
y += TEXT_LINE_ADVANCE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void RenderBlendTexture(void)
|
|
|
|
{
|
|
|
|
SDL_Color color_a = { 238, 70, 166, 255 }; /* red square */
|
|
|
|
SDL_Color color_b = { 147, 255, 0, 255 }; /* green square */
|
|
|
|
SDL_Texture *a;
|
|
|
|
SDL_Texture *b;
|
|
|
|
SDL_FRect rect;
|
|
|
|
|
|
|
|
/* Draw a green square blended over a red square
|
|
|
|
* This will have different effects based on whether sRGB colorspaces and sRGB vs linear blending is used.
|
|
|
|
*/
|
|
|
|
a = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_STATIC, 1, 1);
|
|
|
|
SDL_UpdateTexture(a, NULL, &color_a, sizeof(color_a));
|
|
|
|
b = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_STATIC, 1, 1);
|
|
|
|
SDL_UpdateTexture(b, NULL, &color_b, sizeof(color_b));
|
|
|
|
|
|
|
|
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
|
|
|
|
SDL_RenderClear(renderer);
|
|
|
|
rect.x = WINDOW_WIDTH / 3;
|
|
|
|
rect.y = 0;
|
|
|
|
rect.w = WINDOW_WIDTH / 3;
|
|
|
|
rect.h = WINDOW_HEIGHT;
|
|
|
|
SDL_RenderTexture(renderer, a, NULL, &rect);
|
|
|
|
|
|
|
|
rect.x = 0;
|
|
|
|
rect.y = WINDOW_HEIGHT / 3;
|
|
|
|
rect.w = WINDOW_WIDTH;
|
|
|
|
rect.h = WINDOW_HEIGHT / 6;
|
|
|
|
SDL_RenderTexture(renderer, b, NULL, &rect);
|
|
|
|
rect.y += WINDOW_HEIGHT / 6;
|
|
|
|
SDL_SetTextureBlendMode(b, SDL_BLENDMODE_BLEND);
|
|
|
|
SDL_SetTextureAlphaModFloat(b, 128 / 255.0f);
|
|
|
|
SDL_RenderTexture(renderer, b, NULL, &rect);
|
|
|
|
|
|
|
|
SDL_Color ar, br, cr;
|
|
|
|
if (!ReadPixel(WINDOW_WIDTH / 2, 0, &ar) ||
|
|
|
|
!ReadPixel(WINDOW_WIDTH / 2, WINDOW_HEIGHT / 3, &br) ||
|
|
|
|
!ReadPixel(WINDOW_WIDTH / 2, WINDOW_HEIGHT / 2, &cr)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
float x = TEXT_START_X;
|
|
|
|
float y = TEXT_START_Y;
|
2024-02-01 09:25:25 +08:00
|
|
|
DrawText(x, y, "%s %s", renderer_name, colorspace_name);
|
2024-01-30 10:32:27 +08:00
|
|
|
y += TEXT_LINE_ADVANCE;
|
2024-02-03 04:09:37 +08:00
|
|
|
DrawText(x, y, "Test: Texture Blending");
|
2024-01-30 10:32:27 +08:00
|
|
|
y += TEXT_LINE_ADVANCE;
|
|
|
|
if (cr.r == 199 && cr.g == 193 && cr.b == 121) {
|
2024-02-03 04:09:37 +08:00
|
|
|
DrawText(x, y, "Correct blend color, blending in linear space");
|
2024-01-30 10:32:27 +08:00
|
|
|
} else if ((cr.r == 192 && cr.g == 163 && cr.b == 83) ||
|
|
|
|
(cr.r == 191 && cr.g == 162 && cr.b == 82)) {
|
2024-02-03 04:09:37 +08:00
|
|
|
DrawText(x, y, "Correct blend color, blending in sRGB space");
|
2024-01-30 10:32:27 +08:00
|
|
|
} else {
|
|
|
|
DrawText(x, y, "Incorrect blend color, unknown reason");
|
|
|
|
}
|
|
|
|
y += TEXT_LINE_ADVANCE;
|
|
|
|
|
|
|
|
SDL_DestroyTexture(a);
|
|
|
|
SDL_DestroyTexture(b);
|
|
|
|
}
|
|
|
|
|
2024-02-02 06:21:32 +08:00
|
|
|
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;
|
|
|
|
|
Removed SDL_RenderGeometryRawFloat()
After discussion with @ocornut, SDL_RenderGeometryRaw() will take floating point colors and conversion from 8-bit color can happen on the application side. We can always add an 8-bit color fast path in the future if we need it on handheld platforms.
If you need code to do this in your application, you can use the following:
int SDL_RenderGeometryRaw8BitColor(SDL_Renderer *renderer, SDL_Texture *texture, const float *xy, int xy_stride, const SDL_Color *color, int color_stride, const float *uv, int uv_stride, int num_vertices, const void *indices, int num_indices, int size_indices)
{
int i, retval, isstack;
const Uint8 *color2 = (const Uint8 *)color;
SDL_FColor *color3;
if (num_vertices <= 0) {
return SDL_InvalidParamError("num_vertices");
}
if (!color) {
return SDL_InvalidParamError("color");
}
color3 = (SDL_FColor *)SDL_small_alloc(SDL_FColor, num_vertices, &isstack);
if (!color3) {
return -1;
}
for (i = 0; i < num_vertices; ++i) {
color3[i].r = color->r / 255.0f;
color3[i].g = color->g / 255.0f;
color3[i].b = color->b / 255.0f;
color3[i].a = color->a / 255.0f;
color2 += color_stride;
color = (const SDL_Color *)color2;
}
retval = SDL_RenderGeometryRaw(renderer, texture, xy, xy_stride, color3, sizeof(*color3), uv, uv_stride, num_vertices, indices, num_indices, size_indices);
SDL_small_free(color3, isstack);
return retval;
}
Fixes https://github.com/libsdl-org/SDL/issues/9009
2024-06-29 14:55:23 +08:00
|
|
|
SDL_RenderGeometryRaw(renderer, NULL, xy, xy_stride, color, color_stride, NULL, 0, num_vertices, indices, num_indices, size_indices);
|
2024-02-02 06:21:32 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void RenderGradientDrawing(void)
|
|
|
|
{
|
2024-02-20 00:45:02 +08:00
|
|
|
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
|
2024-02-02 06:21:32 +08:00
|
|
|
SDL_RenderClear(renderer);
|
|
|
|
|
|
|
|
float x = TEXT_START_X;
|
|
|
|
float y = TEXT_START_Y;
|
2024-02-20 00:45:02 +08:00
|
|
|
DrawText(x, y, "%s %s", renderer_name, colorspace_name);
|
2024-02-02 06:21:32 +08:00
|
|
|
y += TEXT_LINE_ADVANCE;
|
2024-02-20 00:45:02 +08:00
|
|
|
DrawText(x, y, "Test: Draw SDR and HDR gradients");
|
2024-02-02 06:21:32 +08:00
|
|
|
y += TEXT_LINE_ADVANCE;
|
|
|
|
|
|
|
|
y += TEXT_LINE_ADVANCE;
|
|
|
|
|
2024-02-20 00:45:02 +08:00
|
|
|
DrawText(x, y, "SDR gradient");
|
2024-02-02 06:21:32 +08:00
|
|
|
y += TEXT_LINE_ADVANCE;
|
2024-02-20 00:45:02 +08:00
|
|
|
DrawGradient(x, y, WINDOW_WIDTH - 2 * x, 64.0f, 0.0f, 1.0f);
|
2024-02-02 06:21:32 +08:00
|
|
|
y += 64.0f;
|
|
|
|
|
|
|
|
y += TEXT_LINE_ADVANCE;
|
|
|
|
y += TEXT_LINE_ADVANCE;
|
|
|
|
|
2024-02-20 00:45:02 +08:00
|
|
|
if (HDR_headroom > 1.0f) {
|
|
|
|
DrawText(x, y, "HDR gradient");
|
|
|
|
} else {
|
|
|
|
DrawText(x, y, "No HDR headroom, HDR and SDR gradient are the same");
|
|
|
|
}
|
2024-02-02 06:21:32 +08:00
|
|
|
y += TEXT_LINE_ADVANCE;
|
2024-02-20 00:45:02 +08:00
|
|
|
/* Drawing is in the sRGB colorspace, so we need to use the color scale, which is applied in linear space, to get into high dynamic range */
|
|
|
|
SDL_SetRenderColorScale(renderer, HDR_headroom);
|
|
|
|
DrawGradient(x, y, WINDOW_WIDTH - 2 * x, 64.0f, 0.0f, 1.0f);
|
2024-02-06 17:53:03 +08:00
|
|
|
SDL_SetRenderColorScale(renderer, 1.0f);
|
2024-02-02 06:21:32 +08:00
|
|
|
y += 64.0f;
|
|
|
|
}
|
|
|
|
|
|
|
|
static SDL_Texture *CreateGradientTexture(int width, float start, float end)
|
|
|
|
{
|
|
|
|
SDL_Texture *texture;
|
|
|
|
float *pixels;
|
|
|
|
|
2024-02-20 00:45:02 +08:00
|
|
|
/* Floating point textures are in the linear colorspace by default */
|
2024-02-02 06:21:32 +08:00
|
|
|
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) {
|
2024-02-03 04:09:37 +08:00
|
|
|
float v = (start + (length * i) / width);
|
2024-02-02 06:21:32 +08:00
|
|
|
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)
|
|
|
|
{
|
2024-02-20 00:45:02 +08:00
|
|
|
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
|
2024-02-02 06:21:32 +08:00
|
|
|
SDL_RenderClear(renderer);
|
|
|
|
|
|
|
|
float x = TEXT_START_X;
|
|
|
|
float y = TEXT_START_Y;
|
2024-02-20 00:45:02 +08:00
|
|
|
DrawText(x, y, "%s %s", renderer_name, colorspace_name);
|
2024-02-02 06:21:32 +08:00
|
|
|
y += TEXT_LINE_ADVANCE;
|
2024-02-20 00:45:02 +08:00
|
|
|
DrawText(x, y, "Test: Texture SDR and HDR gradients");
|
2024-02-02 06:21:32 +08:00
|
|
|
y += TEXT_LINE_ADVANCE;
|
|
|
|
|
2024-02-06 17:53:03 +08:00
|
|
|
y += TEXT_LINE_ADVANCE;
|
|
|
|
|
2024-02-20 00:45:02 +08:00
|
|
|
DrawText(x, y, "SDR gradient");
|
2024-02-06 17:53:03 +08:00
|
|
|
y += TEXT_LINE_ADVANCE;
|
2024-02-20 00:45:02 +08:00
|
|
|
DrawGradientTexture(x, y, WINDOW_WIDTH - 2 * x, 64.0f, 0.0f, 1.0f);
|
2024-02-02 06:21:32 +08:00
|
|
|
y += 64.0f;
|
|
|
|
|
|
|
|
y += TEXT_LINE_ADVANCE;
|
|
|
|
y += TEXT_LINE_ADVANCE;
|
|
|
|
|
2024-02-20 00:45:02 +08:00
|
|
|
if (HDR_headroom > 1.0f) {
|
|
|
|
DrawText(x, y, "HDR gradient");
|
|
|
|
} else {
|
|
|
|
DrawText(x, y, "No HDR headroom, HDR and SDR gradient are the same");
|
2024-02-06 17:53:03 +08:00
|
|
|
}
|
|
|
|
y += TEXT_LINE_ADVANCE;
|
2024-02-20 00:45:02 +08:00
|
|
|
/* The gradient texture is in the linear colorspace, so we can use the HDR_headroom value directly */
|
|
|
|
DrawGradientTexture(x, y, WINDOW_WIDTH - 2 * x, 64.0f, 0.0f, HDR_headroom);
|
2024-02-02 06:21:32 +08:00
|
|
|
y += 64.0f;
|
|
|
|
}
|
|
|
|
|
2024-01-30 10:32:27 +08:00
|
|
|
static void loop(void)
|
|
|
|
{
|
|
|
|
SDL_Event event;
|
|
|
|
|
|
|
|
/* Check for events */
|
|
|
|
while (SDL_PollEvent(&event)) {
|
|
|
|
if (event.type == SDL_EVENT_KEY_DOWN) {
|
2024-06-22 10:50:10 +08:00
|
|
|
switch (event.key.key) {
|
2024-01-30 10:32:27 +08:00
|
|
|
case SDLK_ESCAPE:
|
|
|
|
done = 1;
|
2024-03-19 00:56:22 +08:00
|
|
|
break;
|
2024-01-30 10:32:27 +08:00
|
|
|
case SDLK_SPACE:
|
|
|
|
case SDLK_RIGHT:
|
|
|
|
NextStage();
|
|
|
|
break;
|
|
|
|
case SDLK_LEFT:
|
|
|
|
PrevStage();
|
|
|
|
break;
|
|
|
|
case SDLK_DOWN:
|
|
|
|
NextRenderer();
|
|
|
|
break;
|
|
|
|
case SDLK_UP:
|
|
|
|
PrevRenderer();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2024-06-18 07:23:10 +08:00
|
|
|
} else if (event.type == SDL_EVENT_WINDOW_HDR_STATE_CHANGED) {
|
2024-02-17 09:36:11 +08:00
|
|
|
UpdateHDRState();
|
2024-01-30 10:32:27 +08:00
|
|
|
} else if (event.type == SDL_EVENT_QUIT) {
|
|
|
|
done = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-01 09:25:25 +08:00
|
|
|
if (renderer) {
|
|
|
|
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
|
|
|
|
SDL_RenderClear(renderer);
|
|
|
|
|
|
|
|
switch (stage_index) {
|
2024-02-06 17:53:03 +08:00
|
|
|
case StageClearBackground:
|
2024-02-01 09:25:25 +08:00
|
|
|
RenderClearBackground();
|
|
|
|
break;
|
2024-02-06 17:53:03 +08:00
|
|
|
case StageDrawBackground:
|
2024-02-01 09:25:25 +08:00
|
|
|
RenderDrawBackground();
|
|
|
|
break;
|
2024-09-12 03:54:07 +08:00
|
|
|
case StageTextureBackground:
|
|
|
|
RenderTextureBackground();
|
|
|
|
break;
|
|
|
|
case StageTargetBackground:
|
|
|
|
RenderTargetBackground();
|
|
|
|
break;
|
2024-02-06 17:53:03 +08:00
|
|
|
case StageBlendDrawing:
|
2024-02-01 09:25:25 +08:00
|
|
|
RenderBlendDrawing();
|
|
|
|
break;
|
2024-02-06 17:53:03 +08:00
|
|
|
case StageBlendTexture:
|
2024-02-01 09:25:25 +08:00
|
|
|
RenderBlendTexture();
|
|
|
|
break;
|
2024-02-06 17:53:03 +08:00
|
|
|
case StageGradientDrawing:
|
2024-02-02 06:21:32 +08:00
|
|
|
RenderGradientDrawing();
|
|
|
|
break;
|
2024-02-06 17:53:03 +08:00
|
|
|
case StageGradientTexture:
|
2024-02-02 06:21:32 +08:00
|
|
|
RenderGradientTexture();
|
|
|
|
break;
|
2024-02-01 09:25:25 +08:00
|
|
|
}
|
2024-01-30 10:32:27 +08:00
|
|
|
|
2024-02-01 09:25:25 +08:00
|
|
|
SDL_RenderPresent(renderer);
|
2024-01-30 10:32:27 +08:00
|
|
|
}
|
|
|
|
SDL_Delay(100);
|
|
|
|
|
|
|
|
#ifdef SDL_PLATFORM_EMSCRIPTEN
|
|
|
|
if (done) {
|
|
|
|
emscripten_cancel_main_loop();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2024-02-01 09:25:25 +08:00
|
|
|
static void LogUsage(const char *argv0)
|
|
|
|
{
|
|
|
|
SDL_Log("Usage: %s [--renderer renderer] [--colorspace colorspace]\n", argv0);
|
|
|
|
}
|
|
|
|
|
2024-01-30 10:32:27 +08:00
|
|
|
int main(int argc, char *argv[])
|
|
|
|
{
|
2024-02-01 09:25:25 +08:00
|
|
|
int return_code = 1;
|
2024-01-30 10:32:27 +08:00
|
|
|
int i;
|
|
|
|
|
2024-02-01 09:25:25 +08:00
|
|
|
for (i = 1; i < argc; ++i) {
|
|
|
|
if (SDL_strcmp(argv[i], "--renderer") == 0) {
|
|
|
|
if (argv[i + 1]) {
|
|
|
|
renderer_name = argv[i + 1];
|
|
|
|
++i;
|
|
|
|
} else {
|
|
|
|
LogUsage(argv[0]);
|
|
|
|
goto quit;
|
|
|
|
}
|
|
|
|
} else if (SDL_strcmp(argv[i], "--colorspace") == 0) {
|
|
|
|
if (argv[i + 1]) {
|
|
|
|
colorspace_name = argv[i + 1];
|
2024-02-01 23:53:19 +08:00
|
|
|
if (SDL_strcasecmp(colorspace_name, "sRGB") == 0) {
|
2024-02-01 09:25:25 +08:00
|
|
|
colorspace = SDL_COLORSPACE_SRGB;
|
2024-02-20 00:45:02 +08:00
|
|
|
} else if (SDL_strcasecmp(colorspace_name, "linear") == 0) {
|
|
|
|
colorspace = SDL_COLORSPACE_SRGB_LINEAR;
|
2024-02-02 02:41:15 +08:00
|
|
|
/* Not currently supported
|
2024-02-01 23:53:19 +08:00
|
|
|
} else if (SDL_strcasecmp(colorspace_name, "HDR10") == 0) {
|
2024-02-01 09:25:25 +08:00
|
|
|
colorspace = SDL_COLORSPACE_HDR10;
|
2024-02-02 02:41:15 +08:00
|
|
|
*/
|
2024-02-01 09:25:25 +08:00
|
|
|
} else {
|
|
|
|
SDL_Log("Unknown colorspace %s\n", argv[i + 1]);
|
|
|
|
goto quit;
|
|
|
|
}
|
|
|
|
++i;
|
|
|
|
} else {
|
|
|
|
LogUsage(argv[0]);
|
|
|
|
goto quit;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
LogUsage(argv[0]);
|
|
|
|
goto quit;
|
|
|
|
}
|
2024-01-30 10:32:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
window = SDL_CreateWindow("SDL colorspace test", WINDOW_WIDTH, WINDOW_HEIGHT, 0);
|
|
|
|
if (!window) {
|
|
|
|
SDL_Log("Couldn't create window: %s\n", SDL_GetError());
|
|
|
|
return_code = 2;
|
|
|
|
goto quit;
|
|
|
|
}
|
|
|
|
|
|
|
|
renderer_count = SDL_GetNumRenderDrivers();
|
|
|
|
SDL_Log("There are %d render drivers:\n", renderer_count);
|
|
|
|
for (i = 0; i < renderer_count; ++i) {
|
|
|
|
const char *name = SDL_GetRenderDriver(i);
|
|
|
|
|
2024-02-01 09:25:25 +08:00
|
|
|
if (renderer_name && SDL_strcasecmp(renderer_name, name) == 0) {
|
2024-01-30 10:32:27 +08:00
|
|
|
renderer_index = i;
|
|
|
|
}
|
|
|
|
SDL_Log(" %s\n", name);
|
|
|
|
}
|
|
|
|
CreateRenderer();
|
|
|
|
|
|
|
|
/* Main render loop */
|
|
|
|
done = 0;
|
|
|
|
|
|
|
|
#ifdef SDL_PLATFORM_EMSCRIPTEN
|
|
|
|
emscripten_set_main_loop(loop, 0, 1);
|
|
|
|
#else
|
|
|
|
while (!done) {
|
|
|
|
loop();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return_code = 0;
|
|
|
|
quit:
|
|
|
|
SDL_DestroyRenderer(renderer);
|
|
|
|
SDL_DestroyWindow(window);
|
|
|
|
SDL_Quit();
|
|
|
|
return return_code;
|
|
|
|
}
|