示例#1
0
 public IVertex SetColorBytes(
     int colorIndex,
     byte r,
     byte g,
     byte b,
     byte a)
 => this.SetColor(colorIndex, ColorImpl.FromRgbaBytes(r, g, b, a));
示例#2
0
        private IColor[] DecodeCmprPalette_(ushort color1Value, ushort color2Value)
        {
            var palette = new IColor[4];

            var color1 = ColorUtil.ParseRgb565(color1Value);
            var color2 = ColorUtil.ParseRgb565(color2Value);

            IColor color3, color4;

            if (color1Value > color2Value)
            {
                color3 = ColorUtil.Interpolate(color1, color2, 1d / 3);
                color4 = ColorUtil.Interpolate(color1, color2, 2d / 3);
            }
            else
            {
                color3 = ColorUtil.Interpolate(color1, color2, .5);
                color4 = ColorImpl.FromRgbaBytes(0, 0, 0, 0);
            }

            palette[0] = color1;
            palette[1] = color2;
            palette[2] = color3;
            palette[3] = color4;

            return(palette);
        }
示例#3
0
        protected override IColor[] DecodeBlock(IList <byte> block, int position)
        {
            var bl = new IColor[4 * 4];
            var s  = new VectorReader(block, position, Endianness.Big);

            for (var j = 0; j < 4; ++j)
            {
                for (var i = 0; i < 4; ++i)
                {
                    var intensity = s.ReadU8();
                    var alpha     = s.ReadU8();

                    bl[j * 4 + i] = ColorImpl.FromRgbaBytes(intensity, intensity, intensity, alpha);
                }
            }

            return(bl);
        }
示例#4
0
        protected override IColor[] DecodeBlock(IList <byte> block, int position)
        {
            var bl = new IColor[8 * 4];
            var s  = new VectorReader(block, position, Endianness.Big);

            for (var j = 0; j < 4; ++j)
            {
                for (var i = 0; i < 8; ++i)
                {
                    var pixes = s.ReadU8();

                    var intensity = ColorUtil.ExtractScaled(pixes, 4, 4, 17);
                    var alpha     = ColorUtil.ExtractScaled(pixes, 0, 4, 17);

                    bl[j * 8 + i] = ColorImpl.FromRgbaBytes(intensity, intensity, intensity, alpha);
                }
            }

            return(bl);
        }
示例#5
0
        protected override IColor[] DecodeBlock(IList <byte> block, int position)
        {
            var bl = new IColor[4 * 4];
            var s  = new VectorReader(block, position, Endianness.Big);

            for (var j = 0; j < 4; ++j)
            {
                for (var i = 0; i < 4; ++i)
                {
                    var pix = s.ReadU16();

                    var alphaFlag = BitLogic.ExtractFromRight(pix, 15, 1);

                    byte r, g, b, a;
                    if (alphaFlag == 1)
                    {
                        a = 255;
                        r = ColorUtil.ExtractScaled(pix, 10, 5);
                        g = ColorUtil.ExtractScaled(pix, 5, 5);
                        b = ColorUtil.ExtractScaled(pix, 0, 5);
                    }
                    else
                    {
                        a = ColorUtil.ExtractScaled(pix, 12, 3);

                        r = ColorUtil.ExtractScaled(pix, 8, 4, 17);
                        g = ColorUtil.ExtractScaled(pix, 4, 4, 17);
                        b = ColorUtil.ExtractScaled(pix, 0, 4, 17);
                    }

                    bl[j * 4 + i] = ColorImpl.FromRgbaBytes(r, g, b, a);
                }
            }

            return(bl);
        }
        public unsafe IModel LoadModel(GloModelFileBundle gloModelFileBundle)
        {
            var gloFile            = gloModelFileBundle.GloFile;
            var textureDirectories = gloModelFileBundle.TextureDirectories;
            var fps = 20;

            var glo = gloFile.Impl.ReadNew <Glo>(Endianness.LittleEndian);

            var textureFilesByName = new Dictionary <string, IFileHierarchyFile>();

            foreach (var textureDirectory in textureDirectories)
            {
                foreach (var textureFile in textureDirectory.Files)
                {
                    textureFilesByName[textureFile.Name.ToLower()] = textureFile;
                }
            }

            /*new MeshCsvWriter().WriteToFile(
             *  glo, new FinFile(Path.Join(outputDirectory.FullName, "mesh.csv")));
             * new FaceCsvWriter().WriteToFile(
             *  glo, new FinFile(Path.Join(outputDirectory.FullName, "face.csv")));
             * new VertexCsvWriter().WriteToFile(
             *  glo, new FinFile(Path.Join(outputDirectory.FullName, "vertex.csv")));*/

            var finModel = new ModelImpl();
            var finSkin  = finModel.Skin;

            var finRootBone = finModel.Skeleton.Root;

            var finTextureMap = new LazyDictionary <string, ITexture?>(
                textureFilename => {
                if (!textureFilesByName.TryGetValue(textureFilename.ToLower(),
                                                    out var textureFile))
                {
                    return(null);
                }

                using var rawTextureImage = FinImage.FromFile(textureFile.Impl);
                var textureImageWithAlpha =
                    GloModelLoader.AddTransparencyToGloImage_(rawTextureImage);

                var finTexture = finModel.MaterialManager.CreateTexture(
                    textureImageWithAlpha);
                finTexture.Name = textureFilename;

                if (this.mirrorTextures_.Contains(textureFilename))
                {
                    finTexture.WrapModeU = WrapMode.MIRROR_REPEAT;
                    finTexture.WrapModeV = WrapMode.MIRROR_REPEAT;
                }
                else
                {
                    finTexture.WrapModeU = WrapMode.REPEAT;
                    finTexture.WrapModeV = WrapMode.REPEAT;
                }

                return(finTexture);
            });
            var withCullingMap =
                new LazyDictionary <string, IMaterial>(textureFilename => {
                var finTexture = finTextureMap[textureFilename];
                if (finTexture == null)
                {
                    return(finModel.MaterialManager.AddStandardMaterial());
                }
                return(finModel.MaterialManager.AddTextureMaterial(finTexture));
            });
            var withoutCullingMap = new LazyDictionary <string, IMaterial>(
                textureFilename => {
                var finTexture        = finTextureMap[textureFilename];
                IMaterial finMaterial = finTexture == null
                                        ? finModel.MaterialManager
                                        .AddStandardMaterial()
                                        : finModel.MaterialManager
                                        .AddTextureMaterial(
                    finTexture);
                finMaterial.CullingMode = CullingMode.SHOW_BOTH;
                return(finMaterial);
            });

            var firstMeshMap = new Dictionary <string, GloMesh>();

            // TODO: Consider separating these out as separate models
            foreach (var gloObject in glo.Objects)
            {
                var finObjectRootBone = finRootBone.AddRoot(0, 0, 0);
                var meshQueue         = new Queue <(GloMesh, IBone)>();
                foreach (var topLevelGloMesh in gloObject.Meshes)
                {
                    meshQueue.Enqueue((topLevelGloMesh, finObjectRootBone));
                }

                List <(IAnimation, int, int)> finAndGloAnimations = new();
                foreach (var animSeg in gloObject.AnimSegs)
                {
                    var startFrame = (int)animSeg.StartFrame;
                    var endFrame   = (int)animSeg.EndFrame;

                    var finAnimation = finModel.AnimationManager.AddAnimation();
                    finAnimation.Name       = animSeg.Name;
                    finAnimation.FrameCount =
                        (int)(animSeg.EndFrame - animSeg.StartFrame + 1);

                    finAnimation.FrameRate = fps * animSeg.Speed;

                    finAndGloAnimations.Add((finAnimation, startFrame, endFrame));
                }

                while (meshQueue.Count > 0)
                {
                    var(gloMesh, parentFinBone) = meshQueue.Dequeue();

                    var name = gloMesh.Name;

                    GloMesh idealMesh;
                    if (!firstMeshMap.TryGetValue(name, out idealMesh))
                    {
                        firstMeshMap[name] = idealMesh = gloMesh;
                    }

                    var position = gloMesh.MoveKeys[0].Xyz;

                    var rotation   = gloMesh.RotateKeys[0];
                    var quaternion =
                        new Quaternion(rotation.X, rotation.Y, rotation.Z, rotation.W);
                    var xyzRadians = QuaternionUtil.ToEulerRadians(quaternion);

                    var scale = gloMesh.ScaleKeys[0].Scale;

                    var finBone = parentFinBone
                                  .AddChild(position.X, position.Y, position.Z)
                                  .SetLocalRotationRadians(
                        xyzRadians.X, xyzRadians.Y, xyzRadians.Z)
                                  .SetLocalScale(scale.X, scale.Y, scale.Z);
                    finBone.Name = name + "_bone";

                    var child = gloMesh.Pointers.Child;
                    if (child != null)
                    {
                        meshQueue.Enqueue((child, finBone));
                    }

                    var next = gloMesh.Pointers.Next;
                    if (next != null)
                    {
                        meshQueue.Enqueue((next, parentFinBone));
                    }

                    foreach (var(finAnimation, startFrame, endFrame) in
                             finAndGloAnimations)
                    {
                        var finBoneTracks = finAnimation.AddBoneTracks(finBone);

                        long prevTime = -1;
                        foreach (var moveKey in gloMesh.MoveKeys)
                        {
                            Asserts.True(moveKey.Time > prevTime);
                            prevTime = moveKey.Time;

                            if (!(moveKey.Time >= startFrame && moveKey.Time <= endFrame))
                            {
                                continue;
                            }

                            var time = (int)(moveKey.Time - startFrame);
                            Asserts.True(time >= 0 && time < finAnimation.FrameCount);

                            var moveValue = moveKey.Xyz;
                            finBoneTracks.Positions.Set(time, 0, moveValue.X);
                            finBoneTracks.Positions.Set(time, 1, moveValue.Y);
                            finBoneTracks.Positions.Set(time, 2, moveValue.Z);
                        }

                        prevTime = -1;
                        foreach (var rotateKey in gloMesh.RotateKeys)
                        {
                            Asserts.True(rotateKey.Time > prevTime);
                            prevTime = rotateKey.Time;

                            if (!(rotateKey.Time >= startFrame &&
                                  rotateKey.Time <= endFrame))
                            {
                                continue;
                            }

                            var time = (int)(rotateKey.Time - startFrame);
                            Asserts.True(time >= 0 && time < finAnimation.FrameCount);

                            var quaternionKey =
                                new Quaternion(rotateKey.X, rotateKey.Y, rotateKey.Z,
                                               rotateKey.W);
                            var xyzRadiansKey = QuaternionUtil.ToEulerRadians(quaternionKey);

                            finBoneTracks.Rotations.Set(time, 0,
                                                        xyzRadiansKey.X);
                            finBoneTracks.Rotations.Set(time, 1,
                                                        xyzRadiansKey.Y);
                            finBoneTracks.Rotations.Set(time, 2,
                                                        xyzRadiansKey.Z);
                        }

                        prevTime = -1;
                        foreach (var scaleKey in gloMesh.ScaleKeys)
                        {
                            Asserts.True(scaleKey.Time > prevTime);
                            prevTime = scaleKey.Time;

                            if (!(scaleKey.Time >= startFrame && scaleKey.Time <= endFrame))
                            {
                                continue;
                            }

                            var time = (int)(scaleKey.Time - startFrame);
                            Asserts.True(time >= 0 && time < finAnimation.FrameCount);

                            var scaleValue = scaleKey.Scale;
                            finBoneTracks.Scales.Set(time, 0, scaleValue.X);
                            finBoneTracks.Scales.Set(time, 1, scaleValue.Y);
                            finBoneTracks.Scales.Set(time, 2, scaleValue.Z);
                        }
                    }

                    // Anything with these names are debug objects and can be ignored.
                    if (this.hiddenNames_.Contains(name))
                    {
                        continue;
                    }

                    var finMesh = finSkin.AddMesh();
                    finMesh.Name = name;

                    var gloVertices = idealMesh.Vertices;

                    string    previousTextureName = null;
                    IMaterial?previousMaterial    = null;

                    foreach (var gloFace in idealMesh.Faces)
                    {
                        // TODO: What can we do if texture filename is empty?
                        var textureFilename = gloFace.TextureFilename;

                        var gloFaceColor = gloFace.Color;
                        var finFaceColor = ColorImpl.FromRgbaBytes(
                            gloFaceColor.R, gloFaceColor.G, gloFaceColor.B, gloFaceColor.A);

                        var enableBackfaceCulling = (gloFace.Flags & 1 << 2) == 0;

                        IMaterial?finMaterial;
                        if (textureFilename == previousTextureName)
                        {
                            finMaterial = previousMaterial;
                        }
                        else
                        {
                            previousTextureName = textureFilename;
                            finMaterial         = enableBackfaceCulling
                                ? withCullingMap[textureFilename]
                                : withoutCullingMap[textureFilename];
                            previousMaterial = finMaterial;
                        }

                        // Face flag:
                        // 0: potentially some kind of repeat mode??

                        var color = (gloFace.Flags & 1 << 6) != 0
                            ? ColorImpl.FromRgbaBytes(255, 0, 0, 255)
                            : ColorImpl.FromRgbaBytes(0, 255, 0, 255);

                        var finFaceVertices = new IVertex[3];
                        for (var v = 0; v < 3; ++v)
                        {
                            var gloVertexRef = gloFace.VertexRefs[v];
                            var gloVertex    = gloVertices[gloVertexRef.Index];

                            var finVertex = finSkin
                                            .AddVertex(gloVertex.X, gloVertex.Y, gloVertex.Z)
                                            .SetUv(gloVertexRef.U, gloVertexRef.V);
                            //.SetColor(color);
                            finVertex.SetBoneWeights(finSkin.GetOrCreateBoneWeights(
                                                         PreprojectMode.BONE, finBone));
                            finFaceVertices[v] = finVertex;
                        }

                        // TODO: Merge triangles together
                        var finTriangles = new (IVertex, IVertex, IVertex)[1];
示例#7
0
 public static IColor ParseRgb5A3(ushort color)
 {
     ColorUtil.SplitRgb5A3(color, out var r, out var g, out var b, out var a);
     return(ColorImpl.FromRgbaBytes(r, g, b, a));
 }
示例#8
0
 public static IColor Interpolate(IColor from, IColor to, double amt)
 => ColorImpl.FromRgbaBytes(
     (byte)Math.Round(from.Rb * (1 - amt) + to.Rb * amt),
     (byte)Math.Round(from.Gb * (1 - amt) + to.Gb * amt),
     (byte)Math.Round(from.Bb * (1 - amt) + to.Bb * amt),
     (byte)Math.Round(from.Ab * (1 - amt) + to.Ab * amt));