render: skater-family character fade from the entity opacity field
This commit is contained in:
parent
e19657a45d
commit
bfb3c07839
3 changed files with 56 additions and 0 deletions
|
|
@ -39,6 +39,15 @@ REXCVAR_DEFINE_BOOL(
|
||||||
"unchanged. Off = refused captures stay pending (rescue/fixup paths).")
|
"unchanged. Off = refused captures stay pending (rescue/fixup paths).")
|
||||||
.lifecycle(rex::cvar::Lifecycle::kHotReload);
|
.lifecycle(rex::cvar::Lifecycle::kHotReload);
|
||||||
|
|
||||||
|
REXCVAR_DEFINE_BOOL(
|
||||||
|
skate3_native_render_scene_entity_fade_serve, true, "Skate 3",
|
||||||
|
"Serve skater-family character fade from the entity's own opacity "
|
||||||
|
"field (+496, the exact value the game binds as the shader's alpha "
|
||||||
|
"parameter) instead of the captured alpha row. Fixes spawn fade-ins "
|
||||||
|
"rendered opaque when the row capture lags or fails. LivingWorld "
|
||||||
|
"entities keep the LW store's fade. Off = captured-row fade.")
|
||||||
|
.lifecycle(rex::cvar::Lifecycle::kHotReload);
|
||||||
|
|
||||||
REXCVAR_DEFINE_BOOL(
|
REXCVAR_DEFINE_BOOL(
|
||||||
skate3_native_render_scene_entity_ropa_world_primary, true, "Skate 3",
|
skate3_native_render_scene_entity_ropa_world_primary, true, "Skate 3",
|
||||||
"Serve the ROPA garment world from the owner entity's m_MatLtoWTrans "
|
"Serve the ROPA garment world from the owner entity's m_MatLtoWTrans "
|
||||||
|
|
@ -481,6 +490,29 @@ bool ReadEntityWorldRows(uint8_t* base, uint32_t ctx, float out_rows[12]) {
|
||||||
ReadWorldRowsChecked(base, info.entity, out_rows);
|
ReadWorldRowsChecked(base, info.entity, out_rows);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ReadSkaterFade(uint8_t* base, uint32_t ctx, float* out_alpha) {
|
||||||
|
if (!REXCVAR_GET(skate3_native_render_scene_entity_fade_serve)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
CtxInfo info;
|
||||||
|
if (!LookupCtx(ctx, &info)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const bool skater_family =
|
||||||
|
info.cls == EntClass::kSkater || info.cls == EntClass::kColorized ||
|
||||||
|
info.cls == EntClass::kCac || info.cls == EntClass::kSkaterAux;
|
||||||
|
if (!skater_family) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
float alpha = 0.0f;
|
||||||
|
if (!LoadF32Block(base, info.entity + kEntOpacitySkater, &alpha, 1) ||
|
||||||
|
!(alpha >= -0.01f && alpha <= 1.01f)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*out_alpha = alpha;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t ServeInstancePalette(uint8_t* base, uint32_t ctx, float* out,
|
uint32_t ServeInstancePalette(uint8_t* base, uint32_t ctx, float* out,
|
||||||
uint32_t max_rows) {
|
uint32_t max_rows) {
|
||||||
CtxInfo info;
|
CtxInfo info;
|
||||||
|
|
|
||||||
|
|
@ -113,6 +113,13 @@ void ObserveCharItem(uint8_t* base, uint32_t ctx, uint32_t family,
|
||||||
bool ServeRopaWorld(uint8_t* base, uint32_t ctx, uint32_t vb_obj,
|
bool ServeRopaWorld(uint8_t* base, uint32_t ctx, uint32_t vb_obj,
|
||||||
float out_rows[12]);
|
float out_rows[12]);
|
||||||
|
|
||||||
|
// Fade serve (skater-family classes only; LivingWorld entities are
|
||||||
|
// served by the LW store): the entity's live opacity at +496, the exact
|
||||||
|
// value BindConstants points the shader's alpha parameter at. Returns
|
||||||
|
// false for unmapped ctxs, non-skater classes, or an out-of-range read
|
||||||
|
// (teardown), leaving the caller's captured-row fade untouched.
|
||||||
|
bool ReadSkaterFade(uint8_t* base, uint32_t ctx, float* out_alpha);
|
||||||
|
|
||||||
// True when the ctx maps to an entity whose garment table no longer
|
// True when the ctx maps to an entity whose garment table no longer
|
||||||
// claims vb_obj as a live cloth target; the game DROPPED the garment
|
// claims vb_obj as a live cloth target; the game DROPPED the garment
|
||||||
// (m_numClothModels back to 0, VB objects freed, memory recycled). The
|
// (m_numClothModels back to 0, VB objects freed, memory recycled). The
|
||||||
|
|
|
||||||
|
|
@ -9272,10 +9272,27 @@ void BuildFrameScene(uint8_t* base, const SubmitRecord* records, size_t count) {
|
||||||
// Read-only: the ident[] stats line is the evidence for flipping any
|
// Read-only: the ident[] stats line is the evidence for flipping any
|
||||||
// serve over to the direct fields.
|
// serve over to the direct fields.
|
||||||
{
|
{
|
||||||
|
const bool serve_ent_fade =
|
||||||
|
REXCVAR_GET(skate3_native_render_scene_entity_fade);
|
||||||
for (DrawItem& item : scene.items) {
|
for (DrawItem& item : scene.items) {
|
||||||
if (item.char_family == 0 || item.ctx == 0) {
|
if (item.char_family == 0 || item.ctx == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
// Skater-family fade from the entity's own opacity (+496): the
|
||||||
|
// value the game binds as the shader's alpha parameter. Same serving
|
||||||
|
// contract as the LW store (lw_alpha preferred by CharFadeAlpha;
|
||||||
|
// families whose shader composes the fade keep their captured rows
|
||||||
|
// bounded by it). LW-mapped items were already stamped above.
|
||||||
|
float ent_alpha = 1.0f;
|
||||||
|
if (serve_ent_fade && item.lw_alpha < 0.0f &&
|
||||||
|
skate3::native_entity::ReadSkaterFade(base, item.ctx, &ent_alpha)) {
|
||||||
|
item.lw_alpha = std::clamp(ent_alpha, 0.0f, 1.0f);
|
||||||
|
if (item.char_rows[14 * 4 + 1] > 0.0f &&
|
||||||
|
(item.char_family == 1 || item.char_family == 2 ||
|
||||||
|
item.char_family == 3 || item.char_family == 6)) {
|
||||||
|
item.char_rows[14 * 4 + 0] = item.lw_alpha;
|
||||||
|
}
|
||||||
|
}
|
||||||
skate3::native_entity::ObserveCharItem(base, item.ctx,
|
skate3::native_entity::ObserveCharItem(base, item.ctx,
|
||||||
item.char_family,
|
item.char_family,
|
||||||
item.lw_entity != 0,
|
item.lw_entity != 0,
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue