diff options
Diffstat (limited to 'src/world.cpp')
| -rw-r--r-- | src/world.cpp | 66 |
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 | ||
| 412 | std::vector<unsigned char> g_sky_pixels; | ||
| 413 | int 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. | ||
| 419 | class SkyRegenerator { | ||
| 420 | public: | ||
| 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 | |||
| 453 | SkyRegenerator g_sky_regenerator; | ||
| 454 | |||
| 412 | void *g_sky_tex = nullptr; | 455 | void *g_sky_tex = nullptr; |
| 413 | bool g_sky_tex_tried = false; | 456 | bool g_sky_tex_tried = false; |
| 414 | bool g_sky_applied = false; | 457 | bool 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 |
