Example #1
0
        /// <summary>
        /// Reads a Chunk attach from a byte array
        /// </summary>
        /// <param name="source">Byte source</param>
        /// <param name="address">Address at which the attach is located</param>
        /// <param name="imagebase">Imagebase for every address</param>
        /// <param name="labels">C struct labels</param>
        /// <returns></returns>
        public static ChunkAttach Read(byte[] source, uint address, uint imagebase, Dictionary <uint, string> labels)
        {
            string name       = labels.ContainsKey(address) ? labels[address] : "attach_" + address.ToString("X8");
            string identifier = GenerateIdentifier();

            uint   vertexAddress = source.ToUInt32(address);
            string vertexName    = "vertex_" + identifier;

            VertexChunk[] vertexChunks = null;
            if (vertexAddress != 0)
            {
                vertexAddress -= imagebase;
                vertexName     = labels.ContainsKey(vertexAddress) ? labels[vertexAddress] : "vertex_" + vertexAddress.ToString("X8");

                List <VertexChunk> chunks = new();
                VertexChunk        cnk    = VertexChunk.Read(source, ref vertexAddress);
                while (cnk != null)
                {
                    chunks.Add(cnk);
                    cnk = VertexChunk.Read(source, ref vertexAddress);
                }
                vertexChunks = chunks.ToArray();
            }

            uint   polyAddress = source.ToUInt32(address += 4);
            string polyName    = "poly_" + identifier;

            PolyChunk[] polyChunks = null;
            if (polyAddress != 0)
            {
                polyAddress -= imagebase;
                polyName     = labels.ContainsKey(polyAddress) ? labels[polyAddress] : "poly_" + polyAddress.ToString("X8");

                List <PolyChunk> chunks = new();
                PolyChunk        cnk    = PolyChunk.Read(source, ref polyAddress);
                while (cnk != null && cnk.Type != ChunkType.End)
                {
                    chunks.Add(cnk);
                    cnk = PolyChunk.Read(source, ref polyAddress);
                }
                polyChunks = chunks.ToArray();
            }
            address += 4;
            return(new ChunkAttach(vertexChunks, polyChunks)
            {
                Name = name,
                VertexName = vertexName,
                PolyName = polyName,
                MeshBounds = Bounds.Read(source, ref address)
            });
        }
Example #2
0
        public void Load(byte[] data)
        {
            int dataOffset = 0;

            var header = new Header();

            header.Load(data, ref dataOffset);

            for (int i = 0; i < header.ChunkCount; i++)
            {
                BaseChunk baseChunk;

                //Read the first four bytes to get the tag.
                string tagName = FSHelpers.ReadString(data, dataOffset, 4);

                switch (tagName)
                {
                case "INF1":
                    baseChunk = new InfoChunk();
                    Info      = baseChunk as InfoChunk;
                    break;

                case "VTX1":
                    baseChunk = new VertexChunk();
                    Vertexes  = baseChunk as VertexChunk;
                    break;

                case "EVP1":
                    baseChunk = new EnvelopeChunk();
                    Envelopes = baseChunk as EnvelopeChunk;
                    break;

                case "DRW1":
                    baseChunk = new DrawChunk();
                    Draw      = baseChunk as DrawChunk;
                    break;

                case "JNT1":
                    baseChunk = new JointChunk();
                    Joints    = baseChunk as JointChunk;
                    break;

                case "SHP1":
                    baseChunk = new ShapeChunk();
                    Shapes    = baseChunk as ShapeChunk;
                    break;

                case "TEX1":
                    baseChunk = new TextureChunk();
                    Textures  = baseChunk as TextureChunk;
                    break;

                case "MAT3":
                    baseChunk = new Material3Chunk();
                    Materials = baseChunk as Material3Chunk;
                    break;

                case "ANK1":
                default:
                    Console.WriteLine("Found unknown chunk {0}!", tagName);
                    baseChunk = new DefaultChunk();
                    break;
                }

                baseChunk.Load(data, ref dataOffset);
            }
        }
Example #3
0
        /// <summary>
        /// Reserve a chunk of vertexs inside the buffer's heap.
        /// </summary>
        /// <param name="count">Number of vertexs to reserve.</param>
        /// <returns>An handle to the vertex array resource.</returns>
        public new VertexChunk Alloc(uint count)
        {
            VertexChunk newChunk = new VertexChunk(this, count);

            return(base.Alloc(newChunk) as VertexChunk);
        }
Example #4
0
        static void Main(string[] args)
        {
            string filename;

            if (args.Length > 0)
            {
                filename = args[0];
                Console.WriteLine("File: {0}", filename);
            }
            else
            {
                Console.Write("File: ");
                filename = Console.ReadLine();
            }
            ModelFile model = new ModelFile(filename);

            switch (model.Format)
            {
            case ModelFormat.Basic:
                foreach (NJS_OBJECT obj in model.Model.GetObjects().Where(obj => obj.Attach is BasicAttach))
                {
                    BasicAttach basatt = (BasicAttach)obj.Attach;
                    ChunkAttach cnkatt = new ChunkAttach(true, true)
                    {
                        Name = basatt.Name + "_cnk", Bounds = basatt.Bounds
                    };
                    obj.Attach = cnkatt;
                    VertexChunk vcnk;
                    bool        hasnormal = basatt.Normal?.Length > 0;
                    bool        hasvcolor = basatt.Mesh.Any(a => a.VColor != null);
                    if (hasvcolor)
                    {
                        vcnk = new VertexChunk(ChunkType.Vertex_VertexDiffuse8);
                    }
                    else if (hasnormal)
                    {
                        vcnk = new VertexChunk(ChunkType.Vertex_VertexNormal);
                    }
                    else
                    {
                        vcnk = new VertexChunk(ChunkType.Vertex_Vertex);
                    }
                    List <CachedVertex>       cache  = new List <CachedVertex>(basatt.Vertex.Length);
                    List <List <Strip> >      strips = new List <List <Strip> >();
                    List <List <List <UV> > > uvs    = new List <List <List <UV> > >();
                    foreach (NJS_MESHSET mesh in basatt.Mesh)
                    {
                        List <Strip>      polys = new List <Strip>();
                        List <List <UV> > us    = null;
                        bool hasUV             = mesh.UV != null;
                        bool hasVColor         = mesh.VColor != null;
                        int  currentstriptotal = 0;
                        switch (mesh.PolyType)
                        {
                        case Basic_PolyType.Triangles:
                        {
                            List <ushort>           tris  = new List <ushort>();
                            Dictionary <ushort, UV> uvmap = new Dictionary <ushort, UV>();
                            foreach (Poly poly in mesh.Poly)
                            {
                                for (int i = 0; i < 3; i++)
                                {
                                    ushort ind = (ushort)cache.AddUnique(new CachedVertex(
                                                                             basatt.Vertex[poly.Indexes[i]],
                                                                             basatt.Normal[poly.Indexes[i]],
                                                                             hasVColor ? mesh.VColor[currentstriptotal] : Color.White,
                                                                             mesh.UV?[currentstriptotal]));
                                    if (hasUV)
                                    {
                                        uvmap[ind] = mesh.UV[currentstriptotal];
                                    }
                                    ++currentstriptotal;
                                    tris.Add(ind);
                                }
                            }

                            if (hasUV)
                            {
                                us = new List <List <UV> >();
                            }

                            nvStripifier.GenerateStrips(tris.ToArray(), out var primitiveGroups);

                            // Add strips
                            for (var i = 0; i < primitiveGroups.Length; i++)
                            {
                                var primitiveGroup = primitiveGroups[i];
                                System.Diagnostics.Debug.Assert(primitiveGroup.Type == PrimitiveType.TriangleStrip);

                                var       stripIndices = new ushort[primitiveGroup.Indices.Length];
                                List <UV> stripuv      = new List <UV>();
                                for (var j = 0; j < primitiveGroup.Indices.Length; j++)
                                {
                                    var vertexIndex = primitiveGroup.Indices[j];
                                    stripIndices[j] = vertexIndex;
                                    if (hasUV)
                                    {
                                        stripuv.Add(uvmap[vertexIndex]);
                                    }
                                }

                                polys.Add(new Strip(stripIndices, false));
                                if (hasUV)
                                {
                                    us.Add(stripuv);
                                }
                            }
                        }
                        break;

                        case Basic_PolyType.Quads:
                        {
                            List <ushort>           tris  = new List <ushort>();
                            Dictionary <ushort, UV> uvmap = new Dictionary <ushort, UV>();
                            foreach (Poly poly in mesh.Poly)
                            {
                                ushort[] quad = new ushort[4];
                                for (int i = 0; i < 4; i++)
                                {
                                    ushort ind = (ushort)cache.AddUnique(new CachedVertex(
                                                                             basatt.Vertex[poly.Indexes[i]],
                                                                             basatt.Normal[poly.Indexes[i]],
                                                                             hasVColor ? mesh.VColor[currentstriptotal] : Color.White,
                                                                             mesh.UV?[currentstriptotal]));
                                    if (hasUV)
                                    {
                                        uvmap[ind] = mesh.UV[currentstriptotal];
                                    }
                                    ++currentstriptotal;
                                    quad[i] = ind;
                                }
                                tris.Add(quad[0]);
                                tris.Add(quad[1]);
                                tris.Add(quad[2]);
                                tris.Add(quad[2]);
                                tris.Add(quad[1]);
                                tris.Add(quad[3]);
                            }

                            if (hasUV)
                            {
                                us = new List <List <UV> >();
                            }

                            nvStripifier.GenerateStrips(tris.ToArray(), out var primitiveGroups);

                            // Add strips
                            for (var i = 0; i < primitiveGroups.Length; i++)
                            {
                                var primitiveGroup = primitiveGroups[i];
                                System.Diagnostics.Debug.Assert(primitiveGroup.Type == PrimitiveType.TriangleStrip);

                                var       stripIndices = new ushort[primitiveGroup.Indices.Length];
                                List <UV> stripuv      = new List <UV>();
                                for (var j = 0; j < primitiveGroup.Indices.Length; j++)
                                {
                                    var vertexIndex = primitiveGroup.Indices[j];
                                    stripIndices[j] = vertexIndex;
                                    if (hasUV)
                                    {
                                        stripuv.Add(uvmap[vertexIndex]);
                                    }
                                }

                                polys.Add(new Strip(stripIndices, false));
                                if (hasUV)
                                {
                                    us.Add(stripuv);
                                }
                            }
                        }
                        break;

                        case Basic_PolyType.NPoly:
                        case Basic_PolyType.Strips:
                            if (hasUV)
                            {
                                us = new List <List <UV> >();
                            }
                            foreach (Strip poly in mesh.Poly.Cast <Strip>())
                            {
                                List <UV> stripuv = new List <UV>();
                                ushort[]  inds    = (ushort[])poly.Indexes.Clone();
                                for (int i = 0; i < poly.Indexes.Length; i++)
                                {
                                    inds[i] = (ushort)cache.AddUnique(new CachedVertex(
                                                                          basatt.Vertex[poly.Indexes[i]],
                                                                          basatt.Normal[poly.Indexes[i]],
                                                                          hasVColor ? mesh.VColor[currentstriptotal] : Color.White));
                                    if (hasUV)
                                    {
                                        stripuv.Add(mesh.UV[currentstriptotal]);
                                    }
                                    ++currentstriptotal;
                                }

                                polys.Add(new Strip(inds, poly.Reversed));
                                if (hasUV)
                                {
                                    us.Add(stripuv);
                                }
                            }
                            break;
                        }
                        strips.Add(polys);
                        uvs.Add(us);
                    }
                    foreach (var item in cache)
                    {
                        vcnk.Vertices.Add(item.vertex);
                        if (hasnormal)
                        {
                            vcnk.Normals.Add(item.normal);
                        }
                        if (hasvcolor)
                        {
                            vcnk.Diffuse.Add(item.color);
                        }
                    }
                    vcnk.VertexCount = (ushort)cache.Count;
                    switch (vcnk.Type)
                    {
                    case ChunkType.Vertex_Vertex:
                        vcnk.Size = (ushort)(vcnk.VertexCount * 3 + 1);
                        break;

                    case ChunkType.Vertex_VertexDiffuse8:
                        vcnk.Size = (ushort)(vcnk.VertexCount * 4 + 1);
                        break;

                    case ChunkType.Vertex_VertexNormal:
                        vcnk.Size = (ushort)(vcnk.VertexCount * 6 + 1);
                        break;

                    case ChunkType.Vertex_VertexNormalDiffuse8:
                        vcnk.Size = (ushort)(vcnk.VertexCount * 7 + 1);
                        break;
                    }
                    cnkatt.Vertex.Add(vcnk);
                    for (int i = 0; i < basatt.Mesh.Count; i++)
                    {
                        NJS_MESHSET  mesh = basatt.Mesh[i];
                        NJS_MATERIAL mat  = null;
                        if (basatt.Material != null && mesh.MaterialID < basatt.Material.Count)
                        {
                            mat = basatt.Material[mesh.MaterialID];
                            cnkatt.Poly.Add(new PolyChunkTinyTextureID()
                            {
                                ClampU      = mat.ClampU,
                                ClampV      = mat.ClampV,
                                FilterMode  = mat.FilterMode,
                                FlipU       = mat.FlipU,
                                FlipV       = mat.FlipV,
                                SuperSample = mat.SuperSample,
                                TextureID   = (ushort)mat.TextureID
                            });
                            cnkatt.Poly.Add(new PolyChunkMaterial()
                            {
                                SourceAlpha      = mat.SourceAlpha,
                                DestinationAlpha = mat.DestinationAlpha,
                                Diffuse          = mat.DiffuseColor,
                                Specular         = mat.SpecularColor,
                                SpecularExponent = (byte)mat.Exponent
                            });
                        }
                        PolyChunkStrip strip;
                        if (mesh.UV != null)
                        {
                            strip = new PolyChunkStrip(ChunkType.Strip_StripUVN);
                        }
                        else
                        {
                            strip = new PolyChunkStrip(ChunkType.Strip_Strip);
                        }
                        if (mat != null)
                        {
                            strip.IgnoreLight        = mat.IgnoreLighting;
                            strip.IgnoreSpecular     = mat.IgnoreSpecular;
                            strip.UseAlpha           = mat.UseAlpha;
                            strip.DoubleSide         = mat.DoubleSided;
                            strip.FlatShading        = mat.FlatShading;
                            strip.EnvironmentMapping = mat.EnvironmentMap;
                        }
                        for (int i1 = 0; i1 < strips[i].Count; i1++)
                        {
                            Strip item = strips[i][i1];
                            UV[]  uv2  = null;
                            if (mesh.UV != null)
                            {
                                uv2 = uvs[i][i1].ToArray();
                            }
                            strip.Strips.Add(new PolyChunkStrip.Strip(item.Reversed, item.Indexes, uv2, null));
                        }
                        cnkatt.Poly.Add(strip);
                    }
                }
                ModelFile.CreateFile(System.IO.Path.ChangeExtension(filename, "sa2mdl"), model.Model, null, null, null, null, null, ModelFormat.Chunk);
                break;

            case ModelFormat.Chunk:
                Vertex[] VertexBuffer = new Vertex[0];
                Vertex[] NormalBuffer = new Vertex[0];
                foreach (NJS_OBJECT obj in model.Model.GetObjects().Where(obj => obj.Attach is ChunkAttach))
                {
                    ChunkAttach cnkatt = (ChunkAttach)obj.Attach;
                    BasicAttach basatt = new BasicAttach()
                    {
                        Name = cnkatt.Name, Bounds = cnkatt.Bounds
                    };
                    obj.Attach = basatt;
                    if (cnkatt.Vertex != null)
                    {
                        foreach (VertexChunk chunk in cnkatt.Vertex)
                        {
                            if (VertexBuffer.Length < chunk.IndexOffset + chunk.VertexCount)
                            {
                                Array.Resize(ref VertexBuffer, chunk.IndexOffset + chunk.VertexCount);
                                Array.Resize(ref NormalBuffer, chunk.IndexOffset + chunk.VertexCount);
                            }
                            Array.Copy(chunk.Vertices.ToArray(), 0, VertexBuffer, chunk.IndexOffset, chunk.Vertices.Count);
                            Array.Copy(chunk.Normals.ToArray(), 0, NormalBuffer, chunk.IndexOffset, chunk.Normals.Count);
                        }
                    }
                    NJS_MATERIAL material = new NJS_MATERIAL()
                    {
                        UseTexture = true
                    };
                    int minVtx = int.MaxValue;
                    int maxVtx = int.MinValue;
                    foreach (PolyChunk chunk in cnkatt.Poly)
                    {
                        switch (chunk.Type)
                        {
                        case ChunkType.Bits_BlendAlpha:
                        {
                            PolyChunkBitsBlendAlpha c2 = (PolyChunkBitsBlendAlpha)chunk;
                            material.SourceAlpha      = c2.SourceAlpha;
                            material.DestinationAlpha = c2.DestinationAlpha;
                        }
                        break;

                        case ChunkType.Bits_MipmapDAdjust:
                            break;

                        case ChunkType.Bits_SpecularExponent:
                            material.Exponent = ((PolyChunkBitsSpecularExponent)chunk).SpecularExponent;
                            break;

                        case ChunkType.Tiny_TextureID:
                        case ChunkType.Tiny_TextureID2:
                        {
                            PolyChunkTinyTextureID c2 = (PolyChunkTinyTextureID)chunk;
                            material.ClampU      = c2.ClampU;
                            material.ClampV      = c2.ClampV;
                            material.FilterMode  = c2.FilterMode;
                            material.FlipU       = c2.FlipU;
                            material.FlipV       = c2.FlipV;
                            material.SuperSample = c2.SuperSample;
                            material.TextureID   = c2.TextureID;
                        }
                        break;

                        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 c2 = (PolyChunkMaterial)chunk;
                            material.SourceAlpha      = c2.SourceAlpha;
                            material.DestinationAlpha = c2.DestinationAlpha;
                            if (c2.Diffuse.HasValue)
                            {
                                material.DiffuseColor = c2.Diffuse.Value;
                            }
                            if (c2.Specular.HasValue)
                            {
                                material.SpecularColor = c2.Specular.Value;
                                material.Exponent      = c2.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 c2 = (PolyChunkStrip)chunk;
                            material.DoubleSided    = c2.DoubleSide;
                            material.EnvironmentMap = c2.EnvironmentMapping;
                            material.FlatShading    = c2.FlatShading;
                            material.IgnoreLighting = c2.IgnoreLight;
                            material.IgnoreSpecular = c2.IgnoreSpecular;
                            material.UseAlpha       = c2.UseAlpha;
                            bool hasVColor = false;
                            switch (chunk.Type)
                            {
                            case ChunkType.Strip_StripColor:
                            case ChunkType.Strip_StripUVNColor:
                            case ChunkType.Strip_StripUVHColor:
                                hasVColor = true;
                                break;
                            }
                            bool hasUV = false;
                            switch (chunk.Type)
                            {
                            case ChunkType.Strip_StripUVN:
                            case ChunkType.Strip_StripUVH:
                            case ChunkType.Strip_StripUVNColor:
                            case ChunkType.Strip_StripUVHColor:
                            case ChunkType.Strip_StripUVN2:
                            case ChunkType.Strip_StripUVH2:
                                hasUV = true;
                                break;
                            }
                            List <Strip> strips  = new List <Strip>(c2.StripCount);
                            List <UV>    uvs     = hasUV ? new List <UV>() : null;
                            List <Color> vcolors = hasVColor ? new List <Color>() : null;
                            foreach (PolyChunkStrip.Strip strip in c2.Strips)
                            {
                                minVtx = Math.Min(minVtx, strip.Indexes.Min());
                                maxVtx = Math.Max(maxVtx, strip.Indexes.Max());
                                strips.Add(new Strip((ushort[])strip.Indexes.Clone(), strip.Reversed));
                                if (hasUV)
                                {
                                    uvs.AddRange(strip.UVs);
                                }
                                if (hasVColor)
                                {
                                    vcolors.AddRange(strip.VColors);
                                }
                            }
                            NJS_MESHSET mesh = new NJS_MESHSET(strips.ToArray(), false, hasUV, hasVColor);
                            if (hasUV)
                            {
                                uvs.CopyTo(mesh.UV);
                            }
                            if (hasVColor)
                            {
                                vcolors.CopyTo(mesh.VColor);
                            }
                            mesh.MaterialID = (ushort)basatt.Material.Count;
                            basatt.Mesh.Add(mesh);
                            basatt.Material.Add(material);
                            material = new NJS_MATERIAL(material.GetBytes(), 0);
                        }
                        break;
                        }
                    }
                    int numVtx = maxVtx - minVtx + 1;
                    basatt.ResizeVertexes(numVtx);
                    Array.Copy(VertexBuffer, minVtx, basatt.Vertex, 0, numVtx);
                    Array.Copy(NormalBuffer, minVtx, basatt.Normal, 0, numVtx);
                    foreach (NJS_MESHSET mesh in basatt.Mesh)
                    {
                        foreach (Poly poly in mesh.Poly)
                        {
                            for (int i = 0; i < poly.Indexes.Length; i++)
                            {
                                poly.Indexes[i] = (ushort)(poly.Indexes[i] - minVtx);
                            }
                        }
                    }
                }
                ModelFile.CreateFile(System.IO.Path.ChangeExtension(filename, "sa1mdl"), model.Model, null, null, null, null, null, ModelFormat.Basic);
                break;
            }
        }
Example #5
0
        private static void ConvertCOL(List <COL> newcollist, Dictionary <string, Attach> visitedAttaches, COL col)
        {
            if ((col.SurfaceFlags & SurfaceFlags.Visible) == SurfaceFlags.Visible)
            {
                BasicAttach basatt = (BasicAttach)col.Model.Attach;
                COL         newcol = new COL()
                {
                    Bounds = col.Bounds
                };
                newcol.SurfaceFlags = SurfaceFlags.Visible;
                newcol.Model        = new NJS_OBJECT()
                {
                    Name = col.Model.Name + "_cnk"
                };
                newcol.Model.Position = col.Model.Position;
                newcol.Model.Rotation = col.Model.Rotation;
                newcol.Model.Scale    = col.Model.Scale;
                string newname = basatt.Name + "_cnk";
                if (visitedAttaches != null && visitedAttaches.ContainsKey(newname))
                {
                    newcol.Model.Attach = visitedAttaches[newname];
                }
                else
                {
                    ChunkAttach cnkatt = new ChunkAttach(true, true)
                    {
                        Name = newname, Bounds = basatt.Bounds
                    };
                    if (visitedAttaches != null)
                    {
                        visitedAttaches[newname] = cnkatt;
                    }
                    newcol.Model.Attach = cnkatt;
                    VertexChunk vcnk;
                    bool        hasvcolor = basatt.Mesh.Any(a => a.VColor != null);
                    bool        hasnormal = !hasvcolor && basatt.Normal?.Length > 0;
                    if (hasvcolor)
                    {
                        vcnk = new VertexChunk(ChunkType.Vertex_VertexDiffuse8);
                    }
                    else if (hasnormal)
                    {
                        vcnk = new VertexChunk(ChunkType.Vertex_VertexNormal);
                    }
                    else
                    {
                        vcnk = new VertexChunk(ChunkType.Vertex_Vertex);
                    }
                    List <CachedVertex>       cache  = new List <CachedVertex>(basatt.Vertex.Length);
                    List <List <Strip> >      strips = new List <List <Strip> >();
                    List <List <List <UV> > > uvs    = new List <List <List <UV> > >();
                    foreach (NJS_MESHSET mesh in basatt.Mesh)
                    {
                        List <Strip>      polys = new List <Strip>();
                        List <List <UV> > us    = null;
                        bool hasUV             = mesh.UV != null;
                        bool hasVColor         = mesh.VColor != null;
                        int  currentstriptotal = 0;
                        switch (mesh.PolyType)
                        {
                        case Basic_PolyType.Triangles:
                        {
                            List <ushort>           tris  = new List <ushort>();
                            Dictionary <ushort, UV> uvmap = new Dictionary <ushort, UV>();
                            foreach (Poly poly in mesh.Poly)
                            {
                                for (int i = 0; i < 3; i++)
                                {
                                    ushort ind = (ushort)cache.AddUnique(new CachedVertex(
                                                                             basatt.Vertex[poly.Indexes[i]],
                                                                             basatt.Normal[poly.Indexes[i]],
                                                                             hasVColor ? mesh.VColor[currentstriptotal] : Color.White,
                                                                             mesh.UV?[currentstriptotal]));
                                    if (hasUV)
                                    {
                                        uvmap[ind] = mesh.UV[currentstriptotal];
                                    }
                                    ++currentstriptotal;
                                    tris.Add(ind);
                                }
                            }

                            if (hasUV)
                            {
                                us = new List <List <UV> >();
                            }

                            System.Diagnostics.Debug.Assert(nvStripifier.GenerateStrips(tris.ToArray(), out var primitiveGroups));

                            // Add strips
                            for (var i = 0; i < primitiveGroups.Length; i++)
                            {
                                var primitiveGroup = primitiveGroups[i];
                                System.Diagnostics.Debug.Assert(primitiveGroup.Type == NvTriStripDotNet.PrimitiveType.TriangleStrip);

                                var       stripIndices = new ushort[primitiveGroup.Indices.Length];
                                List <UV> stripuv      = new List <UV>();
                                for (var j = 0; j < primitiveGroup.Indices.Length; j++)
                                {
                                    var vertexIndex = primitiveGroup.Indices[j];
                                    stripIndices[j] = vertexIndex;
                                    if (hasUV)
                                    {
                                        stripuv.Add(uvmap[vertexIndex]);
                                    }
                                }

                                polys.Add(new Strip(stripIndices, false));
                                if (hasUV)
                                {
                                    us.Add(stripuv);
                                }
                            }
                        }
                        break;

                        case Basic_PolyType.Quads:
                        {
                            List <ushort>           tris  = new List <ushort>();
                            Dictionary <ushort, UV> uvmap = new Dictionary <ushort, UV>();
                            foreach (Poly poly in mesh.Poly)
                            {
                                ushort[] quad = new ushort[4];
                                for (int i = 0; i < 4; i++)
                                {
                                    ushort ind = (ushort)cache.AddUnique(new CachedVertex(
                                                                             basatt.Vertex[poly.Indexes[i]],
                                                                             basatt.Normal[poly.Indexes[i]],
                                                                             hasVColor ? mesh.VColor[currentstriptotal] : Color.White,
                                                                             mesh.UV?[currentstriptotal]));
                                    if (hasUV)
                                    {
                                        uvmap[ind] = mesh.UV[currentstriptotal];
                                    }
                                    ++currentstriptotal;
                                    quad[i] = ind;
                                }
                                tris.Add(quad[0]);
                                tris.Add(quad[1]);
                                tris.Add(quad[2]);
                                tris.Add(quad[2]);
                                tris.Add(quad[1]);
                                tris.Add(quad[3]);
                            }

                            if (hasUV)
                            {
                                us = new List <List <UV> >();
                            }

                            System.Diagnostics.Debug.Assert(nvStripifier.GenerateStrips(tris.ToArray(), out var primitiveGroups));

                            // Add strips
                            for (var i = 0; i < primitiveGroups.Length; i++)
                            {
                                var primitiveGroup = primitiveGroups[i];
                                System.Diagnostics.Debug.Assert(primitiveGroup.Type == NvTriStripDotNet.PrimitiveType.TriangleStrip);

                                var       stripIndices = new ushort[primitiveGroup.Indices.Length];
                                List <UV> stripuv      = new List <UV>();
                                for (var j = 0; j < primitiveGroup.Indices.Length; j++)
                                {
                                    var vertexIndex = primitiveGroup.Indices[j];
                                    stripIndices[j] = vertexIndex;
                                    if (hasUV)
                                    {
                                        stripuv.Add(uvmap[vertexIndex]);
                                    }
                                }

                                polys.Add(new Strip(stripIndices, false));
                                if (hasUV)
                                {
                                    us.Add(stripuv);
                                }
                            }
                        }
                        break;

                        case Basic_PolyType.NPoly:
                        case Basic_PolyType.Strips:
                            if (hasUV)
                            {
                                us = new List <List <UV> >();
                            }
                            foreach (Strip poly in mesh.Poly.Cast <Strip>())
                            {
                                List <UV> stripuv = new List <UV>();
                                ushort[]  inds    = (ushort[])poly.Indexes.Clone();
                                for (int i = 0; i < poly.Indexes.Length; i++)
                                {
                                    inds[i] = (ushort)cache.AddUnique(new CachedVertex(
                                                                          basatt.Vertex[poly.Indexes[i]],
                                                                          basatt.Normal[poly.Indexes[i]],
                                                                          hasVColor ? mesh.VColor[currentstriptotal] : Color.White));
                                    if (hasUV)
                                    {
                                        stripuv.Add(mesh.UV[currentstriptotal]);
                                    }
                                    ++currentstriptotal;
                                }

                                polys.Add(new Strip(inds, poly.Reversed));
                                if (hasUV)
                                {
                                    us.Add(stripuv);
                                }
                            }
                            break;
                        }
                        strips.Add(polys);
                        uvs.Add(us);
                    }
                    foreach (var item in cache)
                    {
                        vcnk.Vertices.Add(item.vertex);
                        if (hasnormal)
                        {
                            vcnk.Normals.Add(item.normal);
                        }
                        if (hasvcolor)
                        {
                            vcnk.Diffuse.Add(item.color);
                        }
                    }
                    vcnk.VertexCount = (ushort)cache.Count;
                    switch (vcnk.Type)
                    {
                    case ChunkType.Vertex_Vertex:
                        vcnk.Size = (ushort)(vcnk.VertexCount * 3 + 1);
                        break;

                    case ChunkType.Vertex_VertexDiffuse8:
                        vcnk.Size = (ushort)(vcnk.VertexCount * 4 + 1);
                        break;

                    case ChunkType.Vertex_VertexNormal:
                        vcnk.Size = (ushort)(vcnk.VertexCount * 6 + 1);
                        break;
                    }
                    cnkatt.Vertex.Add(vcnk);
                    for (int i = 0; i < basatt.Mesh.Count; i++)
                    {
                        NJS_MESHSET  mesh = basatt.Mesh[i];
                        NJS_MATERIAL mat  = null;
                        if (basatt.Material != null && mesh.MaterialID < basatt.Material.Count)
                        {
                            mat = basatt.Material[mesh.MaterialID];
                            cnkatt.Poly.Add(new PolyChunkTinyTextureID()
                            {
                                ClampU      = mat.ClampU,
                                ClampV      = mat.ClampV,
                                FilterMode  = mat.FilterMode,
                                FlipU       = mat.FlipU,
                                FlipV       = mat.FlipV,
                                SuperSample = mat.SuperSample,
                                TextureID   = (ushort)mat.TextureID
                            });
                            cnkatt.Poly.Add(new PolyChunkMaterial()
                            {
                                SourceAlpha      = mat.SourceAlpha,
                                DestinationAlpha = mat.DestinationAlpha,
                                Diffuse          = mat.DiffuseColor,
                                Specular         = mat.SpecularColor,
                                SpecularExponent = (byte)mat.Exponent
                            });
                        }
                        PolyChunkStrip strip;
                        if (mesh.UV != null)
                        {
                            strip = new PolyChunkStrip(ChunkType.Strip_StripUVN);
                        }
                        else
                        {
                            strip = new PolyChunkStrip(ChunkType.Strip_Strip);
                        }
                        if (mat != null)
                        {
                            strip.IgnoreLight        = mat.IgnoreLighting;
                            strip.IgnoreSpecular     = mat.IgnoreSpecular;
                            strip.UseAlpha           = mat.UseAlpha;
                            strip.DoubleSide         = mat.DoubleSided;
                            strip.FlatShading        = mat.FlatShading;
                            strip.EnvironmentMapping = mat.EnvironmentMap;
                        }
                        for (int i1 = 0; i1 < strips[i].Count; i1++)
                        {
                            Strip item = strips[i][i1];
                            UV[]  uv2  = null;
                            if (mesh.UV != null)
                            {
                                uv2 = uvs[i][i1].ToArray();
                            }
                            strip.Strips.Add(new PolyChunkStrip.Strip(item.Reversed, item.Indexes, uv2, null));
                        }
                        cnkatt.Poly.Add(strip);
                    }
                }
                newcollist.Add(newcol);
            }
            if ((col.SurfaceFlags & ~SurfaceFlags.Visible) != 0)
            {
                int newflags = col.Flags & 0xF;
                if (col.SurfaceFlags.HasFlag(SurfaceFlags.Diggable))
                {
                    newflags |= 0x20;
                }
                if (col.SurfaceFlags.HasFlag(SurfaceFlags.Unclimbable))
                {
                    newflags |= 0x80;
                }
                if (col.SurfaceFlags.HasFlag(SurfaceFlags.Hurt))
                {
                    newflags |= 0x400;
                }
                if (col.SurfaceFlags.HasFlag(SurfaceFlags.CannotLand))
                {
                    newflags |= 0x1000;
                }
                col.Flags = newflags;
                newcollist.Add(col);
            }
        }
Example #6
0
        static void Main(string[] args)
        {
            string filename;

            if (args.Length > 0)
            {
                filename = args[0];
                Console.WriteLine("File: {0}", filename);
            }
            else
            {
                Console.Write("File: ");
                filename = Console.ReadLine();
            }
            LandTable level = LandTable.LoadFromFile(filename);

            switch (level.Format)
            {
            case LandTableFormat.SA1:
            {
                List <COL> newcollist = new List <COL>();
                foreach (COL col in level.COL.Where((col) => col.Model != null && col.Model.Attach != null))
                {
                    if ((col.SurfaceFlags & SurfaceFlags.Visible) == SurfaceFlags.Visible)
                    {
                        COL newcol = new COL()
                        {
                            Bounds = col.Bounds
                        };
                        newcol.SurfaceFlags = SurfaceFlags.Visible;
                        newcol.Model        = new SonicRetro.SAModel.NJS_OBJECT()
                        {
                            Name = col.Model.Name + "_cnk"
                        };
                        newcol.Model.Position = col.Model.Position;
                        newcol.Model.Rotation = col.Model.Rotation;
                        newcol.Model.Scale    = col.Model.Scale;
                        BasicAttach basatt = (BasicAttach)col.Model.Attach;
                        ChunkAttach cnkatt = new ChunkAttach(true, true)
                        {
                            Name = basatt.Name + "_cnk", Bounds = basatt.Bounds
                        };
                        newcol.Model.Attach = cnkatt;
                        VertexChunk vcnk;
                        if (basatt.Normal != null && basatt.Normal.Length > 0)
                        {
                            vcnk = new VertexChunk(ChunkType.Vertex_VertexNormal);
                        }
                        else
                        {
                            vcnk = new VertexChunk(ChunkType.Vertex_Vertex);
                        }
                        vcnk.Vertices = new List <Vertex>(basatt.Vertex);
                        if (basatt.Normal != null)
                        {
                            vcnk.Normals = new List <Vertex>(basatt.Normal);
                        }
                        vcnk.VertexCount = (ushort)basatt.Vertex.Length;
                        vcnk.Size        = (ushort)((vcnk.Type == ChunkType.Vertex_VertexNormal ? vcnk.VertexCount * 6 : vcnk.VertexCount * 3) + 1);
                        cnkatt.Vertex.Add(vcnk);
                        foreach (NJS_MESHSET mesh in basatt.Mesh)
                        {
                            if (mesh.PolyType != Basic_PolyType.Strips)
                            {
                                Console.WriteLine("Warning: Skipping non-strip mesh in {0} ({1}).", basatt.MeshName, mesh.PolyType);
                                continue;
                            }
                            NJS_MATERIAL mat = null;
                            if (basatt.Material != null && mesh.MaterialID < basatt.Material.Count)
                            {
                                mat = basatt.Material[mesh.MaterialID];
                                cnkatt.Poly.Add(new PolyChunkBitsBlendAlpha()
                                    {
                                        SourceAlpha      = mat.SourceAlpha,
                                        DestinationAlpha = mat.DestinationAlpha
                                    });
                                cnkatt.Poly.Add(new PolyChunkTinyTextureID()
                                    {
                                        ClampU      = mat.ClampU,
                                        ClampV      = mat.ClampV,
                                        FilterMode  = mat.FilterMode,
                                        FlipU       = mat.FlipU,
                                        FlipV       = mat.FlipV,
                                        SuperSample = mat.SuperSample,
                                        TextureID   = (ushort)mat.TextureID
                                    });
                                cnkatt.Poly.Add(new PolyChunkMaterial()
                                    {
                                        Diffuse          = mat.DiffuseColor,
                                        Specular         = mat.SpecularColor,
                                        SpecularExponent = (byte)mat.Exponent
                                    });
                            }
                            PolyChunkStrip strip;
                            if (mesh.UV != null & mesh.VColor != null)
                            {
                                strip = new PolyChunkStrip(ChunkType.Strip_StripUVNColor);
                            }
                            else if (mesh.UV != null)
                            {
                                strip = new PolyChunkStrip(ChunkType.Strip_StripUVN);
                            }
                            else if (mesh.VColor != null)
                            {
                                strip = new PolyChunkStrip(ChunkType.Strip_StripColor);
                            }
                            else
                            {
                                strip = new PolyChunkStrip(ChunkType.Strip_Strip);
                            }
                            if (mat != null)
                            {
                                strip.IgnoreLight        = mat.IgnoreLighting;
                                strip.IgnoreSpecular     = mat.IgnoreSpecular;
                                strip.UseAlpha           = mat.UseAlpha;
                                strip.DoubleSide         = mat.DoubleSided;
                                strip.FlatShading        = mat.FlatShading;
                                strip.EnvironmentMapping = mat.EnvironmentMap;
                            }
                            int striptotal = 0;
                            foreach (Strip item in mesh.Poly.Cast <Strip>())
                            {
                                UV[] uvs = null;
                                if (mesh.UV != null)
                                {
                                    uvs = new UV[item.Indexes.Length];
                                    Array.Copy(mesh.UV, striptotal, uvs, 0, item.Indexes.Length);
                                }
                                Color[] vcolors = null;
                                if (mesh.VColor != null)
                                {
                                    vcolors = new Color[item.Indexes.Length];
                                    Array.Copy(mesh.VColor, striptotal, vcolors, 0, item.Indexes.Length);
                                }
                                strip.Strips.Add(new PolyChunkStrip.Strip(item.Reversed, item.Indexes, uvs, vcolors));
                                striptotal += item.Indexes.Length;
                            }
                            cnkatt.Poly.Add(strip);
                        }
                        newcollist.Add(newcol);
                    }
                    if ((col.SurfaceFlags & ~SurfaceFlags.Visible) != 0)
                    {
                        col.SurfaceFlags &= ~SurfaceFlags.Visible;
                        newcollist.Add(col);
                    }
                }
                level.COL = newcollist;
            }
                level.Anim = new List <GeoAnimData>();
                level.Tool = "SA Tools Level Converter";
                level.SaveToFile(System.IO.Path.ChangeExtension(filename, "sa2lvl"), LandTableFormat.SA2);
                break;

            case LandTableFormat.SA2:
                Vertex[] VertexBuffer = new Vertex[0];
                Vertex[] NormalBuffer = new Vertex[0];
                foreach (COL col in level.COL.Where((col) => col.Model != null && col.Model.Attach is ChunkAttach))
                {
                    ChunkAttach cnkatt = (ChunkAttach)col.Model.Attach;
                    BasicAttach basatt = new BasicAttach()
                    {
                        Name = cnkatt.Name, Bounds = cnkatt.Bounds
                    };
                    if (cnkatt.Vertex != null)
                    {
                        foreach (VertexChunk chunk in cnkatt.Vertex)
                        {
                            if (VertexBuffer.Length < chunk.IndexOffset + chunk.VertexCount)
                            {
                                Array.Resize(ref VertexBuffer, chunk.IndexOffset + chunk.VertexCount);
                                Array.Resize(ref NormalBuffer, chunk.IndexOffset + chunk.VertexCount);
                            }
                            Array.Copy(chunk.Vertices.ToArray(), 0, VertexBuffer, chunk.IndexOffset, chunk.Vertices.Count);
                            Array.Copy(chunk.Normals.ToArray(), 0, NormalBuffer, chunk.IndexOffset, chunk.Normals.Count);
                        }
                    }
                    NJS_MATERIAL material = new NJS_MATERIAL()
                    {
                        UseTexture = true
                    };
                    int minVtx = int.MaxValue;
                    int maxVtx = int.MinValue;
                    foreach (PolyChunk chunk in cnkatt.Poly)
                    {
                        switch (chunk.Type)
                        {
                        case ChunkType.Bits_BlendAlpha:
                        {
                            PolyChunkBitsBlendAlpha c2 = (PolyChunkBitsBlendAlpha)chunk;
                            material.SourceAlpha      = c2.SourceAlpha;
                            material.DestinationAlpha = c2.DestinationAlpha;
                        }
                        break;

                        case ChunkType.Bits_MipmapDAdjust:
                            break;

                        case ChunkType.Bits_SpecularExponent:
                            material.Exponent = ((PolyChunkBitsSpecularExponent)chunk).SpecularExponent;
                            break;

                        case ChunkType.Tiny_TextureID:
                        case ChunkType.Tiny_TextureID2:
                        {
                            PolyChunkTinyTextureID c2 = (PolyChunkTinyTextureID)chunk;
                            material.ClampU      = c2.ClampU;
                            material.ClampV      = c2.ClampV;
                            material.FilterMode  = c2.FilterMode;
                            material.FlipU       = c2.FlipU;
                            material.FlipV       = c2.FlipV;
                            material.SuperSample = c2.SuperSample;
                            material.TextureID   = c2.TextureID;
                        }
                        break;

                        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 c2 = (PolyChunkMaterial)chunk;
                            if (c2.Diffuse.HasValue)
                            {
                                material.DiffuseColor = c2.Diffuse.Value;
                            }
                            if (c2.Specular.HasValue)
                            {
                                material.SpecularColor = c2.Specular.Value;
                                material.Exponent      = c2.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 c2 = (PolyChunkStrip)chunk;
                            material.DoubleSided    = c2.DoubleSide;
                            material.EnvironmentMap = c2.EnvironmentMapping;
                            material.FlatShading    = c2.FlatShading;
                            material.IgnoreLighting = c2.IgnoreLight;
                            material.IgnoreSpecular = c2.IgnoreSpecular;
                            material.UseAlpha       = c2.UseAlpha;
                            bool hasVColor = false;
                            switch (chunk.Type)
                            {
                            case ChunkType.Strip_StripColor:
                            case ChunkType.Strip_StripUVNColor:
                            case ChunkType.Strip_StripUVHColor:
                                hasVColor = true;
                                break;
                            }
                            bool hasUV = false;
                            switch (chunk.Type)
                            {
                            case ChunkType.Strip_StripUVN:
                            case ChunkType.Strip_StripUVH:
                            case ChunkType.Strip_StripUVNColor:
                            case ChunkType.Strip_StripUVHColor:
                            case ChunkType.Strip_StripUVN2:
                            case ChunkType.Strip_StripUVH2:
                                hasUV = true;
                                break;
                            }
                            List <Strip> strips  = new List <Strip>(c2.StripCount);
                            List <UV>    uvs     = hasUV ? new List <UV>() : null;
                            List <Color> vcolors = hasVColor ? new List <Color>() : null;
                            foreach (PolyChunkStrip.Strip strip in c2.Strips)
                            {
                                minVtx = Math.Min(minVtx, strip.Indexes.Min());
                                maxVtx = Math.Max(maxVtx, strip.Indexes.Max());
                                strips.Add(new Strip(strip.Indexes, strip.Reversed));
                                if (hasUV)
                                {
                                    uvs.AddRange(strip.UVs);
                                }
                                if (hasVColor)
                                {
                                    vcolors.AddRange(strip.VColors);
                                }
                            }
                            NJS_MESHSET mesh = new NJS_MESHSET(strips.ToArray(), false, hasUV, hasVColor);
                            if (hasUV)
                            {
                                uvs.CopyTo(mesh.UV);
                            }
                            if (hasVColor)
                            {
                                vcolors.CopyTo(mesh.VColor);
                            }
                            mesh.MaterialID = (ushort)basatt.Material.Count;
                            basatt.Mesh.Add(mesh);
                            basatt.Material.Add(material);
                            material = new NJS_MATERIAL(material.GetBytes(), 0);
                        }
                        break;
                        }
                    }
                    int numVtx = maxVtx - minVtx + 1;
                    basatt.ResizeVertexes(numVtx);
                    Array.Copy(VertexBuffer, minVtx, basatt.Vertex, 0, numVtx);
                    Array.Copy(NormalBuffer, minVtx, basatt.Normal, 0, numVtx);
                    foreach (NJS_MESHSET mesh in basatt.Mesh)
                    {
                        foreach (Poly poly in mesh.Poly)
                        {
                            for (int i = 0; i < poly.Indexes.Length; i++)
                            {
                                poly.Indexes[i] = (ushort)(poly.Indexes[i] - minVtx);
                            }
                        }
                    }
                    col.Model.Attach = basatt;
                }
                level.Anim = new List <GeoAnimData>();
                level.Tool = "SA Tools Level Converter";
                level.SaveToFile(System.IO.Path.ChangeExtension(filename, "sa1lvl"), LandTableFormat.SA1);
                break;
            }
        }
Example #7
0
        public static ChunkAttach ToChunk(this BasicAttach basatt)
        {
            ChunkAttach cnkatt = new ChunkAttach(true, true)
            {
                Name = basatt.Name + "_cnk", Bounds = basatt.Bounds
            };
            VertexChunk vcnk;
            bool        hasnormal = basatt.Normal?.Length > 0;
            bool        hasvcolor = basatt.Mesh.Any(a => a.VColor != null);

            if (hasvcolor)
            {
                vcnk      = new VertexChunk(ChunkType.Vertex_VertexDiffuse8);
                hasnormal = false;
            }
            else if (hasnormal)
            {
                vcnk = new VertexChunk(ChunkType.Vertex_VertexNormal);
            }
            else
            {
                vcnk = new VertexChunk(ChunkType.Vertex_Vertex);
            }
            List <CachedVertex>       cache  = new List <CachedVertex>(basatt.Vertex.Length);
            List <List <Strip> >      strips = new List <List <Strip> >();
            List <List <List <UV> > > uvs    = new List <List <List <UV> > >();

            foreach (NJS_MESHSET mesh in basatt.Mesh)
            {
                List <Strip>      polys = new List <Strip>();
                List <List <UV> > us    = null;
                bool hasUV             = mesh.UV != null;
                bool hasVColor         = mesh.VColor != null;
                int  currentstriptotal = 0;
                switch (mesh.PolyType)
                {
                case Basic_PolyType.Triangles:
                {
                    List <ushort>           tris  = new List <ushort>();
                    Dictionary <ushort, UV> uvmap = new Dictionary <ushort, UV>();
                    foreach (Poly poly in mesh.Poly)
                    {
                        for (int i = 0; i < 3; i++)
                        {
                            ushort ind = (ushort)cache.AddUnique(new CachedVertex(
                                                                     basatt.Vertex[poly.Indexes[i]],
                                                                     basatt.Normal[poly.Indexes[i]],
                                                                     hasVColor ? mesh.VColor[currentstriptotal] : Color.White,
                                                                     mesh.UV?[currentstriptotal]));
                            if (hasUV)
                            {
                                uvmap[ind] = mesh.UV[currentstriptotal];
                            }
                            ++currentstriptotal;
                            tris.Add(ind);
                        }
                    }

                    if (hasUV)
                    {
                        us = new List <List <UV> >();
                    }

                    nvStripifier.GenerateStrips(tris.ToArray(), out var primitiveGroups);

                    // Add strips
                    for (var i = 0; i < primitiveGroups.Length; i++)
                    {
                        var primitiveGroup = primitiveGroups[i];
                        System.Diagnostics.Debug.Assert(primitiveGroup.Type == PrimitiveType.TriangleStrip);

                        var       stripIndices = new ushort[primitiveGroup.Indices.Length];
                        List <UV> stripuv      = new List <UV>();
                        for (var j = 0; j < primitiveGroup.Indices.Length; j++)
                        {
                            var vertexIndex = primitiveGroup.Indices[j];
                            stripIndices[j] = vertexIndex;
                            if (hasUV)
                            {
                                stripuv.Add(uvmap[vertexIndex]);
                            }
                        }

                        polys.Add(new Strip(stripIndices, false));
                        if (hasUV)
                        {
                            us.Add(stripuv);
                        }
                    }
                }
                break;

                case Basic_PolyType.Quads:
                {
                    List <ushort>           tris  = new List <ushort>();
                    Dictionary <ushort, UV> uvmap = new Dictionary <ushort, UV>();
                    foreach (Poly poly in mesh.Poly)
                    {
                        ushort[] quad = new ushort[4];
                        for (int i = 0; i < 4; i++)
                        {
                            ushort ind = (ushort)cache.AddUnique(new CachedVertex(
                                                                     basatt.Vertex[poly.Indexes[i]],
                                                                     basatt.Normal[poly.Indexes[i]],
                                                                     hasVColor ? mesh.VColor[currentstriptotal] : Color.White,
                                                                     mesh.UV?[currentstriptotal]));
                            if (hasUV)
                            {
                                uvmap[ind] = mesh.UV[currentstriptotal];
                            }
                            ++currentstriptotal;
                            quad[i] = ind;
                        }
                        tris.Add(quad[0]);
                        tris.Add(quad[1]);
                        tris.Add(quad[2]);
                        tris.Add(quad[2]);
                        tris.Add(quad[1]);
                        tris.Add(quad[3]);
                    }

                    if (hasUV)
                    {
                        us = new List <List <UV> >();
                    }

                    nvStripifier.GenerateStrips(tris.ToArray(), out var primitiveGroups);

                    // Add strips
                    for (var i = 0; i < primitiveGroups.Length; i++)
                    {
                        var primitiveGroup = primitiveGroups[i];
                        System.Diagnostics.Debug.Assert(primitiveGroup.Type == PrimitiveType.TriangleStrip);

                        var       stripIndices = new ushort[primitiveGroup.Indices.Length];
                        List <UV> stripuv      = new List <UV>();
                        for (var j = 0; j < primitiveGroup.Indices.Length; j++)
                        {
                            var vertexIndex = primitiveGroup.Indices[j];
                            stripIndices[j] = vertexIndex;
                            if (hasUV)
                            {
                                stripuv.Add(uvmap[vertexIndex]);
                            }
                        }

                        polys.Add(new Strip(stripIndices, false));
                        if (hasUV)
                        {
                            us.Add(stripuv);
                        }
                    }
                }
                break;

                case Basic_PolyType.NPoly:
                case Basic_PolyType.Strips:
                    if (hasUV)
                    {
                        us = new List <List <UV> >();
                    }
                    foreach (Strip poly in mesh.Poly.Cast <Strip>())
                    {
                        List <UV> stripuv = new List <UV>();
                        ushort[]  inds    = (ushort[])poly.Indexes.Clone();
                        for (int i = 0; i < poly.Indexes.Length; i++)
                        {
                            inds[i] = (ushort)cache.AddUnique(new CachedVertex(
                                                                  basatt.Vertex[poly.Indexes[i]],
                                                                  basatt.Normal[poly.Indexes[i]],
                                                                  hasVColor ? mesh.VColor[currentstriptotal] : Color.White));
                            if (hasUV)
                            {
                                stripuv.Add(mesh.UV[currentstriptotal]);
                            }
                            ++currentstriptotal;
                        }

                        polys.Add(new Strip(inds, poly.Reversed));
                        if (hasUV)
                        {
                            us.Add(stripuv);
                        }
                    }
                    break;
                }
                strips.Add(polys);
                uvs.Add(us);
            }
            foreach (var item in cache)
            {
                vcnk.Vertices.Add(item.vertex);
                if (hasnormal)
                {
                    vcnk.Normals.Add(item.normal);
                }
                if (hasvcolor)
                {
                    vcnk.Diffuse.Add(item.color);
                }
            }
            cnkatt.Vertex.Add(vcnk);
            for (int i = 0; i < basatt.Mesh.Count; i++)
            {
                NJS_MESHSET  mesh = basatt.Mesh[i];
                NJS_MATERIAL mat  = null;
                if (basatt.Material != null && mesh.MaterialID < basatt.Material.Count)
                {
                    mat = basatt.Material[mesh.MaterialID];
                    cnkatt.Poly.Add(new PolyChunkTinyTextureID()
                    {
                        ClampU      = mat.ClampU,
                        ClampV      = mat.ClampV,
                        FilterMode  = mat.FilterMode,
                        FlipU       = mat.FlipU,
                        FlipV       = mat.FlipV,
                        SuperSample = mat.SuperSample,
                        TextureID   = (ushort)mat.TextureID
                    });
                    cnkatt.Poly.Add(new PolyChunkMaterial()
                    {
                        SourceAlpha      = mat.SourceAlpha,
                        DestinationAlpha = mat.DestinationAlpha,
                        Diffuse          = mat.DiffuseColor,
                        Specular         = mat.SpecularColor,
                        SpecularExponent = (byte)mat.Exponent
                    });
                }
                PolyChunkStrip strip;
                if (mesh.UV != null)
                {
                    strip = new PolyChunkStrip(ChunkType.Strip_StripUVN);
                }
                else
                {
                    strip = new PolyChunkStrip(ChunkType.Strip_Strip);
                }
                if (mat != null)
                {
                    strip.IgnoreLight        = mat.IgnoreLighting;
                    strip.IgnoreSpecular     = mat.IgnoreSpecular;
                    strip.UseAlpha           = mat.UseAlpha;
                    strip.DoubleSide         = mat.DoubleSided;
                    strip.FlatShading        = mat.FlatShading;
                    strip.EnvironmentMapping = mat.EnvironmentMap;
                }
                for (int i1 = 0; i1 < strips[i].Count; i1++)
                {
                    Strip item = strips[i][i1];
                    UV[]  uv2  = null;
                    if (mesh.UV != null)
                    {
                        uv2 = uvs[i][i1].ToArray();
                    }
                    strip.Strips.Add(new PolyChunkStrip.Strip(item.Reversed, item.Indexes, uv2, null));
                }
                cnkatt.Poly.Add(strip);
            }

            return(cnkatt);
        }
Example #8
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();
            }
        }