コード例 #1
0
ファイル: SkeletalAnimation.cs プロジェクト: Cryru/Emotion
        private void ApplyBoneMatricesInternal(SkeletonAnimRigNode node, MeshEntity entity, Matrix4x4[] boneMatrices, float timeStamp, Matrix4x4 parentTransform)
        {
            string    name          = node.Name;
            Matrix4x4 nodeTransform = node.LocalTransform;

            SkeletonAnimChannel animChannel = GetMeshAnimBone(name);

            if (animChannel != null)
            {
                nodeTransform = animChannel.GetMatrixAtTimestamp(timeStamp);
            }

            Matrix4x4 globalTransform = nodeTransform * parentTransform;

            MeshBone bone = BoneIndexFromEntity(entity, name);

            if (bone != null)
            {
                boneMatrices[bone.BoneIndex] = bone.OffsetMatrix * globalTransform;
            }

            if (node.Children == null)
            {
                return;
            }
            for (var i = 0; i < node.Children.Length; i++)
            {
                SkeletonAnimRigNode child = node.Children[i];
                ApplyBoneMatricesInternal(child, entity, boneMatrices, timeStamp, globalTransform);
            }
        }
コード例 #2
0
ファイル: SkeletalAnimation.cs プロジェクト: Cryru/Emotion
        private MeshBone BoneIndexFromEntity(MeshEntity entity, string boneName)
        {
            for (var i = 0; i < entity.Meshes.Length; i++)
            {
                Mesh mesh = entity.Meshes[i];
                if (mesh.Bones == null)
                {
                    continue;
                }
                for (var j = 0; j < mesh.Bones.Length; j++)
                {
                    MeshBone bone = mesh.Bones[j];
                    if (bone.Name == boneName)
                    {
                        return(bone);
                    }
                }
            }

            return(null);
        }
コード例 #3
0
        protected override void Run()
        {
            MeshEntity meshEntity = _input.Read();

            double srcUMin = 9999, srcVMin = 9999;
            double srcUMax = -9999, srcVMax = -9999;

            // Determine the boundaries or set them to (0,0)..(1,1) and treat the UV coordinates as a subset within.
            if (_stretch.Value)
            {
                foreach (Face face in meshEntity)
                {
                    foreach (HalfVertex hv in face.HalfVertices)
                    {
                        if (hv.UV0.X < srcUMin)
                        {
                            srcUMin = hv.UV0.X;
                        }
                        if (hv.UV0.X > srcUMax)
                        {
                            srcUMax = hv.UV0.X;
                        }
                        if (hv.UV0.Y < srcVMin)
                        {
                            srcVMin = hv.UV0.Y;
                        }
                        if (hv.UV0.Y > srcVMax)
                        {
                            srcVMax = hv.UV0.Y;
                        }
                    }
                }
            }
            else
            {
                srcUMin = 0;
                srcVMin = 0;
                srcUMax = 1;
                srcVMax = 1;
            }

            // Calculate the extent within the target texture
            if (srcUMax == srcUMin || srcVMax == srcVMin)
            {
                Logger.Log("Source UV coordinates do not expand themselves to a face, cannot proceed", Logging.LogType.Error);
                return;
            }

            double dstUStretch = (_UMax.Value - _UMin.Value) / (srcUMax - srcUMin);
            double dstVStretch = (_VMax.Value - _VMin.Value) / (srcVMax - srcVMin);

            // And remap all the UV coordinates.
            foreach (Face face in meshEntity)
            {
                foreach (HalfVertex hv in face.HalfVertices)
                {
                    hv.UV0 = new Vector2D(
                        (float)((hv.UV0.X - srcUMin) * dstUStretch + _UMin.Value),
                        (float)((hv.UV0.Y - srcVMin) * dstVStretch + _VMin.Value)
                        );
                }
            }

            //finally, return the newly create pathentity
            _output.Write(meshEntity);
        }
コード例 #4
0
        protected override void RenderImGui()
        {
            if (ImGui.BeginMenuBar())
            {
                ImGui.PushStyleColor(ImGuiCol.Button, new Vector4(0.3f, 0.3f, 0.3f, 1f));
                if (ImGui.Button("Open OBJ"))
                {
                    var explorer = new FileExplorer <ObjMeshAsset>(asset => { DisplayObject.Entity = asset.Entity; });
                    _toolsRoot.AddLegacyWindow(explorer);
                }

                if (ImGui.Button("Open EM3"))
                {
                    var explorer = new FileExplorer <EmotionMeshAsset>(asset => { DisplayObject.Entity = asset.Entity; });
                    _toolsRoot.AddLegacyWindow(explorer);
                }

                if (ImGui.Button("Open Sprite Stack Texture"))
                {
                    var explorer = new FileExplorer <SpriteStackTexture>(asset =>
                    {
                        _toolsRoot.AddLegacyWindow(new Vec2Modal(size =>
                        {
                            MeshEntity entity    = asset.GetSpriteStackEntity(size);
                            DisplayObject.Entity = entity;
                        }, "Sprite Stack Settings", "Individual Frame Size", new Vector2(32, 32)));
                    });
                    _toolsRoot.AddLegacyWindow(explorer);
                }

                ImGui.EndMenuBar();
            }

            ImGui.Checkbox("Show Terrain", ref _showTerrain);

            Vector3 pos = DisplayObject.Position;

            if (ImGui.DragFloat3("Position", ref pos))
            {
                DisplayObject.Position = pos;
            }

            float scale = DisplayObject.Scale;

            if (ImGui.DragFloat("Scale", ref scale))
            {
                DisplayObject.Scale = scale;
            }

            Vector3 rot = DisplayObject.RotationDeg;

            if (ImGui.DragFloat3("Rotation", ref rot))
            {
                DisplayObject.RotationDeg = rot;
            }

            if (DisplayObject.Entity != null && DisplayObject.Entity.Animations != null && ImGui.BeginCombo("Animation", DisplayObject.CurrentAnimation))
            {
                if (ImGui.Button("None"))
                {
                    DisplayObject.SetAnimation(null);
                }

                for (var i = 0; i < DisplayObject.Entity.Animations.Length; i++)
                {
                    SkeletalAnimation anim = DisplayObject.Entity.Animations[i];
                    if (ImGui.Button($"{anim.Name}"))
                    {
                        DisplayObject.SetAnimation(anim.Name);
                    }
                }

                ImGui.EndCombo();
            }
        }
コード例 #5
0
ファイル: SpriteStackTexture.cs プロジェクト: Cryru/Emotion
        public MeshEntity GetSpriteStackEntity(Vector2 frameSize)
        {
            Vector2 size        = Texture.Size;
            var     frameWidth  = (int)frameSize.X;
            var     frameHeight = (int)frameSize.Y;
            var     frameCount  = (int)(size.X / frameWidth);

            var frames = new SpriteStackFrame[frameCount];

            for (var i = 0; i < frameCount; i++)
            {
                var frame = new SpriteStackFrame(frameWidth, frameHeight);
                frames[i] = frame;
            }

            // Get the non 0 alpha pixels from the image.
            for (var i = 0; i < _textureData.Length; i += 4)
            {
                var c = new Color(_textureData[i], _textureData[i + 1], _textureData[i + 2], _textureData[i + 3], _textureDataFormat);
                if (c.A == 0)
                {
                    continue;
                }

                int pixelIdx = i / 4;
                int x        = pixelIdx % (int)size.X;
                int y        = pixelIdx / (int)size.X;
                int frame    = x / frameWidth;

                int frameStart = frame * frameWidth;
                int frameX     = x - frameStart;

                frames[frame].SetPixel(frameX + y * frameWidth, c);
            }

            // Convert the pixels to voxel cubes.
            Vector3 center = new Vector3(frameWidth / 2, frameCount / 2, frameHeight / 2) * 2;

            for (var fIdx = 0; fIdx < frameCount; fIdx++)
            {
                SpriteStackFrame frame = frames[fIdx];
                frame.Vertices = new VertexData[frame.FilledPixels * 8];
                frame.Indices  = new ushort[frame.FilledPixels * 6 * 6]; // 6 sides, one quad is 6 indices
                var pixelCount = 0;

                for (var pIdx = 0; pIdx < frame.Pixels.Length; pIdx++)
                {
                    Color color = frame.Pixels[pIdx];
                    if (color.A == 0)
                    {
                        continue;
                    }

                    // Check if the pixel is not occluded by another.
                    var pixelTwoDeeCoord = new Vector2(pIdx % frameWidth, pIdx / frameWidth);
                    var anyTransp        = false;
                    foreach (Vector2 dir in Maths.CardinalDirections2D)
                    {
                        Vector2 otherPixel = pixelTwoDeeCoord + dir;
                        if (otherPixel.X < 0 || otherPixel.Y < 0 || otherPixel.X > frameWidth || otherPixel.Y > frameHeight)
                        {
                            anyTransp = true;
                            break;
                        }

                        var   oneDeeCoord = (int)(otherPixel.Y * frameWidth + otherPixel.X);
                        Color otherC      = frame.Pixels[oneDeeCoord];
                        if (otherC.A < 255)
                        {
                            anyTransp = true;
                            break;
                        }
                    }

                    // Check between frames (layers).
                    if (!anyTransp)
                    {
                        if (fIdx == 0 || fIdx == frameCount - 1)
                        {
                            anyTransp = true;
                        }
                        else
                        {
                            SpriteStackFrame prevFrame = frames[fIdx - 1];
                            SpriteStackFrame nextFrame = frames[fIdx + 1];
                            Color            cBelow    = prevFrame.Pixels[pIdx];
                            Color            cAbove    = nextFrame.Pixels[pIdx];
                            if (cBelow.A < 255 || cAbove.A < 255)
                            {
                                anyTransp = true;
                            }
                        }

                        if (!anyTransp)
                        {
                            continue;
                        }
                    }

                    Span <VertexData> thisPixel        = new Span <VertexData>(frame.Vertices).Slice(pixelCount * 8, 8);
                    Span <ushort>     thisPixelIndices = new Span <ushort>(frame.Indices).Slice(pixelCount * 6 * 6, 6 * 6);

                    // Darken the lower layers.
                    //int halfway = (frames.Length - 1) / 2;
                    //if (i < halfway)
                    //{
                    //    int layerFromTop = halfway - i;
                    //    int darkening = Emotion.Utility.Maths.Clamp(3 * layerFromTop, 0, 255);
                    //    int r = Emotion.Utility.Maths.Clamp(color.R - darkening, 0, 255);
                    //    int g = Emotion.Utility.Maths.Clamp(color.G - darkening, 0, 255);
                    //    int b = Emotion.Utility.Maths.Clamp(color.B - darkening, 0, 255);

                    //    color.R = (byte)r;
                    //    color.G = (byte)g;
                    //    color.B = (byte)b;
                    //}

                    uint c = color.ToUint();
                    for (var ic = 0; ic < thisPixel.Length; ic++)
                    {
                        thisPixel[ic].Color = c;
                    }

                    // Cube - 36 vertices, 12 triangles, 6 sides
                    // Cube - 36 indices, 8 vertices, 6 quads
                    thisPixel[0].Vertex = new Vector3(-1, -1, 1);
                    thisPixel[1].Vertex = new Vector3(1, -1, 1);
                    thisPixel[2].Vertex = new Vector3(1, 1, 1);
                    thisPixel[3].Vertex = new Vector3(-1, 1, 1);

                    thisPixel[4].Vertex = new Vector3(-1, -1, -1);
                    thisPixel[5].Vertex = new Vector3(1, -1, -1);
                    thisPixel[6].Vertex = new Vector3(1, 1, -1);
                    thisPixel[7].Vertex = new Vector3(-1, 1, -1);

                    // Front
                    thisPixelIndices[00] = 0;
                    thisPixelIndices[01] = 1;
                    thisPixelIndices[02] = 2;
                    thisPixelIndices[03] = 2;
                    thisPixelIndices[04] = 3;
                    thisPixelIndices[05] = 0;

                    // Right
                    thisPixelIndices[06] = 1;
                    thisPixelIndices[07] = 5;
                    thisPixelIndices[08] = 6;
                    thisPixelIndices[09] = 6;
                    thisPixelIndices[10] = 2;
                    thisPixelIndices[11] = 1;

                    // Back
                    thisPixelIndices[12] = 7;
                    thisPixelIndices[13] = 6;
                    thisPixelIndices[14] = 5;
                    thisPixelIndices[15] = 5;
                    thisPixelIndices[16] = 4;
                    thisPixelIndices[17] = 7;

                    // Left
                    thisPixelIndices[18] = 4;
                    thisPixelIndices[19] = 0;
                    thisPixelIndices[20] = 3;
                    thisPixelIndices[21] = 3;
                    thisPixelIndices[22] = 7;
                    thisPixelIndices[23] = 4;

                    // Bottom
                    thisPixelIndices[24] = 4;
                    thisPixelIndices[25] = 5;
                    thisPixelIndices[26] = 1;
                    thisPixelIndices[27] = 1;
                    thisPixelIndices[28] = 0;
                    thisPixelIndices[29] = 4;

                    // Top
                    thisPixelIndices[30] = 3;
                    thisPixelIndices[31] = 2;
                    thisPixelIndices[32] = 6;
                    thisPixelIndices[33] = 6;
                    thisPixelIndices[34] = 7;
                    thisPixelIndices[35] = 3;

                    // Add frame vertex index offset as the whole frame will be drawn together.
                    int indexOffset = pixelCount * 8;
                    for (var k = 0; k < thisPixelIndices.Length; k++)
                    {
                        thisPixelIndices[k] = (ushort)(thisPixelIndices[k] + indexOffset);
                    }

                    int x = pIdx % frameWidth;
                    int y = pIdx / frameWidth;

                    var pixelPositionMatrix = Matrix4x4.CreateTranslation(x * 2 - center.X, y * 2 - center.Y, fIdx * 2 + 1);
                    for (var iv = 0; iv < thisPixel.Length; iv++)
                    {
                        thisPixel[iv].Vertex = Vector3.Transform(thisPixel[iv].Vertex, pixelPositionMatrix);
                    }

                    pixelCount++;
                }
            }

            var spriteStackEntity = new MeshEntity
            {
                Name   = Name,
                Meshes = frames
            };

            return(spriteStackEntity);
        }
コード例 #6
0
ファイル: SkeletalAnimation.cs プロジェクト: Cryru/Emotion
 /// <summary>
 /// Apply the transformations of this animation to the bone matrices of a particular entity.
 /// </summary>
 /// <param name="entity">The entity the bone matrices are to be filled for.</param>
 /// <param name="boneMatrices">Array of matrices. Indexed relative to bone indices in the entity.</param>
 /// <param name="timeStamp">The current animation time 0-Duration</param>
 public void ApplyBoneMatrices(MeshEntity entity, Matrix4x4[] boneMatrices, float timeStamp)
 {
     ApplyBoneMatricesInternal(entity.AnimationRig, entity, boneMatrices, timeStamp, Matrix4x4.Identity);
 }
コード例 #7
0
ファイル: EmotionMeshAsset.cs プロジェクト: Cryru/Emotion
        public static MeshEntity EntityFromByteArray(ReadOnlyMemory <byte> byteArray)
        {
            var entity = new MeshEntity();

            var memoryStream = new ReadOnlyMemoryStream(byteArray);
            var reader       = new BinaryReader(memoryStream);

            char check  = reader.ReadChar();
            char check2 = reader.ReadChar();
            char check3 = reader.ReadChar();

            Debug.Assert(check == 'E' && check2 == 'M' && check3 == '3');

            byte version = reader.ReadByte();

            if (version != 1)
            {
                return(null);
            }

            entity.Name  = reader.ReadString();
            entity.Scale = reader.ReadSingle();

            var materialMap = new Dictionary <string, MeshMaterial>();
            var textureMap  = new Dictionary <string, Texture>();

            int meshesCount = reader.ReadInt32();
            var meshArray   = new Mesh[meshesCount];

            entity.Meshes = meshArray;
            for (var i = 0; i < meshesCount; i++)
            {
                var newMesh = new Mesh
                {
                    Name = reader.ReadString()
                };

                string materialName = reader.ReadString();
                if (materialMap.TryGetValue(materialName, out MeshMaterial mat))
                {
                    newMesh.Material = mat;
                }
                else
                {
                    mat = new MeshMaterial
                    {
                        Name         = materialName,
                        DiffuseColor = new Color(reader.ReadUInt32())
                    };

                    bool hasDiffuseTexture = reader.ReadBoolean();
                    if (hasDiffuseTexture)
                    {
                        string textureName = reader.ReadString();
                        mat.DiffuseTextureName = textureName;

                        if (textureMap.TryGetValue(textureName, out Texture diffuseTexture))
                        {
                            mat.DiffuseTexture = diffuseTexture;
                        }
                        else
                        {
                            int     textureByteLength = reader.ReadInt32();
                            float   width             = reader.ReadSingle();
                            float   height            = reader.ReadSingle();
                            int     textureFormat     = reader.ReadInt32();
                            Texture t = Texture.NonGLThreadInitialize(new Vector2(width, height));
                            mat.DiffuseTexture = t;

                            byte[] data = reader.ReadBytes(textureByteLength);
                            GLThread.ExecuteGLThreadAsync(() =>
                            {
                                Texture.NonGLThreadInitializedCreatePointer(t);
                                t.Upload(t.Size, data, (PixelFormat)textureFormat);
                            });

                            textureMap.Add(textureName, t);
                        }
                    }

                    newMesh.Material = mat;
                    materialMap.Add(materialName, mat);
                }

                int vertexFormat = reader.ReadByte();
                int length       = reader.ReadInt32();
                if (vertexFormat == 0) // Normal vertices
                {
                    var vertices = new VertexData[length];

                    for (var j = 0; j < length; j++)
                    {
                        ref VertexData vert = ref vertices[j];

                        vert.Vertex = ReadVector3(reader);
                        vert.UV     = ReadVector2(reader);
                        vert.Color  = reader.ReadUInt32();
                    }

                    newMesh.Vertices = vertices;
                }
コード例 #8
0
ファイル: EmotionMeshAsset.cs プロジェクト: Cryru/Emotion
 protected override void DisposeInternal()
 {
     Entity = null;
     // todo: maybe clean up entity textures or w/e?
 }
コード例 #9
0
ファイル: EmotionMeshAsset.cs プロジェクト: Cryru/Emotion
 protected override void CreateInternal(ReadOnlyMemory <byte> data)
 {
     Entity = EntityFromByteArray(data);
 }
コード例 #10
0
ファイル: AssimpAsset.cs プロジェクト: Cryru/Emotion
        protected override void CreateInternal(ReadOnlyMemory <byte> data)
        {
            var str = new ReadOnlyLinkedMemoryStream();

            str.AddMemory(data);

            _assContext ??= new AssimpContext();
            Scene scene = _assContext.ImportFileFromStream(str,
                                                           PostProcessSteps.Triangulate |
                                                           PostProcessSteps.FlipUVs |
                                                           PostProcessSteps.OptimizeGraph |
                                                           PostProcessSteps.OptimizeMeshes);

            var embeddedTextures = new List <Texture>();

            for (var i = 0; i < scene.TextureCount; i++)
            {
                EmbeddedTexture assTexture      = scene.Textures[i];
                var             embeddedTexture = new TextureAsset();
                embeddedTexture.Create(assTexture.CompressedData);
                embeddedTextures.Add(embeddedTexture.Texture);
            }

            _materials = new List <MeshMaterial>();
            for (var i = 0; i < scene.MaterialCount; i++)
            {
                Material material  = scene.Materials[i];
                Color4D  diffColor = material.ColorDiffuse;

                bool embeddedTexture = material.HasTextureDiffuse && embeddedTextures.Count > material.TextureDiffuse.TextureIndex;
                var  emotionMaterial = new MeshMaterial
                {
                    Name               = material.Name,
                    DiffuseColor       = new Color(new Vector4(diffColor.R, diffColor.G, diffColor.B, diffColor.A)),
                    DiffuseTextureName = embeddedTexture ? $"EmbeddedTexture{material.TextureDiffuse.TextureIndex}" : null,
                    DiffuseTexture     = embeddedTexture ? embeddedTextures[material.TextureDiffuse.TextureIndex] : null
                };

                _materials.Add(emotionMaterial);
            }

            _animations = new List <SkeletalAnimation>();
            ProcessAnimations(scene);

            _meshes = new List <Mesh>();
            Node rootNode = scene.RootNode;
            SkeletonAnimRigNode animRigRoot = ProcessNode(scene, rootNode);

            animRigRoot.LocalTransform *= Matrix4x4.CreateRotationX(-90 * Maths.DEG2_RAD); // Convert to right handed Z is up.

            Entity = new MeshEntity
            {
                Name         = Name,
                Meshes       = _meshes.ToArray(),
                Animations   = _animations.ToArray(),
                AnimationRig = animRigRoot
            };

            object scaleData = scene.RootNode.Metadata.GetValueOrDefault("UnitScaleFactor").Data;
            var    scaleF    = 1f;

            if (scaleData is float f)
            {
                scaleF = f;
            }
            Entity.Scale = scaleF;
        }