示例#1
0
        public static SKBitmap?Decode(this UTexture2D texture, FTexture2DMipMap?mip, ETexturePlatform platform = ETexturePlatform.DesktopMobile)
        {
            if (!texture.IsVirtual && mip != null)
            {
                byte[]      data;
                SKColorType colorType;

                switch (platform)
                {
                case ETexturePlatform.Playstation:
                    PlaystationDecoder.DecodeTexturePlaystation(mip, texture.Format, texture.isNormalMap, out data, out colorType);
                    break;

                case ETexturePlatform.NintendoSwitch:
                    NintendoSwitchDecoder.DecodeTextureNSW(mip, texture.Format, texture.isNormalMap, out data, out colorType);
                    break;

                default:
                    DecodeTexture(mip, texture.Format, texture.isNormalMap, out data, out colorType);
                    break;
                }

                var width  = mip.SizeX;
                var height = mip.SizeY;
                var info   = new SKImageInfo(width, height, colorType, SKAlphaType.Unpremul);
                var bitmap = new SKBitmap();

                unsafe
                {
                    var pixelsPtr = NativeMemory.Alloc((nuint)data.Length);
                    fixed(byte *p = data)
                    {
                        Unsafe.CopyBlockUnaligned(pixelsPtr, p, (uint)data.Length);
                    }

                    bitmap.InstallPixels(info, new IntPtr(pixelsPtr), info.RowBytes, (address, _) => NativeMemory.Free(address.ToPointer()));
                }

                if (!texture.bRenderNearestNeighbor)
                {
                    return(bitmap);
                }

                var resized = bitmap.Resize(new SKImageInfo(width, height), SKFilterQuality.None);
                bitmap.Dispose();
                return(resized);
            }

            return(null);
        }
示例#2
0
 public static SKBitmap?Decode(this UTexture2D texture, ETexturePlatform platform = ETexturePlatform.DesktopMobile) => texture.Decode(texture.GetFirstMip(), platform);
示例#3
0
        public MeshExporter(UStaticMesh originalMesh, ELodFormat lodFormat = ELodFormat.FirstLod, bool exportMaterials = true, EMeshFormat meshFormat = EMeshFormat.ActorX, ETexturePlatform platform = ETexturePlatform.DesktopMobile)
        {
            MeshLods = new List <Mesh>();
            MeshName = originalMesh.Owner?.Name ?? originalMesh.Name;

            if (!originalMesh.TryConvert(out var convertedMesh) || convertedMesh.LODs.Count == 0)
            {
                Log.Logger.Warning($"Mesh '{MeshName}' has no LODs");
                return;
            }

            var i = 0;

            foreach (var lod in convertedMesh.LODs)
            {
                if (lod.SkipLod)
                {
                    Log.Logger.Warning($"LOD {i} in mesh '{MeshName}' should be skipped");
                    continue;
                }

                using var Ar = new FArchiveWriter();
                var    materialExports = exportMaterials ? new List <MaterialExporter>() : null;
                string ext;
                switch (meshFormat)
                {
                case EMeshFormat.ActorX:
                    ext = "pskx";
                    ExportStaticMeshLods(lod, Ar, materialExports);
                    break;

                case EMeshFormat.Gltf2:
                    ext = "glb";
                    new Gltf(MeshName.SubstringAfterLast("/"), lod, materialExports).Save(meshFormat, Ar);
                    break;

                case EMeshFormat.OBJ:
                    ext = "obj";
                    new Gltf(MeshName.SubstringAfterLast("/"), lod, materialExports).Save(meshFormat, Ar);
                    break;

                default:
                    throw new ArgumentOutOfRangeException(nameof(meshFormat), meshFormat, null);
                }

                MeshLods.Add(new Mesh($"{MeshName}_LOD{i}.{ext}", Ar.GetBuffer(), materialExports ?? new List <MaterialExporter>()));
                if (lodFormat == ELodFormat.FirstLod)
                {
                    break;
                }
                i++;
            }
        }
示例#4
0
        private void ExportCommonMeshData(FArchiveWriter Ar, CMeshSection[] sections, CMeshVertex[] verts,
                                          FRawStaticIndexBuffer indices, CVertexShare share, List <MaterialExporter>?materialExports, ETexturePlatform platform = ETexturePlatform.DesktopMobile)
        {
            var mainHdr  = new VChunkHeader();
            var ptsHdr   = new VChunkHeader();
            var wedgHdr  = new VChunkHeader();
            var facesHdr = new VChunkHeader();
            var matrHdr  = new VChunkHeader();
            var normHdr  = new VChunkHeader();

            mainHdr.TypeFlag = Constants.PSK_VERSION;
            Ar.SerializeChunkHeader(mainHdr, "ACTRHEAD");

            var numPoints = share.Points.Count;

            ptsHdr.DataCount = numPoints;
            ptsHdr.DataSize  = 12;
            Ar.SerializeChunkHeader(ptsHdr, "PNTS0000");
            for (var i = 0; i < numPoints; i++)
            {
                var point = share.Points[i];
                point.Y = -point.Y; // MIRROR_MESH
                point.Serialize(Ar);
            }

            var numFaces    = 0;
            var numVerts    = verts.Length;
            var numSections = sections.Length;
            var wedgeMat    = new int[numVerts];

            for (var i = 0; i < numSections; i++)
            {
                var faces = sections[i].NumFaces;
                numFaces += faces;
                for (var j = 0; j < faces * 3; j++)
                {
                    wedgeMat[indices[j + sections[i].FirstIndex]] = i;
                }
            }

            wedgHdr.DataCount = numVerts;
            wedgHdr.DataSize  = 16;
            Ar.SerializeChunkHeader(wedgHdr, "VTXW0000");
            for (var i = 0; i < numVerts; i++)
            {
                Ar.Write(share.WedgeToVert[i]);
                Ar.Write(verts[i].UV.U);
                Ar.Write(verts[i].UV.V);
                Ar.Write((byte)wedgeMat[i]);
                Ar.Write((byte)0);
                Ar.Write((short)0);
            }

            facesHdr.DataCount = numFaces;
            if (numVerts <= 65536)
            {
                facesHdr.DataSize = 12;
                Ar.SerializeChunkHeader(facesHdr, "FACE0000");
                for (var i = 0; i < numSections; i++)
                {
                    for (var j = 0; j < sections[i].NumFaces; j++)
                    {
                        var wedgeIndex = new ushort[3];
                        for (var k = 0; k < wedgeIndex.Length; k++)
                        {
                            wedgeIndex[k] = (ushort)indices[sections[i].FirstIndex + j * 3 + k];
                        }

                        Ar.Write(wedgeIndex[1]); // MIRROR_MESH
                        Ar.Write(wedgeIndex[0]); // MIRROR_MESH
                        Ar.Write(wedgeIndex[2]);
                        Ar.Write((byte)i);
                        Ar.Write((byte)0);
                        Ar.Write((uint)1);
                    }
                }
            }
            else
            {
                facesHdr.DataSize = 18;
                Ar.SerializeChunkHeader(facesHdr, "FACE3200");
                for (var i = 0; i < numSections; i++)
                {
                    for (var j = 0; j < sections[i].NumFaces; j++)
                    {
                        var wedgeIndex = new int[3];
                        for (var k = 0; k < wedgeIndex.Length; k++)
                        {
                            wedgeIndex[k] = indices[sections[i].FirstIndex + j * 3 + k];
                        }

                        Ar.Write(wedgeIndex[1]); // MIRROR_MESH
                        Ar.Write(wedgeIndex[0]); // MIRROR_MESH
                        Ar.Write(wedgeIndex[2]);
                        Ar.Write((byte)i);
                        Ar.Write((byte)0);
                        Ar.Write((uint)1);
                    }
                }
            }

            matrHdr.DataCount = numSections;
            matrHdr.DataSize  = 88;
            Ar.SerializeChunkHeader(matrHdr, "MATT0000");
            for (var i = 0; i < numSections; i++)
            {
                string materialName;
                if (sections[i].Material?.Load <UMaterialInterface>() is { } tex)
                {
                    materialName = tex.Name;
                    materialExports?.Add(new MaterialExporter(tex, true, platform));
                }
示例#5
0
        private void ExportSkeletalMeshLod(CSkelMeshLod lod, List <CSkelMeshBone> bones, FArchiveWriter Ar, List <MaterialExporter>?materialExports, ETexturePlatform platform = ETexturePlatform.DesktopMobile)
        {
            var share  = new CVertexShare();
            var infHdr = new VChunkHeader();

            share.Prepare(lod.Verts);
            foreach (var vert in lod.Verts)
            {
                var weightsHash = vert.PackedWeights;
                for (var i = 0; i < vert.Bone.Length; i++)
                {
                    weightsHash ^= (uint)vert.Bone[i] << i;
                }

                share.AddVertex(vert.Position, vert.Normal, weightsHash);
            }

            ExportCommonMeshData(Ar, lod.Sections.Value, lod.Verts, lod.Indices.Value, share, materialExports, platform);
            ExportSkeletonData(Ar, bones);

            var numInfluences = 0;

            for (var i = 0; i < share.Points.Count; i++)
            {
                for (var j = 0; j < Constants.NUM_INFLUENCES_UE4; j++)
                {
                    if (lod.Verts[share.VertToWedge.Value[i]].Bone[j] < 0)
                    {
                        break;
                    }
                    numInfluences++;
                }
            }
            infHdr.DataCount = numInfluences;
            infHdr.DataSize  = 12;
            Ar.SerializeChunkHeader(infHdr, "RAWWEIGHTS");
            for (var i = 0; i < share.Points.Count; i++)
            {
                var v = lod.Verts[share.VertToWedge.Value[i]];
                var unpackedWeights = v.UnpackWeights();

                for (var j = 0; j < Constants.NUM_INFLUENCES_UE4; j++)
                {
                    if (v.Bone[j] < 0)
                    {
                        break;
                    }

                    Ar.Write(unpackedWeights[j]);
                    Ar.Write(i);
                    Ar.Write((int)v.Bone[j]);
                }
            }

            ExportVertexColors(Ar, lod.VertexColors, lod.NumVerts);
            ExportExtraUV(Ar, lod.ExtraUV.Value, lod.NumVerts, lod.NumTexCoords);
        }
示例#6
0
        private void ExportStaticMeshLods(CStaticMeshLod lod, FArchiveWriter Ar, List <MaterialExporter>?materialExports, ETexturePlatform platform = ETexturePlatform.DesktopMobile)
        {
            var share   = new CVertexShare();
            var boneHdr = new VChunkHeader();
            var infHdr  = new VChunkHeader();

            share.Prepare(lod.Verts);
            foreach (var vert in lod.Verts)
            {
                share.AddVertex(vert.Position, vert.Normal);
            }

            ExportCommonMeshData(Ar, lod.Sections.Value, lod.Verts, lod.Indices.Value, share, materialExports, platform);

            boneHdr.DataCount = 0;
            boneHdr.DataSize  = 120;
            Ar.SerializeChunkHeader(boneHdr, "REFSKELT");

            infHdr.DataCount = 0;
            infHdr.DataSize  = 12;
            Ar.SerializeChunkHeader(infHdr, "RAWWEIGHTS");

            ExportVertexColors(Ar, lod.VertexColors, lod.NumVerts);
            ExportExtraUV(Ar, lod.ExtraUV.Value, lod.NumVerts, lod.NumTexCoords);
        }
示例#7
0
        public MaterialExporter(UUnrealMaterial?unrealMaterial, bool bNoOtherTextures, ETexturePlatform platform = ETexturePlatform.DesktopMobile) : this()
        {
            if (unrealMaterial == null)
            {
                return;
            }
            _internalFilePath = unrealMaterial.Owner?.Name ?? unrealMaterial.Name;

            var allTextures = new List <UUnrealMaterial>();

            unrealMaterial.AppendReferencedTextures(allTextures, false);

            var parameters = new CMaterialParams();

            unrealMaterial.GetParams(parameters);
            if ((parameters.IsNull || parameters.Diffuse == unrealMaterial) && allTextures.Count == 0)
            {
                return;
            }

            var sb       = new StringBuilder();
            var toExport = new List <UUnrealMaterial>();

            void Proc(string name, UUnrealMaterial?arg)
            {
                if (arg == null)
                {
                    return;
                }
                sb.AppendLine($"{name}={arg.Name}");
                switch (bNoOtherTextures)
                {
                case true when !name.StartsWith("Other["):
                case false:
                    toExport.Add(arg);
                    break;
                }
            }

            Proc("Diffuse", parameters.Diffuse);
            Proc("Normal", parameters.Normal);
            Proc("Specular", parameters.Specular);
            Proc("SpecPower", parameters.SpecPower);
            Proc("Opacity", parameters.Opacity);
            Proc("Emissive", parameters.Emissive);
            Proc("Cube", parameters.Cube);
            Proc("Mask", parameters.Mask);
            Proc("Misc", parameters.Misc);

            // Export other textures
            var numOtherTextures = 0;

            foreach (var texture in allTextures)
            {
                if (toExport.Contains(texture))
                {
                    continue;
                }
                Proc($"Other[{numOtherTextures++}]", texture);
            }

            _fileData = sb.ToString().Trim();

            foreach (var texture in toExport)
            {
                if (texture == unrealMaterial || texture is not UTexture2D t)
                {
                    continue;
                }
                _textures[t.Owner?.Name ?? t.Name] = t.Decode(platform);
            }

            if (!bNoOtherTextures && unrealMaterial is UMaterialInstanceConstant {
                Parent : { }
            } material)
            {
                _parentData = new MaterialExporter(material.Parent, bNoOtherTextures);
            }
        }