Issue #3: wreck scorch quad ramp + RGBA4444 alpha cutout (the 'dark square')
MECHMD's scorch base (basev:bvx9_mtl, bexp9_tex = BEXP.BSL RGBA4444 slice 8, ramp cdusty) drew as a hard-edged dark square for two stacked reasons: 1. The blanket 'truecolor BSL slice (channel >= 6) never ramps' gate blocked its cdusty ramp. Corpus scan: only 4 shipped textures use truecolor slices; bexp9/bdet9 are grayscale in RGB (100% / 98.8% r==g==b) and their materials author ramps -- only bdam8 (damage sheet) is truly coloured. bgfload rampableSlice() now probes the decoded slice: a truecolor slice ramps iff effectively gray (>=95%), keeping bdam8's colour protected. 2. The RGBA4444 authored alpha channel -- a binary 0/240 cutout mask (the splat silhouette, 78.5% transparent) -- was never alpha-tested, so the quad's transparent surround rendered as an opaque rectangle. New BgfDrawBatch.texAlpha (channel >= 8) routes these batches through the PUNCH alpha-test draw states, WITHOUT the black-texel keying (which would hole the near-black charred centre). Side benefit: tree9 (tree/leaf cards) + bdet9 (trans-rail lattice) get their authored cutouts too. Pixel-verified (ram-kill run, BT_SHOT): irregular char splat, dark brown (71,44,34) lifting to near-terrain tan (115,100,91 vs terrain 131,119,108), no rectangle; pre-death frames unregressed (vehicles stay lit/diffuse -- hasNormals gate untouched). Awaiting human verification. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
557e9fd243
commit
9fff079df4
@@ -1,6 +1,7 @@
|
||||
// bgfload.cpp - see bgfload.h. Parse logic ported from port/src/bgf.cpp; directory
|
||||
// scanning reimplemented on Win32 (FindFirstFile) so it builds under C++14.
|
||||
#include "bgfload.h"
|
||||
#include "image.h" // truecolor-slice grayscale probe (rampableSlice, issue #3)
|
||||
|
||||
#include <windows.h>
|
||||
#include <cstdio>
|
||||
@@ -247,6 +248,40 @@ bool hasNormals(uint16_t id) {
|
||||
return id == TAG_VERTEX_XYZ_N || id == TAG_VERTEX_XYZ_N_UV;
|
||||
}
|
||||
|
||||
// TRUECOLOR-slice ramp eligibility (issue #3, the wreck scorch quad). Only 4
|
||||
// shipped textures use a truecolor BSL slice (bdam8=RGB444; bdet9/bexp9/tree9=
|
||||
// RGBA4444). bexp9 (MECHMD's scorch splat, material basev:bvx9_mtl ramp
|
||||
// 'cdusty') and bdet9 (the trans-rail lattice, ramps 'softer'/'cdusty') are
|
||||
// GRAYSCALE in their RGB (100% / 98.8% r==g==b texels, corpus-measured) -- they
|
||||
// author the same luminance->ramp colouring as every mono slice, and the old
|
||||
// blanket "channel < 6" gate left the scorch a raw dark quad instead of the
|
||||
// cdusty dark-brown->dusty-tan gradient. bdam8 (the damage sheet) is genuinely
|
||||
// COLOURED (33% non-gray texels) -- luminance-ramping it would destroy its
|
||||
// colour, which is what the blanket gate was protecting. Gate on the actual
|
||||
// slice content: a truecolor slice ramps only when its RGB is effectively
|
||||
// grayscale. Cached per path#channel (decode runs once per texture).
|
||||
bool rampableSlice(const std::string& texPath, int channel) {
|
||||
if (channel < 6 || texPath.empty()) return true; // mono slices always ramp-eligible
|
||||
static std::map<std::string, bool> cache;
|
||||
std::string key = texPath;
|
||||
key += '#';
|
||||
key += (char)('0' + (channel % 10));
|
||||
auto it = cache.find(key);
|
||||
if (it != cache.end()) return it->second;
|
||||
bool gray = false;
|
||||
Image img = decodeImage(texPath, channel);
|
||||
if (img.ok && !img.argb.empty()) {
|
||||
size_t same = 0;
|
||||
for (uint32_t p : img.argb) {
|
||||
const uint8_t r = (uint8_t)(p >> 16), g = (uint8_t)(p >> 8), b = (uint8_t)p;
|
||||
if (r == g && g == b) ++same;
|
||||
}
|
||||
gray = ((float)same / (float)img.argb.size()) >= 0.95f;
|
||||
}
|
||||
cache[key] = gray;
|
||||
return gray;
|
||||
}
|
||||
|
||||
struct Chunk {
|
||||
uint16_t id = 0;
|
||||
const uint8_t* data = nullptr;
|
||||
@@ -689,10 +724,13 @@ struct Builder {
|
||||
// RAMP applies ONLY to no-normal geometry (see hasNormals()): normal-bearing
|
||||
// vehicle/missile batches keep their material diffuse colour + texture (lit path),
|
||||
// so they must NOT be ramped even when the material carries a ramp ref (cdusty).
|
||||
// TRUECOLOR BSL slices (channel >= 6: RGB444/RGBA4444, e.g. damcolor's bdam8
|
||||
// damage sheet) are real colour images -- luminance-ramping them would
|
||||
// destroy their colour, so they take the plain textured path.
|
||||
const bool useRamp = currentHasRamp && (!hasNormals(vtag) || currentTSphere) && currentTexChannel < 6;
|
||||
// TRUECOLOR BSL slices (channel >= 6: RGB444/RGBA4444) ramp only when their RGB
|
||||
// is effectively GRAYSCALE (rampableSlice): bexp9/bdet9 are authored gray + ramp
|
||||
// (the wreck scorch splat's cdusty gradient, issue #3); damcolor's bdam8 damage
|
||||
// sheet is a real colour image -- luminance-ramping it would destroy its colour,
|
||||
// so it takes the plain textured path.
|
||||
const bool useRamp = currentHasRamp && (!hasNormals(vtag) || currentTSphere)
|
||||
&& rampableSlice(currentTex, currentTexChannel);
|
||||
|
||||
const uint32_t base = (uint32_t)px.size();
|
||||
const uint32_t localCount = (uint32_t)lx.size();
|
||||
@@ -839,6 +877,10 @@ struct Builder {
|
||||
batch.texScrollU = currentTexScrollU;
|
||||
batch.texScrollV = currentTexScrollV;
|
||||
batch.vertexAlpha = vertexAlpha;
|
||||
// RGBA4444 slice (channel >= 8): the texture's AUTHORED alpha channel is
|
||||
// a cutout mask (bexp9 scorch splat / bdet9 rail lattice / tree9 cards)
|
||||
// -- the renderer alpha-tests it in the opaque pass (see bgfload.h).
|
||||
batch.texAlpha = (currentTexChannel >= 8) && !currentTex.empty();
|
||||
batch.hasRamp = useRamp;
|
||||
// tsphere warp flag: warpBands>0 signals L4D3D's ramp bake to CONTRAST-
|
||||
// COMPRESS the bintA cloud toward mid-grey (BT_WARP_CONTRAST) before applying
|
||||
|
||||
Reference in New Issue
Block a user