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(); }; public string FileName { get; protected set; } public RenderCommandNode RootNode { get; protected set; } public Transformation RootTransformation { get; protected set; } public BluModel(BluModelParams parameters) { this.FileName = parameters.FileName; creationParams = parameters; this.RootNode = new RenderCommandNode(); this.RootTransformation = new Transformation(new DefaultTransformationBindings()); Engine.FileSystem.Attach(parameters.FileName, OnFileChanged); } private void OnFileChanged(Stream stream) { var result = new BluImportResult(); result.FileName = this.FileName; using (stream) 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; } } } this.RootNode.Children.Clear(); // 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; } } }; }