Created
January 12, 2015 20:48
-
-
Save ousttrue/f8a6e05e8db5c55f7aa0 to your computer and use it in GitHub Desktop.
PmdModel
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
using VVVV.Utils.VColor; | |
using VVVV.Utils.VMath; | |
using SlimDX; | |
namespace VVVV.Nodes | |
{ | |
static class MathExtensions | |
{ | |
public static Vector3D ToVVVV(this SlimDX.Vector3 src) | |
{ | |
return new Vector3D(src.X, src.Y, src.Z); | |
} | |
public static Vector2D ToVVVV(this SlimDX.Vector2 src) | |
{ | |
return new Vector2D(src.X, src.Y); | |
} | |
} | |
public class CustomBinaryReader : System.IO.BinaryReader | |
{ | |
public CustomBinaryReader(System.IO.Stream s) | |
: base(s) | |
{ | |
} | |
public String ReadStringBytes(int length, Encoding encoding=null) | |
{ | |
if (encoding == null) | |
{ | |
encoding = Encoding.ASCII; | |
} | |
return encoding.GetString(ReadBytes(length).TakeWhile(b => b!=0).ToArray()); | |
} | |
public RGBAColor ReadColor3() | |
{ | |
return new RGBAColor(ReadSingle(), ReadSingle(), ReadSingle(), 1.0f); | |
} | |
public RGBAColor ReadColor4() | |
{ | |
return new RGBAColor(ReadSingle(), ReadSingle(), ReadSingle(), ReadSingle()); | |
} | |
} | |
public class PmdModel | |
{ | |
public struct Vertex | |
{ | |
public Vector3 Position; | |
public Vector3 Normal; | |
public Vector2 UV; | |
public Color4 Color; | |
public Single EdgeFactor; | |
} | |
public enum SkinningType | |
{ | |
BDEF1, | |
BDEF2, | |
BDEF4, | |
SDEF, | |
} | |
public struct Skinning | |
{ | |
public SkinningType SkinningType; | |
public Int32[] BoneIndices; | |
public Single[] BoneWeights; | |
public Vector3 SdefC; | |
public Vector3 SdefR0; | |
public Vector3 SdefR1; | |
} | |
[Flags] | |
public enum MaterialFlag : byte | |
{ | |
None = 0, | |
BothSide = 1, | |
GroundShadow = 1 << 1, | |
SelfShadowMap = 1 << 2, | |
SelfShadow = 1 << 3, | |
Edge = 1 << 4, | |
} | |
public enum SphereMode : byte | |
{ | |
None = 0, | |
Mul = 1, | |
Add = 2, | |
SubTexture = 3, | |
} | |
public enum ToonMode : byte | |
{ | |
Own = 0, | |
Shared = 1, | |
} | |
public class Material | |
{ | |
public String Name { get; set; } | |
public String NameEnglish { get; set; } | |
public Color4 Diffuse { get; set; } | |
public Color3 Specular { get; set; } | |
public Single Shininess { get; set; } | |
public Color3 Ambient { get; set; } | |
public MaterialFlag Flags { get; set; } | |
public Color4 EdgeColor { get; set; } | |
public Single EdgeSize { get; set; } | |
public Int32 TextureIndex { get; set; } | |
public Int32 SphereTextureIndex { get; set; } | |
public SphereMode SphereMode { get; set; } | |
public ToonMode ToonMode { get; set; } | |
public Int32 ToonTextureIndex { get; set; } | |
public String Comment { get; set; } | |
} | |
public class SubMesh | |
{ | |
public Int32 Count { get; set; } | |
public Int32 Offset { get; set; } | |
public SubMesh(int count, int offset = 0) | |
{ | |
Count = count; | |
Offset = offset; | |
} | |
} | |
public String Path { get; set; } | |
public Single FormatVersion { get; set; } | |
public String Name { get; set; } | |
public String NameEnglish { get; set; } | |
public String Comment { get; set; } | |
public String CommentEnglish { get; set; } | |
public List<Vertex> Vertices { get; set; } | |
public List<Int32> Indices { get; set; } | |
public List<Skinning> SkinningList { get; set; } | |
public List<String> Textures { get; set; } | |
public List<Material> Materials { get; set; } | |
public List<SubMesh> SubMeshes { get; set; } | |
public PmdModel() | |
{ | |
} | |
public override string ToString() | |
{ | |
return String.Format("[{0}: {1}verts]", Name, Vertices.Count); | |
} | |
public static PmdModel Load(String path) | |
{ | |
using(var s=new System.IO.FileStream(path, System.IO.FileMode.Open)){ | |
if(s!=null){ | |
var bytes=new Byte[s.Length]; | |
s.Read(bytes, 0, bytes.Length); | |
var model=Load(bytes); | |
if (model != null) | |
{ | |
model.Path = path; | |
} | |
return model; | |
} | |
} | |
return null; | |
} | |
public static PmdModel Load(Byte[] bytes) | |
{ | |
var model = new PmdModel(); | |
var r = new CustomBinaryReader(new System.IO.MemoryStream(bytes)); | |
var magic = r.ReadStringBytes(3); | |
if (magic != "Pmd") | |
{ | |
return null; | |
} | |
model.FormatVersion = r.ReadSingle(); | |
var cp932Encoding=Encoding.GetEncoding(932); | |
model.Name = r.ReadStringBytes(20, cp932Encoding); | |
model.Comment = r.ReadStringBytes(256, cp932Encoding); | |
var vertexCount = r.ReadInt32(); | |
model.Vertices = new List<Vertex>(vertexCount); | |
model.SkinningList = new List<Skinning>(vertexCount); | |
for (int i = 0; i < vertexCount; ++i) | |
{ | |
var vertex=new Vertex | |
{ | |
Position = new Vector3(r.ReadSingle(), r.ReadSingle(), r.ReadSingle()), | |
Normal = new Vector3(r.ReadSingle(), r.ReadSingle(), r.ReadSingle()), | |
UV = new Vector2(r.ReadSingle(), r.ReadSingle()), | |
}; | |
var skinning=new Skinning | |
{ | |
BoneIndices = new Int32[] { r.ReadUInt16(), r.ReadUInt16() }, | |
}; | |
var weight = r.ReadByte() / 255.0f; | |
skinning.BoneWeights = new[] { weight, 1.0f - weight }; | |
vertex.EdgeFactor = r.ReadByte(); | |
model.Vertices.Add(vertex); | |
model.SkinningList.Add(skinning); | |
} | |
var indexCount=r.ReadInt32(); | |
model.Indices = Enumerable.Range(0, indexCount) | |
.Select(_ => (int)r.ReadUInt16()).ToList(); | |
return model; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment