diff --git a/src/rendering/character_renderer.cpp b/src/rendering/character_renderer.cpp index 8835f3b6..726a09de 100644 --- a/src/rendering/character_renderer.cpp +++ b/src/rendering/character_renderer.cpp @@ -58,6 +58,10 @@ size_t approxTextureBytesWithMips(int w, int h) { static constexpr uint32_t MAX_MATERIAL_SETS = 4096; static constexpr uint32_t MAX_BONE_SETS = 8192; +// Texture compositing sizes (NPC skin upscale) +static constexpr int kBaseTexSize = 256; // NPC baked texture default +static constexpr int kUpscaleTexSize = 512; // Target size for region compositing + // CharMaterial UBO layout (matches character.frag.glsl set=1 binding=1) struct CharMaterialUBO { float opacity; @@ -1163,17 +1167,17 @@ VkTexture* CharacterRenderer::compositeWithRegions(const std::string& basePath, // If base texture is 256x256 (e.g., baked NPC texture), upscale to 512x512 // so equipment regions can be composited at correct coordinates - if (width == 256 && height == 256 && !regionLayers.empty()) { - width = 512; - height = 512; + if (width == kBaseTexSize && height == kBaseTexSize && !regionLayers.empty()) { + width = kUpscaleTexSize; + height = kUpscaleTexSize; composite.resize(width * height * 4); // Simple 2x nearest-neighbor upscale - for (int y = 0; y < 512; y++) { - for (int x = 0; x < 512; x++) { + for (int y = 0; y < kUpscaleTexSize; y++) { + for (int x = 0; x < kUpscaleTexSize; x++) { int srcX = x / 2; int srcY = y / 2; - int srcIdx = (srcY * 256 + srcX) * 4; - int dstIdx = (y * 512 + x) * 4; + int srcIdx = (srcY * kBaseTexSize + srcX) * 4; + int dstIdx = (y * kUpscaleTexSize + x) * 4; composite[dstIdx + 0] = base.data[srcIdx + 0]; composite[dstIdx + 1] = base.data[srcIdx + 1]; composite[dstIdx + 2] = base.data[srcIdx + 2]; @@ -1188,7 +1192,7 @@ VkTexture* CharacterRenderer::compositeWithRegions(const std::string& basePath, // Blend face + underwear overlays // If we upscaled from 256->512, scale coords and texels with blitOverlayScaled2x. // For native 512/1024 textures, face overlays are full atlas size (hit width==width branch). - bool upscaled = (base.width == 256 && base.height == 256 && width == 512); + bool upscaled = (base.width == kBaseTexSize && base.height == kBaseTexSize && width == kUpscaleTexSize); for (const auto& ul : baseLayers) { if (ul.empty()) continue; pipeline::BLPImage overlay; diff --git a/src/rendering/terrain_manager.cpp b/src/rendering/terrain_manager.cpp index 50a12d0d..c20801ae 100644 --- a/src/rendering/terrain_manager.cpp +++ b/src/rendering/terrain_manager.cpp @@ -42,6 +42,12 @@ namespace rendering { namespace { +// Alpha map format constants +constexpr size_t ALPHA_MAP_SIZE = 4096; // 64×64 uncompressed alpha bytes +constexpr size_t ALPHA_MAP_PACKED = 2048; // 64×64 packed 4-bit alpha (half size) +constexpr uint8_t ALPHA_FILL_FLAG = 0x80; // RLE command: fill vs. copy +constexpr uint8_t ALPHA_COUNT_MASK = 0x7F; // RLE command: count bits + int computeTerrainWorkerCount() { const char* raw = std::getenv("WOWEE_TERRAIN_WORKERS"); if (raw && *raw) { @@ -78,24 +84,24 @@ bool decodeLayerAlpha(const pipeline::MapChunk& chunk, size_t layerIdx, std::vec } } - outAlpha.assign(4096, 255); + outAlpha.assign(ALPHA_MAP_SIZE, 255); if (layer.compressedAlpha()) { size_t readPos = offset; size_t writePos = 0; - while (writePos < 4096 && readPos < chunk.alphaMap.size()) { + while (writePos < ALPHA_MAP_SIZE && readPos < chunk.alphaMap.size()) { uint8_t cmd = chunk.alphaMap[readPos++]; - bool fill = (cmd & 0x80) != 0; - int count = (cmd & 0x7F) + 1; + bool fill = (cmd & ALPHA_FILL_FLAG) != 0; + int count = (cmd & ALPHA_COUNT_MASK) + 1; if (fill) { if (readPos >= chunk.alphaMap.size()) break; uint8_t val = chunk.alphaMap[readPos++]; - for (int i = 0; i < count && writePos < 4096; i++) { + for (int i = 0; i < count && writePos < ALPHA_MAP_SIZE; i++) { outAlpha[writePos++] = val; } } else { - for (int i = 0; i < count && writePos < 4096 && readPos < chunk.alphaMap.size(); i++) { + for (int i = 0; i < count && writePos < ALPHA_MAP_SIZE && readPos < chunk.alphaMap.size(); i++) { outAlpha[writePos++] = chunk.alphaMap[readPos++]; } } @@ -103,13 +109,13 @@ bool decodeLayerAlpha(const pipeline::MapChunk& chunk, size_t layerIdx, std::vec return true; } - if (layerSize >= 4096) { - std::copy(chunk.alphaMap.begin() + offset, chunk.alphaMap.begin() + offset + 4096, outAlpha.begin()); + if (layerSize >= ALPHA_MAP_SIZE) { + std::copy(chunk.alphaMap.begin() + offset, chunk.alphaMap.begin() + offset + ALPHA_MAP_SIZE, outAlpha.begin()); return true; } - if (layerSize >= 2048) { - for (size_t i = 0; i < 2048; i++) { + if (layerSize >= ALPHA_MAP_PACKED) { + for (size_t i = 0; i < ALPHA_MAP_PACKED; i++) { uint8_t v = chunk.alphaMap[offset + i]; outAlpha[i * 2] = (v & 0x0F) * 17; outAlpha[i * 2 + 1] = (v >> 4) * 17;