Beispiel #1
0
        /// <summary>
        /// Reads a poly chunk from a byte array
        /// </summary>
        /// <param name="source">Byte source</param>
        /// <param name="address">Address at which the poly chunk is located</param>
        /// <returns></returns>
        public static PolyChunk Read(byte[] source, ref uint address)
        {
            ushort    header  = source.ToUInt16(address);
            ChunkType type    = (ChunkType)(header & 0xFF);
            byte      attribs = (byte)(header >> 8);

            PolyChunk chunk;

            switch (type)
            {
            case ChunkType.Null:
                chunk = new PolyChunkNull();
                break;

            case ChunkType.End:
                chunk = new PolyChunkEnd();
                break;

            case ChunkType.Bits_BlendAlpha:
                chunk = new PolyChunkBlendAlpha();
                break;

            case ChunkType.Bits_MipmapDAdjust:
                chunk = new PolyChunksMipmapDAdjust();
                break;

            case ChunkType.Bits_SpecularExponent:
                chunk = new PolyChunkSpecularExponent();
                break;

            case ChunkType.Bits_CachePolygonList:
                chunk = new PolyChunkCachePolygonList();
                break;

            case ChunkType.Bits_DrawPolygonList:
                chunk = new PolyChunkDrawPolygonList();
                break;

            case ChunkType.Tiny_TextureID:
            case ChunkType.Tiny_TextureID2:
                chunk = PolyChunkTextureID.Read(source, address);
                break;

            case ChunkType.Material:
            case ChunkType.Material_Diffuse:
            case ChunkType.Material_Ambient:
            case ChunkType.Material_DiffuseAmbient:
            case ChunkType.Material_Specular:
            case ChunkType.Material_DiffuseSpecular:
            case ChunkType.Material_AmbientSpecular:
            case ChunkType.Material_DiffuseAmbientSpecular:
            case ChunkType.Material_Diffuse2:
            case ChunkType.Material_Ambient2:
            case ChunkType.Material_DiffuseAmbient2:
            case ChunkType.Material_Specular2:
            case ChunkType.Material_DiffuseSpecular2:
            case ChunkType.Material_AmbientSpecular2:
            case ChunkType.Material_DiffuseAmbientSpecular2:
                chunk = PolyChunkMaterial.Read(source, address);
                break;

            case ChunkType.Material_Bump:
                chunk = PolyChunkMaterialBump.Read(source, address);
                break;

            case ChunkType.Volume_Polygon3:
            case ChunkType.Volume_Polygon4:
            case ChunkType.Volume_Strip:
                chunk = PolyChunkVolume.Read(source, address);
                break;

            case ChunkType.Strip_Strip:
            case ChunkType.Strip_StripUVN:
            case ChunkType.Strip_StripUVH:
            case ChunkType.Strip_StripNormal:
            case ChunkType.Strip_StripUVNNormal:
            case ChunkType.Strip_StripUVHNormal:
            case ChunkType.Strip_StripColor:
            case ChunkType.Strip_StripUVNColor:
            case ChunkType.Strip_StripUVHColor:
            case ChunkType.Strip_Strip2:
            case ChunkType.Strip_StripUVN2:
            case ChunkType.Strip_StripUVH2:
                chunk = PolyChunkStrip.Read(source, address);
                break;

            default:
                throw new InvalidOperationException($"Chunk {type} is not a valid poly chunk type at {address.ToString("X8")}");
            }
            chunk.Attributes = attribs;
            address         += chunk.ByteSize;
            return(chunk);
        }
Beispiel #2
0
        public static void ConvertModelFromChunk(NJObject model, bool optimize = true)
        {
            if (model.Parent != null)
            {
                throw new FormatException($"Model {model.Name} is not hierarchy root!");
            }

            HashSet <ChunkAttach> attaches = new();

            NJObject[] models = model.GetObjects();

            foreach (NJObject obj in models)
            {
                if (obj.Attach == null)
                {
                    continue;
                }
                if (obj.Attach.Format != AttachFormat.CHUNK)
                {
                    throw new FormatException("Not all Attaches inside the model are a CHUNK attaches! Cannot convert");
                }

                ChunkAttach atc = (ChunkAttach)obj.Attach;

                attaches.Add(atc);
            }

            Array.Clear(PolyChunkCache, 0, PolyChunkCache.Length);

            foreach (ChunkAttach atc in attaches)
            {
                List <BufferMesh> meshes = new();

                BufferVertex[] vertices       = null;
                bool           continueWeight = false;

                if (atc.VertexChunks != null)
                {
                    for (int i = 0; i < atc.VertexChunks.Length; i++)
                    {
                        VertexChunk cnk = atc.VertexChunks[i];

                        List <BufferVertex> vertexList = new();
                        if (!cnk.HasWeight)
                        {
                            for (int j = 0; j < cnk.Vertices.Length; j++)
                            {
                                ChunkVertex vtx = cnk.Vertices[j];
                                vertexList.Add(new BufferVertex(vtx.Position, vtx.Normal, (ushort)(j + cnk.IndexOffset)));
                            }
                        }
                        else
                        {
                            for (int j = 0; j < cnk.Vertices.Length; j++)
                            {
                                ChunkVertex vtx = cnk.Vertices[j];
                                vertexList.Add(new BufferVertex(vtx.Position, vtx.Normal, (ushort)(vtx.Index + cnk.IndexOffset), vtx.Weight));
                            }
                        }
                        vertices       = vertexList.ToArray();
                        continueWeight = cnk.WeightStatus != WeightStatus.Start;

                        if (i < atc.VertexChunks.Length - 1)
                        {
                            meshes.Add(new BufferMesh(vertices, continueWeight));
                        }
                    }
                }


                List <PolyChunk> active = new();

                if (atc.PolyChunks != null)
                {
                    int cacheID = -1;
                    foreach (PolyChunk cnk in atc.PolyChunks)
                    {
                        switch (cnk.Type)
                        {
                        case ChunkType.Bits_CachePolygonList:
                            PolyChunkCachePolygonList cacheListCnk = (PolyChunkCachePolygonList)cnk;
                            cacheID = cacheListCnk.List;

                            if (PolyChunkCache.Length <= cacheID)
                            {
                                Array.Resize(ref PolyChunkCache, cacheID + 1);
                            }

                            PolyChunkCache[cacheID] = new List <PolyChunk>();
                            break;

                        case ChunkType.Bits_DrawPolygonList:
                            PolyChunkDrawPolygonList drawListCnk = (PolyChunkDrawPolygonList)cnk;
                            active.AddRange(PolyChunkCache[drawListCnk.List]);
                            break;

                        default:
                            if (cacheID > -1)
                            {
                                PolyChunkCache[cacheID].Add(cnk);
                            }
                            else
                            {
                                active.Add(cnk);
                            }
                            break;
                        }
                    }
                }


                if (active.Count > 0)
                {
                    BufferMaterial material = new()
                    {
                        MaterialAttributes = MaterialAttributes.useTexture
                    };
                    foreach (PolyChunk cnk in active)
                    {
                        switch (cnk.Type)
                        {
                        case ChunkType.Bits_BlendAlpha:
                            PolyChunkBlendAlpha blendCnk = (PolyChunkBlendAlpha)cnk;
                            material.SourceBlendMode      = blendCnk.SourceAlpha;
                            material.DestinationBlendmode = blendCnk.DestinationAlpha;
                            break;

                        case ChunkType.Bits_MipmapDAdjust:
                            PolyChunksMipmapDAdjust mipmapCnk = (PolyChunksMipmapDAdjust)cnk;
                            material.MipmapDistanceAdjust = mipmapCnk.MipmapDAdjust;
                            break;

                        case ChunkType.Bits_SpecularExponent:
                            PolyChunkSpecularExponent specularCnk = (PolyChunkSpecularExponent)cnk;
                            material.SpecularExponent = specularCnk.SpecularExponent;
                            break;

                        case ChunkType.Tiny_TextureID:
                        case ChunkType.Tiny_TextureID2:
                            PolyChunkTextureID textureCnk = (PolyChunkTextureID)cnk;
                            material.TextureIndex         = textureCnk.TextureID;
                            material.MirrorU              = textureCnk.MirrorU;
                            material.MirrorV              = textureCnk.MirrorV;
                            material.ClampU               = textureCnk.ClampU;
                            material.ClampV               = textureCnk.ClampV;
                            material.AnisotropicFiltering = textureCnk.SuperSample;
                            material.TextureFiltering     = textureCnk.FilterMode;
                            break;

                        case ChunkType.Material:
                        case ChunkType.Material_Diffuse:
                        case ChunkType.Material_Ambient:
                        case ChunkType.Material_DiffuseAmbient:
                        case ChunkType.Material_Specular:
                        case ChunkType.Material_DiffuseSpecular:
                        case ChunkType.Material_AmbientSpecular:
                        case ChunkType.Material_DiffuseAmbientSpecular:
                        case ChunkType.Material_Diffuse2:
                        case ChunkType.Material_Ambient2:
                        case ChunkType.Material_DiffuseAmbient2:
                        case ChunkType.Material_Specular2:
                        case ChunkType.Material_DiffuseSpecular2:
                        case ChunkType.Material_AmbientSpecular2:
                        case ChunkType.Material_DiffuseAmbientSpecular2:
                            PolyChunkMaterial materialCnk = (PolyChunkMaterial)cnk;
                            material.SourceBlendMode      = materialCnk.SourceAlpha;
                            material.DestinationBlendmode = materialCnk.DestinationAlpha;
                            if (materialCnk.Diffuse.HasValue)
                            {
                                material.Diffuse = materialCnk.Diffuse.Value;
                            }
                            if (materialCnk.Ambient.HasValue)
                            {
                                material.Ambient = materialCnk.Ambient.Value;
                            }
                            if (materialCnk.Specular.HasValue)
                            {
                                material.Specular         = materialCnk.Specular.Value;
                                material.SpecularExponent = materialCnk.SpecularExponent;
                            }
                            break;

                        case ChunkType.Strip_Strip:
                        case ChunkType.Strip_StripUVN:
                        case ChunkType.Strip_StripUVH:
                        case ChunkType.Strip_StripNormal:
                        case ChunkType.Strip_StripUVNNormal:
                        case ChunkType.Strip_StripUVHNormal:
                        case ChunkType.Strip_StripColor:
                        case ChunkType.Strip_StripUVNColor:
                        case ChunkType.Strip_StripUVHColor:
                        case ChunkType.Strip_Strip2:
                        case ChunkType.Strip_StripUVN2:
                        case ChunkType.Strip_StripUVH2:
                            PolyChunkStrip stripCnk = (PolyChunkStrip)cnk;

                            material.SetAttribute(MaterialAttributes.Flat, stripCnk.FlatShading);
                            material.SetAttribute(MaterialAttributes.noAmbient, stripCnk.IgnoreAmbient);
                            material.SetAttribute(MaterialAttributes.noDiffuse, stripCnk.IgnoreLight);
                            material.SetAttribute(MaterialAttributes.noSpecular, stripCnk.IgnoreSpecular);
                            material.SetAttribute(MaterialAttributes.normalMapping, stripCnk.EnvironmentMapping);
                            material.UseAlpha = stripCnk.UseAlpha;
                            material.Culling  = !stripCnk.DoubleSide;

                            List <BufferCorner> corners   = new();
                            List <uint>         triangles = new();

                            foreach (var s in stripCnk.Strips)
                            {
                                uint l = (uint)corners.Count;

                                bool rev = s.Reversed;
                                for (uint i = 2; i < s.Corners.Length; i++)
                                {
                                    uint li = l + i;
                                    if (!rev)
                                    {
                                        triangles.AddRange(new uint[] { li - 2, li - 1, li });
                                    }
                                    else
                                    {
                                        triangles.AddRange(new uint[] { li - 1, li - 2, li });
                                    }
                                    rev = !rev;
                                }

                                foreach (var c in s.Corners)
                                {
                                    corners.Add(new BufferCorner(c.Index, c.Color, c.Texcoord));
                                }
                            }

                            if (vertices != null)
                            {
                                meshes.Add(new BufferMesh(vertices, continueWeight, corners.ToArray(), triangles.ToArray(), material.Clone()));
                                vertices = null;
                            }
                            else
                            {
                                meshes.Add(new BufferMesh(corners.ToArray(), triangles.ToArray(), material.Clone()));
                            }
                            break;
                        }
                    }
                }
                else if (vertices != null)
                {
                    meshes.Add(new BufferMesh(vertices, continueWeight));
                }

                if (optimize)
                {
                    for (int i = 0; i < meshes.Count; i++)
                    {
                        meshes[i].Optimize();
                    }
                }

                atc.MeshData = meshes.ToArray();
            }
        }