Пример #1
0
 /// <summary>
 /// Creates a new geometry animation
 /// </summary>
 /// <param name="frame">Start frame</param>
 /// <param name="step">Animation speed</param>
 /// <param name="maxFrame"></param>
 /// <param name="model"></param>
 /// <param name="motion"></param>
 /// <param name="texListPtr"></param>
 public LandEntryMotion(float frame, float step, float maxFrame, NJObject model, Action action, uint texListPtr)
 {
     Frame        = frame;
     Step         = step;
     MaxFrame     = maxFrame;
     Model        = model;
     MotionAction = action;
     TexListPtr   = texListPtr;
 }
Пример #2
0
        private static void PrepareModel(
            this NJObject obj,
            List <RenderMesh> opaque,
            List <RenderMesh> transparent,
            BufferingBridge buffer,
            Camera cam,
            NJObject activeObj,
            Matrix4?parentWorld,
            bool weighted)
        {
            Matrix4 world = obj.LocalMatrix;

            if (parentWorld.HasValue)
            {
                world *= parentWorld.Value;
            }

            if (obj.Attach != null && obj.Attach.MeshData.Length > 0)
            {
                // if a model is weighted, then the buffered vertex positions/normals will have to be set to world space, which means that world and normal matrix should be identities
                if (weighted)
                {
                    buffer.LoadToCache(obj.Attach.MeshData, world, obj == activeObj);
                }
                else if (!buffer.IsBuffered(obj.Attach.MeshData[0]))
                {
                    buffer.LoadToCache(obj.Attach.MeshData, null, false);
                }

                RenderMatrices matrices = weighted ? new(cam.ViewMatrix * cam.ProjectionMatrix) : new(world, world *cam.ViewMatrix *cam.ProjectionMatrix);

                var meshes = obj.Attach.GetDisplayMeshes();

                if (meshes.opaque.Length > 0)
                {
                    opaque.Add(new RenderMesh(meshes.opaque, matrices));
                }

                if (meshes.transparent.Length > 0)
                {
                    transparent.Add(new RenderMesh(meshes.transparent, matrices));
                }
            }

            for (int i = 0; i < obj.ChildCount; i++)
            {
                obj[i].PrepareModel(opaque, transparent, buffer, cam, activeObj, world, weighted);
            }
        }
Пример #3
0
        /// <summary>
        /// Reads a geometry animation from a byte array
        /// </summary>
        /// <param name="source">Byte source</param>
        /// <param name="address">Address at which the geometry animation is located</param>
        /// <param name="imageBase">Image base for all addresses</param>
        /// <param name="format">Attach format</param>
        /// <param name="DX">Whether the animation is for sadx</param>
        /// <param name="labels">C struct labels</param>
        /// <param name="models">Models that have already been read</param>
        /// <param name="attaches">Attaches that have already been read</param>
        /// <returns></returns>
        public static LandEntryMotion Read(byte[] source, uint address, uint imageBase, AttachFormat format, bool DX,
                                           Dictionary <uint, string> labels, Dictionary <uint, Attach> attaches)
        {
            float frame    = source.ToSingle(address);
            float step     = source.ToSingle(address + 4);
            float maxFrame = source.ToSingle(address + 8);

            uint     modelAddress = source.ToUInt32(address + 0xC) - imageBase;
            NJObject model        = NJObject.Read(source, modelAddress, imageBase, format, DX, labels, attaches);

            uint   motionAddress = source.ToUInt32(address + 0x10) - imageBase;
            Action action        = Action.Read(source, motionAddress, imageBase, format, DX, labels, attaches);

            uint texListPtr = source.ToUInt32(address + 0x14);

            return(new LandEntryMotion(frame, step, maxFrame, model, action, texListPtr));
        }
Пример #4
0
        internal static void GetModelLine(NJObject obj, List <Vector3> lines, Matrix4?parentWorld)
        {
            Matrix4 world = obj.LocalMatrix;

            if (parentWorld.HasValue)
            {
                world *= parentWorld.Value;

                lines.Add(Vector3.Transform(Vector3.Zero, parentWorld.Value));
                lines.Add(Vector3.Transform(Vector3.Zero, world));
            }

            for (int i = 0; i < obj.ChildCount; i++)
            {
                GetModelLine(obj[i], lines, world);
            }
        }
Пример #5
0
        /// <summary>
        /// Reads an action from a byte array
        /// </summary>
        /// <param name="source">Byte source</param>
        /// <param name="address">Address at which the action is located</param>
        /// <param name="imagebase">Image base for all addresses</param>
        /// <param name="format">Attach format</param>
        /// <param name="DX">Whether the file is for sadx</param>
        /// <param name="labels">C struct labels</param>
        /// <param name="attaches">Attaches that have already been read</param>
        /// <returns></returns>
        public static Action Read(byte[] source, uint address, uint imagebase, AttachFormat format, bool DX, Dictionary <uint, string> labels, Dictionary <uint, Attach> attaches)
        {
            uint mdlAddress = source.ToUInt32(address);

            if (mdlAddress == 0)
            {
                throw new FormatException($"Action at {address:X8} does not have a model!");
            }
            mdlAddress -= imagebase;
            NJObject mdl = NJObject.Read(source, mdlAddress, imagebase, format, DX, labels, attaches);

            uint aniAddress = source.ToUInt32(address + 4);

            if (aniAddress == 0)
            {
                throw new FormatException($"Action at {address:X8} does not have a model!");
            }
            aniAddress -= imagebase;
            Motion mtn = Motion.Read(source, ref aniAddress, imagebase, (uint)mdl.Count(), labels);

            return(new(mdl, mtn));
        }
Пример #6
0
 /// <summary>
 /// Creates a new geometry animation
 /// </summary>
 /// <param name="frame">Start frame</param>
 /// <param name="step">Animation speed</param>
 public LandEntryMotion(float frame, float step, float maxFrame, NJObject model, Motion motion, uint texListPtr)
     : this(frame, step, maxFrame, model, new Action(model, motion), texListPtr)
 {
 }
Пример #7
0
 /// <summary>
 /// Create a new action
 /// </summary>
 /// <param name="model"></param>
 /// <param name="animation"></param>
 public Action(NJObject model, Motion animation)
 {
     Model     = model;
     Animation = animation;
 }
Пример #8
0
        /// <summary>
        /// Converts a buffer model to the GC format
        /// </summary>
        /// <param name="model">The model to converter</param>
        /// <param name="optimize">Whether to optimize the attaches</param>
        /// <param name="ignoreWeights">If conversion should still happen, despite weights existing</param>
        /// <param name="forceUpdate">Whether to convert, regardless of whether the attaches are already GC</param>
        public static void ConvertModelToGC(NJObject model, bool optimize = true, bool ignoreWeights = false, bool forceUpdate = false)
        {
            if (model.Parent != null)
            {
                throw new FormatException($"Model {model.Name} is not hierarchy root!");
            }

            if (model.AttachFormat == AttachFormat.GC && !forceUpdate)
            {
                return;
            }

            if (model.HasWeight && !ignoreWeights)
            {
                throw new FormatException("Model is weighted, cannot convert to basic format!");
            }

            AttachHelper.ProcessWeightlessModel(model, (cacheAtc, ogAtc) =>
            {
                // getting the vertex information
                Vector3[] positions = new Vector3[cacheAtc.vertices.Length];
                Vector3[] normals   = new Vector3[positions.Length];

                for (int i = 0; i < positions.Length; i++)
                {
                    var vtx      = cacheAtc.vertices[i];
                    positions[i] = vtx.Position;
                    normals[i]   = vtx.Normal;
                }

                // getting the corner information
                int cornerCount = 0;
                for (int i = 0; i < cacheAtc.corners.Length; i++)
                {
                    cornerCount += cacheAtc.corners[i].Length;
                }

                Vector2[] texcoords = new Vector2[cornerCount];
                Color[] colors      = new Color[cornerCount];
                Corner[][] corners  = new Corner[cacheAtc.corners.Length][];

                ushort cornerIndex = 0;
                for (int i = 0; i < corners.Length; i++)
                {
                    BufferCorner[] bufferCorners = cacheAtc.corners[i];
                    Corner[] meshCorners         = new Corner[bufferCorners.Length];
                    for (int j = 0; j < bufferCorners.Length; j++)
                    {
                        BufferCorner bcorner = bufferCorners[j];

                        texcoords[cornerIndex] = bcorner.Texcoord;
                        colors[cornerIndex]    = bcorner.Color;

                        meshCorners[j] = new Corner()
                        {
                            PositionIndex = bcorner.VertexIndex,
                            NormalIndex   = bcorner.VertexIndex,
                            UV0Index      = cornerIndex,
                            Color0Index   = cornerIndex
                        };

                        cornerIndex++;
                    }
                    corners[i] = meshCorners;
                }

                bool hasUVs = texcoords.Any(x => x != default);
                // if it has no normals, always use colors (even if they are all white)
                bool hasColors = colors.Any(x => x != Color.White) || !normals.Any(x => x != Vector3.UnitY);

                // Puttin together the vertex sets
                VertexSet[] vertexData = new VertexSet[2 + (hasUVs ? 1 : 0)];

                IndexAttributeParameter iaParam = new() { IndexAttributes = IndexAttributes.HasPosition };
                if (positions.Length > 256)
                {
                    iaParam.IndexAttributes |= IndexAttributes.Position16BitIndex;
                }
                vertexData[0] = new VertexSet(positions, false);

                if (hasColors)
                {
                    iaParam.IndexAttributes |= IndexAttributes.HasColor;
                    if (colors.Length > 256)
                    {
                        iaParam.IndexAttributes |= IndexAttributes.Color16BitIndex;
                    }

                    vertexData[1] = new VertexSet(colors);
                }
                else
                {
                    iaParam.IndexAttributes |= IndexAttributes.HasNormal;
                    if (normals.Length > 256)
                    {
                        iaParam.IndexAttributes |= IndexAttributes.Normal16BitIndex;
                    }

                    vertexData[1] = new VertexSet(normals, true);
                }

                if (hasUVs)
                {
                    iaParam.IndexAttributes |= IndexAttributes.HasUV;
                    if (texcoords.Length > 256)
                    {
                        iaParam.IndexAttributes |= IndexAttributes.UV16BitIndex;
                    }
                    vertexData[2] = new VertexSet(texcoords);
                }

                // stitching polygons together
                BufferMaterial currentMaterial = null;
                Mesh ProcessBufferMesh(int index)
                {
                    // generating parameter info
                    List <IParameter> parameters = new();

                    BufferMaterial cacheMaterial = cacheAtc.materials[index];
                    if (currentMaterial == null)
                    {
                        parameters.Add(new VtxAttrFmtParameter(VertexAttribute.Position));
                        parameters.Add(new VtxAttrFmtParameter(hasColors ? VertexAttribute.Color0 : VertexAttribute.Normal));
                        if (hasUVs)
                        {
                            parameters.Add(new VtxAttrFmtParameter(VertexAttribute.Tex0));
                        }
                        parameters.Add(iaParam);

                        if (cacheMaterial == null)
                        {
                            currentMaterial = new BufferMaterial()
                            {
                                MaterialAttributes = MaterialAttributes.noSpecular
                            };
                        }
                        else
                        {
                            currentMaterial = cacheMaterial;
                        }

                        parameters.Add(new LightingParameter()
                        {
                            LightingAttributes = LightingParameter.DefaultLighting.LightingAttributes,
                            ShadowStencil      = currentMaterial.ShadowStencil
                        });

                        parameters.Add(new BlendAlphaParameter()
                        {
                            SourceAlpha = currentMaterial.SourceBlendMode,
                            DestAlpha   = currentMaterial.DestinationBlendmode
                        });

                        parameters.Add(new AmbientColorParameter()
                        {
                            AmbientColor = currentMaterial.Ambient
                        });

                        TextureParameter texParam = new();
                        texParam.TextureID        = (ushort)currentMaterial.TextureIndex;

                        if (!currentMaterial.ClampU)
                        {
                            texParam.Tiling |= GCTileMode.RepeatU;
                        }

                        if (!currentMaterial.ClampV)
                        {
                            texParam.Tiling |= GCTileMode.RepeatV;
                        }

                        if (currentMaterial.MirrorU)
                        {
                            texParam.Tiling |= GCTileMode.MirrorU;
                        }

                        if (currentMaterial.MirrorV)
                        {
                            texParam.Tiling |= GCTileMode.MirrorV;
                        }

                        parameters.Add(texParam);

                        parameters.Add(Unknown9Parameter.DefaultValues);
                        parameters.Add(new TexCoordGenParameter()
                        {
                            TexCoordID = currentMaterial.TexCoordID,
                            TexGenType = currentMaterial.TexGenType,
                            TexGenSrc  = currentMaterial.TexGenSrc,
                            MatrixID   = currentMaterial.MatrixID
                        });
                    }
                    else
                    {
                        if (currentMaterial.ShadowStencil != cacheMaterial.ShadowStencil)
                        {
                            parameters.Add(new LightingParameter()
                            {
                                ShadowStencil = cacheMaterial.ShadowStencil
                            });
                        }

                        if (currentMaterial.SourceBlendMode != cacheMaterial.SourceBlendMode ||
                            currentMaterial.DestinationBlendmode != cacheMaterial.DestinationBlendmode)
                        {
                            parameters.Add(new BlendAlphaParameter()
                            {
                                SourceAlpha = cacheMaterial.SourceBlendMode,
                                DestAlpha   = cacheMaterial.DestinationBlendmode
                            });
                        }

                        if (currentMaterial.Ambient != cacheMaterial.Ambient)
                        {
                            parameters.Add(new AmbientColorParameter()
                            {
                                AmbientColor = cacheMaterial.Ambient
                            });
                        }

                        if (currentMaterial.TextureIndex != cacheMaterial.TextureIndex ||
                            currentMaterial.MirrorU != cacheMaterial.MirrorU ||
                            currentMaterial.MirrorV != cacheMaterial.MirrorV ||
                            currentMaterial.ClampU != cacheMaterial.ClampU ||
                            currentMaterial.ClampV != cacheMaterial.ClampV)
                        {
                            TextureParameter texParam = new();
                            texParam.TextureID        = (ushort)cacheMaterial.TextureIndex;

                            if (!cacheMaterial.ClampU)
                            {
                                texParam.Tiling |= GCTileMode.RepeatU;
                            }

                            if (!cacheMaterial.ClampV)
                            {
                                texParam.Tiling |= GCTileMode.RepeatV;
                            }

                            if (cacheMaterial.MirrorU)
                            {
                                texParam.Tiling |= GCTileMode.MirrorU;
                            }

                            if (cacheMaterial.MirrorV)
                            {
                                texParam.Tiling |= GCTileMode.MirrorV;
                            }

                            parameters.Add(texParam);
                        }

                        if (currentMaterial.TexCoordID != cacheMaterial.TexCoordID ||
                            currentMaterial.TexGenType != cacheMaterial.TexGenType ||
                            currentMaterial.TexGenSrc != cacheMaterial.TexGenSrc ||
                            currentMaterial.MatrixID != cacheMaterial.MatrixID)
                        {
                            parameters.Add(new TexCoordGenParameter()
                            {
                                TexCoordID = cacheMaterial.TexCoordID,
                                TexGenType = cacheMaterial.TexGenType,
                                TexGenSrc  = cacheMaterial.HasAttribute(MaterialAttributes.normalMapping) ? TexGenSrc.Normal : cacheMaterial.TexGenSrc,
                                MatrixID   = cacheMaterial.MatrixID
                            });
                        }

                        currentMaterial = cacheMaterial;
                    }

                    // note: a single triangle polygon can only carry 0xFFFF corners, so about 22k tris
                    Corner[] triangleCorners = corners[index];

                    List <Poly> polygons = new();
                    if (triangleCorners.Length > 0xFFFF)
                    {
                        int remainingLength = triangleCorners.Length;
                        int offset          = 0;
                        while (remainingLength > 0)
                        {
                            Corner[] finalCorners = new Corner[Math.Max(0xFFFF, remainingLength)];
                            Array.Copy(triangleCorners, offset, finalCorners, 0, finalCorners.Length);
                            offset          += finalCorners.Length;
                            remainingLength -= finalCorners.Length;

                            Poly triangle = new(PolyType.Triangles, finalCorners);
                            polygons.Add(triangle);
                        }
Пример #9
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();
            }
        }
Пример #10
0
        public static Contents Read(ModelRoot gltfModel, bool importTextures, float?animationFPS)
        {
            // First we'll get the textures, by far the easiest part
            TextureSet textures = null;

            if (importTextures && gltfModel.LogicalTextures.Count > 0)
            {
                textures = new();
                foreach (var t in gltfModel.LogicalTextures)
                {
                    string name = t.Name ?? $"Tex_{t}";
                    textures.Textures.Add(new SAArchive.Texture(name, GetBitmap(t.PrimaryImage.Content)));
                }
            }

            // lets first set up the object hierarchy
            Dictionary <Node, NJObject> objectsPairs = new();

            List <NJObject> roots = new();

            foreach (var n in gltfModel.LogicalNodes)
            {
                if (n.VisualParent == null)
                {
                    roots.Add(FromNode(n, objectsPairs));
                }
            }

            NJObject root;

            if (roots.Count > 1)
            {
                root = new NJObject()
                {
                    Name = "Root"
                };

                root.AddChildren(roots);
            }
            else
            {
                root = roots[0];
            }

            Dictionary <Mesh, Attach> nonWeightAttaches = new();

            NJObject[] objects = root.GetObjects();

            foreach (NJObject njo in objects)
            {
                Node node = objectsPairs.First(x => x.Value == njo).Key;

                if (node.Mesh == null)
                {
                    continue;
                }

                if (node.Skin == null)
                {
                    if (!nonWeightAttaches.TryGetValue(node.Mesh, out Attach atc))
                    {
                        atc = FromNoWeight(node.Mesh);
                        nonWeightAttaches.Add(node.Mesh, atc);
                    }
                    njo.Attach = atc;
                }
                else
                {
                    Skin skin = node.Skin;

                    NJObject[] bones = new NJObject[skin.JointsCount];

                    for (int i = 0; i < skin.JointsCount; i++)
                    {
                        (Node bone, _) = skin.GetJoint(i);
                        bones[i]       = objectsPairs[bone];
                    }

                    var(vertices, polydata) = FromWeight(node.Mesh);
                    Matrix4x4 meshMatrix = node.GetWorldMatrix(null, 0);
                    AttachHelper.FromWeightedBuffer(bones, meshMatrix, vertices, polydata);
                }
            }

            // lastly, we load the animations
            Motion[] animations;
            if (animationFPS.HasValue)
            {
                animations = new Motion[gltfModel.LogicalAnimations.Count];

                for (int i = 0; i < animations.Length; i++)
                {
                    animations[i] = GetAnimation(gltfModel.LogicalAnimations[i], gltfModel.LogicalNodes.Count, animationFPS.Value);
                }
            }
            else
            {
                animations = Array.Empty <Motion>();
            }

            return(new Contents(root, textures, animations));
        }
Пример #11
0
 public Contents(NJObject root, TextureSet textures, Motion[] animations)
 {
     Root       = root;
     Textures   = textures;
     Animations = animations;
 }
Пример #12
0
        public static List <(DisplayTask task, List <RenderMesh> opaque, List <RenderMesh> transparent)> PrepareModels(IReadOnlyCollection <GameTask> tasks, NJObject active, Camera cam, BufferingBridge buffer)
        {
            List <(DisplayTask task, List <RenderMesh> opaque, List <RenderMesh> transparent)> result = new();

            foreach (GameTask t in tasks)
            {
                t.Display();

                if (t is DisplayTask dtsk && dtsk.Model != null)
                {
                    List <RenderMesh> opaque      = new();
                    List <RenderMesh> transparent = new();
                    dtsk.Model.PrepareModel(opaque, transparent, buffer, cam, active, null, dtsk.Model.HasWeight);
                    result.Add((dtsk, opaque, transparent));
                }
            }

            return(result);
        }
Пример #13
0
 public VmModelHead(NJObject objectData)
 {
     ObjectData = objectData;
 }
Пример #14
0
        /// <summary>
        /// Converts the buffer data of a model to BASIC attaches
        /// </summary>
        /// <param name="model">The tip of the model hierarchy to convert</param>
        /// <param name="optimize">Whether to optimize the data</param>
        /// <param name="ignoreWeights">Convert regardless of weight information being lost</param>
        /// <param name="forceUpdate">Still convert, even if the attaches are Basic already</param>
        public static void ConvertModelToBasic(NJObject model, bool optimize = true, bool ignoreWeights = false, bool forceUpdate = false)
        {
            if (model.Parent != null)
            {
                throw new FormatException($"Model {model.Name} is not hierarchy root!");
            }

            if (model.AttachFormat == AttachFormat.BASIC && !forceUpdate)
            {
                return;
            }

            if (model.HasWeight && !ignoreWeights)
            {
                throw new FormatException("Model is weighted, cannot convert to basic format!");
            }

            AttachHelper.ProcessWeightlessModel(model, (cacheAtc, ogAtc) =>
            {
                // getting the vertex information
                Vector3[] positions = new Vector3[cacheAtc.vertices.Length];
                Vector3[] normals   = new Vector3[positions.Length];
                bool hasNormals     = false;

                for (int i = 0; i < positions.Length; i++)
                {
                    var vtx      = cacheAtc.vertices[i];
                    positions[i] = vtx.Position;
                    normals[i]   = vtx.Normal;
                    if (vtx.Normal != Vector3.UnitY)
                    {
                        hasNormals = true;
                    }
                }

                if (!hasNormals)
                {
                    normals = null;
                }

                // putting together polygons
                Mesh[] meshes        = new Mesh[cacheAtc.corners.Length];
                Material[] materials = new Material[cacheAtc.corners.Length];

                for (int i = 0; i < cacheAtc.corners.Length; i++)
                {
                    // creating the material
                    Material mat        = new();
                    BufferMaterial bmat = cacheAtc.materials[i];
                    if (bmat != null)
                    {
                        mat.DiffuseColor     = bmat.Diffuse;
                        mat.SpecularColor    = bmat.Specular;
                        mat.Exponent         = bmat.SpecularExponent;
                        mat.TextureID        = bmat.TextureIndex;
                        mat.FilterMode       = bmat.TextureFiltering;
                        mat.MipmapDAdjust    = bmat.MipmapDistanceAdjust;
                        mat.SuperSample      = bmat.AnisotropicFiltering;
                        mat.ClampU           = bmat.ClampU;
                        mat.ClampV           = bmat.ClampV;
                        mat.MirrorU          = bmat.MirrorU;
                        mat.MirrorV          = bmat.MirrorV;
                        mat.UseAlpha         = bmat.UseAlpha;
                        mat.SourceAlpha      = bmat.SourceBlendMode;
                        mat.DestinationAlpha = bmat.DestinationBlendmode;
                        mat.DoubleSided      = !bmat.Culling;

                        mat.IgnoreLighting = bmat.HasAttribute(MaterialAttributes.noDiffuse);
                        mat.IgnoreSpecular = bmat.HasAttribute(MaterialAttributes.noSpecular);
                        mat.UseTexture     = bmat.HasAttribute(MaterialAttributes.useTexture);
                        mat.EnvironmentMap = bmat.HasAttribute(MaterialAttributes.normalMapping);
                    }
                    materials[i] = mat;

                    // creating the polygons

                    BufferCorner[] bCorners = cacheAtc.corners[i];
                    IPoly[] triangles       = new IPoly[bCorners.Length / 3];
                    Vector2[] texcoords     = new Vector2[bCorners.Length];
                    Color[] colors          = new Color[bCorners.Length];

                    Triangle current = new();
                    for (int j = 0; j < bCorners.Length; j++)
                    {
                        BufferCorner corner = bCorners[j];

                        int vIndex = j % 3;
                        current.Indices[vIndex] = corner.VertexIndex;
                        if (vIndex == 2)
                        {
                            triangles[(j - 2) / 3] = current;
                            current = new Triangle();
                        }

                        texcoords[j] = corner.Texcoord;
                        colors[j]    = corner.Color;
                    }

                    bool hasTexcoords = texcoords.Any(x => x != default);
                    bool hasColors    = colors.Any(x => x != Color.White);

                    Mesh basicmesh = new (BASICPolyType.Triangles, triangles, false, hasColors, hasTexcoords, (ushort)i);
                    if (hasColors)
                    {
                        basicmesh.Colors = colors;
                    }
                    if (hasTexcoords)
                    {
                        basicmesh.Texcoords = texcoords;
                    }

                    meshes[i] = basicmesh;
                }