using System; using System.IO; using System.Linq; using Aiwaz.Common; using Aiwaz.Contracts; using Aiwaz.Core; using System.Collections.Generic; using Aiwaz.Resources.Attributes; using System.Collections.ObjectModel; using SlimDX; namespace Aiwaz.Resources { public class FileInegrityBroken : Exception { public FileInegrityBroken() : base() { } public FileInegrityBroken(string message) : base(message) { } } [CreationParameters("Blu Model from file")] public class BluModelParams : ICreationParams { public string FileName; public BluModelParams() { } } [AiwazResource("Blu Model", "A model loaded from a .blu file")] public class BluModel : Resource { private enum BluSectionType { Mesh = 0, Material = 1, Bone = 2, Animation = 3, LastKnownType = 3 }; private class BluImportResult { public struct BluImportedGeometryBuffer { public IGeometryBuffer GeometryBuffer; public string MaterialName; }; public string FileName; public Dictionary GeometryBuffers = new Dictionary(); public Dictionary ShaderParamererSets = new Dictionary(); public Dictionary Shaders = new Dictionary(); //Dictionary Bones; //Dictionary Animations; }; public string FileName { get; protected set; } public RenderCommandNode RootNode { get; protected set; } public Transformation RootTransformation { get; protected set; } //IBoneController BoneController; public BluModel(BluModelParams parameters) { creationParams = parameters; var result = new BluImportResult(); this.FileName = result.FileName = parameters.FileName; using (var stream = Engine.FileSystem.Open(parameters.FileName)) using (var reader = new BinaryReader(stream)) { var magic = reader.ReadNullTerminatedString(); if (magic != "BLUF") throw new FileInegrityBroken(); var fileVersion = reader.ReadInt32(); // sections while (stream.Position < stream.Length) { var objectType = (BluSectionType)reader.ReadInt32(); if (objectType > BluSectionType.LastKnownType) throw new FileInegrityBroken("Unknown object section detected."); var objectName = reader.ReadNullTerminatedString(); if (string.IsNullOrEmpty(objectName)) throw new FileInegrityBroken("Object name not set."); // content switch (objectType) { case BluSectionType.Mesh: this.ImportMesh(reader, objectName, result); break; case BluSectionType.Material: this.ImportMaterial(reader, objectName, result); break; case BluSectionType.Bone: this.ImportBone(reader, objectName, result); break; case BluSectionType.Animation: this.ImportAnimation(reader, objectName, result); break; } } } // build bone hierarchy //std::map::iterator lk_BonesIter = lr_Result.m_Bones.begin(); //for (; lk_BonesIter != lr_Result.m_Bones.end(); ++lk_BonesIter) //{ // BluImportedBone lr_Bone = lk_BonesIter->second; // std::map::iterator lk_Found = lr_Result.m_Bones.find(lr_Bone.m_ParentName); // if (lk_Found != lr_Result.m_Bones.end()) // lr_Bone.m_Bone->set_Parent(lk_Found->second.m_Bone); //} // add bone animations to bones //std::map::iterator lk_AnimIter = lr_Result.m_Animations.begin(); //for (; lk_AnimIter != lr_Result.m_Animations.end(); ++lk_AnimIter) //{ // std::map::iterator lk_Found = lr_Result.m_Bones.find(lk_AnimIter->first); // if (lk_Found != lr_Result.m_Bones.end()) // { // lk_Found->second.m_Bone->set_TransformationAnimation(lk_AnimIter->second); // } //} // collapse bone map to super parent bones only //lk_BonesIter = lr_Result.m_Bones.begin(); //for (; lk_BonesIter != lr_Result.m_Bones.end();) // if (!lk_BonesIter->second.m_ParentName.empty()) // lk_BonesIter = lr_Result.m_Bones.erase(lk_BonesIter); // else // { // // create the boneindexlist structure while we are here // lk_BonesIter->second.m_Bone->get_BoneIndexList(); // ++lk_BonesIter; // } //if (lr_Result.m_Bones.size() > 1) // throw _T("BLUImporter: Only one bone root allowed!"); // Create a default BoneController //if (!lr_Result.m_Bones.empty()) //{ // lr_Result.m_BoneController = &m_Engine.get_ResourceFactory().CreateOrFindBoneController(); // lr_Result.m_BoneController->Initialize(*lr_Result.m_Bones.begin()->second.m_Bone); // float lf_MaxDuration = 0.0f; // for (lk_AnimIter = lr_Result.m_Animations.begin(); lk_AnimIter != lr_Result.m_Animations.end(); ++lk_AnimIter) // lf_MaxDuration = lf_MaxDuration < lk_AnimIter->second->get_Duration() ? lk_AnimIter->second->get_Duration() : lf_MaxDuration; // lr_Result.m_BoneController->RegisterSequence(L"all", 0.0f, lf_MaxDuration, true); //} this.RootNode = new RenderCommandNode(); this.RootTransformation = new Transformation(new DefaultTransformationBindings()); //if (!m_Bones.empty()) // m_Bones.begin()->second.m_Bone->GetTransformationAtTime(0.0f, D3DXMATRIX()); //if (m_BoneController != NULL) //{ // AddToNode(rootNode, m_BoneController); // m_BoneController->PlaySequence(L"all"); //} // Create sub nodes foreach (var geoBufferInfo in result.GeometryBuffers) { var meshInfo = geoBufferInfo.Value; var shader = result.Shaders[meshInfo.MaterialName]; var shaderParameter = result.ShaderParamererSets[meshInfo.MaterialName]; if (shader != null && shaderParameter != null) { var subNode = new RenderCommandNode(); subNode.Children.Add((CommandUser)shader); subNode.Children.Add((CommandUser)this.RootTransformation); subNode.Children.Add((CommandUser)shaderParameter); subNode.Children.Add((CommandUser)meshInfo.GeometryBuffer); this.RootNode.Children.Add(subNode); } } } private void ImportMesh(BinaryReader reader, string objectName, BluImportResult result) { var materialName = reader.ReadNullTerminatedString(); var vertexCount = reader.ReadInt32(); var vertexElementCount = reader.ReadInt32(); var vertexElements = new VertexElement[vertexElementCount]; for (int i = 0; i < vertexElementCount; ++i) { int vertexElementOldId = reader.ReadInt32(); switch (vertexElementOldId) { case 1: vertexElements[i] = new VertexElement(VertexElement.Format.Position); break; case 3: vertexElements[i] = new VertexElement(VertexElement.Format.Normal); break; case 8: vertexElements[i] = new VertexElement(VertexElement.Format.Texture2D); break; case 11: vertexElements[i] = new VertexElement(VertexElement.Format.Tangent); break; case 13: vertexElements[i] = new VertexElement(VertexElement.Format.BlendIndices); break; case 14: vertexElements[i] = new VertexElement(VertexElement.Format.BlendWeight); break; } } var vertexData = reader.ReadBytes(vertexCount * vertexElements.Sum(v => v.Size)); var indexCount = reader.ReadInt32(); var indexRawData = reader.ReadBytes(sizeof(Int32) * indexCount); int[] indexData = new int[indexCount]; for (int i = 0; i < indexCount; ++i) indexData[i] = (int)BitConverter.ToInt32(indexRawData, i * sizeof(uint)); string uniqueName = result.FileName + "." + objectName; var vBuffer = new DataStream(vertexData, true, true); var iBuffer = new DataStream(indexData, true, true); var geoBuffer = new GeometryBuffer( indexCount, iBuffer, vertexCount, vBuffer, vertexElements, false); geoBuffer.IsPickable = true; //geoBuffer.ConvertToAdjacency(); var mesh = new BluImportResult.BluImportedGeometryBuffer(); mesh.GeometryBuffer = geoBuffer; mesh.MaterialName = result.FileName + "." + materialName; result.GeometryBuffers.Add(uniqueName, mesh); } private string GetPath(string orignalPath) { if (string.IsNullOrEmpty(orignalPath)) return orignalPath; return Path.Combine(Path.GetDirectoryName(this.FileName), Path.GetFileName(orignalPath)); } private void ImportMaterial(BinaryReader reader, string objectName, BluImportResult result) { string diffuseTexture = this.GetPath(reader.ReadNullTerminatedString()); string specularTexture = this.GetPath(reader.ReadNullTerminatedString()); string normalTexture = this.GetPath(reader.ReadNullTerminatedString()); string glowTexture = this.GetPath(reader.ReadNullTerminatedString()); string reflectionTexture = this.GetPath(reader.ReadNullTerminatedString()); var ambientColor = new SlimDX.Vector4(); ambientColor.X = reader.ReadSingle() / 255.0f; ambientColor.Y = reader.ReadSingle() / 255.0f; ambientColor.Z = reader.ReadSingle() / 255.0f; ambientColor.W = reader.ReadSingle() / 255.0f; var diffuseColor = new SlimDX.Vector4(); diffuseColor.X = reader.ReadSingle() / 255.0f; diffuseColor.Y = reader.ReadSingle() / 255.0f; diffuseColor.Z = reader.ReadSingle() / 255.0f; diffuseColor.W = reader.ReadSingle() / 255.0f; var specularColor = new SlimDX.Vector4(); specularColor.X = reader.ReadSingle() / 255.0f; specularColor.Y = reader.ReadSingle() / 255.0f; specularColor.Z = reader.ReadSingle() / 255.0f; specularColor.W = reader.ReadSingle() / 255.0f; var emissiveColor = new SlimDX.Vector4(); emissiveColor.X = reader.ReadSingle() / 255.0f; emissiveColor.Y = reader.ReadSingle() / 255.0f; emissiveColor.Z = reader.ReadSingle() / 255.0f; emissiveColor.W = reader.ReadSingle() / 255.0f; var specularlevel = reader.ReadSingle(); var glossiness = reader.ReadSingle(); string uniqueName = result.FileName + "." + objectName; var material = new ShaderParameterSet(); material.SetParameter("AmbientColor", ambientColor, ParameterBindType.BindBySemantic); material.SetParameter("DiffuseColor", diffuseColor, ParameterBindType.BindBySemantic); material.SetParameter("SpecularColor", specularColor * glossiness, ParameterBindType.BindBySemantic); material.SetParameter("EmissiveColor", emissiveColor, ParameterBindType.BindBySemantic); material.SetParameter("Shininess", specularlevel, ParameterBindType.BindBySemantic); var modelShader = new Shader(new ShaderParams() { FileName = "Data/NormalOutput.fx", TechniqueName = "Render" }); result.Shaders.Add(uniqueName, modelShader); if (!string.IsNullOrEmpty(diffuseTexture)) { Texture tex = Engine.FindNamedObject(diffuseTexture) as Texture; if (tex == null) { tex = new Texture(new FileTextureParams() { FileName = diffuseTexture }); tex.WellKnownName = diffuseTexture; } material.SetParameter("Diffuse", tex, ParameterBindType.BindBySemantic); } if (!string.IsNullOrEmpty(specularTexture)) { Texture tex = Engine.FindNamedObject(specularTexture) as Texture; if (tex == null) { tex = new Texture(new FileTextureParams() { FileName = specularTexture }); tex.WellKnownName = specularTexture; } material.SetParameter("Specular", tex, ParameterBindType.BindBySemantic); } if (!string.IsNullOrEmpty(normalTexture)) { Texture tex = Engine.FindNamedObject(normalTexture) as Texture; if (tex == null) { tex = new Texture(new FileTextureParams() { FileName = normalTexture }); tex.WellKnownName = normalTexture; } material.SetParameter("Normal", tex, ParameterBindType.BindBySemantic); } if (!string.IsNullOrEmpty(glowTexture)) { Texture tex = Engine.FindNamedObject(glowTexture) as Texture; if (tex == null) { tex = new Texture(new FileTextureParams() { FileName = glowTexture }); tex.WellKnownName = glowTexture; } material.SetParameter("Glow", tex, ParameterBindType.BindBySemantic); } if (!string.IsNullOrEmpty(reflectionTexture)) { Texture tex = Engine.FindNamedObject(reflectionTexture) as Texture; if (tex == null) { tex = new Texture(new FileTextureParams() { FileName = reflectionTexture }); tex.WellKnownName = reflectionTexture; } material.SetParameter("Reflection", tex, ParameterBindType.BindBySemantic); } result.ShaderParamererSets.Add(uniqueName, material); } private void ImportBone(BinaryReader reader, string objectName, BluImportResult result) { throw new NotImplementedException(); } private void ImportAnimation(BinaryReader reader, string objectName, BluImportResult result) { throw new NotImplementedException(); } private ICreationParams creationParams; public override ICreationParams CreationParams { get { return creationParams; } } private ObservableCollection children; [ReadOnly] public override ObservableCollection Children { get { if (children == null) { children = new ObservableCollection(); children.Add(RootNode); } return children; } } }; }