private bool _LoadMesh(BlendTypeRepository repository, BlendValueCapsule meshObj) { var mesh = meshObj.GetMember("data").GetRawValue <BlendAddress>().DereferenceOne(); string meshName = meshObj.GetMember("id").GetMember("name").GetAllValueAsString(); int mtlCount = meshObj.GetMember("totcol").GetRawValue <int>(); // Build Armature DrawSystem.BoneData[] boneArray = null; int[] deformGroupIndex2BoneIndex = null; AnimType.AnimationData animData; if (!_LoadArmature(repository, meshObj, out boneArray, out deformGroupIndex2BoneIndex, out animData)) { // igrnore } // Build original vertices var originVertices = _CreateOriginalVertices(repository, mesh, deformGroupIndex2BoneIndex); // Build materials var pmtlType = new BlendPointerType(repository.Find("Material")); var mtls = mesh.GetMember("mat").GetRawValue <BlendAddress>().DereferenceAll(pmtlType); Debug.Assert(mtls.Count == mtlCount, "material count is unmatched"); for (int mtlIndex = 0; mtlIndex < mtlCount; ++mtlIndex) { // Build a vertex buffer(s) var vertices = originVertices .Where(v => v.MaterialIndex == mtlIndex) .ToArray(); var bMaterial = mtls[mtlIndex].GetRawValue <BlendAddress>().DereferenceOne(); if (bMaterial != null) { Dictionary <DrawSystem.TextureTypes, TextureInfo> textureInfos = null; MaterialBase material; if (!_LoadMaterial(repository, bMaterial, out textureInfos, out material)) { continue; } var node = new SceneNode() { Name = meshName, Vertics = vertices, MaterialData = material, TextureInfos = textureInfos, BoneArray = mtlIndex == 0 ? boneArray : null, // set boneArray for the first node Animation = animData.Actions != null ? (AnimType.AnimationData?)animData : null, }; m_nodeList.Add(node); } } return(m_nodeList.Count != 0); }
private bool _LoadMaterial(BlendTypeRepository repository, BlendValueCapsule bMaterial, out Dictionary <DrawSystem.TextureTypes, TextureInfo> outTextureInfos, out MaterialBase outMaterial) { string mtlName = bMaterial.GetMember("id").GetMember("name").GetAllValueAsString(); Console.WriteLine(" found material : " + mtlName); var texInfos = new Dictionary <DrawSystem.TextureTypes, TextureInfo>(); string materialTypeName = Path.GetExtension(mtlName); switch (materialTypeName) { case "": case ".std": _LoadTextures(repository, bMaterial, ref texInfos, new DrawSystem.TextureTypes[] { DrawSystem.TextureTypes.Diffuse0, DrawSystem.TextureTypes.Bump0 }); outMaterial = new StandardMaterial(); outTextureInfos = texInfos; return(true); case ".map": _LoadTextures(repository, bMaterial, ref texInfos, new DrawSystem.TextureTypes[] { DrawSystem.TextureTypes.Diffuse0 }); outMaterial = new MinimapMaterial(); texInfos.Add(DrawSystem.TextureTypes.MinimapRoute, new TextureInfo { Name = "route.png", UvScale = new Vector2(1, 1) }); // add a special texture outTextureInfos = texInfos; return(true); case ".mark": { var prop = _FindCustomProperty(bMaterial.GetMember("id"), "id"); if (prop == null) { Debug.Fail("marker material must have id property"); break; } outMaterial = MarkerMaterial.Create(prop.Value); outTextureInfos = texInfos; } return(true); default: Debug.Fail("unknown material type : " + materialTypeName); break; } outMaterial = null; outTextureInfos = texInfos; return(false); }
/// <summary> /// find a custom property which contains a given name /// </summary> /// <param name="bId">material id</param> /// <param name="propertyName">search key</param> /// <returns></returns> private CustomProperty _FindCustomProperty(BlendValueCapsule bId, string propertyName) { var bTopIdProperty = bId.GetMember("properties").GetRawValue <BlendAddress>().DereferenceOne(); var bNextIdProperty = bTopIdProperty.GetMember("data").GetMember("group").GetMember("first").GetRawValue <BlendAddress>().DereferenceOne(); while (bNextIdProperty != null) { // found var name = bNextIdProperty.GetMember("name").GetAllValueAsString(); if (propertyName == name) { var prop = new CustomProperty() { Name = name, Value = bNextIdProperty.GetMember("data").GetMember("val").GetRawValue <int>() }; return(prop); } bNextIdProperty = bNextIdProperty.GetMember("next").GetRawValue <BlendAddress>().DereferenceOne(); } // not fund return(null); }
private void _LoadTextures(BlendTypeRepository repository, BlendValueCapsule bMaterial, ref Dictionary <DrawSystem.TextureTypes, TextureInfo> outTextureInfos, DrawSystem.TextureTypes[] supportTypes) { var mtexs = bMaterial.GetMember("mtex"); var mtexsType = mtexs.Type as BlendArrayType; for (int mtexIndex = 0; mtexIndex < mtexsType.GetLength(0); ++mtexIndex) { // Build textures var mtex = mtexs.GetAt(mtexIndex).GetRawValue <BlendAddress>().DereferenceOne(); if (mtex != null) { float scaleU = mtex.GetMember("size").GetAt(0).GetRawValue <float>(); float scaleV = mtex.GetMember("size").GetAt(1).GetRawValue <float>(); var tex = mtex.GetMember("tex").GetRawValue <BlendAddress>().DereferenceOne(); if (tex != null) { var ima = tex.GetMember("ima").GetRawValue <BlendAddress>().DereferenceOne(); if (ima != null) { var typename = tex.GetMember("id").GetMember("name").GetAllValueAsString(); typename = Path.GetFileNameWithoutExtension(typename); // TEdiffuse.001 => TEdiffuse var path = Path.GetFileName(ima.GetMember("name").GetAllValueAsString()); Console.WriteLine(" found texture : " + path); DrawSystem.TextureTypes type = DrawSystem.TextureTypes.Diffuse0; switch (typename) { case "TEdiffuse": type = DrawSystem.TextureTypes.Diffuse0; break; case "TEnormal": type = DrawSystem.TextureTypes.Bump0; break; default: Debug.Fail("unsupported texture typename " + typename); break; } outTextureInfos.Add(type, new TextureInfo { Name = path, UvScale = new Vector2(scaleU, scaleV) }); } } } } }
private void _LoadBone(BlendTypeRepository repository, BlendValueCapsule bone, int parentBoneIndex, ref List <DrawSystem.BoneData> outList) { if (bone != null) { // make bone data var name = bone.GetMember("name").GetAllValueAsString(); float length = bone.GetMember("length").GetRawValue <float>(); var offset = new Vector3() { X = bone.GetMember("head").GetAt(0).GetRawValue <float>(), Y = bone.GetMember("head").GetAt(1).GetRawValue <float>(), Z = bone.GetMember("head").GetAt(2).GetRawValue <float>(), }; offset = BlenderUtil.ChangeCoordsSystem(offset); var elements = new float[16]; for (int i = 0; i < 4; ++i) { for (int j = 0; j < 4; ++j) { elements[i * 4 + j] = bone.GetMember("arm_mat").GetAt(i, j).GetRawValue <float>(); } } var modelTrans = new Matrix(elements); modelTrans = BlenderUtil.ChangeCoordsSystem(modelTrans); var result = new DrawSystem.BoneData() { Name = name, Parent = parentBoneIndex, BoneTransform = modelTrans, // convert local bone transformation after BoneOffset = Matrix.Invert(modelTrans), Length = length, }; outList.Add(result); parentBoneIndex = outList.Count() - 1; //Console.WriteLine(" found bone : " + name); // call for children var childBone = bone.GetMember("childbase").GetMember("first").GetRawValue <BlendAddress>().DereferenceOne(); while (childBone != null) { _LoadBone(repository, childBone, parentBoneIndex, ref outList); childBone = childBone.GetMember("next").GetRawValue <BlendAddress>().DereferenceOne(); } } }
private bool _LoadArmature(BlendTypeRepository repository, BlendValueCapsule meshObj, out DrawSystem.BoneData[] outBoneArray, out int[] outDeformGroupIndex2BoneIndex, out AnimType.AnimationData outAnimData) { BlendValueCapsule bArmature = null; BlendValueCapsule bAnimData = null; // find blend value { var mod = meshObj.GetMember("modifiers").GetMember("first").GetRawValue <BlendAddress>().DereferenceOne(); while (mod != null) { if (mod.Type.Equals(repository.Find("ArmatureModifierData"))) { // animation modifier var armatureObj = mod.GetMember("object").GetRawValue <BlendAddress>().DereferenceOne(); if (armatureObj != null) { bArmature = armatureObj.GetMember("data").GetRawValue <BlendAddress>().DereferenceOne(); bAnimData = armatureObj.GetMember("adt").GetRawValue <BlendAddress>().DereferenceOne(); break; } } mod = mod.GetMember("modifier").GetMember("next").GetRawValue <BlendAddress>().DereferenceOne(); } } // build boneList from armature var boneList = new List <DrawSystem.BoneData>(); if (bArmature != null) { var firstBone = bArmature.GetMember("bonebase").GetMember("first").GetRawValue <BlendAddress>().DereferenceOne(); var tmpBoneList = new List <DrawSystem.BoneData>(); _LoadBone(repository, firstBone, -1, ref tmpBoneList); // compute local bone matrix for (int boneIndex = 0; boneIndex < tmpBoneList.Count(); ++boneIndex) { var tmp = tmpBoneList[boneIndex]; if (!tmp.IsMasterBone()) { tmp.BoneTransform = tmp.BoneTransform * Matrix.Invert(tmpBoneList[tmp.Parent].BoneTransform); } boneList.Add(tmp); } } // build anime data from animAction var animActionList = new List <AnimType.ActionData>(); if (bAnimData != null) { var bAnimAction = bAnimData.GetMember("action").GetRawValue <BlendAddress>().DereferenceOne(); // seek the top of action while (bAnimAction != null) { var bTmpAnimAction = bAnimAction.GetMember("id").GetMember("prev").GetRawValue <BlendAddress>().DereferenceOne(); if (bTmpAnimAction == null) { break; } bAnimAction = bTmpAnimAction; } // load action while (bAnimAction != null) { _LoadAction(repository, bAnimAction, ref animActionList); bAnimAction = bAnimAction.GetMember("id").GetMember("next").GetRawValue <BlendAddress>().DereferenceOne(); } } var deformGroupNameList = new List <string>(); var deformGroup = meshObj.GetMember("defbase").GetMember("first").GetRawValue <BlendAddress>().DereferenceOne(); while (deformGroup != null) { var groupName = deformGroup.GetMember("name").GetAllValueAsString(); //Console.WriteLine(" found deform group : " + groupName); deformGroupNameList.Add(groupName); deformGroup = deformGroup.GetMember("next").GetRawValue <BlendAddress>().DereferenceOne(); } if (deformGroupNameList.Count != 0 && boneList.Count != 0) { // sort boneArray by deform group outDeformGroupIndex2BoneIndex = new int[boneList.Count()]; int nextIndex = 0; foreach (var defName in deformGroupNameList) { var bone = boneList.Select((n, index) => new { n, index }).FirstOrDefault(ni => ni.n.Name == defName); if (bone != null) { outDeformGroupIndex2BoneIndex[nextIndex] = bone.index; } nextIndex++; } outBoneArray = boneList.ToArray(); if (animActionList.Count == 0) { outAnimData = new AnimType.AnimationData(); } else { outAnimData = new AnimType.AnimationData(); outAnimData.Actions = animActionList.ToArray(); } return(true); } else { outDeformGroupIndex2BoneIndex = new int[0]; outBoneArray = new DrawSystem.BoneData[0]; outAnimData = new AnimType.AnimationData(); return(false); } }
private void _LoadAction(BlendTypeRepository repository, BlendValueCapsule bAnimAction, ref List <AnimType.ActionData> animActionList) { var groupList = new List <AnimType.ActionGroupData>(); var bGroup = bAnimAction.GetMember("groups").GetMember("first").GetRawValue <BlendAddress>().DereferenceOne(); while (bGroup != null) { var groupData = new AnimType.ActionGroupData(); groupData.BoneName = bGroup.GetMember("name").GetAllValueAsString(); groupData.Location = AnimType.ChannelData <Vector3> .Empty(); groupData.Rotation = AnimType.ChannelData <Quaternion> .Empty(); groupData.Scale = AnimType.ChannelData <Vector3> .Empty(); //Console.WriteLine(" found anim action group : " + groupData.BoneName); var channelList = new List <AnimType.ChannelData <float> >(); var bChannel = bGroup.GetMember("channels").GetMember("first").GetRawValue <BlendAddress>().DereferenceOne(); while (bChannel != null) { string boneName = ""; string propertyName = ""; var bRnaPath = bChannel.GetMember("rna_path").GetRawValue <BlendAddress>().DereferenceAll(Blender.BlendPrimitiveType.Char()); string rnaPath = Blender.ConvertUtil.CharArray2String(bRnaPath.Select(c => (object)c.GetRawValue <char>())); if (!BlenderUtil.ParseRnaPath(rnaPath, ref boneName, ref propertyName)) { Debug.Fail("Failed to parse rna path(" + rnaPath + ")"); return; } int arrayIndex = bChannel.GetMember("array_index").GetRawValue <int>(); if (boneName == groupData.BoneName) { //Console.WriteLine(String.Format(" {0}.{1}[{2}]", boneName, propertyName, arrayIndex)); var bBeztList = bChannel.GetMember("bezt").GetRawValue <BlendAddress>().DereferenceAll(); var channel = new AnimType.ChannelData <float>(); channel.KeyFrames = new AnimType.KeyData <float> [bBeztList.Count()]; foreach (var bBezt in bBeztList.Select((value, index) => new { value, index })) { float frame = bBezt.value.GetMember("vec").GetAt(1, 0).GetRawValue <float>(); float value = bBezt.value.GetMember("vec").GetAt(1, 1).GetRawValue <float>(); channel.KeyFrames[bBezt.index] = new AnimType.KeyData <float>((int)frame, value); } channelList.Add(channel); } bChannel = bChannel.GetMember("next").GetRawValue <BlendAddress>().DereferenceOne(); } // while if (channelList.Count() == 10) { // channel type convertion // location : floatx3 to Vector3 // rotation : floatx4 to Quatanion // scale : floatx3 to Vector3 groupData.Location.KeyFrames = channelList[0].KeyFrames .Select((key, index) => new AnimType.KeyData <Vector3>(key.Frame, new Vector3(key.Value, channelList[1].KeyFrames[index].Value, channelList[2].KeyFrames[index].Value))) .Select(key => { key.Value = BlenderUtil.ChangeCoordsSystem(key.Value); return(key); }) //.Select(key => { key.Frame--; return key; }) // blender frame index starts from 1 .ToArray(); groupData.Rotation.KeyFrames = channelList[3].KeyFrames .Select((key, index) => new AnimType.KeyData <Quaternion>(key.Frame, new Quaternion(channelList[4].KeyFrames[index].Value, channelList[5].KeyFrames[index].Value, channelList[6].KeyFrames[index].Value, key.Value))) .Select(key => { key.Value = BlenderUtil.ChangeCoordsSystem(key.Value); return(key); }) //.Select(key => { key.Frame--; return key; }) // blender frame index starts from 1 .ToArray(); groupData.Scale.KeyFrames = channelList[7].KeyFrames .Select((key, index) => new AnimType.KeyData <Vector3>(key.Frame, new Vector3(key.Value, channelList[8].KeyFrames[index].Value, channelList[9].KeyFrames[index].Value))) .Select(key => { key.Value = BlenderUtil.ChangeCoordsSystem(key.Value); return(key); }) //.Select(key => { key.Frame--; return key; }) // blender frame index starts from 1 .ToArray(); groupList.Add(groupData); bGroup = bGroup.GetMember("next").GetRawValue <BlendAddress>().DereferenceOne(); } else { Debug.Fail("unexpected the number of channels."); return; } } if (groupList.Count != 0) { var actionData = new AnimType.ActionData(); var actionName = bAnimAction.GetMember("id").GetMember("name").GetAllValueAsString(); actionName = actionName.Substring(2, actionName.Length - 2); // ACArmatureAction => ArmatureAction actionData.Name = actionName; actionData.Groups = groupList.ToArray(); animActionList.Add(actionData); } }
private bool _LoadScene(BlendTypeRepository repository, List <BlockHeaderEntity> entityList) { // find root BlendValueCapsule root = entityList.Where(e => e.Name == "GLOB").Select(e => e.Children[0].Value).First(); if (root == null) { return(false); } var scene = root.GetMember("curscene").GetRawValue <BlendAddress>().DereferenceOne(); var listBase = scene.GetMember("base"); var nextBase = listBase.GetMember("first").GetRawValue <BlendAddress>().DereferenceOne(); // load mesh while (nextBase != null) { var obj = nextBase.GetMember("object").GetRawValue <BlendAddress>().DereferenceOne(); if (obj != null) { string name = obj.GetMember("id").GetMember("name").GetAllValueAsString(); int restrictFlag = obj.GetMember("restrictflag").GetRawValue <char>(); if ((restrictFlag & 1) != 0) { // invisible object } var data = obj.GetMember("data").GetRawValue <BlendAddress>().DereferenceOne(); if (data != null && data.Type.Name == "Mesh") { // mesh object Console.WriteLine("found mesh : " + name); if (!_LoadMesh(repository, obj)) { return(false); } } var groupId = obj.GetMember("dup_group").GetRawValue <BlendAddress>().DereferenceOne(); if (groupId != null) { // link object Console.WriteLine("found link obj: " + name); var lib = groupId.GetMember("lib").GetRawValue <BlendAddress>().DereferenceOne(); var path = lib.GetMember("filepath").GetAllValueAsString(); // make layout matrix var elements = new float[16]; for (int i = 0; i < 4; ++i) { for (int j = 0; j < 4; ++j) { elements[i * 4 + j] = obj.GetMember("obmat").GetAt(i, j).GetRawValue <float>(); } } var layoutTrans = new Matrix(elements); layoutTrans = BlenderUtil.ChangeCoordsSystem(layoutTrans); var node = new LinkNode() { Name = name, Layout = layoutTrans, TargetFileName = Path.GetFileName(path), }; m_linkList.Add(node); } } nextBase = nextBase.GetMember("next").GetRawValue <BlendAddress>().DereferenceOne(); } return(true); }
private VertexOriginal[] _CreateOriginalVertices(BlendTypeRepository repository, BlendValueCapsule mesh, int[] deformGroupIndex2BoneIndex) { var mpolyList = mesh.GetMember("mpoly").GetRawValue <BlendAddress>().DereferenceAll(); var mloopList = mesh.GetMember("mloop").GetRawValue <BlendAddress>().DereferenceAll(); var mloopuvList = mesh.GetMember("mloopuv").GetRawValue <BlendAddress>().DereferenceAll(); var mvertList = mesh.GetMember("mvert").GetRawValue <BlendAddress>().DereferenceAll(); var dvertList = mesh.GetMember("dvert").GetRawValue <BlendAddress>().DereferenceAll(); int capacity = mpolyList.Count() * 6; // assume that all polygons is square. var vertices = new List <VertexOriginal>(capacity); foreach (var mpoly in mpolyList) { int offset = mpoly.GetMember("loopstart").GetRawValue <int>(); int count = mpoly.GetMember("totloop").GetRawValue <int>(); short materialIndex = mpoly.GetMember("mat_nr").GetRawValue <short>(); Debug.Assert(count >= 0, "negative totloop is here!"); // todo: ref previous loop int[] plan = null; switch (count) { case 3: plan = new int[] { offset + 2, offset + 1, offset + 0 }; break; case 4: // triangulation plan = new int[] { offset + 2, offset + 1, offset, offset + 3, offset + 2, offset }; break; default: Debug.Fail("tutloop must be 3 or 4"); // todo: ref previous loop break; } if (plan == null) { continue; } foreach (int i in plan) { int vIndex = mloopList[i].GetMember("v").GetRawValue <int>(); var position = mvertList[vIndex].GetMember("co"); var normal = mvertList[vIndex].GetMember("no"); VertexOriginal vertex; vertex.Position.X = position.GetAt(0).GetRawValue <float>(); vertex.Position.Y = position.GetAt(1).GetRawValue <float>(); vertex.Position.Z = position.GetAt(2).GetRawValue <float>(); vertex.Position.W = 1; vertex.Position = BlenderUtil.ChangeCoordsSystem(vertex.Position); vertex.Normal.X = normal.GetAt(0).GetRawValue <short>(); vertex.Normal.Y = normal.GetAt(1).GetRawValue <short>(); vertex.Normal.Z = normal.GetAt(2).GetRawValue <short>(); vertex.Normal = BlenderUtil.ChangeCoordsSystem(vertex.Normal); vertex.Normal.Normalize(); var uv = mloopuvList[i].GetMember("uv"); vertex.Texcoord.X = uv.GetAt(0).GetRawValue <float>(); vertex.Texcoord.Y = 1 - uv.GetAt(1).GetRawValue <float>(); vertex.Tangent = Vector3.Zero; vertex.Binormal = Vector3.Zero; vertex.MaterialIndex = materialIndex; var weights = dvertList == null ? null : dvertList[vIndex].GetMember("dw").GetRawValue <BlendAddress>().DereferenceAll(); if (weights == null || deformGroupIndex2BoneIndex == null) { vertex.BoneWeights = null; vertex.BoneIndices = null; } else { // load bone weights // bone weight can be stored 0, so we ignore this case. //int maxWeightCount = dvertList[vIndex].GetMember("totweight").GetRawValue<int>(); var noneZeroWeightList = weights.Select(w => new Tuple <float, int>(w.GetMember("weight").GetRawValue <float>(), w.GetMember("def_nr").GetRawValue <int>())) .OrderByDescending(tuple => tuple.Item1) // sort by descending .Where(tuple => tuple.Item1 > 0.0f); // ignore zero value too int weightCount = noneZeroWeightList.Count(); vertex.BoneWeights = new float[weightCount]; vertex.BoneIndices = new uint[weightCount]; int wIndex = 0; foreach (var tuple in noneZeroWeightList) { float weight = tuple.Item1; int deformGroupIndex = tuple.Item2; vertex.BoneWeights[wIndex] = weight; // def_nr is NOT index of bones, but index of deform group // we must replace to index of bones using bone-deform mapping. vertex.BoneIndices[wIndex] = (uint)deformGroupIndex2BoneIndex[deformGroupIndex]; wIndex++; } } vertices.Add(vertex); } } // compute tangent and binormal int polyCount = vertices.Count / 3; for (int polyIndex = 0; polyIndex < polyCount; ++polyIndex) { var posArray = new Vector4[] { vertices[polyIndex * 3].Position, vertices[polyIndex * 3 + 1].Position, vertices[polyIndex * 3 + 2].Position, }; var normalArray = new Vector3[] { vertices[polyIndex * 3].Normal, vertices[polyIndex * 3 + 1].Normal, vertices[polyIndex * 3 + 2].Normal, }; var uvArray = new Vector2[] { vertices[polyIndex * 3].Texcoord, vertices[polyIndex * 3 + 1].Texcoord, vertices[polyIndex * 3 + 2].Texcoord, }; var faceTangent = MathUtil.ComputeFaceTangent(posArray[0], posArray[1], posArray[2], uvArray[0], uvArray[1], uvArray[2]); for (int vIndex = 0; vIndex < 3; ++vIndex) { // calc tangent var normal = normalArray[vIndex]; var tangent = faceTangent; MathUtil.Orthonormalize(ref normal, ref tangent); // calc binormal var binormal = Vector3.Cross(normalArray[vIndex], tangent); //binormal.Normalize(); var oldVertex = vertices[polyIndex * 3 + vIndex]; oldVertex.Tangent = tangent; oldVertex.Binormal = binormal; vertices[polyIndex * 3 + vIndex] = oldVertex; } } return(vertices.ToArray()); }