From 4f384f94504a2027febc8b5cc3e2b3e3034c0b23 Mon Sep 17 00:00:00 2001 From: salmonik Date: Wed, 4 Nov 2026 00:16:09 +0100 Subject: Skybox image: decode PNG ourselves to avoid symbol interposition client.so, engine.so and vguimatsurface.so all export their own png_create_read_struct. Loading the system libpng16 made its internal calls bind to the game's older libpng, whose png_struct layout differs, so png_safe_warning read a NULL error_ptr and crashed. Replace libpng with a small PNG reader: zlib's uncompress (dlopen'ed) plus the five PNG row filters, supporting 8-bit non-interlaced RGB/RGBA/gray/palette images with tRNS alpha for palettes. Output verified byte-identical to libpng for the skybox.png in use. --- CONTEXT.md | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'CONTEXT.md') diff --git a/CONTEXT.md b/CONTEXT.md index 669c1fb..5bd0436 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -363,11 +363,16 @@ vocabulary / decisions. - Replaces the map skybox with `/skybox.png` (same directory as the INI). Not `sv_skyname`: that did not take effect at runtime in this build, so the skybox card now works on materials instead. -- PNG is decoded with libpng16's simplified API (`dlopen`ed, no link - dependency). This build's `IMaterialSystem` interface ends at - `GetDisplayDeviceName` (the slots after it belong to `CMaterialSystem` - itself), so there is **no `CreateTextureFromBits`**. The pixels are uploaded - through `CreateProceduralTexture` (vtable 81) + an `ITextureRegenerator` +- The PNG is decoded by our own reader (`zlib`'s `uncompress` + PNG filters; + 8-bit non-interlaced RGB/RGBA/gray/palette). Do **not** use the system + libpng: `client.so`, `engine.so` and `vguimatsurface.so` each export their + own `png_create_read_struct`, so libpng16's internal PLT calls bind to the + game's older libpng with a different `png_struct` layout and crash in + `png_safe_warning` (error_ptr at +0xb0 reads NULL). +- This build's `IMaterialSystem` interface ends at `GetDisplayDeviceName` + (the slots after it belong to `CMaterialSystem` itself), so there is **no + `CreateTextureFromBits`**. The pixels are uploaded through + `CreateProceduralTexture` (vtable 81) + an `ITextureRegenerator` (`SetTextureRegenerator` 12, `Download` 13), which fills mip 0 through `IVTFTexture::ImageData(frame,face,mip)` (39). `IVTFTexture`'s virtual destructor occupies two slots, so Width=15, Height=16, RowSizeInBytes=19. -- cgit v1.2.3