pvision solved (texture-value ramp) + i860/hardware reverse-engineering

Predator/IR vision: reverse-engineered from the original firmware and
confirmed by the build team -- it is the Division board's TEXTURE-VALUE RAMP
mode (a "check your texture maps" diagnostic the devs hijacked), NOT a
grayscale squash or a false-colour palette. Located in VREND.MNG (effect
handler @0xe6c0, wire action 0x1b, type -1 ON / -2 OFF); ramp colours from
VR_DRAW.C. Renderer reworked to match: vrview_gl now does the 4-ramp
lerp(color0,color1,luminance(texel)) in the mesh pass (grayscale+defog
removed). Live-rendered on a new night-clear arena egg; crew A/B verdict
pending.

Firmware-decomp toolchain (emulator/firmware-decomp/), all built from the
project's own artifacts and validated:
- coff860.py    i860 COFF reader (symbols/sections), names match AS860 source
- derive860.py  derives the i860 opcode map from matched .S<->.O pairs
- dis860.py     i860 disassembler (98% on clean ground truth; proven on
                VREND.MNG -- velocirender_statistics decodes correctly)
- sigmatch860.py reloc-invariant signature matcher onto the stripped image
- i860-encoding.md / FIRMWARE-SYMBOLS.txt / README.md

PVISION-IMPLEMENTATION-GUIDE.md: self-contained hand-off for the BT411 team.

HARDWARE-ARCHITECTURE.md + hardware-photos/ (15 board shots): the Division
VelociRender card is a 2-board stack driving a 3-processor pipeline --
INMOS IMS T425-J25S (comms/control, runs vrendmon.btl) + Intel i860 XP-50 (FP
geometry, runs vrender.mng) + Division PXPL IGC 5.2 ASIC with ~48x PXPL EMC
5.1 (UNC Pixel-Planes-5 SIMD array; "EMC" = the firmware's configEMCs) +
Analog Devices ADV7150 RAMDAC + NTSC. Plus the VWE Video Distribution Board
(P/N 1404: AMD MACH130 + 3x Brooktree Bt477) for the 3-VGA-head cockpit split.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Cyd
2026-07-14 22:29:53 -05:00
co-authored by Claude Fable 5
parent 5593d57d48
commit 1323397a50
28 changed files with 2436 additions and 27 deletions
+44 -27
View File
@@ -103,6 +103,9 @@ uniform float u_opacity; // DITHER n -> screen-door
uniform vec3 u_fogcol;
uniform int u_fog_on;
uniform vec2 u_fogrange; // near, far
uniform int u_pv; // IR / predator vision: texture-value ramp mode
uniform vec3 u_pvcol0; // ramp dark endpoint (low texel value)
uniform vec3 u_pvcol1; // ramp bright endpoint (high texel value)
in vec3 v_base;
in vec2 v_uv;
in float v_fog;
@@ -115,14 +118,20 @@ void main() {
if (bay > u_opacity) discard;
}
vec3 rgb;
vec3 t = v_base; // texel value; defaults to shaded base if untextured
if (u_has_tex == 1) {
vec3 t = texture(u_tex, v_uv + u_uvoff).rgb;
t = texture(u_tex, v_uv + u_uvoff).rgb;
if (u_alpha_cut == 1 && (t.r + t.g + t.b) <= 24.0 / 255.0)
discard; // near-black texel = transparent
rgb = t * (v_base * 1.275); // software: texel * (base/200), base 0..255
} else {
rgb = v_base;
}
if (u_pv == 1) {
// Division texture-value ramp: texel brightness -> colour gradient
float val = clamp(dot(t, vec3(0.299, 0.587, 0.114)), 0.0, 1.0);
rgb = mix(u_pvcol0, u_pvcol1, val);
}
// alpha only takes effect in the deferred blended pass (opaque pass
// renders with BLEND disabled)
float fogf = (u_fog_on == 1)
@@ -189,36 +198,36 @@ void main() { // fullscreen triangle from gl_VertexID
PRESENT_FS = """
#version 330
uniform sampler2D u_tex;
uniform int u_pv; // IR / predator-vision on (board.pvision)
uniform int u_pvmode; // 0 mono, 1 green, 2 amber, 3 heat-ramp
uniform int u_pv; // retained (set 0); pvision is now in the mesh pass
uniform int u_pvmode;
in vec2 v_uv;
out vec4 f_color;
vec3 heat(float t) { // black -> red -> yellow -> white heat ramp
vec3 c = mix(vec3(0.0), vec3(1.0, 0.0, 0.0), clamp(t / 0.40, 0.0, 1.0));
c = mix(c, vec3(1.0, 1.0, 0.0), clamp((t - 0.40) / 0.40, 0.0, 1.0));
c = mix(c, vec3(1.0), clamp((t - 0.80) / 0.20, 0.0, 1.0));
return c;
}
void main() {
vec3 c = texture(u_tex, v_uv).rgb;
if (u_pv == 1) { // thermal false-colour from scene luminance
float lum = dot(c, vec3(0.299, 0.587, 0.114));
if (u_pvmode == 0) c = vec3(lum);
else if (u_pvmode == 1) c = vec3(lum * 0.15, lum, lum * 0.15);
else if (u_pvmode == 2) c = vec3(lum, lum * 0.72, lum * 0.18);
else c = heat(lum);
}
f_color = vec4(pow(c, vec3(1.0 / 1.25)), 1.0); // Division DAC gamma
}
"""
# IR / "predator vision" thermal view. The game toggles it via dpl_Effect on
# action 0x1b (mode -1 ON / -2 OFF) -> board.pvision; VRVIEW_PVISION=1 or the
# bridge 'v' key forces it on for evaluation without pressing the cockpit IR
# button. Palette: VRVIEW_PVISION_PALETTE = mono|green|amber|heat (default
# heat/Predator-style, operator's interim pick 2026-07-14; exact original TBD).
# IR / "predator vision". The game toggles it via dpl_Effect on action 0x1b
# (mode -1 ON / -2 OFF) -> board.pvision; VRVIEW_PVISION=1 or the bridge 'v' key
# forces it on for evaluation without the cockpit IR button.
#
# ANSWER (firmware-decompiled + confirmed by the original team, 2026-07-14): it
# is the Division board's TEXTURE-VALUE RAMP mode -- a "check your texture maps"
# diagnostic the devs hijacked. Each textured surface renders as
# lerp(color0, color1, luminance(texel)): the texel's *value* drives a colour
# ramp. Multicolour because each material picks one of FOUR ramps (VR_DRAW.C
# 704-707). ramp_entry isn't plumbed through vrboard yet, so we assign a ramp
# per geometry (stable hash) to reproduce the multicolour look; swap to the real
# per-material index when material-ramp parsing lands. See
# emulator/firmware-decomp/README.md.
PVISION = [os.environ.get('VRVIEW_PVISION', '0') != '0']
_PV_MODES = {'mono': 0, 'green': 1, 'amber': 2, 'heat': 3}
# color0 = dark endpoint (low texel value), color1 = bright endpoint (high).
PV_RAMP0 = ((0.0, 0.0, 0.0), (0.3, 0.0, 0.0), (0.0, 0.5, 0.0), (0.0, 0.0, 0.4))
PV_RAMP1 = ((1.0, 1.0, 1.0), (1.0, 1.0, 0.9), (1.0, 1.0, 1.0), (0.9, 0.9, 1.0))
# VRVIEW_PVISION_RAMP=0..3 forces a single ramp for all surfaces (A/B testing);
# unset = per-geometry ramp (multicolour, the authentic look).
_PV_FORCE = os.environ.get('VRVIEW_PVISION_RAMP')
HUD_VS = """
@@ -578,11 +587,10 @@ class GLRenderer(vrview.Renderer):
ctx.disable(mgl.DEPTH_TEST)
self._fbo_tex.use(0)
self._set(self._present_prog, 'u_tex', 0)
self._set(self._present_prog, 'u_pv',
1 if (PVISION[0] or getattr(board, 'pvision', False)) else 0)
self._set(self._present_prog, 'u_pvmode',
_PV_MODES.get(os.environ.get('VRVIEW_PVISION_PALETTE',
'heat'), 3))
# pvision moved to the mesh pass (texture-value ramp); present is a
# plain gamma present now.
self._set(self._present_prog, 'u_pv', 0)
self._set(self._present_prog, 'u_pvmode', 0)
self._present_vao.render(mgl.TRIANGLES, vertices=3)
pg.display.flip()
cam = self.cam_matrix(board)
@@ -661,6 +669,15 @@ class GLRenderer(vrview.Renderer):
self._set(prog, 'u_has_nrm', 1 if mesh['nrm'] is not None else 0)
self._set(prog, 'u_has_col', 1 if mesh['col'] is not None else 0)
# IR / predator vision: texture-value ramp. ramp_entry isn't plumbed, so
# pick a stable ramp per geometry (or a forced one) for the multicolour look.
pv_on = 1 if (PVISION[0] or getattr(board, 'pvision', False)) else 0
self._set(prog, 'u_pv', pv_on)
if pv_on:
ri = int(_PV_FORCE) & 3 if _PV_FORCE is not None else hash(gh) & 3
self._set(prog, 'u_pvcol0', PV_RAMP0[ri])
self._set(prog, 'u_pvcol1', PV_RAMP1[ri])
tex = c.geom_tex.get(gh)
has_tex = tex is not None and mesh['uv'] is not None
self._set(prog, 'u_has_tex', 1 if has_tex else 0)