374 lines
16 KiB
C#
374 lines
16 KiB
C#
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<string, BluImportedGeometryBuffer> GeometryBuffers = new Dictionary<string, BluImportedGeometryBuffer>();
|
|
public Dictionary<string, IShaderParameterSet> ShaderParamererSets = new Dictionary<string, IShaderParameterSet>();
|
|
public Dictionary<string, IShader> Shaders = new Dictionary<string, IShader>();
|
|
//Dictionary<string, BluImportedBone> Bones;
|
|
//Dictionary<string, ITransformationAnimation> 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<string8, BluImportedBone>::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<string8, BluImportedBone>::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<string8, ITransformationAnimation*>::iterator lk_AnimIter = lr_Result.m_Animations.begin();
|
|
//for (; lk_AnimIter != lr_Result.m_Animations.end(); ++lk_AnimIter)
|
|
//{
|
|
// std::map<string8, BluImportedBone>::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<IResource> children;
|
|
[ReadOnly]
|
|
public override ObservableCollection<IResource> Children
|
|
{
|
|
get
|
|
{
|
|
if (children == null)
|
|
{
|
|
children = new ObservableCollection<IResource>();
|
|
children.Add(RootNode);
|
|
}
|
|
return children;
|
|
}
|
|
}
|
|
};
|
|
}
|