summaryrefslogtreecommitdiffstats
path: root/src/world.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/world.cpp')
-rw-r--r--src/world.cpp66
1 files changed, 60 insertions, 6 deletions
diff --git a/src/world.cpp b/src/world.cpp
index cf85795..391ab1a 100644
--- a/src/world.cpp
+++ b/src/world.cpp
@@ -409,6 +409,49 @@ bool load_png_rgba(const char *path, std::vector<unsigned char> &pixels,
409 return true; 409 return true;
410} 410}
411 411
412std::vector<unsigned char> g_sky_pixels;
413int g_sky_px_w = 0, g_sky_px_h = 0;
414
415// ITextureRegenerator has two virtuals: RegenerateTextureBits then Release.
416// This build has no IMaterialSystem::CreateTextureFromBits (its interface stops
417// at GetDisplayDeviceName), so the pixels are uploaded through a procedural
418// texture + regenerator instead.
419class SkyRegenerator {
420public:
421 virtual void RegenerateTextureBits(void *texture, void *vtf, void *rect) {
422 (void)texture;
423 (void)rect;
424 if (!vtf || g_sky_pixels.empty())
425 return;
426 using IntFn = int (*)(void *);
427 using PitchFn = int (*)(void *, int);
428 using DataFn = unsigned char *(*)(void *, int, int, int);
429 // IVTFTexture vtable: dtor takes 2 slots, then Init, so Width=15,
430 // Height=16, RowSizeInBytes=19, ImageData(frame,face,mip)=39.
431 int w = vfunc<IntFn>(vtf, 15)(vtf); // IVTFTexture::Width
432 int h = vfunc<IntFn>(vtf, 16)(vtf); // IVTFTexture::Height
433 if (w <= 0 || h <= 0)
434 return;
435 int pitch = vfunc<PitchFn>(vtf, 19)(vtf, 0); // RowSizeInBytes(0)
436 unsigned char *dst = vfunc<DataFn>(vtf, 39)(vtf, 0, 0, 0); // ImageData
437 if (!dst || pitch <= 0)
438 return;
439 int rows = h < g_sky_px_h ? h : g_sky_px_h;
440 int src_stride = g_sky_px_w * 4;
441 int copy = w * 4;
442 if (copy > src_stride)
443 copy = src_stride;
444 for (int y = 0; y < rows; y++) {
445 const unsigned char *src =
446 g_sky_pixels.data() + (size_t)y * (size_t)src_stride;
447 memcpy(dst + (size_t)y * (size_t)pitch, src, (size_t)copy);
448 }
449 }
450 virtual void Release() {}
451};
452
453SkyRegenerator g_sky_regenerator;
454
412void *g_sky_tex = nullptr; 455void *g_sky_tex = nullptr;
413bool g_sky_tex_tried = false; 456bool g_sky_tex_tried = false;
414bool g_sky_applied = false; 457bool g_sky_applied = false;
@@ -573,16 +616,27 @@ void load_sky_texture() {
573 } 616 }
574 return; 617 return;
575 } 618 }
576 using CreateTexFn = void *(*)(void *, int, int, int, int, int, 619 g_sky_pixels.swap(pixels);
577 unsigned char *); 620 g_sky_px_w = w;
578 g_sky_tex = vfunc<CreateTexFn>(ms, 134)(ms, w, h, 1, 0 /* RGBA8888 */, 621 g_sky_px_h = h;
579 (int)pixels.size(), pixels.data()); 622
623 // The procedural texture keeps its own copy through the regenerator, which
624 // is called on Download() and again on device restore.
625 using CreateProcFn = void *(*)(void *, const char *, const char *, int, int,
626 int, int);
627 g_sky_tex = vfunc<CreateProcFn>(ms, 81)(
628 ms, "hl2hake/skybox", GROUP_SKYBOX, w, h, 0 /* RGBA8888 */,
629 0x10C /* CLAMPS|CLAMPT|NOMIP */);
580 if (!g_sky_tex) { 630 if (!g_sky_tex) {
581 logf("skybox: CreateTextureFromBits failed for %dx%d", w, h); 631 logf("skybox: CreateProceduralTexture failed for %dx%d", w, h);
582 return; 632 return;
583 } 633 }
634 using SetRegenFn = void (*)(void *, void *);
635 using DownloadFn = void (*)(void *, void *, int);
636 vfunc<SetRegenFn>(g_sky_tex, 12)(g_sky_tex, &g_sky_regenerator);
637 vfunc<DownloadFn>(g_sky_tex, 13)(g_sky_tex, nullptr, 0);
584 g_sky_fail_logged = false; 638 g_sky_fail_logged = false;
585 logf("skybox: image %s (%dx%d) loaded", path, w, h); 639 logf("skybox: image %s (%dx%d) uploaded", path, w, h);
586} 640}
587 641
588} // namespace 642} // namespace