/* * Copyright (c) 2006-2014, openmetaverse.org * All rights reserved. * * - Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * - Neither the name of the openmetaverse.org nor the names * of its contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ using System; using System.Collections.Generic; using OpenMetaverse.Rendering; using OpenMetaverse.StructuredData; namespace OpenMetaverse.ImportExport { public class ModelMaterial { public string ID; public Color4 DiffuseColor = Color4.White; public string Texture; public byte[] TextureData; } public class ModelFace { public List Vertices = new List(); public List Indices = new List(); public string MaterialID = string.Empty; public ModelMaterial Material = new ModelMaterial(); Dictionary LookUp = new Dictionary(); public void AddVertex(Vertex v) { int index; if (LookUp.ContainsKey(v)) { index = LookUp[v]; } else { index = Vertices.Count; Vertices.Add(v); LookUp[v] = index; } Indices.Add((uint)index); } } public class ModelPrim { public List Positions; public Vector3 BoundMin = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue); public Vector3 BoundMax = new Vector3(float.MinValue, float.MinValue, float.MinValue); public Vector3 Position; public Vector3 Scale; public Quaternion Rotation = Quaternion.Identity; public List Faces = new List(); public string ID; public byte[] Asset; public void CreateAsset(UUID creator) { OSDMap header = new OSDMap(); header["version"] = 1; header["creator"] = creator; header["date"] = DateTime.Now; OSDArray faces = new OSDArray(); foreach (var face in Faces) { OSDMap faceMap = new OSDMap(); // Find UV min/max Vector2 uvMin = new Vector2(float.MaxValue, float.MaxValue); Vector2 uvMax = new Vector2(float.MinValue, float.MinValue); foreach (var v in face.Vertices) { if (v.TexCoord.X < uvMin.X) uvMin.X = v.TexCoord.X; if (v.TexCoord.Y < uvMin.Y) uvMin.Y = v.TexCoord.Y; if (v.TexCoord.X > uvMax.X) uvMax.X = v.TexCoord.X; if (v.TexCoord.Y > uvMax.Y) uvMax.Y = v.TexCoord.Y; } OSDMap uvDomain = new OSDMap(); uvDomain["Min"] = uvMin; uvDomain["Max"] = uvMax; faceMap["TexCoord0Domain"] = uvDomain; OSDMap positionDomain = new OSDMap(); positionDomain["Min"] = new Vector3(-0.5f, -0.5f, -0.5f); positionDomain["Max"] = new Vector3(0.5f, 0.5f, 0.5f); faceMap["PositionDomain"] = positionDomain; List posBytes = new List(face.Vertices.Count * sizeof(UInt16) * 3); List norBytes = new List(face.Vertices.Count * sizeof(UInt16) * 3); List uvBytes = new List(face.Vertices.Count * sizeof(UInt16) * 2); foreach (var v in face.Vertices) { posBytes.AddRange(Utils.UInt16ToBytes(Utils.FloatToUInt16(v.Position.X, -0.5f, 0.5f))); posBytes.AddRange(Utils.UInt16ToBytes(Utils.FloatToUInt16(v.Position.Y, -0.5f, 0.5f))); posBytes.AddRange(Utils.UInt16ToBytes(Utils.FloatToUInt16(v.Position.Z, -0.5f, 0.5f))); norBytes.AddRange(Utils.UInt16ToBytes(Utils.FloatToUInt16(v.Normal.X, -1f, 1f))); norBytes.AddRange(Utils.UInt16ToBytes(Utils.FloatToUInt16(v.Normal.Y, -1f, 1f))); norBytes.AddRange(Utils.UInt16ToBytes(Utils.FloatToUInt16(v.Normal.Z, -1f, 1f))); uvBytes.AddRange(Utils.UInt16ToBytes(Utils.FloatToUInt16(v.TexCoord.X, uvMin.X, uvMax.X))); uvBytes.AddRange(Utils.UInt16ToBytes(Utils.FloatToUInt16(v.TexCoord.Y, uvMin.Y, uvMax.Y))); } faceMap["Position"] = posBytes.ToArray(); faceMap["Normal"] = norBytes.ToArray(); faceMap["TexCoord0"] = uvBytes.ToArray(); List indexBytes = new List(face.Indices.Count * sizeof(UInt16)); foreach (var t in face.Indices) { indexBytes.AddRange(Utils.UInt16ToBytes((ushort)t)); } faceMap["TriangleList"] = indexBytes.ToArray(); faces.Add(faceMap); } byte[] physicStubBytes = Helpers.ZCompressOSD(PhysicsStub()); byte[] meshBytes = Helpers.ZCompressOSD(faces); int n = 0; OSDMap lodParms = new OSDMap(); lodParms["offset"] = n; lodParms["size"] = meshBytes.Length; header["high_lod"] = lodParms; n += meshBytes.Length; lodParms = new OSDMap(); lodParms["offset"] = n; lodParms["size"] = physicStubBytes.Length; header["physics_convex"] = lodParms; n += physicStubBytes.Length; byte[] headerBytes = OSDParser.SerializeLLSDBinary(header, false); n += headerBytes.Length; Asset = new byte[n]; int offset = 0; Buffer.BlockCopy(headerBytes, 0, Asset, offset, headerBytes.Length); offset += headerBytes.Length; Buffer.BlockCopy(meshBytes, 0, Asset, offset, meshBytes.Length); offset += meshBytes.Length; Buffer.BlockCopy(physicStubBytes, 0, Asset, offset, physicStubBytes.Length); offset += physicStubBytes.Length; } public static OSD PhysicsStub() { OSDMap ret = new OSDMap(); ret["Max"] = new Vector3(0.5f, 0.5f, 0.5f); ret["Min"] = new Vector3(-0.5f, -0.5f, -0.5f); ret["BoundingVerts"] = new byte[] { 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 255, 255, 255, 127, 0, 0, 255, 255, 255, 127, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 127, 255, 255, 255, 255, 255, 255, 0, 0, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 0, 0, 255, 255 }; return ret; } } }