summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-11-04 00:50:59 +0100
committersalmonik <salmonik@tuta.io>2026-11-04 00:50:59 +0100
commitfac6acf7daf3efd872814af34a8faac11a0a5c9d (patch)
tree5a54e3349034de1d4f9a7528ee094b5caae9b977 /src
parentSkybox image: drop Refresh/SetUndefined (crash after apply) (diff)
downloadhl2h-fac6acf7daf3efd872814af34a8faac11a0a5c9d.tar.gz
hl2h-fac6acf7daf3efd872814af34a8faac11a0a5c9d.zip
Skybox image: match HDR sky colour decode
The HDR "sky" shader samples the compressed texture as rgb *= alpha, multiplies by 8, then converts linear->sRGB for display. Feeding it the raw sRGB image produced the blown-out / oversaturated sky. When the map uses the HDR sky shader, pre-convert the image to linear and set alpha to 1/8 so the 8x scale cancels and the final linear->sRGB conversion restores the original colours. For LDR (UnlitGeneric) materials, create the texture with TEXTUREFLAGS_SRGB so the normal sRGB sampling is used. The first sky material's shader name is logged for confirmation.
Diffstat (limited to 'src')
-rw-r--r--src/world.cpp66
1 files changed, 61 insertions, 5 deletions
diff --git a/src/world.cpp b/src/world.cpp
index eac31d9..ddd047a 100644
--- a/src/world.cpp
+++ b/src/world.cpp
@@ -18,6 +18,7 @@
18#include "hl2h.h" 18#include "hl2h.h"
19#include <cstdio> 19#include <cstdio>
20#include <cstdlib> 20#include <cstdlib>
21#include <cmath>
21#include <cstring> 22#include <cstring>
22#include <ctime> 23#include <ctime>
23#include <dlfcn.h> 24#include <dlfcn.h>
@@ -386,7 +387,7 @@ int paeth(int a, int b, int c) {
386} 387}
387 388
388bool load_png_rgba(const char *path, std::vector<unsigned char> &pixels, 389bool load_png_rgba(const char *path, std::vector<unsigned char> &pixels,
389 int &out_w, int &out_h) { 390 int &out_w, int &out_h, bool hdr_compensation) {
390 FILE *f = fopen(path, "rb"); 391 FILE *f = fopen(path, "rb");
391 if (!f) { 392 if (!f) {
392 logf("skybox: cannot open %s", path); 393 logf("skybox: cannot open %s", path);
@@ -609,6 +610,24 @@ bool load_png_rgba(const char *path, std::vector<unsigned char> &pixels,
609 } 610 }
610 } 611 }
611 612
613 // HDR sky materials use the "sky" shader. It samples the compressed HDR
614 // texture as rgb *= alpha, multiplies by 8, then converts linear->sRGB for
615 // display. Cancel the 8x with alpha = 1/8 and feed linear values so the
616 // final conversion restores the original sRGB image.
617 if (hdr_compensation) {
618 for (size_t i = 0; i + 3 < pixels.size(); i += 4) {
619 float rgb[3];
620 for (int c = 0; c < 3; c++) {
621 float v = (float)pixels[i + (size_t)c] / 255.0f;
622 rgb[c] = (v <= 0.04045f) ? v / 12.92f
623 : powf((v + 0.055f) / 1.055f, 2.4f);
624 pixels[i + (size_t)c] = (unsigned char)(rgb[c] * 255.0f + 0.5f);
625 }
626 pixels[i + 3] = 32; // 1/8 * 255
627 }
628 logf("skybox: HDR sky shader, using linear colours with 1/8 alpha");
629 }
630
612 out_w = (int)w; 631 out_w = (int)w;
613 out_h = (int)h; 632 out_h = (int)h;
614 return true; 633 return true;
@@ -826,6 +845,39 @@ void restore_sky_texture() {
826 g_sky_applied = false; 845 g_sky_applied = false;
827} 846}
828 847
848bool sky_uses_hdr_shader() {
849 void *ms = material_system();
850 if (!ms)
851 return false;
852 auto invalid = vfunc<MatCalls::InvalidFn>(ms, MATSYS_InvalidMaterial);
853 auto first = vfunc<MatCalls::FirstFn>(ms, MATSYS_FirstMaterial);
854 auto next = vfunc<MatCalls::NextFn>(ms, MATSYS_NextMaterial);
855 auto get = vfunc<MatCalls::GetFn>(ms, MATSYS_GetMaterial);
856 auto count = vfunc<MatCalls::CountFn>(ms, MATSYS_GetNumMaterials);
857 int total = count(ms);
858 if (total <= 0 || total > 200000)
859 return false;
860 using ShaderFn = const char *(*)(void *);
861 unsigned short inv = invalid(ms);
862 int seen = 0;
863 for (unsigned short h = first(ms); h != inv; h = next(ms, h)) {
864 if (++seen > total + 16)
865 break;
866 void *mat = get(ms, h);
867 if (!mat)
868 continue;
869 const char *name = vfunc<MatCalls::NameFn>(mat, MAT_GetName)(mat);
870 const char *group =
871 vfunc<MatCalls::GroupFn>(mat, MAT_GetTextureGroupName)(mat);
872 if (!is_sky_material(name, group))
873 continue;
874 const char *shader = vfunc<ShaderFn>(mat, 49)(mat);
875 if (shader && strcmp(shader, "sky") == 0)
876 return true;
877 }
878 return false;
879}
880
829void load_sky_texture() { 881void load_sky_texture() {
830 g_sky_tex_tried = true; 882 g_sky_tex_tried = true;
831 void *ms = material_system(); 883 void *ms = material_system();
@@ -836,7 +888,8 @@ void load_sky_texture() {
836 std::vector<unsigned char> pixels; 888 std::vector<unsigned char> pixels;
837 int w = 0, h = 0; 889 int w = 0, h = 0;
838 const char *path = config_file_cstr("skybox.png"); 890 const char *path = config_file_cstr("skybox.png");
839 if (!load_png_rgba(path, pixels, w, h)) { 891 bool hdr = sky_uses_hdr_shader();
892 if (!load_png_rgba(path, pixels, w, h, hdr)) {
840 if (!g_sky_fail_logged) { 893 if (!g_sky_fail_logged) {
841 g_sky_fail_logged = true; 894 g_sky_fail_logged = true;
842 toastf(TOAST_ERROR, "Skybox image missing or unreadable: %s", path); 895 toastf(TOAST_ERROR, "Skybox image missing or unreadable: %s", path);
@@ -851,9 +904,12 @@ void load_sky_texture() {
851 // is called on Download() and again on device restore. 904 // is called on Download() and again on device restore.
852 using CreateProcFn = void *(*)(void *, const char *, const char *, int, int, 905 using CreateProcFn = void *(*)(void *, const char *, const char *, int, int,
853 int, int); 906 int, int);
854 g_sky_tex = vfunc<CreateProcFn>(ms, 81)( 907 // 0x40 = TEXTUREFLAGS_SRGB: the LDR sky path decodes sRGB from the texture
855 ms, "hl2hake/skybox", GROUP_SKYBOX, w, h, 0 /* RGBA8888 */, 908 // flags, the HDR path forces sRGB reads off and does its own conversion.
856 0x10C /* CLAMPS|CLAMPT|NOMIP */); 909 int tex_flags = 0x10C /* CLAMPS|CLAMPT|NOMIP */ | (hdr ? 0 : 0x40);
910 g_sky_tex = vfunc<CreateProcFn>(ms, 81)(ms, "hl2hake/skybox",
911 GROUP_SKYBOX, w, h, 0 /*RGBA8888*/,
912 tex_flags);
857 if (!g_sky_tex) { 913 if (!g_sky_tex) {
858 logf("skybox: CreateProceduralTexture failed for %dx%d", w, h); 914 logf("skybox: CreateProceduralTexture failed for %dx%d", w, h);
859 return; 915 return;