Phase 3f: lighting from wire normals; defuse shipped-in debug crash
Lighting: stride-8/9 vertices carry a normal (floats 3-5, uv at 6-7). The backend transforms normals by the instance rotation and lights with a single directional sun (GL_LIGHT0, smooth, two-sided, GL_COLOR_MATERIAL). Terrain and hulls shade instead of reading flat. LOD: the lod flush has no switch distances -- the host keeps the active LOD at the child-list head and re-orders over the wire, so children[0] is right and LOD changes come through as the sim runs. The crash that halted the game once the RIO drove the sim was not ours: fault at 0047E1D1 writing 0xFFFFFFFF is the RIO driver's DISABLE_AND_DIE debug macro (PCSPAK.ASM, DIE_ON_ERROR=1), which deliberately faults on a serial-tx anomaly -- error 3 = body char >0x7F during a RIO packet, i.e. a glitch on a board reset. Release build (DIE_ON_ERROR=0) compiles it out and recovers (and al,07Fh). patch_btl4opt.py NOPs all 12 sites by signature (with .orig backup) = release behavior; game then survives RIO resets (1200+ frames). (ALPHA_1 is git-ignored, so the tool ships, not the patched binary.) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -439,6 +439,7 @@ struct VPoly {
|
||||
float rgb[3];
|
||||
std::vector<float> xyz; /* x,y,z triples */
|
||||
std::vector<float> uv; /* u,v pairs (empty = untextured) */
|
||||
std::vector<float> nrm; /* nx,ny,nz triples (empty = unlit) */
|
||||
unsigned matkey; /* material name for texture lookup, 0 = none */
|
||||
VPoly() : matkey(0) {}
|
||||
};
|
||||
@@ -472,6 +473,7 @@ static struct VScene {
|
||||
std::map<unsigned, unsigned> type; /* name -> node type */
|
||||
std::map<unsigned, std::vector<float> > verts; /* geometry -> xyz */
|
||||
std::map<unsigned, std::vector<float> > uvs; /* geometry -> u,v */
|
||||
std::map<unsigned, std::vector<float> > nrms; /* geometry -> nx,ny,nz */
|
||||
std::map<unsigned, std::vector<std::vector<int> > > polys;
|
||||
std::map<unsigned, VCol> mat; /* material -> RGB */
|
||||
std::map<unsigned, unsigned> ggmat; /* geogroup -> material */
|
||||
@@ -512,6 +514,10 @@ static void m16_xform(const M16 &w, const float *v, float *o) {
|
||||
for (int c = 0; c < 3; c++)
|
||||
o[c] = v[0] * w.m[c] + v[1] * w.m[4 + c] + v[2] * w.m[8 + c] + w.m[12 + c];
|
||||
}
|
||||
static void m16_xform_dir(const M16 &w, const float *v, float *o) {
|
||||
for (int c = 0; c < 3; c++) /* rotation only (normals) */
|
||||
o[c] = v[0] * w.m[c] + v[1] * w.m[4 + c] + v[2] * w.m[8 + c];
|
||||
}
|
||||
/* world transform of a dcs: local * parent_world (row-vector convention) */
|
||||
static void dcs_world(unsigned dcs, std::map<unsigned, M16> &cache, M16 &out,
|
||||
int depth = 0) {
|
||||
@@ -567,8 +573,22 @@ static void rt_draw(HDC dc, const VFrame &f, int cw, int ch) {
|
||||
glTranslatef(-f.eye[0], -f.eye[1], -f.eye[2]);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_LIGHTING);
|
||||
glShadeModel(GL_FLAT);
|
||||
glShadeModel(GL_SMOOTH);
|
||||
/* directional sun (world coords; modelview is loaded, so GL maps it
|
||||
* into eye space). World is y-down: up = -y. */
|
||||
{
|
||||
GLfloat lpos[4] = { 0.35f, -0.85f, 0.40f, 0.0f };
|
||||
GLfloat lamb[4] = { 0.45f, 0.45f, 0.45f, 1.0f };
|
||||
GLfloat ldif[4] = { 0.80f, 0.80f, 0.78f, 1.0f };
|
||||
glLightfv(GL_LIGHT0, GL_POSITION, lpos);
|
||||
glLightfv(GL_LIGHT0, GL_AMBIENT, lamb);
|
||||
glLightfv(GL_LIGHT0, GL_DIFFUSE, ldif);
|
||||
glEnable(GL_LIGHT0);
|
||||
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 1);
|
||||
glEnable(GL_COLOR_MATERIAL);
|
||||
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
|
||||
glEnable(GL_NORMALIZE);
|
||||
}
|
||||
/* upload any new/changed baked material textures */
|
||||
static std::map<unsigned, GLuint> gltex; /* matkey -> GL name */
|
||||
static std::map<unsigned, unsigned> gltex_ver;
|
||||
@@ -610,14 +630,18 @@ static void rt_draw(HDC dc, const VFrame &f, int cw, int ch) {
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glColor3f(p.rgb[0], p.rgb[1], p.rgb[2]);
|
||||
}
|
||||
bool lit = !p.nrm.empty();
|
||||
if (lit) glEnable(GL_LIGHTING); else glDisable(GL_LIGHTING);
|
||||
glBegin(GL_POLYGON);
|
||||
for (size_t v = 0; v + 2 < p.xyz.size(); v += 3) {
|
||||
if (tex) glTexCoord2f(p.uv[v / 3 * 2], p.uv[v / 3 * 2 + 1]);
|
||||
if (lit) glNormal3f(p.nrm[v], p.nrm[v + 1], p.nrm[v + 2]);
|
||||
glVertex3f(p.xyz[v], p.xyz[v + 1], p.xyz[v + 2]);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glDisable(GL_LIGHTING);
|
||||
}
|
||||
SwapBuffers(dc);
|
||||
}
|
||||
@@ -740,10 +764,18 @@ static void emit_geogroup(VFrame &f, unsigned gg, const M16 *world) {
|
||||
if (vi == S.verts.end() || pi == S.polys.end()) continue;
|
||||
const std::vector<float> &vv = vi->second;
|
||||
const std::vector<float> *uv = NULL;
|
||||
const std::vector<float> *nr = NULL;
|
||||
std::map<unsigned, std::vector<float> >::const_iterator ui =
|
||||
S.uvs.find(geo);
|
||||
if (ui != S.uvs.end() && ui->second.size() * 3 == vv.size() * 2)
|
||||
uv = &ui->second;
|
||||
std::map<unsigned, std::vector<float> >::const_iterator ni =
|
||||
S.nrms.find(geo);
|
||||
if (ni != S.nrms.end() && ni->second.size() == vv.size()) {
|
||||
/* only meaningful if not all-zero (stride < 8 stores zeros) */
|
||||
for (size_t z = 0; z < ni->second.size(); z++)
|
||||
if (ni->second[z] != 0.0f) { nr = &ni->second; break; }
|
||||
}
|
||||
for (size_t q = 0; q < pi->second.size(); q++) {
|
||||
const std::vector<int> &idx = pi->second[q];
|
||||
VPoly poly;
|
||||
@@ -762,7 +794,17 @@ static void emit_geogroup(VFrame &f, unsigned gg, const M16 *world) {
|
||||
poly.uv.push_back((*uv)[(size_t)idx[j] * 2]);
|
||||
poly.uv.push_back((*uv)[(size_t)idx[j] * 2 + 1]);
|
||||
}
|
||||
if (nr) {
|
||||
float nout[3];
|
||||
if (world) m16_xform_dir(*world, &(*nr)[o], nout);
|
||||
else { nout[0] = (*nr)[o]; nout[1] = (*nr)[o + 1];
|
||||
nout[2] = (*nr)[o + 2]; }
|
||||
poly.nrm.push_back(nout[0]);
|
||||
poly.nrm.push_back(nout[1]);
|
||||
poly.nrm.push_back(nout[2]);
|
||||
}
|
||||
}
|
||||
if (poly.nrm.size() != poly.xyz.size()) poly.nrm.clear();
|
||||
if (poly.xyz.size() >= 9) f.polys.push_back(poly);
|
||||
}
|
||||
}
|
||||
@@ -790,7 +832,10 @@ static void scene_publish_frame(void) {
|
||||
std::map<unsigned, std::vector<unsigned> >::const_iterator li =
|
||||
S.children.find(oi->second);
|
||||
if (li == S.children.end() || li->second.empty()) continue;
|
||||
unsigned lod = li->second[0]; /* highest LOD */
|
||||
/* First LOD child: the host maintains the active LOD at the list
|
||||
* head (the wire lod flush carries no switch distances -- LOD
|
||||
* selection is host-side). */
|
||||
unsigned lod = li->second[0];
|
||||
std::map<unsigned, std::vector<unsigned> >::const_iterator ggi =
|
||||
S.children.find(lod);
|
||||
if (ggi == S.children.end()) continue;
|
||||
@@ -824,11 +869,13 @@ static void scene_burst(const unsigned char *p, size_t n) {
|
||||
if (S.geom_acc.size() >= S.geom_need * S.geom_stride) {
|
||||
std::vector<float> &vl = S.verts[S.geom_node];
|
||||
std::vector<float> &tl = S.uvs[S.geom_node];
|
||||
vl.clear(); tl.clear();
|
||||
/* uv offset within a vertex record by stride: 5 = xyz+uv,
|
||||
* 8/9 = xyz+normal+uv(+extra) */
|
||||
std::vector<float> &nl = S.nrms[S.geom_node];
|
||||
vl.clear(); tl.clear(); nl.clear();
|
||||
/* record layout by stride: 5 = xyz+uv,
|
||||
* 8/9 = xyz + normal(3..5) + uv(6..7) (+extra) */
|
||||
size_t uvo = (S.geom_stride >= 8) ? 6 :
|
||||
(S.geom_stride == 5) ? 3 : 0;
|
||||
bool has_n = S.geom_stride >= 8;
|
||||
for (size_t i = 0; i + 2 < S.geom_need * S.geom_stride;
|
||||
i += S.geom_stride) {
|
||||
vl.push_back(S.geom_acc[i]);
|
||||
@@ -838,6 +885,11 @@ static void scene_burst(const unsigned char *p, size_t n) {
|
||||
tl.push_back(S.geom_acc[i + uvo]);
|
||||
tl.push_back(S.geom_acc[i + uvo + 1]);
|
||||
} else { tl.push_back(0); tl.push_back(0); }
|
||||
if (has_n && i + 5 < S.geom_acc.size()) {
|
||||
nl.push_back(S.geom_acc[i + 3]);
|
||||
nl.push_back(S.geom_acc[i + 4]);
|
||||
nl.push_back(S.geom_acc[i + 5]);
|
||||
} else { nl.push_back(0); nl.push_back(0); nl.push_back(0); }
|
||||
}
|
||||
S.geom_acc.clear();
|
||||
S.geom_active = false;
|
||||
|
||||
Reference in New Issue
Block a user