diff options
Diffstat (limited to '')
| -rw-r--r-- | src/world.cpp | 66 |
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 | ||
| 388 | bool load_png_rgba(const char *path, std::vector<unsigned char> &pixels, | 389 | bool 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 | ||
| 848 | bool 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 | |||
| 829 | void load_sky_texture() { | 881 | void 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; |
