Exemplo n.º 1
0
        public Face AddAttrToFace(byte[] filebytes, int pos, VertexAttributeArrayType attr, Face f, int vertIndex)
        {
            switch (attr)
            {
            case VertexAttributeArrayType.GX_VA_POS:

                switch (vertIndex)              //I'm aware that this is an awful way to do it, but I don't want to go back and refactor the skyheroes code right now
                {
                case 0: f.v1 = Utility.ReadUInt16BigEndian(filebytes, pos); pos += 2; break;

                case 1: f.v2 = Utility.ReadUInt16BigEndian(filebytes, pos); pos += 2; break;

                case 2: f.v3 = Utility.ReadUInt16BigEndian(filebytes, pos); pos += 2; break;

                case 3: f.v4 = Utility.ReadUInt16BigEndian(filebytes, pos); pos += 2; break;
                }
                break;

            case VertexAttributeArrayType.GX_VA_NRM:
                switch (vertIndex)
                {            //I'm aware that this is an awful way to do it, but I don't want to go back and refactor the skyheroes code right now
                case 0: f.vn1 = Utility.ReadUInt16BigEndian(filebytes, pos); pos += 2; break;

                case 1: f.vn2 = Utility.ReadUInt16BigEndian(filebytes, pos); pos += 2; break;

                case 2: f.vn3 = Utility.ReadUInt16BigEndian(filebytes, pos); pos += 2; break;

                case 3: f.vn4 = Utility.ReadUInt16BigEndian(filebytes, pos); pos += 2; break;
                }
                break;

            case VertexAttributeArrayType.GX_VA_TEX0:
                switch (vertIndex)
                {            //I'm aware that this is an awful way to do it, but I don't want to go back and refactor the skyheroes code right now
                case 0: f.vt1 = Utility.ReadUInt16BigEndian(filebytes, pos); pos += 2; break;

                case 1: f.vt2 = Utility.ReadUInt16BigEndian(filebytes, pos); pos += 2; break;

                case 2: f.vt3 = Utility.ReadUInt16BigEndian(filebytes, pos); pos += 2; break;

                case 3: f.vt4 = Utility.ReadUInt16BigEndian(filebytes, pos); pos += 2; break;
                }
                break;

            case VertexAttributeArrayType.GX_VA_TEX1:
                pos += 2;       //skip for now until multiple UVs are implemented
                break;

            case VertexAttributeArrayType.GX_VA_TEX2:
                pos += 2;       //skip for now until multiple UVs are implemented
                break;

            case VertexAttributeArrayType.GX_VA_TEX3:
                pos += 2;       //skip for now until multiple UVs are implemented
                break;

            case VertexAttributeArrayType.GX_VA_TEX4:
                pos += 2;       //skip for now until multiple UVs are implemented
                break;

            case VertexAttributeArrayType.GX_VA_TEX5:
                pos += 2;       //skip for now until multiple UVs are implemented
                break;

            case VertexAttributeArrayType.GX_VA_TEX6:
                pos += 2;       //skip for now until multiple UVs are implemented
                break;

            case VertexAttributeArrayType.GX_VA_TEX7:
                pos += 2;       //skip for now until multiple UVs are implemented
                break;

            case VertexAttributeArrayType.GX_VA_CLR0:
            case VertexAttributeArrayType.GX_VA_CLR1:
                switch (vertIndex)
                {            //I'm aware that this is an awful way to do it, but I don't want to go back and refactor the skyheroes code right now
                case 0: f.vc1 = Utility.ReadUInt16BigEndian(filebytes, pos); pos += 2; break;

                case 1: f.vc2 = Utility.ReadUInt16BigEndian(filebytes, pos); pos += 2; break;

                case 2: f.vc3 = Utility.ReadUInt16BigEndian(filebytes, pos); pos += 2; break;

                case 3: f.vc4 = Utility.ReadUInt16BigEndian(filebytes, pos); pos += 2; break;
                }
                break;

            default:
                System.Windows.Forms.MessageBox.Show("Unhandled vertex array type at " + pos + ": " + attr);
                break;
            }

            f.temp = pos;

            return(f);
        }
Exemplo n.º 2
0
        public RevoModel(Subfile basis)
        {
            int pos = 0;

            magic = Utility.ReadUInt32BigEndian(basis.filebytes, pos); pos += 4;
            flags = Utility.ReadUInt32BigEndian(basis.filebytes, pos); pos += 4;

            pos += 0x18;

            int meshcount       = Utility.ReadInt32BigEndian(basis.filebytes, pos); pos += 4;
            int meshtableoffset = Utility.ReadInt32BigEndian(basis.filebytes, pos); pos += 4;

            for (int m = 0; m < meshcount; m++)
            {
                Mesh newMesh = new Mesh();

                pos = meshtableoffset + (m * 4);
                int meshInfoTableOffset = Utility.ReadInt32BigEndian(basis.filebytes, pos); pos += 4;

                pos = meshInfoTableOffset;

                int displayListSize   = Utility.ReadInt32BigEndian(basis.filebytes, pos); pos += 4;
                int displayListOffset = Utility.ReadInt32BigEndian(basis.filebytes, pos); pos += 4;
                int numVertAttributes = Utility.ReadInt32BigEndian(basis.filebytes, pos); pos += 4;
                int vertDataOffset    = Utility.ReadInt32BigEndian(basis.filebytes, pos); pos += 4;

                newMesh.hash_of_material = Utility.ReadUInt64BigEndian(basis.filebytes, pos); pos += 8;
                uint typeID_of_material = Utility.ReadUInt32BigEndian(basis.filebytes, pos); pos += 4;
                uint unk2 = Utility.ReadUInt32BigEndian(basis.filebytes, pos); pos += 4;

                float boundsMinX = Utility.ReadSingleBigEndian(basis.filebytes, pos); pos += 4;
                float boundsMinY = Utility.ReadSingleBigEndian(basis.filebytes, pos); pos += 4;
                float boundsMinZ = Utility.ReadSingleBigEndian(basis.filebytes, pos); pos += 4;

                float boundsMaxX = Utility.ReadSingleBigEndian(basis.filebytes, pos); pos += 4;
                float boundsMaxY = Utility.ReadSingleBigEndian(basis.filebytes, pos); pos += 4;
                float boundsMaxZ = Utility.ReadSingleBigEndian(basis.filebytes, pos); pos += 4;

                uint unk3 = Utility.ReadUInt32BigEndian(basis.filebytes, pos); pos += 4;
                uint unk4 = Utility.ReadUInt32BigEndian(basis.filebytes, pos); pos += 4;

                uint unk5 = Utility.ReadUInt32BigEndian(basis.filebytes, pos); pos += 4; //FNV-1 hash of "none" in MySims Kingdom. Different in Agents.

                pos += 12;

                int boneToMatrixBindingInfoOffset = Utility.ReadInt32BigEndian(basis.filebytes, pos); pos += 4;
                int boneNamesOffset = Utility.ReadInt32BigEndian(basis.filebytes, pos); pos += 4;
                int boneInfoOffset  = Utility.ReadInt32BigEndian(basis.filebytes, pos); pos += 4;

                //now read vertex data

                for (int v = 0; v < numVertAttributes; v++)
                {
                    pos = vertDataOffset + (v * 8);

                    VertexAttributeArrayType vertexArrayType = (VertexAttributeArrayType)basis.filebytes[pos]; pos++;
                    //what kind of data is stored in the array: positions? lights? etc.
                    newMesh.presentAttributes.Add(vertexArrayType);

                    VertexAttributeComponentType vertexComponentType = (VertexAttributeComponentType)(basis.filebytes[pos] >> 3);
                    //how many components are there to the data, e.g. is it XYZ, or just XY? etc.

                    VertexAttributeComponentSize vertexComponentSize = (VertexAttributeComponentSize)(basis.filebytes[pos] & 0x07); pos++;
                    //what format is the data in, e.g. 32 bit float, u8, RGB565, etc...

                    pos += 2;                                               //skip padding

                    pos = Utility.ReadInt32BigEndian(basis.filebytes, pos); //now go to the start of the actual entries



                    int stopPoint = boneToMatrixBindingInfoOffset;  //absolute endpoint is the beginning of the next section
                    if (stopPoint == 0)
                    {
                        if (m == meshcount - 1)
                        {
                            stopPoint = basis.filebytes.Length;
                        }
                        else
                        {
                            stopPoint = Utility.ReadInt32BigEndian(basis.filebytes, meshtableoffset + ((m + 1) * 4));
                        }
                    }

                    if (v < numVertAttributes - 1)   //but if we're not at the last vertex array yet, then the endpoint is the start of the next array
                    {
                        stopPoint = Utility.ReadInt32BigEndian(basis.filebytes, vertDataOffset + ((v + 1) * 8) + 4);
                    }

                    int checkAheadAmount = 12;

                    if (vertexArrayType == VertexAttributeArrayType.GX_LIGHTARRAY)   //it will probably ask for RGB values etc
                    {
                        switch (vertexComponentSize)
                        {
                        case VertexAttributeComponentSize.GX_RGBA4:
                            checkAheadAmount = 1;
                            break;

                        case VertexAttributeComponentSize.GX_RGB565:
                            checkAheadAmount = 2;
                            break;

                        case VertexAttributeComponentSize.GX_RGB8:      //more accurately described as RGB24
                        case VertexAttributeComponentSize.GX_RGBA6:     //more accurately described as RGBA24
                            checkAheadAmount = 3;
                            break;

                        case VertexAttributeComponentSize.GX_RGBA8:
                        case VertexAttributeComponentSize.GX_RGBX8:
                            checkAheadAmount = 4;
                            break;
                        }
                    }
                    else
                    {
                        switch (vertexComponentSize)
                        {
                        case VertexAttributeComponentSize.GX_S8:
                        case VertexAttributeComponentSize.GX_U8:
                            checkAheadAmount = 1;
                            break;

                        case VertexAttributeComponentSize.GX_S16:
                        case VertexAttributeComponentSize.GX_U16:
                            checkAheadAmount = 2;
                            break;

                        case VertexAttributeComponentSize.GX_F32:
                            checkAheadAmount = 4;
                            break;
                        }
                    }

                    switch (vertexComponentType)
                    {
                    case VertexAttributeComponentType.GX_POS_XY:
                        checkAheadAmount *= 2;
                        break;

                    case VertexAttributeComponentType.GX_POS_XYZ:
                        checkAheadAmount *= 3;
                        break;

                    default:
                        System.Windows.Forms.MessageBox.Show("Unhandled component type, and therefore couldn't find an appopriate multiplier: " + vertexComponentType);
                        break;
                    }

                    //now actually go and read those vertices

                    List <Vertex> vertexAttributes = new List <Vertex>();

                    do
                    {
                        Vertex newVertex = new Vertex();

                        Console.WriteLine("Loading attribute " + vertexArrayType);

                        if (vertexArrayType == VertexAttributeArrayType.GX_VA_POS)
                        {
                            switch (vertexComponentType)
                            {
                            case VertexAttributeComponentType.GX_POS_XY:

                                if (vertexComponentSize == VertexAttributeComponentSize.GX_F32)
                                {
                                    checkAheadAmount     = 8;
                                    newVertex.position.x = Utility.ReadSingleBigEndian(basis.filebytes, pos); pos += 4;
                                    newVertex.position.y = Utility.ReadSingleBigEndian(basis.filebytes, pos); pos += 4;
                                }
                                else
                                {
                                    System.Windows.Forms.MessageBox.Show("Argh! The vertex coordinates are not floats! How annoying.");
                                }
                                break;

                            case VertexAttributeComponentType.GX_POS_XYZ:

                                if (vertexComponentSize == VertexAttributeComponentSize.GX_F32)
                                {
                                    checkAheadAmount     = 12;
                                    newVertex.position.x = Utility.ReadSingleBigEndian(basis.filebytes, pos); pos += 4;
                                    newVertex.position.y = Utility.ReadSingleBigEndian(basis.filebytes, pos); pos += 4;
                                    newVertex.position.z = Utility.ReadSingleBigEndian(basis.filebytes, pos); pos += 4;
                                }
                                else
                                {
                                    System.Windows.Forms.MessageBox.Show("Argh! The vertex coordinates are not floats! How annoying.");
                                }
                                break;

                            default:
                                Console.WriteLine("Unhandled vertex component type: " + vertexComponentType);
                                break;
                            }
                        }
                        else if (vertexArrayType == VertexAttributeArrayType.GX_VA_NRM || vertexArrayType == VertexAttributeArrayType.GX_VA_TEX0 || vertexArrayType == VertexAttributeArrayType.GX_VA_TEX1 || vertexArrayType == VertexAttributeArrayType.GX_VA_TEX2 || vertexArrayType == VertexAttributeArrayType.GX_VA_TEX3 || vertexArrayType == VertexAttributeArrayType.GX_VA_TEX4 || vertexArrayType == VertexAttributeArrayType.GX_VA_TEX5 || vertexArrayType == VertexAttributeArrayType.GX_VA_TEX6 || vertexArrayType == VertexAttributeArrayType.GX_VA_TEX7)
                        {
                            switch (vertexComponentType)
                            {
                            case VertexAttributeComponentType.GX_NRM_XYZ:

                                if (vertexComponentSize == VertexAttributeComponentSize.GX_F32)
                                {
                                    checkAheadAmount   = 12;
                                    newVertex.normal.x = Utility.ReadSingleBigEndian(basis.filebytes, pos); pos += 4;
                                    newVertex.normal.y = Utility.ReadSingleBigEndian(basis.filebytes, pos); pos += 4;
                                    newVertex.normal.z = Utility.ReadSingleBigEndian(basis.filebytes, pos); pos += 4;
                                }
                                else
                                {
                                    System.Windows.Forms.MessageBox.Show("Argh! The normal coordinates are not floats! How annoying.");
                                }
                                break;

                            case VertexAttributeComponentType.GX_NRM_NBT3:

                                if (vertexComponentSize == VertexAttributeComponentSize.GX_F32)
                                {
                                    checkAheadAmount     = 36;
                                    newVertex.normal.x   = Utility.ReadSingleBigEndian(basis.filebytes, pos); pos += 4;
                                    newVertex.normal.y   = Utility.ReadSingleBigEndian(basis.filebytes, pos); pos += 4;
                                    newVertex.normal.z   = Utility.ReadSingleBigEndian(basis.filebytes, pos); pos += 4;
                                    newVertex.binormal.x = Utility.ReadSingleBigEndian(basis.filebytes, pos); pos += 4;
                                    newVertex.binormal.y = Utility.ReadSingleBigEndian(basis.filebytes, pos); pos += 4;
                                    newVertex.binormal.z = Utility.ReadSingleBigEndian(basis.filebytes, pos); pos += 4;
                                    newVertex.tangent.x  = Utility.ReadSingleBigEndian(basis.filebytes, pos); pos += 4;
                                    newVertex.tangent.y  = Utility.ReadSingleBigEndian(basis.filebytes, pos); pos += 4;
                                    newVertex.tangent.z  = Utility.ReadSingleBigEndian(basis.filebytes, pos); pos += 4;
                                }
                                else
                                {
                                    System.Windows.Forms.MessageBox.Show("Argh! The normal coordinates are not floats! How annoying.");
                                }
                                break;

                            case VertexAttributeComponentType.GX_NRM_NBT:

                                if (vertexComponentSize == VertexAttributeComponentSize.GX_F32)
                                {
                                    checkAheadAmount   = 12;
                                    newVertex.normal.x = Utility.ReadSingleBigEndian(basis.filebytes, pos); pos += 4;
                                    newVertex.normal.y = Utility.ReadSingleBigEndian(basis.filebytes, pos); pos += 4;
                                    newVertex.normal.z = Utility.ReadSingleBigEndian(basis.filebytes, pos); pos += 4;
                                }
                                else if (vertexComponentSize == VertexAttributeComponentSize.GX_U8)
                                {
                                    checkAheadAmount = 8;      //APPARENTLY IT IGNORES THE U8 AND READS FLOATS INSTEAD.

                                    float U = Utility.ReadSingleBigEndian(basis.filebytes, pos); pos += 4;
                                    float V = Utility.ReadSingleBigEndian(basis.filebytes, pos); pos += 4;

                                    newVertex.UVchannels[(int)vertexArrayType - 13] = new MorcuMath.Vector2(U, V);
                                }
                                else
                                {
                                    System.Windows.Forms.MessageBox.Show("Argh! The normal coordinates are not floats! How annoying.");
                                }
                                break;

                            default:
                                Console.WriteLine("Unhandled tex or normal component type: " + vertexComponentType);
                                break;
                            }
                        }
                        else if (vertexArrayType == VertexAttributeArrayType.GX_VA_CLR0 || vertexArrayType == VertexAttributeArrayType.GX_VA_CLR1)
                        {
                            switch (vertexComponentType)
                            {
                            case VertexAttributeComponentType.GX_CLR_RGB:
                                if (vertexComponentSize == VertexAttributeComponentSize.GX_RGBA6)     //RGBA24 basically
                                {
                                    checkAheadAmount = 3;
                                    newVertex.color  = imageTools.ReadRGBA24(basis.filebytes, pos);
                                    pos += 3;
                                }
                                else
                                {
                                    System.Windows.Forms.MessageBox.Show("Argh! The rgb component size was unhandled! It was: " + vertexComponentSize);
                                }
                                break;

                            default:
                                Console.WriteLine("Unhandled colour component type: " + vertexComponentType);
                                break;
                            }
                        }
                        else
                        {
                            Console.WriteLine("Don't know how to read a vertex array of type: " + vertexArrayType + "! Component type is: " + vertexComponentType);
                            break;
                        }

                        vertexAttributes.Add(newVertex);
                    } while (pos + checkAheadAmount <= stopPoint);


                    switch (vertexArrayType)
                    {
                    case VertexAttributeArrayType.GX_VA_POS:
                        newMesh.vertices = vertexAttributes;
                        break;

                    case VertexAttributeArrayType.GX_VA_NRM:
                        foreach (Vertex vn in vertexAttributes)
                        {
                            newMesh.normals.Add(vn);
                        }
                        break;

                    case VertexAttributeArrayType.GX_VA_TEX0:
                        newMesh.texCoords = vertexAttributes;
                        break;
                    }
                }

                //now read display list data

                pos = displayListOffset;

                while (pos < displayListOffset + displayListSize)
                {
                    byte cmd = basis.filebytes[pos]; pos++;

                    switch ((DisplayListCommand)cmd)
                    {
                    case DisplayListCommand.kGXCmdNOP:
                        break;

                    case DisplayListCommand.kGXCmdLoadIndxA:
                    case DisplayListCommand.kGXCmdLoadIndxB:
                    case DisplayListCommand.kGXCmdLoadIndxC:
                    case DisplayListCommand.kGXCmdLoadIndxD:
                        pos += 4;
                        break;

                    default:
                    {
                        byte drawCmd = (byte)((cmd & 0x78) >> 3);
                        byte vat     = (byte)(cmd & 0x07);

                        if (drawCmd > 7)
                        {
                            Console.WriteLine("Invalid Display List command " + cmd + " at offset " + pos);
                        }
                        else
                        {
                            DrawType drawType = (DrawType)drawCmd;

                            //Console.WriteLine("Found drawtype at "+pos+": " + drawType);

                            // Read element amount
                            int elemCount = Utility.ReadUInt16BigEndian(basis.filebytes, pos); pos += 2;

                            switch (drawType)
                            {
                            case DrawType.quads:
                            case DrawType.quads2:
                            case DrawType.triangles:
                                int vertsMax = 4;
                                if (drawType == DrawType.triangles)
                                {
                                    vertsMax = 3;
                                }

                                for (int f = 0; f < elemCount / vertsMax; f++)
                                {
                                    Face newFace = new Face();
                                    for (int i = 0; i < vertsMax; i++)
                                    {
                                        if (boneNamesOffset != 0)
                                        {
                                            switch (i)
                                            {
                                            case 0: newFace.v1BoneIndex = basis.filebytes[pos];  break;

                                            case 1: newFace.v2BoneIndex = basis.filebytes[pos]; break;

                                            case 2: newFace.v3BoneIndex = basis.filebytes[pos]; break;

                                            case 3: newFace.v4BoneIndex = basis.filebytes[pos]; newFace.is_quad = true; break;
                                            }
                                            pos++;
                                        }

                                        for (int attr = 0; attr < 20; attr++)
                                        {              //for each possible vertex attribute, if it exists, process it in order
                                            if (newMesh.presentAttributes.Contains((VertexAttributeArrayType)attr))
                                            {
                                                newFace = AddAttrToFace(basis.filebytes, pos, (VertexAttributeArrayType)attr, newFace, i);
                                                pos     = newFace.temp;
                                            }
                                        }

                                        newMesh.faces.Add(newFace);
                                    }
                                }
                                break;

                            case DrawType.triangleStrip:
                            {
                                Face newFace   = new Face();
                                int  currentV  = 0;
                                int  backupPos = 0;
                                bool winding   = false;

                                for (int i = 0; i < elemCount; i++)
                                {
                                    if (currentV == 1)
                                    {                   //if we're reading the penultimate vertex in a triangle, remember our pos because we'll need to come back to it when we process the next triangle (which overlaps slightly)
                                        backupPos = pos;
                                    }

                                    if (boneNamesOffset != 0)
                                    {
                                        switch (currentV)
                                        {
                                        case 0: newFace.v1BoneIndex = basis.filebytes[pos]; break;

                                        case 1: newFace.v2BoneIndex = basis.filebytes[pos]; break;

                                        case 2: newFace.v3BoneIndex = basis.filebytes[pos]; break;

                                        case 3: newFace.v4BoneIndex = basis.filebytes[pos]; newFace.is_quad = true; break;                      //this won't get triggered by a triangle, but might as well keep it here so I don't forget for quads
                                        }
                                        pos++;
                                    }

                                    if (winding && currentV == 0)
                                    {
                                        currentV = 1;
                                    }
                                    else if (winding && currentV == 1)
                                    {
                                        currentV = 0;
                                    }

                                    for (int attr = 0; attr < 20; attr++)
                                    {                  //for each possible vertex attribute, if it exists, process it in order
                                        if (newMesh.presentAttributes.Contains((VertexAttributeArrayType)attr))
                                        {
                                            newFace = AddAttrToFace(basis.filebytes, pos, (VertexAttributeArrayType)attr, newFace, currentV);
                                            pos     = newFace.temp;
                                        }
                                    }

                                    if (winding && currentV == 1)
                                    {
                                        currentV = 0;
                                    }
                                    else if (winding && currentV == 0)
                                    {
                                        currentV = 1;
                                    }

                                    currentV++;

                                    if (currentV == 3)
                                    {                 //if we just finished making a triangle
                                        newMesh.faces.Add(newFace);
                                        newFace  = new Face();
                                        currentV = 0;
                                        if (i < elemCount - 1)
                                        {                 //as long as we're not on the very last one, there's still work to do so back up a bit and keep reading the strip
                                            i      -= 2;
                                            pos     = backupPos;
                                            winding = !winding;
                                        }
                                    }
                                }
                            }
                            break;

                            default:
                                Console.WriteLine("Unhandled draw type at offset " + pos + ": " + drawType);
                                break;
                            }
                        }
                    }
                    break;
                    }
                }

                //now get the materials ready

                newMesh.materials = new List <MaterialData>();

                if (newMesh.hash_of_material != 0)
                {
                    has_materials = true;
                }

                foreach (Subfile s in global.activePackage.subfiles)
                {
                    if (s.hash == newMesh.hash_of_material && s.typeID == typeID_of_material)
                    {
                        switch ((global.TypeID)s.typeID)
                        {
                        case global.TypeID.MATD_MSK:
                        case global.TypeID.MATD_MSA:

                            if (s.filebytes == null || s.filebytes.Length == 0)
                            {
                                s.Load();
                            }
                            newMesh.materials.Add(s.matd);
                            break;

                        case global.TypeID.MTST_MSK:
                        case global.TypeID.MTST_MSA:
                            if (s.filebytes == null || s.filebytes.Length == 0)
                            {
                                s.Load();
                            }

                            foreach (MaterialData mat in s.mtst.mats)
                            {
                                newMesh.materials.Add(mat);
                            }

                            break;

                        default:
                            System.Windows.Forms.MessageBox.Show("RMDL tried to use a material of unexpected type ID: " + (global.TypeID)s.typeID);
                            break;
                        }
                        break;
                    }
                }

                meshes.Add(newMesh);
            }
        }