Ejemplo n.º 1
0
        static Mathbox.Mesh TryGetMeshAt(UInt16 address)
        {
            // don't bother with these addresses
            if (address == 0x40DC || address == 0x4344)
            {
                return(null);
            }

            if (!ROM.TryRead(address, out UInt16 vertex_base))
            {
                return(null);
            }
            if (vertex_base < 0x2000 || vertex_base >= 0x8000)
            {
                return(null);
            }

            // at this point we should try and parse an object
            // the parsing could fail, in which case the catch block will catch us
            try
            {
                Mesh mesh = new Mathbox.Mesh(address, vertex_base);
                return(mesh.IsValid ? mesh : null);
            }
            catch
            {
                return(null);
            }
        }
Ejemplo n.º 2
0
            static internal bool Parse(Mathbox.Mesh mesh, UInt16 address)
            {
                // scan forever until exit condition reached
                for (; ;)
                {
                    // ensure no duplicate surfaces
                    foreach (Surface p in mesh.mSurfaces)
                    {
                        if (p.Address == address)
                        {
                            return(true); // everything OK, we just can't add any more polys
                        }
                    }

                    // try and create a new surface object
                    if (!Surface.TryCreateSurface(ref address, out Surface surface))
                    {
                        return(false);
                    }

                    /// is this the end of the surface list?
                    if (surface.VertexOffsetTable == 0x8000)
                    {
                        return(true); // end of surface list reached
                    }
                    // should the surface be drawn?
                    if (!surface.Flags.IsCullInstruction || surface.Flags.CullInstruction == CULL.AlwaysBranch)
                    {
                        // yes

                        // scan the vertex index list
                        int pIndices = surface.VertexOffsetTable;

                        // read the first offset
                        if (!ROM.TryRead(pIndices++, out UInt16 offset))
                        {
                            return(false);
                        }

                        // first vertex specifies the (optional) normal vector
                        if ((offset & 0x4000) == 0)
                        {
                            // normal vector exists
                            Vector3D normal = mesh.Vector(offset);
                            normal.Normalize();
                            surface.Normal = normal;
                        }

                        // remaining vertices are the points that make up the surface
                        while (offset < 0x8000)
                        {
                            if (!ROM.TryRead(pIndices++, out offset))
                            {
                                return(false);
                            }
                            surface.mPoints.Add(mesh.Point(offset));
                        }

                        // make sure the surface type matches the number of vertices
                        switch (surface.mPoints.Count)
                        {
                        case 0: return(false);

                        case 1:
                            // always set to "DOT"
                            surface.Flags.Type = TYPE.Dot;
                            break;

                        case 2:
                            // must be dot or vector
                            if (surface.Type == TYPE.Polygon)
                            {
                                surface.Flags.Type = TYPE.Vector;
                            }
                            break;

                        default:
                            if (surface.Type == TYPE.Vector)
                            {
                                surface.mPoints.Add(surface.mPoints[0]);     // close the vector list
                            }
                            break;
                        }

                        // shade certain objects
                        if (surface.Type == TYPE.Polygon)
                        {
                            switch (mesh.Address)
                            {
                            case 0x3892:     // eyeball
                            case 0x38A4:     // eyeball
                            case 0x38B6:     // eyeball
                            case 0x38C8:     // eyeball
                            case 0x38DA:     // eyeball
                                if (surface.ColorIndex > 0 && surface.ColorIndex <= 7)
                                {
                                    surface.Flags.IsShaded = true;     // make shaded
                                }
                                break;

                            //case 0x5767: // transporter
                            //case 0x577B: // transporter
                            //case 0x5791: // transporter
                            case 0x5B56:                       // tanker
                            case 0x5B68:                       // spike
                            case 0x5B6E:                       // spike
                            case 0x5B72:                       // spike
                            case 0x5B8C:                       // spike
                            case 0x5BB5:                       // spike
                            case 0x5BE7:                       // spike
                            case 0x5C22:                       // spike
                            case 0x5F08:                       // colored "big ball"
                            case 0x692F:                       // hand
                            case 0x730A:                       // cube
                            case 0x7318:                       // cube
                            case 0x7326:                       // cube
                            case 0x7334:                       // cube
                            case 0x7342:                       // cube
                            case 0x7350:                       // cube
                            case 0x735E:                       // cube
                            //case 0x755D: // dodecahedron
                            case 0x77D0:                       // ring
                            case 0x7DF4:                       // viewer killer
                                surface.Flags.IsShaded = true; // make shaded
                                break;
                            }
                        }

                        // fix objects
                        switch (mesh.Address)
                        {
                        case 0x2958:     // robot visor
                        case 0x29EE:     // robot visor
                        case 0x2A84:     // robot visor
                        case 0x2B1A:     // robot visor
                        case 0x2C00:     // robot visor
                            if (surface.ColorIndex == 0x38 || surface.ColorIndex == 0x39)
                            {
                                for (int n = 0; n < surface.mPoints.Count; n++)
                                {
                                    surface.mPoints[n] = surface.mPoints[n] + new Vector3D(-0.1, 0, 0);
                                }
                            }
                            break;

                        case 0x51E0:     // bird eye
                        case 0x5234:     // bird eye
                        case 0x5288:     // bird eye
                            if (surface.ColorIndex == 0x38 || surface.ColorIndex == 0x39)
                            {
                                for (int n = 0; n < surface.mPoints.Count; n++)
                                {
                                    surface.mPoints[n] = new Point3D(
                                        surface.mPoints[n].X * 15f / 18f,
                                        surface.mPoints[n].Y - 6f,
                                        surface.mPoints[n].Z + 3f);
                                }
                            }
                            break;
                        }

                        // this is a good surface

                        // check for duplicates
                        bool keep = true;
                        foreach (Surface s in mesh.mSurfaces)
                        {
                            if (surface.Equals(s))
                            {
                                keep = false;
                                break;
                            }
                        }

                        // keep surface if it is unique
                        if (keep)
                        {
                            mesh.mSurfaces.Add(surface);
                        }
                    }

                    // manage branching
                    if (surface.Flags.IsCullInstruction)
                    {
                        // find address of branch
                        UInt16 branch_addr = address;
                        if (!ROM.TryRead(address++, out UInt16 offset))
                        {
                            return(false);
                        }
                        branch_addr += offset;

                        // what type of branch is this
                        switch (surface.Flags.CullInstruction)
                        {
                        case CULL.AlwaysBranch:
                            address = branch_addr;     // take the branch
                            break;

                        case CULL.BranchIfVisible:  // branch if surface visible
                        case CULL.BranchIfHidden:   // branch if surface hidden
                        case CULL.BranchAlways:     // branch never (never draw)
                                                    // parse branch
                            if (!Parse(mesh, branch_addr))
                            {
                                return(false); // something went wrong
                            }
                            break;             // now continue parsing the original branch
                        }
                    }
                }
            }