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:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user