RAD-912: Added mesh decoding to rendering

git-svn-id: http://libopenmetaverse.googlecode.com/svn/libopenmetaverse/trunk@3546 52acb1d6-8a22-11de-b505-999d5b087335
This commit is contained in:
Latif Khalifa
2011-06-10 09:57:12 +00:00
parent 0837897926
commit 73c2a836c3
2 changed files with 184 additions and 2 deletions

View File

@@ -63,8 +63,8 @@ namespace OpenMetaverse.Assets
public override void Encode() { }
/// <summary>
/// Decodes mesh asset
/// </summary>
/// Decodes mesh asset. See <see cref="OpenMetaverse.Rendering.FacetedMesh.TryDecodeFromAsset"/>
/// to furter decode it for rendering</summary>
/// <returns>true</returns>
public override bool Decode()
{

View File

@@ -29,6 +29,8 @@ using System.IO;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.InteropServices;
using OpenMetaverse.Assets;
using OpenMetaverse.StructuredData;
// The common elements shared between rendering plugins are defined here
@@ -198,9 +200,189 @@ namespace OpenMetaverse.Rendering
}
}
/// <summary>
/// Contains all mesh faces that belong to a prim
/// </summary>
public class FacetedMesh : Mesh
{
/// <summary>List of primitive faces</summary>
public List<Face> Faces;
/// <summary>
/// Decodes mesh asset into FacetedMesh
/// </summary>
/// <param name="prim">Mesh primitive</param>
/// <param name="meshAsset">Asset retrieved from the asset server</param>
/// <param name="LOD">Level of detail</param>
/// <param name="mesh">Resulting decoded FacetedMesh</param>
/// <returns>True if mesh asset decoding was successful</returns>
public static bool TryDecodeFromAsset(Primitive prim, AssetMesh meshAsset, DetailLevel LOD, out FacetedMesh mesh)
{
mesh = null;
try
{
if (!meshAsset.Decode())
{
return false;
}
OSDMap MeshData = meshAsset.MeshData;
mesh = new FacetedMesh();
mesh.Faces = new List<Face>();
mesh.Prim = prim;
mesh.Profile.Faces = new List<ProfileFace>();
mesh.Profile.Positions = new List<Vector3>();
mesh.Path.Points = new List<PathPoint>();
OSD facesOSD = null;
switch (LOD)
{
default:
case DetailLevel.Highest:
facesOSD = MeshData["high_lod"];
break;
case DetailLevel.High:
facesOSD = MeshData["medium_lod"];
break;
case DetailLevel.Medium:
facesOSD = MeshData["low_lod"];
break;
case DetailLevel.Low:
facesOSD = MeshData["lowest_lod"];
break;
}
if (facesOSD == null || !(facesOSD is OSDArray))
{
return false;
}
OSDArray decodedMeshOsdArray = (OSDArray)facesOSD;
for (int faceNr = 0; faceNr < decodedMeshOsdArray.Count; faceNr++)
{
OSD subMeshOsd = decodedMeshOsdArray[faceNr];
// Decode each individual face
if (subMeshOsd is OSDMap)
{
Face oface = new Face();
oface.ID = faceNr;
oface.Vertices = new List<Vertex>();
oface.Indices = new List<ushort>();
oface.TextureFace = prim.Textures.GetFace((uint)faceNr);
OSDMap subMeshMap = (OSDMap)subMeshOsd;
Vector3 posMax;
Vector3 posMin;
// If PositionDomain is not specified, the default is from -0.5 to 0.5
if (subMeshMap.ContainsKey("PositionDomain"))
{
posMax = ((OSDMap)subMeshMap["PositionDomain"])["Max"];
posMin = ((OSDMap)subMeshMap["PositionDomain"])["Min"];
}
else
{
posMax = new Vector3(0.5f, 0.5f, 0.5f);
posMin = new Vector3(-0.5f, -0.5f, -0.5f);
}
// Vertex positions
byte[] posBytes = subMeshMap["Position"];
// Normals
byte[] norBytes = null;
if (subMeshMap.ContainsKey("Normal"))
{
norBytes = subMeshMap["Normal"];
}
// UV texture map
Vector2 texPosMax = Vector2.Zero;
Vector2 texPosMin = Vector2.Zero;
byte[] texBytes = null;
if (subMeshMap.ContainsKey("TexCoord0"))
{
texBytes = subMeshMap["TexCoord0"];
texPosMax = ((OSDMap)subMeshMap["TexCoord0Domain"])["Max"];
texPosMin = ((OSDMap)subMeshMap["TexCoord0Domain"])["Min"];
}
// Extract the vertex position data
// If present normals and texture coordinates too
for (int i = 0; i < posBytes.Length; i += 6)
{
ushort uX = Utils.BytesToUInt16(posBytes, i);
ushort uY = Utils.BytesToUInt16(posBytes, i + 2);
ushort uZ = Utils.BytesToUInt16(posBytes, i + 4);
Vertex vx = new Vertex();
vx.Position = new Vector3(
Utils.UInt16ToFloat(uX, posMin.X, posMax.X),
Utils.UInt16ToFloat(uY, posMin.Y, posMax.Y),
Utils.UInt16ToFloat(uZ, posMin.Z, posMax.Z));
if (norBytes != null && norBytes.Length >= i + 4)
{
ushort nX = Utils.BytesToUInt16(norBytes, i);
ushort nY = Utils.BytesToUInt16(norBytes, i + 2);
ushort nZ = Utils.BytesToUInt16(norBytes, i + 4);
vx.Normal = new Vector3(
Utils.UInt16ToFloat(nX, posMin.X, posMax.X),
Utils.UInt16ToFloat(nY, posMin.Y, posMax.Y),
Utils.UInt16ToFloat(nZ, posMin.Z, posMax.Z));
}
var vertexIndexOffset = oface.Vertices.Count * 4;
if (texBytes != null && texBytes.Length >= vertexIndexOffset + 4)
{
ushort tX = Utils.BytesToUInt16(texBytes, vertexIndexOffset);
ushort tY = Utils.BytesToUInt16(texBytes, vertexIndexOffset + 2);
vx.TexCoord = new Vector2(
Utils.UInt16ToFloat(tX, texPosMin.X, texPosMax.X),
Utils.UInt16ToFloat(tY, texPosMin.Y, texPosMax.Y));
}
oface.Vertices.Add(vx);
}
byte[] triangleBytes = subMeshMap["TriangleList"];
for (int i = 0; i < triangleBytes.Length; i += 6)
{
ushort v1 = (ushort)(Utils.BytesToUInt16(triangleBytes, i));
oface.Indices.Add(v1);
ushort v2 = (ushort)(Utils.BytesToUInt16(triangleBytes, i + 2));
oface.Indices.Add(v2);
ushort v3 = (ushort)(Utils.BytesToUInt16(triangleBytes, i + 4));
oface.Indices.Add(v3);
}
mesh.Faces.Add(oface);
}
}
}
catch (Exception ex)
{
Logger.Log("Failed to decode mesh asset: " + ex.Message, Helpers.LogLevel.Warning);
return false;
}
return true;
}
}
public class SimpleMesh : Mesh