Files
2026-04-18 22:31:51 +02:00

324 lines
13 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>();
};
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<IResource> children;
[ReadOnly]
public override ObservableCollection<IResource> Children
{
get
{
if (children == null)
{
children = new ObservableCollection<IResource>();
children.Add(RootNode);
}
return children;
}
}
};
}