SDL: Generalize SDR white level handling into a color scale

From d4caef5b89266c4244c83c1de7132e319e1c774c Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Mon, 5 Feb 2024 23:20:43 -0800
Subject: [PATCH] Generalize SDR white level handling into a color scale

This gives applications better control over how and when light levels are adjusted when working with HDR content and display.
---
 include/SDL3/SDL_render.h                     |  32 +
 src/dynapi/SDL_dynapi.sym                     |   2 +
 src/dynapi/SDL_dynapi_overrides.h             |   2 +
 src/dynapi/SDL_dynapi_procs.h                 |   2 +
 src/render/SDL_render.c                       |  55 +-
 src/render/SDL_sysrender.h                    |   3 +
 src/render/direct3d/SDL_render_d3d.c          |  14 +-
 .../direct3d11/D3D11_PixelShader_Colors.h     | 322 +++---
 .../direct3d11/D3D11_PixelShader_Common.incl  |  43 +-
 .../direct3d11/D3D11_PixelShader_HDR10.h      | 508 +++++-----
 .../direct3d11/D3D11_PixelShader_HDR10.hlsl   |  15 +-
 .../direct3d11/D3D11_PixelShader_NV12.h       | 290 +++---
 .../direct3d11/D3D11_PixelShader_NV21.h       | 290 +++---
 .../direct3d11/D3D11_PixelShader_Textures.h   | 369 ++++---
 src/render/direct3d11/D3D11_PixelShader_YUV.h | 302 +++---
 src/render/direct3d11/SDL_render_d3d11.c      |  91 +-
 .../direct3d12/D3D12_PixelShader_Colors.h     | 419 ++++----
 .../direct3d12/D3D12_PixelShader_Common.incl  |  43 +-
 .../direct3d12/D3D12_PixelShader_HDR10.h      | 922 +++++++++---------
 .../direct3d12/D3D12_PixelShader_HDR10.hlsl   |  15 +-
 .../direct3d12/D3D12_PixelShader_NV12.h       | 579 +++++------
 .../direct3d12/D3D12_PixelShader_NV21.h       | 579 +++++------
 .../direct3d12/D3D12_PixelShader_Textures.h   | 560 +++++------
 src/render/direct3d12/D3D12_PixelShader_YUV.h | 591 +++++------
 src/render/direct3d12/SDL_render_d3d12.c      |  60 +-
 src/render/metal/SDL_render_metal.m           |  43 +-
 src/render/opengl/SDL_render_gl.c             |  29 +-
 src/render/opengles2/SDL_render_gles2.c       |  30 +-
 src/render/ps2/SDL_render_ps2.c               |  27 +-
 src/render/psp/SDL_render_psp.c               |  25 +-
 src/render/software/SDL_render_sw.c           |  25 +-
 src/render/vitagxm/SDL_render_vita_gxm.c      |  21 +-
 test/testcolorspace.c                         |  17 +
 test/testffmpeg.c                             |  20 +
 34 files changed, 3195 insertions(+), 3150 deletions(-)

diff --git a/include/SDL3/SDL_render.h b/include/SDL3/SDL_render.h
index 4e5157e5ccf9..7a0862dcb083 100644
--- a/include/SDL3/SDL_render.h
+++ b/include/SDL3/SDL_render.h
@@ -1459,6 +1459,38 @@ extern DECLSPEC int SDLCALL SDL_GetRenderDrawColor(SDL_Renderer *renderer, Uint8
  */
 extern DECLSPEC int SDLCALL SDL_GetRenderDrawColorFloat(SDL_Renderer *renderer, float *r, float *g, float *b, float *a);
 
+/**
+ * Set the color scale used for render operations.
+ *
+ * The color scale is an additional scale multiplied into the pixel color value while rendering. This can be used to adjust the brightness of colors during HDR rendering, or changing HDR video brightness when playing on an SDR display.
+ *
+ * The color scale does not affect the alpha channel, only the color brightness.
+ *
+ * \param renderer the rendering context
+ * \param scale the color scale value
+ * \returns 0 on success or a negative error code on failure; call
+ *          SDL_GetError() for more information.
+ *
+ * \since This function is available since SDL 3.0.0.
+ *
+ * \sa SDL_GetRenderColorScale
+ */
+extern DECLSPEC int SDLCALL SDL_SetRenderColorScale(SDL_Renderer *renderer, float scale);
+
+/**
+ * Get the color scale used for render operations.
+ *
+ * \param renderer the rendering context
+ * \param scale a pointer filled in with the current color scale value
+ * \returns 0 on success or a negative error code on failure; call
+ *          SDL_GetError() for more information.
+ *
+ * \since This function is available since SDL 3.0.0.
+ *
+ * \sa SDL_SetRenderColorScale
+ */
+extern DECLSPEC int SDLCALL SDL_GetRenderColorScale(SDL_Renderer *renderer, float *scale);
+
 /**
  * Set the blend mode used for drawing operations (Fill and Line).
  *
diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym
index 07f36e853532..c196aee418b9 100644
--- a/src/dynapi/SDL_dynapi.sym
+++ b/src/dynapi/SDL_dynapi.sym
@@ -967,6 +967,8 @@ SDL3_0.0.0 {
     SDL_GetSurfaceColorspace;
     SDL_ConvertSurfaceFormatAndColorspace;
     SDL_CopyProperties;
+    SDL_SetRenderColorScale;
+    SDL_GetRenderColorScale;
     # extra symbols go here (don't modify this line)
   local: *;
 };
diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h
index 208eb12382a3..2aa25f12be95 100644
--- a/src/dynapi/SDL_dynapi_overrides.h
+++ b/src/dynapi/SDL_dynapi_overrides.h
@@ -992,3 +992,5 @@
 #define SDL_GetSurfaceColorspace SDL_GetSurfaceColorspace_REAL
 #define SDL_ConvertSurfaceFormatAndColorspace SDL_ConvertSurfaceFormatAndColorspace_REAL
 #define SDL_CopyProperties SDL_CopyProperties_REAL
+#define SDL_SetRenderColorScale SDL_SetRenderColorScale_REAL
+#define SDL_GetRenderColorScale SDL_GetRenderColorScale_REAL
diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h
index d870d42c3c2c..6f93f2ff1185 100644
--- a/src/dynapi/SDL_dynapi_procs.h
+++ b/src/dynapi/SDL_dynapi_procs.h
@@ -1017,3 +1017,5 @@ SDL_DYNAPI_PROC(int,SDL_SetSurfaceColorspace,(SDL_Surface *a, SDL_Colorspace b),
 SDL_DYNAPI_PROC(int,SDL_GetSurfaceColorspace,(SDL_Surface *a, SDL_Colorspace *b),(a,b),return)
 SDL_DYNAPI_PROC(SDL_Surface*,SDL_ConvertSurfaceFormatAndColorspace,(SDL_Surface *a, Uint32 b, SDL_Colorspace c),(a,b,c),return)
 SDL_DYNAPI_PROC(int,SDL_CopyProperties,(SDL_PropertiesID a, SDL_PropertiesID b),(a,b),return)
+SDL_DYNAPI_PROC(int,SDL_SetRenderColorScale,(SDL_Renderer *a, float b),(a,b),return)
+SDL_DYNAPI_PROC(int,SDL_GetRenderColorScale,(SDL_Renderer *a, float *b),(a,b),return)
diff --git a/src/render/SDL_render.c b/src/render/SDL_render.c
index 58d6ece86625..2623fe5ef905 100644
--- a/src/render/SDL_render.c
+++ b/src/render/SDL_render.c
@@ -196,72 +196,72 @@ static SDL_INLINE void DebugLogRenderCommands(const SDL_RenderCommand *cmd)
                 break;
 
             case SDL_RENDERCMD_SETDRAWCOLOR:
-                SDL_Log(" %u. set draw color (first=%u, r=%d, g=%d, b=%d, a=%d)", i++,
+                SDL_Log(" %u. set draw color (first=%u, r=%d, g=%d, b=%d, a=%d, color_scale=%g)", i++,
                         (unsigned int) cmd->data.color.first,
                         (int) cmd->data.color.r, (int) cmd->data.color.g,
-                        (int) cmd->data.color.b, (int) cmd->data.color.a);
+                        (int) cmd->data.color.b, (int) cmd->data.color.a, cmd->data.color.color_scale);
                 break;
 
             case SDL_RENDERCMD_CLEAR:
-                SDL_Log(" %u. clear (first=%u, r=%d, g=%d, b=%d, a=%d)", i++,
+                SDL_Log(" %u. clear (first=%u, r=%d, g=%d, b=%d, a=%d, color_scale=%g)", i++,
                         (unsigned int) cmd->data.color.first,
                         (int) cmd->data.color.r, (int) cmd->data.color.g,
-                        (int) cmd->data.color.b, (int) cmd->data.color.a);
+                        (int) cmd->data.color.b, (int) cmd->data.color.a, cmd->data.color.color_scale);
                 break;
 
             case SDL_RENDERCMD_DRAW_POINTS:
-                SDL_Log(" %u. draw points (first=%u, count=%u, r=%d, g=%d, b=%d, a=%d, blend=%d)", i++,
+                SDL_Log(" %u. draw points (first=%u, count=%u, r=%d, g=%d, b=%d, a=%d, blend=%d, color_scale=%g)", i++,
                         (unsigned int) cmd->data.draw.first,
                         (unsigned int) cmd->data.draw.count,
                         (int) cmd->data.draw.r, (int) cmd->data.draw.g,
                         (int) cmd->data.draw.b, (int) cmd->data.draw.a,
-                        (int) cmd->data.draw.blend);
+                        (int) cmd->data.draw.blend, cmd->data.draw.color_scale);
                 break;
 
             case SDL_RENDERCMD_DRAW_LINES:
-                SDL_Log(" %u. draw lines (first=%u, count=%u, r=%d, g=%d, b=%d, a=%d, blend=%d)", i++,
+                SDL_Log(" %u. draw lines (first=%u, count=%u, r=%d, g=%d, b=%d, a=%d, blend=%d, color_scale=%g)", i++,
                         (unsigned int) cmd->data.draw.first,
                         (unsigned int) cmd->data.draw.count,
                         (int) cmd->data.draw.r, (int) cmd->data.draw.g,
                         (int) cmd->data.draw.b, (int) cmd->data.draw.a,
-                        (int) cmd->data.draw.blend);
+                        (int) cmd->data.draw.blend, cmd->data.draw.color_scale);
                 break;
 
             case SDL_RENDERCMD_FILL_RECTS:
-                SDL_Log(" %u. fill rects (first=%u, count=%u, r=%d, g=%d, b=%d, a=%d, blend=%d)", i++,
+                SDL_Log(" %u. fill rects (first=%u, count=%u, r=%d, g=%d, b=%d, a=%d, blend=%d, color_scale=%g)", i++,
                         (unsigned int) cmd->data.draw.first,
                         (unsigned int) cmd->data.draw.count,
                         (int) cmd->data.draw.r, (int) cmd->data.draw.g,
                         (int) cmd->data.draw.b, (int) cmd->data.draw.a,
-                        (int) cmd->data.draw.blend);
+                        (int) cmd->data.draw.blend, cmd->data.draw.color_scale);
                 break;
 
             case SDL_RENDERCMD_COPY:
-                SDL_Log(" %u. copy (first=%u, count=%u, r=%d, g=%d, b=%d, a=%d, blend=%d, tex=%p)", i++,
+                SDL_Log(" %u. copy (first=%u, count=%u, r=%d, g=%d, b=%d, a=%d, blend=%d, color_scale=%g, tex=%p)", i++,
                         (unsigned int) cmd->data.draw.first,
                         (unsigned int) cmd->data.draw.count,
                         (int) cmd->data.draw.r, (int) cmd->data.draw.g,
                         (int) cmd->data.draw.b, (int) cmd->data.draw.a,
-                        (int) cmd->data.draw.blend, cmd->data.draw.texture);
+                        (int) cmd->data.draw.blend, cmd->data.draw.color_scale, cmd->data.draw.texture);
                 break;
 
 
             case SDL_RENDERCMD_COPY_EX:
-                SDL_Log(" %u. copyex (first=%u, count=%u, r=%d, g=%d, b=%d, a=%d, blend=%d, tex=%p)", i++,
+                SDL_Log(" %u. copyex (first=%u, count=%u, r=%d, g=%d, b=%d, a=%d, blend=%d, color_scale=%g, tex=%p)", i++,
                         (unsigned int) cmd->data.draw.first,
                         (unsigned int) cmd->data.draw.count,
                         (int) cmd->data.draw.r, (int) cmd->data.draw.g,
                         (int) cmd->data.draw.b, (int) cmd->data.draw.a,
-                        (int) cmd->data.draw.blend, cmd->data.draw.texture);
+                        (int) cmd->data.draw.blend, cmd->data.draw.color_scale, cmd->data.draw.texture);
                 break;
 
             case SDL_RENDERCMD_GEOMETRY:
-                SDL_Log(" %u. geometry (first=%u, count=%u, r=%d, g=%d, b=%d, a=%d, blend=%d, tex=%p)", i++,
+                SDL_Log(" %u. geometry (first=%u, count=%u, r=%d, g=%d, b=%d, a=%d, blend=%d, color_scale=%g, tex=%p)", i++,
                         (unsigned int) cmd->data.draw.first,
                         (unsigned int) cmd->data.draw.count,
                         (int) cmd->data.draw.r, (int) cmd->data.draw.g,
                         (int) cmd->data.draw.b, (int) cmd->data.draw.a,
-                        (int) cmd->data.draw.blend, cmd->data.draw.texture);
+                        (int) cmd->data.draw.blend, cmd->data.draw.color_scale, cmd->data.draw.texture);
                 break;
 
         }
@@ -467,6 +467,7 @@ static int QueueCmdSetDrawColor(SDL_Renderer *renderer, SDL_FColor *color)
         if (cmd) {
             cmd->command = SDL_RENDERCMD_SETDRAWCOLOR;
             cmd->data.color.first = 0; /* render backend will fill this in. */
+            cmd->data.color.color_scale = renderer->color_scale;
             cmd->data.color.color = *color;
             retval = renderer->QueueSetDrawColor(renderer, cmd);
             if (retval < 0) {
@@ -489,6 +490,7 @@ static int QueueCmdClear(SDL_Renderer *renderer)
 
     cmd->command = SDL_RENDERCMD_CLEAR;
     cmd->data.color.first = 0;
+    cmd->data.color.color_scale = renderer->color_scale;
     cmd->data.color.color = renderer->color;
     return 0;
 }
@@ -527,6 +529,7 @@ static SDL_RenderCommand *PrepQueueCmdDraw(SDL_Renderer *renderer, const SDL_Ren
             cmd->command = cmdtype;
             cmd->data.draw.first = 0; /* render backend will fill this in. */
             cmd->data.draw.count = 0; /* render backend will fill this in. */
+            cmd->data.draw.color_scale = renderer->color_scale;
             cmd->data.draw.color = *color;
             cmd->data.draw.blend = blendMode;
             cmd->data.draw.texture = texture;
@@ -953,6 +956,8 @@ SDL_Renderer *SDL_CreateRendererWithProperties(SDL_PropertiesID props)
 
     renderer->line_method = SDL_GetRenderLineMethod();
 
+    renderer->color_scale = 1.0f;
+
     if (SDL_GetWindowFlags(window) & (SDL_WINDOW_HIDDEN | SDL_WINDOW_MINIMIZED)) {
         renderer->hidden = SDL_TRUE;
     } else {
@@ -2835,6 +2840,24 @@ int SDL_GetRenderDrawColorFloat(SDL_Renderer *renderer, float *r, float *g, floa
     return 0;
 }
 
+int SDL_SetRenderColorScale(SDL_Renderer *renderer, float scale)
+{
+    CHECK_RENDERER_MAGIC(renderer, -1);
+
+    renderer->color_scale = scale;
+    return 0;
+}
+
+int SDL_GetRenderColorScale(SDL_Renderer *renderer, float *scale)
+{
+    CHECK_RENDERER_MAGIC(renderer, -1);
+
+    if (scale) {
+        *scale = renderer->color_scale;
+    }
+    return 0;
+}
+
 int SDL_SetRenderDrawBlendMode(SDL_Renderer *renderer, SDL_BlendMode blendMode)
 {
     CHECK_RENDERER_MAGIC(renderer, -1);
diff --git a/src/render/SDL_sysrender.h b/src/render/SDL_sysrender.h
index 627fd890ea76..a953be5ce8e3 100644
--- a/src/render/SDL_sysrender.h
+++ b/src/render/SDL_sysrender.h
@@ -127,6 +127,7 @@ typedef struct SDL_RenderCommand
         {
             size_t first;
             size_t count;
+            float color_scale;
             SDL_FColor color;
             SDL_BlendMode blend;
             SDL_Texture *texture;
@@ -134,6 +135,7 @@ typedef struct SDL_RenderCommand
         struct
         {
             size_t first;
+            float color_scale;
             SDL_FColor color;
         } color;
     } data;
@@ -251,6 +253,7 @@ struct SDL_Renderer
 
     SDL_Colorspace output_colorspace;
 
+    float color_scale;
     SDL_FColor color;        /**< Color for drawing operations values */
     SDL_BlendMode blendMode; /**< The drawing blend mode */
 
diff --git a/src/render/direct3d/SDL_render_d3d.c b/src/render/direct3d/SDL_render_d3d.c
index d0381b9ba0a8..588a349127a0 100644
--- a/src/render/direct3d/SDL_render_d3d.c
+++ b/src/render/direct3d/SDL_render_d3d.c
@@ -815,9 +815,9 @@ static int D3D_QueueSetViewport(SDL_Renderer *renderer, SDL_RenderCommand *cmd)
 
 static int D3D_QueueDrawPoints(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FPoint *points, int count)
 {
-    const DWORD color = D3DCOLOR_COLORVALUE(cmd->data.draw.color.r,
-                                            cmd->data.draw.color.g,
-                                            cmd->data.draw.color.b,
+    const DWORD color = D3DCOLOR_COLORVALUE(cmd->data.draw.color.r * cmd->data.draw.color_scale,
+                                            cmd->data.draw.color.g * cmd->data.draw.color_scale,
+                                            cmd->data.draw.color.b * cmd->data.draw.color_scale,
                                             cmd->data.draw.color.a);
     const size_t vertslen = count * sizeof(Vertex);
     Vertex *verts = (Vertex *)SDL_AllocateRenderVertices(renderer, vertslen, 0, &cmd->data.draw.first);
@@ -847,6 +847,7 @@ static int D3D_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL
     int i;
     int count = indices ? num_indices : num_vertices;
     Vertex *verts = (Vertex *)SDL_AllocateRenderVertices(renderer, count * sizeof(Vertex), 0, &cmd->data.draw.first);
+    const float color_scale = cmd->data.draw.color_scale;
 
     if (!verts) {
         return -1;
@@ -875,7 +876,7 @@ static int D3D_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL
         verts->x = xy_[0] * scale_x - 0.5f;
         verts->y = xy_[1] * scale_y - 0.5f;
         verts->z = 0.0f;
-        verts->color = D3DCOLOR_COLORVALUE(col_->r, col_->g, col_->b, col_->a);
+        verts->color = D3DCOLOR_COLORVALUE(col_->r * color_scale, col_->g * color_scale, col_->b * color_scale, col_->a);
 
         if (texture) {
             float *uv_ = (float *)((char *)uv + j * uv_stride);
@@ -1205,7 +1206,10 @@ static int D3D_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, v
 
         case SDL_RENDERCMD_CLEAR:
         {
-            const DWORD color = D3DCOLOR_COLORVALUE(cmd->data.color.color.r, cmd->data.color.color.g, cmd->data.color.color.b, cmd->data.color.color.a);
+            const DWORD color = D3DCOLOR_COLORVALUE(cmd->data.color.color.r * cmd->data.color.color_scale,
+                                                    cmd->data.color.color.g * cmd->data.color.color_scale,
+                                                    cmd->data.color.color.b * cmd->data.color.color_scale,
+                                                    cmd->data.color.color.a);
             const SDL_Rect *viewport = &data->drawstate.viewport;
             const int backw = istarget ? renderer->target->w : data->pparams.BackBufferWidth;
             const int backh = istarget ? renderer->target->h : data->pparams.BackBufferHeight;
diff --git a/src/render/direct3d11/D3D11_PixelShader_Colors.h b/src/render/direct3d11/D3D11_PixelShader_Colors.h
index 955c2532dcde..ad68f93bb76a 100644
--- a/src/render/direct3d11/D3D11_PixelShader_Colors.h
+++ b/src/render/direct3d11/D3D11_PixelShader_Colors.h
@@ -8,10 +8,10 @@
 // cbuffer Constants
 // {
 //
-//   float scRGB_output;                // Offset:    0 Size:     4
-//   float SDR_whitelevel;              // Offset:    4 Size:     4
-//   float HDR_whitelevel;              // Offset:    8 Size:     4 [unused]
-//   float maxCLL;                      // Offset:   12 Size:     4 [unused]
+//   float scRGB_output;                // Offset:    0 Size:     4 [unused]
+//   float color_scale;                 // Offset:    4 Size:     4
+//   float unused1;                     // Offset:    8 Size:     4 [unused]
+//   float unused2;                     // Offset:   12 Size:     4 [unused]
 //   float4 Yoffset;                    // Offset:   16 Size:    16 [unused]
 //   float4 Rcoeff;                     // Offset:   32 Size:    16 [unused]
 //   float4 Gcoeff;                     // Offset:   48 Size:    16 [unused]
@@ -54,123 +54,85 @@
 // Level9 shader bytecode:
 //
     ps_2_0
-    def c1, 0.0125000002, 1, 0, 0
     dcl t1
-    mul r0.w, c0.x, c0.x
-    mov r0.x, c1.x
-    mul r0.x, r0.x, c0.y
-    cmp r0.xyz, -r0.w, c1.y, r0.x
-    mov r0.w, c1.y
-    mul r0, r0, t1
+    mul r0.xyz, t1, c0.y
+    mov r0.w, t1.w
     mov oC0, r0
 
-// approximately 7 instruction slots used
+// approximately 3 instruction slots used
 ps_4_0
 dcl_constantbuffer CB0[1], immediateIndexed
 dcl_input_ps linear v2.xyzw
 dcl_output o0.xyzw
 dcl_temps 1
-ne r0.x, l(0.000000, 0.000000, 0.000000, 0.000000), cb0[0].x
-mul r0.y, cb0[0].y, l(0.012500)
-movc r0.xyz, r0.xxxx, r0.yyyy, l(1.000000,1.000000,1.000000,0)
+mov r0.x, cb0[0].y
 mov r0.w, l(1.000000)
-mul o0.xyzw, r0.xyzw, v2.xyzw
+mul o0.xyzw, r0.xxxw, v2.xyzw
 ret 
-// Approximately 6 instruction slots used
+// Approximately 4 instruction slots used
 #endif
 
 const BYTE g_main[] =
 {
-     68,  88,  66,  67, 132,  13, 
-    165,  35,  17, 157, 163, 217, 
-    158,  71, 117, 171,  46, 252, 
-      9, 215,   1,   0,   0,   0, 
-    224,   4,   0,   0,   6,   0, 
+     68,  88,  66,  67,  76, 154, 
+    233, 103, 201,  50, 167, 173, 
+    112, 159, 134,  20, 133, 254, 
+    166,  35,   1,   0,   0,   0, 
+     24,   4,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
-      4,   1,   0,   0, 244,   1, 
-      0,   0, 112,   2,   0,   0, 
-     56,   4,   0,   0, 172,   4, 
+    172,   0,   0,   0,  56,   1, 
+      0,   0, 180,   1,   0,   0, 
+    112,   3,   0,   0, 228,   3, 
       0,   0,  65, 111, 110,  57, 
-    196,   0,   0,   0, 196,   0, 
+    108,   0,   0,   0, 108,   0, 
       0,   0,   0,   2, 255, 255, 
-    148,   0,   0,   0,  48,   0, 
+     60,   0,   0,   0,  48,   0, 
       0,   0,   1,   0,  36,   0, 
       0,   0,  48,   0,   0,   0, 
      48,   0,   0,   0,  36,   0, 
       0,   0,  48,   0,   0,   0, 
       0,   0,   1,   0,   0,   0, 
       0,   0,   0,   0,   0,   2, 
-    255, 255,  81,   0,   0,   5, 
-      1,   0,  15, 160, 205, 204, 
-     76,  60,   0,   0, 128,  63, 
-      0,   0,   0,   0,   0,   0, 
-      0,   0,  31,   0,   0,   2, 
+    255, 255,  31,   0,   0,   2, 
       0,   0,   0, 128,   1,   0, 
      15, 176,   5,   0,   0,   3, 
-      0,   0,   8, 128,   0,   0, 
-      0, 160,   0,   0,   0, 160, 
-      1,   0,   0,   2,   0,   0, 
-      1, 128,   1,   0,   0, 160, 
-      5,   0,   0,   3,   0,   0, 
-      1, 128,   0,   0,   0, 128, 
-      0,   0,  85, 160,  88,   0, 
-      0,   4,   0,   0,   7, 128, 
-      0,   0, 255, 129,   1,   0, 
-     85, 160,   0,   0,   0, 128, 
+      0,   0,   7, 128,   1,   0, 
+    228, 176,   0,   0,  85, 160, 
       1,   0,   0,   2,   0,   0, 
-      8, 128,   1,   0,  85, 160, 
-      5,   0,   0,   3,   0,   0, 
+      8, 128,   1,   0, 255, 176, 
+      1,   0,   0,   2,   0,   8, 
      15, 128,   0,   0, 228, 128, 
-      1,   0, 228, 176,   1,   0, 
-      0,   2,   0,   8,  15, 128, 
-      0,   0, 228, 128, 255, 255, 
-      0,   0,  83,  72,  68,  82, 
-    232,   0,   0,   0,  64,   0, 
-      0,   0,  58,   0,   0,   0, 
-     89,   0,   0,   4,  70, 142, 
-     32,   0,   0,   0,   0,   0, 
-      1,   0,   0,   0,  98,  16, 
-      0,   3, 242,  16,  16,   0, 
-      2,   0,   0,   0, 101,   0, 
-      0,   3, 242,  32,  16,   0, 
-      0,   0,   0,   0, 104,   0, 
-      0,   2,   1,   0,   0,   0, 
-     57,   0,   0,  11,  18,   0, 
+    255, 255,   0,   0,  83,  72, 
+     68,  82, 132,   0,   0,   0, 
+     64,   0,   0,   0,  33,   0, 
+      0,   0,  89,   0,   0,   4, 
+     70, 142,  32,   0,   0,   0, 
+      0,   0,   1,   0,   0,   0, 
+     98,  16,   0,   3, 242,  16, 
+     16,   0,   2,   0,   0,   0, 
+    101,   0,   0,   3, 242,  32, 
      16,   0,   0,   0,   0,   0, 
-      2,  64,   0,   0,   0,   0, 
-      0,   0,   0,   0,   0,   0, 
-      0,   0,   0,   0,   0,   0, 
-      0,   0,  10, 128,  32,   0, 
-      0,   0,   0,   0,   0,   0, 
-      0,   0,  56,   0,   0,   8, 
-     34,   0,  16,   0,   0,   0, 
+    104,   0,   0,   2,   1,   0, 
+      0,   0,  54,   0,   0,   6, 
+     18,   0,  16,   0,   0,   0, 
       0,   0,  26, 128,  32,   0, 
       0,   0,   0,   0,   0,   0, 
+      0,   0,  54,   0,   0,   5, 
+    130,   0,  16,   0,   0,   0, 
       0,   0,   1,  64,   0,   0, 
-    205, 204,  76,  60,  55,   0, 
-      0,  12, 114,   0,  16,   0, 
-      0,   0,   0,   0,   6,   0, 
+      0,   0, 128,  63,  56,   0, 
+      0,   7, 242,  32,  16,   0, 
+      0,   0,   0,   0,   6,  12, 
      16,   0,   0,   0,   0,   0, 
-     86,   5,  16,   0,   0,   0, 
-      0,   0,   2,  64,   0,   0, 
-      0,   0, 128,  63,   0,   0, 
-    128,  63,   0,   0, 128,  63, 
-      0,   0,   0,   0,  54,   0, 
-      0,   5, 130,   0,  16,   0, 
-      0,   0,   0,   0,   1,  64, 
-      0,   0,   0,   0, 128,  63, 
-     56,   0,   0,   7, 242,  32, 
-     16,   0,   0,   0,   0,   0, 
-     70,  14,  16,   0,   0,   0, 
-      0,   0,  70,  30,  16,   0, 
-      2,   0,   0,   0,  62,   0, 
-      0,   1,  83,  84,  65,  84, 
-    116,   0,   0,   0,   6,   0, 
-      0,   0,   1,   0,   0,   0, 
-      0,   0,   0,   0,   2,   0, 
+     70,  30,  16,   0,   2,   0, 
+      0,   0,  62,   0,   0,   1, 
+     83,  84,  65,  84, 116,   0, 
+      0,   0,   4,   0,   0,   0, 
+      1,   0,   0,   0,   0,   0, 
       0,   0,   2,   0,   0,   0, 
+      1,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
-      0,   0,   1,   0,   0,   0, 
+      1,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
@@ -178,115 +140,113 @@ const BYTE g_main[] =
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
-      0,   0,   1,   0,   0,   0, 
-      1,   0,   0,   0,   1,   0, 
+      2,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
-     82,  68,  69,  70, 192,   1, 
+      0,   0,   0,   0,  82,  68, 
+     69,  70, 180,   1,   0,   0, 
+      1,   0,   0,   0,  72,   0, 
       0,   0,   1,   0,   0,   0, 
-     72,   0,   0,   0,   1,   0, 
-      0,   0,  28,   0,   0,   0, 
-      0,   4, 255, 255,   0,   1, 
-      0,   0, 149,   1,   0,   0, 
-     60,   0,   0,   0,   0,   0, 
+     28,   0,   0,   0,   0,   4, 
+    255, 255,   0,   1,   0,   0, 
+    137,   1,   0,   0,  60,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
-      1,   0,   0,   0,   1,   0, 
-      0,   0,  67, 111, 110, 115, 
-    116,  97, 110, 116, 115,   0, 
-    171, 171,  60,   0,   0,   0, 
-      8,   0,   0,   0,  96,   0, 
+      0,   0,   0,   0,   1,   0, 
+      0,   0,   1,   0,   0,   0, 
+     67, 111, 110, 115, 116,  97, 
+    110, 116, 115,   0, 171, 171, 
+     60,   0,   0,   0,   8,   0, 
+      0,   0,  96,   0,   0,   0, 
+     80,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+     32,   1,   0,   0,   0,   0, 
+      0,   0,   4,   0,   0,   0, 
+      0,   0,   0,   0,  48,   1, 
+      0,   0,   0,   0,   0,   0, 
+     64,   1,   0,   0,   4,   0, 
+      0,   0,   4,   0,   0,   0, 
+      2,   0,   0,   0,  48,   1, 
+      0,   0,   0,   0,   0,   0, 
+     76,   1,   0,   0,   8,   0, 
+      0,   0,   4,   0,   0,   0, 
+      0,   0,   0,   0,  48,   1, 
+      0,   0,   0,   0,   0,   0, 
+     84,   1,   0,   0,  12,   0, 
+      0,   0,   4,   0,   0,   0, 
+      0,   0,   0,   0,  48,   1, 
+      0,   0,   0,   0,   0,   0, 
+     92,   1,   0,   0,  16,   0, 
+      0,   0,  16,   0,   0,   0, 
+      0,   0,   0,   0, 100,   1, 
+      0,   0,   0,   0,   0,   0, 
+    116,   1,   0,   0,  32,   0, 
+      0,   0,  16,   0,   0,   0, 
+      0,   0,   0,   0, 100,   1, 
+      0,   0,   0,   0,   0,   0, 
+    123,   1,   0,   0,  48,   0, 
+      0,   0,  16,   0,   0,   0, 
+      0,   0,   0,   0, 100,   1, 
+      0,   0,   0,   0,   0,   0, 
+    130,   1,   0,   0,  64,   0, 
+      0,   0,  16,   0,   0,   0, 
+      0,   0,   0,   0, 100,   1, 
+      0,   0,   0,   0,   0,   0, 
+    115,  99,  82,  71,  66,  95, 
+    111, 117, 116, 112, 117, 116, 
+      0, 171, 171, 171,   0,   0, 
+      3,   0,   1,   0,   1,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,  99, 111, 108, 111, 
+    114,  95, 115,  99,  97, 108, 
+    101,   0, 117, 110, 117, 115, 
+    101, 100,  49,   0, 117, 110, 
+    117, 115, 101, 100,  50,   0, 
+     89, 111, 102, 102, 115, 101, 
+    116,   0,   1,   0,   3,   0, 
+      1,   0,   4,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+     82,  99, 111, 101, 102, 102, 
+      0,  71,  99, 111, 101, 102, 
+    102,   0,  66,  99, 111, 101, 
+    102, 102,   0,  77, 105,  99, 
+    114, 111, 115, 111, 102, 116, 
+     32,  40,  82,  41,  32,  72, 
+     76,  83,  76,  32,  83, 104, 
+     97, 100, 101, 114,  32,  67, 
+    111, 109, 112, 105, 108, 101, 
+    114,  32,  49,  48,  46,  49, 
+      0, 171, 171, 171,  73,  83, 
+     71,  78, 108,   0,   0,   0, 
+      3,   0,   0,   0,   8,   0, 
       0,   0,  80,   0,   0,   0, 
-      0,   0,   0,   0,   0,   0, 
-      0,   0,  32,   1,   0,   0, 
-      0,   0,   0,   0,   4,   0, 
-      0,   0,   2,   0,   0,   0, 
-     48,   1,   0,   0,   0,   0, 
-      0,   0,  64,   1,   0,   0, 
-      4,   0,   0,   0,   4,   0, 
-      0,   0,   2,   0,   0,   0, 
-     48,   1,   0,   0,   0,   0, 
-      0,   0,  79,   1,   0,   0, 
-      8,   0,   0,   0,   4,   0, 
-      0,   0,   0,   0,   0,   0, 
-     48,   1,   0,   0,   0,   0, 
-      0,   0,  94,   1,   0,   0, 
-     12,   0,   0,   0,   4,   0, 
-      0,   0,   0,   0,   0,   0, 
-     48,   1,   0,   0,   0,   0, 
-      0,   0, 101,   1,   0,   0, 
-     16,   0,   0,   0,  16,   0, 
-      0,   0,   0,   0,   0,   0, 
-    112,   1,   0,   0,   0,   0, 
-      0,   0, 128,   1,   0,   0, 
-     32,   0,   0,   0,  16,   0, 
-      0,   0,   0,   0,   0,   0, 
-    112,   1,   0,   0,   0,   0, 
-      0,   0, 135,   1,   0,   0, 
-     48,   0,   0,   0,  16,   0, 
-      0,   0,   0,   0,   0,   0, 
-    112,   1,   0,   0,   0,   0, 
-      0,   0, 142,   1,   0,   0, 
-     64,   0,   0,   0,  16,   0, 
-      0,   0,   0,   0,   0,   0, 
-    112,   1,   0,   0,   0,   0, 
-      0,   0, 115,  99,  82,  71, 
-     66,  95, 111, 117, 116, 112, 
-    117, 116,   0, 171, 171, 171, 
-      0,   0,   3,   0,   1,   0, 
-      1,   0,   0,   0,   0,   0, 
-      0,   0,   0,   0,  83,  68, 
-     82,  95, 119, 104, 105, 116, 
-    101, 108, 101, 118, 101, 108, 
-      0,  72,  68,  82,  95, 119, 
-    104, 105, 116, 101, 108, 101, 
-    118, 101, 108,   0, 109,  97, 
-    120,  67,  76,  76,   0,  89, 
-    111, 102, 102, 115, 101, 116, 
-      0, 171, 171, 171,   1,   0, 
-      3,   0,   1,   0,   4,   0, 
-      0,   0,   0,   0,   0,   0, 
-      0,   0,  82,  99, 111, 101, 
-    102, 102,   0,  71,  99, 111, 
-    101, 102, 102,   0,  66,  99, 
-    111, 101, 102, 102,   0,  77, 
-    105,  99, 114, 111, 115, 111, 
-    102, 116,  32,  40,  82,  41, 
-     32,  72,  76,  83,  76,  32, 
-     83, 104,  97, 100, 101, 114, 
-     32,  67, 111, 109, 112, 105, 
-    108, 101, 114,  32,  49,  48, 
-     46,  49,   0, 171, 171, 171, 
-     73,  83,  71,  78, 108,   0, 
+      0,   0,   0,   0,   1,   0, 
       0,   0,   3,   0,   0,   0, 
-      8,   0,   0,   0,  80,   0, 
+      0,   0,   0,   0,  15,   0, 
+      0,   0,  92,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
+      0,   0,   3,   0,   0,   0, 
       1,   0,   0,   0,   3,   0, 
+      0,   0, 101,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
-     15,   0,   0,   0,  92,   0, 
-      0,   0,   0,   0,   0,   0, 
-      0,   0,   0,   0,   3,   0, 
+      0,   0,   3,   0,   0,   0, 
+      2,   0,   0,   0,  15,  15, 
+      0,   0,  83,  86,  95,  80, 
+     79,  83,  73,  84,  73,  79, 
+     78,   0,  84,  69,  88,  67, 
+     79,  79,  82,  68,   0,  67, 
+     79,  76,  79,  82,   0, 171, 
+     79,  83,  71,  78,  44,   0, 
       0,   0,   1,   0,   0,   0, 
-      3,   0,   0,   0, 101,   0, 
+      8,   0,   0,   0,  32,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   3,   0, 
-      0,   0,   2,   0,   0,   0, 
-     15,  15,   0,   0,  83,  86, 
-     95,  80,  79,  83,  73,  84, 
-     73,  79,  78,   0,  84,  69, 
-     88,  67,  79,  79,  82,  68, 
-      0,  67,  79,  76,  79,  82, 
-      0, 171,  79,  83,  71,  78, 
-     44,   0,   0,   0,   1,   0, 
-      0,   0,   8,   0,   0,   0, 
-     32,   0,   0,   0,   0,   0, 
-      0,   0,

(Patch may be truncated, please check the link at the top of this post.)