public void Rasterize() { // locate the tile table in memory System.Diagnostics.Debug.Assert(Memory[TERRAIN_BASE_ADDRESS] == 0xE00); TileTableBaseAddress = Memory[TERRAIN_BASE_ADDRESS]; // always 0x0E00 Parent.StartRender(); Parent.LoadLightVector(); Parent.LoadViewPosition(); Parent.LoadViewMatrix(0x15); Rotation = Parent.ViewRotation; Parent.SetWorldMatrix(ref Parent.Terrain.Rotation); // determine rendering method (dot/vector/polygon) switch (Memory[TERRAIN_RENDERING_MODE]) { case 0x0000: renderMode = Mathbox.RenderMode.Polygon; break; case 0x0100: renderMode = Mathbox.RenderMode.Vector; break; default: renderMode = Mathbox.RenderMode.Dot; break; } // get address of terrain object buffer ObjectList = Memory[TERRAIN_OBJECT_LIST_ADDRESS]; Int16 z_max = (Int16)Memory[TERRAIN_Z_MAX]; Int16 z_min = (Int16)Memory[TERRAIN_Z_MIN]; Int16 x = (Int16)Memory[TERRAIN_X]; Int16 z_frac = (Int16)Memory[TERRAIN_Z_FRAC]; Int16 x_offset = (Int16)Memory[TERRAIN_X_OFFSET]; Int16 z_offset = (Int16)Memory[TERRAIN_Z_OFFSET]; // locate left front tile corner (x1,y1,z1) // +-------+ // / /| // / / | x2 = x1 + Mathbox.Tile.SIZE_X // y1-- +-------+ | y2 = y1 + Mathbox.Tile.SIZE_Y // | | + --z2 z2 = z1 + Mathbox.Tile.SIZE_Z // | | / // | |/ // y2-- +-------+ --z1 // | | // x1 x2 Vector3 corner = new Vector3( Tile.WIDTH_X - x_offset * 128 - x, -Parent.ViewPosition.Y, z_max * 128 - z_frac); // render each row in the terrain int row = z_offset / 16 + z_max; // first absolute row to be rendered Row.Count = z_max - z_min + 1; // number of rows to display while (Row.Count-- > 0) { DrawTerrainRow(row-- & 31, corner); corner.Z -= Tile.DEPTH_Z; // move to next row along the Z axis } Parent.EndRender(); }
/// <summary> /// Parses the list of objects to render /// </summary> /// <param name="address">base address of object list</param> public void ParseObjectList(UInt16 address) { // address+0 Object position.X // address+1 Object position.Y // address+2 Object position.Z // address+3 Object Instruction // address+4 Address of view matrix // address+5 Address of rotation matrix (only if specified by instruction) // address+6 Address of surface list (only if specified by instruction) // address +5 or + 7 first child object #if false Debug.WriteLine($"{Memory[address+0].HexString()} {Memory[address + 1].HexString()} {Memory[address + 2].HexString()} {Memory[address + 3].HexString()} {Memory[address + 4].HexString()} {Memory[address + 5].HexString()} {Memory[address + 6].HexString()}"); #endif for (; ;) { // check for end of list if (address == 0 || address >= 0x8000) { return; } // Control word encoding // 0x8000 = stop flag // 0x4000 = don't load camera matrix // 0x1000 = ? // 0x0800 = don't load base address or rotation matrix // 0x0400 = x/y/z value is relative offset, not absolute position Mathbox.ObjectInstruction opcode = Memory[address + 3]; // load camera matrix if (!opcode.SkipObjectRotation) { Parent.LoadViewMatrix(Memory[address + 4]); } // Get new primitive list address and rotation matrix if they exist int childAddr = address + 5; if (!opcode.UsePreviousObjectPointsAndFaces) { PrimitiveListAddress = Memory[address + 6]; if (PrimitiveListAddress >= 0x8000) { return; } Parent.LoadRotationMatrix(Memory[address + 5]); childAddr += 2; } // Don't render invalid objects if (PrimitiveListAddress >= 0x8000) { return; } // Determine position of object Vector3 pt = Parent.GetVectorAt(address); if (opcode.ObjectPositionIsRelative) { // relative position Parent.WorldPosition += Vector3.Transform(pt, Parent.ViewRotation); } else { // absolute position pt -= Parent.ViewPosition; Parent.WorldPosition = Vector3.Transform(pt, Parent.ViewRotation); } Parent.SetWorldMatrix(ref Parent.WorldPosition, ref Parent.WorldRotation); #if WIDESCREEN_STARS if (PrimitiveListAddress >= 0x4AE8 && PrimitiveListAddress <= 0x4B44) { for (int n = 0; n < Stars.Length; n++) { Vertices[n] = Vector3.Transform(Stars[n], Parent.D3DTS_WORLD); } DisplayListManager.AddPrimitive(Mathbox.RenderMode.Dot, Vertices, Stars.Length, Parent.GetColor(7)); return; } #endif // parese the surfaces in this object ParsePrimitiveList(PrimitiveListAddress); // parse all child objects for (; ;) { UInt16 child = Memory[childAddr++]; if (child == 0 || child >= 0x8000) { return; } if (child == 0x0002) { address += 8; break; } ParseObjectList(child); } } }