void ParsePrimitiveList(UInt16 address) { // get pointer to vertex list VertexTableAddr = Memory[address++]; for (; ;) { // get primitive pointer UInt16 primitiveAddress = Memory[address++]; // exit when end of primitive list is encountered if (primitiveAddress >= 0x8000) { return; } // get control flags PrimitiveInstruction opCode = Memory[address++]; // fill vertex buffer bool faceVisible = RenderPrimitive(primitiveAddress, opCode); // keep/remove hidden surface 'groups'/'chunks' if (opCode.IsBranchInstruction) { // assume we will branch (this takes care of BRA states) bool branch = true; switch (opCode.BranchType) { case PrimitiveInstruction.eBranchType.BranchIfFaceHidden: branch = !faceVisible; break; case PrimitiveInstruction.eBranchType.BranchIfFaceVisible: branch = faceVisible; break; } if (!branch) { address++; } else if (opCode.IsBranchRelative) { address += Memory[address]; // NOTE: branch is Int16, could jump forward or backward } else { address = Memory[address]; } } } }
bool RenderPrimitive(UInt16 address, PrimitiveInstruction opCode) { float shade = 0; // check if first vertex is a normal vector VertexInstruction vertex = Memory[address]; if (vertex.IsNormalVector) { // get the normal vector Vector3 normal = GetVertexFromTable(vertex); normal = Vector3.Transform(normal, Parent.WorldRotation); // get the first coordinate Vector3 pt = GetVertexFromTable(Memory[address + 1]); pt = Vector3.Transform(pt, Parent.D3DTS_WORLD); // check if surface is visible if (Vector3.Dot(normal, pt) <= 0) { return(false); // not visible } // if shading enabled if (opCode.IsShaded) { // both values are 14 bit fractional precision // so dot product must be dividied by 2^(14+14) to normalize from 0.0 - 1.0 // but then we multiply by 8 (2^3) to convert to a pallete index // so we divide by 2^(14+14-3) const float scale = 1.0f / (1 << 25); shade = Vector3.Dot(normal, Parent.Light) * scale; shade = Math.Min(7, Math.Max(0, shade)); } } // should we skip rendering? if (opCode.SkipRender) { return(true); // would have been visible } // prepare the vertex buffer BuildPrimitive(address, Parent.GetColor(opCode.ColorIndex, shade), opCode.RenderMode); return(true); }