aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Physics/Meshing/Meshmerizer.cs')
-rw-r--r--OpenSim/Region/Physics/Meshing/Meshmerizer.cs761
1 files changed, 0 insertions, 761 deletions
diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
deleted file mode 100644
index 8145d61..0000000
--- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
+++ /dev/null
@@ -1,761 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27//#define SPAM
28
29using System;
30using System.Collections.Generic;
31using OpenSim.Framework;
32using OpenSim.Region.Physics.Manager;
33using OpenMetaverse;
34using OpenMetaverse.StructuredData;
35using System.Drawing;
36using System.Drawing.Imaging;
37using System.IO.Compression;
38using PrimMesher;
39using log4net;
40using Nini.Config;
41using System.Reflection;
42using System.IO;
43using ComponentAce.Compression.Libs.zlib;
44
45namespace OpenSim.Region.Physics.Meshing
46{
47 public class MeshmerizerPlugin : IMeshingPlugin
48 {
49 public MeshmerizerPlugin()
50 {
51 }
52
53 public string GetName()
54 {
55 return "Meshmerizer";
56 }
57
58 public IMesher GetMesher(IConfigSource config)
59 {
60 return new Meshmerizer(config);
61 }
62 }
63
64 public class Meshmerizer : IMesher
65 {
66 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
67
68 // Setting baseDir to a path will enable the dumping of raw files
69 // raw files can be imported by blender so a visual inspection of the results can be done
70#if SPAM
71 const string baseDir = "rawFiles";
72#else
73 private const string baseDir = null; //"rawFiles";
74#endif
75
76 private bool cacheSculptMaps = true;
77 private string decodedSculptMapPath = null;
78 private bool useMeshiesPhysicsMesh = false;
79
80 private float minSizeForComplexMesh = 0.2f; // prims with all dimensions smaller than this will have a bounding box mesh
81
82 private Dictionary<ulong, Mesh> m_uniqueMeshes = new Dictionary<ulong, Mesh>();
83
84 public Meshmerizer(IConfigSource config)
85 {
86 IConfig start_config = config.Configs["Startup"];
87 IConfig mesh_config = config.Configs["Mesh"];
88
89 decodedSculptMapPath = start_config.GetString("DecodedSculptMapPath","j2kDecodeCache");
90 cacheSculptMaps = start_config.GetBoolean("CacheSculptMaps", cacheSculptMaps);
91 if(mesh_config != null)
92 useMeshiesPhysicsMesh = mesh_config.GetBoolean("UseMeshiesPhysicsMesh", useMeshiesPhysicsMesh);
93
94 try
95 {
96 if (!Directory.Exists(decodedSculptMapPath))
97 Directory.CreateDirectory(decodedSculptMapPath);
98 }
99 catch (Exception e)
100 {
101 m_log.WarnFormat("[SCULPT]: Unable to create {0} directory: ", decodedSculptMapPath, e.Message);
102 }
103 }
104
105 /// <summary>
106 /// creates a simple box mesh of the specified size. This mesh is of very low vertex count and may
107 /// be useful as a backup proxy when level of detail is not needed or when more complex meshes fail
108 /// for some reason
109 /// </summary>
110 /// <param name="minX"></param>
111 /// <param name="maxX"></param>
112 /// <param name="minY"></param>
113 /// <param name="maxY"></param>
114 /// <param name="minZ"></param>
115 /// <param name="maxZ"></param>
116 /// <returns></returns>
117 private static Mesh CreateSimpleBoxMesh(float minX, float maxX, float minY, float maxY, float minZ, float maxZ)
118 {
119 Mesh box = new Mesh();
120 List<Vertex> vertices = new List<Vertex>();
121 // bottom
122
123 vertices.Add(new Vertex(minX, maxY, minZ));
124 vertices.Add(new Vertex(maxX, maxY, minZ));
125 vertices.Add(new Vertex(maxX, minY, minZ));
126 vertices.Add(new Vertex(minX, minY, minZ));
127
128 box.Add(new Triangle(vertices[0], vertices[1], vertices[2]));
129 box.Add(new Triangle(vertices[0], vertices[2], vertices[3]));
130
131 // top
132
133 vertices.Add(new Vertex(maxX, maxY, maxZ));
134 vertices.Add(new Vertex(minX, maxY, maxZ));
135 vertices.Add(new Vertex(minX, minY, maxZ));
136 vertices.Add(new Vertex(maxX, minY, maxZ));
137
138 box.Add(new Triangle(vertices[4], vertices[5], vertices[6]));
139 box.Add(new Triangle(vertices[4], vertices[6], vertices[7]));
140
141 // sides
142
143 box.Add(new Triangle(vertices[5], vertices[0], vertices[3]));
144 box.Add(new Triangle(vertices[5], vertices[3], vertices[6]));
145
146 box.Add(new Triangle(vertices[1], vertices[0], vertices[5]));
147 box.Add(new Triangle(vertices[1], vertices[5], vertices[4]));
148
149 box.Add(new Triangle(vertices[7], vertices[1], vertices[4]));
150 box.Add(new Triangle(vertices[7], vertices[2], vertices[1]));
151
152 box.Add(new Triangle(vertices[3], vertices[2], vertices[7]));
153 box.Add(new Triangle(vertices[3], vertices[7], vertices[6]));
154
155 return box;
156 }
157
158 /// <summary>
159 /// Creates a simple bounding box mesh for a complex input mesh
160 /// </summary>
161 /// <param name="meshIn"></param>
162 /// <returns></returns>
163 private static Mesh CreateBoundingBoxMesh(Mesh meshIn)
164 {
165 float minX = float.MaxValue;
166 float maxX = float.MinValue;
167 float minY = float.MaxValue;
168 float maxY = float.MinValue;
169 float minZ = float.MaxValue;
170 float maxZ = float.MinValue;
171
172 foreach (Vector3 v in meshIn.getVertexList())
173 {
174 if (v.X < minX) minX = v.X;
175 if (v.Y < minY) minY = v.Y;
176 if (v.Z < minZ) minZ = v.Z;
177
178 if (v.X > maxX) maxX = v.X;
179 if (v.Y > maxY) maxY = v.Y;
180 if (v.Z > maxZ) maxZ = v.Z;
181 }
182
183 return CreateSimpleBoxMesh(minX, maxX, minY, maxY, minZ, maxZ);
184 }
185
186 private void ReportPrimError(string message, string primName, PrimMesh primMesh)
187 {
188 m_log.Error(message);
189 m_log.Error("\nPrim Name: " + primName);
190 m_log.Error("****** PrimMesh Parameters ******\n" + primMesh.ParamsToDisplayString());
191 }
192
193 /// <summary>
194 /// Add a submesh to an existing list of coords and faces.
195 /// </summary>
196 /// <param name="subMeshData"></param>
197 /// <param name="size">Size of entire object</param>
198 /// <param name="coords"></param>
199 /// <param name="faces"></param>
200 private void AddSubMesh(OSDMap subMeshData, Vector3 size, List<Coord> coords, List<Face> faces)
201 {
202 // Console.WriteLine("subMeshMap for {0} - {1}", primName, Util.GetFormattedXml((OSD)subMeshMap));
203
204 // As per http://wiki.secondlife.com/wiki/Mesh/Mesh_Asset_Format, some Mesh Level
205 // of Detail Blocks (maps) contain just a NoGeometry key to signal there is no
206 // geometry for this submesh.
207 if (subMeshData.ContainsKey("NoGeometry") && ((OSDBoolean)subMeshData["NoGeometry"]))
208 return;
209
210 OpenMetaverse.Vector3 posMax = ((OSDMap)subMeshData["PositionDomain"])["Max"].AsVector3();
211 OpenMetaverse.Vector3 posMin = ((OSDMap)subMeshData["PositionDomain"])["Min"].AsVector3();
212 ushort faceIndexOffset = (ushort)coords.Count;
213
214 byte[] posBytes = subMeshData["Position"].AsBinary();
215 for (int i = 0; i < posBytes.Length; i += 6)
216 {
217 ushort uX = Utils.BytesToUInt16(posBytes, i);
218 ushort uY = Utils.BytesToUInt16(posBytes, i + 2);
219 ushort uZ = Utils.BytesToUInt16(posBytes, i + 4);
220
221 Coord c = new Coord(
222 Utils.UInt16ToFloat(uX, posMin.X, posMax.X) * size.X,
223 Utils.UInt16ToFloat(uY, posMin.Y, posMax.Y) * size.Y,
224 Utils.UInt16ToFloat(uZ, posMin.Z, posMax.Z) * size.Z);
225
226 coords.Add(c);
227 }
228
229 byte[] triangleBytes = subMeshData["TriangleList"].AsBinary();
230 for (int i = 0; i < triangleBytes.Length; i += 6)
231 {
232 ushort v1 = (ushort)(Utils.BytesToUInt16(triangleBytes, i) + faceIndexOffset);
233 ushort v2 = (ushort)(Utils.BytesToUInt16(triangleBytes, i + 2) + faceIndexOffset);
234 ushort v3 = (ushort)(Utils.BytesToUInt16(triangleBytes, i + 4) + faceIndexOffset);
235 Face f = new Face(v1, v2, v3);
236 faces.Add(f);
237 }
238 }
239
240 /// <summary>
241 /// Create a physics mesh from data that comes with the prim. The actual data used depends on the prim type.
242 /// </summary>
243 /// <param name="primName"></param>
244 /// <param name="primShape"></param>
245 /// <param name="size"></param>
246 /// <param name="lod"></param>
247 /// <returns></returns>
248 private Mesh CreateMeshFromPrimMesher(string primName, PrimitiveBaseShape primShape, Vector3 size, float lod)
249 {
250// m_log.DebugFormat(
251// "[MESH]: Creating physics proxy for {0}, shape {1}",
252// primName, (OpenMetaverse.SculptType)primShape.SculptType);
253
254 List<Coord> coords;
255 List<Face> faces;
256
257 if (primShape.SculptEntry)
258 {
259 if (((OpenMetaverse.SculptType)primShape.SculptType) == SculptType.Mesh)
260 {
261 if (!useMeshiesPhysicsMesh)
262 return null;
263
264 if (!GenerateCoordsAndFacesFromPrimMeshData(primName, primShape, size, out coords, out faces))
265 return null;
266 }
267 else
268 {
269 if (!GenerateCoordsAndFacesFromPrimSculptData(primName, primShape, size, lod, out coords, out faces))
270 return null;
271 }
272 }
273 else
274 {
275 if (!GenerateCoordsAndFacesFromPrimShapeData(primName, primShape, size, lod, out coords, out faces))
276 return null;
277 }
278
279 // Remove the reference to any JPEG2000 sculpt data so it can be GCed
280 primShape.SculptData = Utils.EmptyBytes;
281
282 int numCoords = coords.Count;
283 int numFaces = faces.Count;
284
285 // Create the list of vertices
286 List<Vertex> vertices = new List<Vertex>();
287 for (int i = 0; i < numCoords; i++)
288 {
289 Coord c = coords[i];
290 vertices.Add(new Vertex(c.X, c.Y, c.Z));
291 }
292
293 Mesh mesh = new Mesh();
294 // Add the corresponding triangles to the mesh
295 for (int i = 0; i < numFaces; i++)
296 {
297 Face f = faces[i];
298 mesh.Add(new Triangle(vertices[f.v1], vertices[f.v2], vertices[f.v3]));
299 }
300
301 return mesh;
302 }
303
304 /// <summary>
305 /// Generate the co-ords and faces necessary to construct a mesh from the mesh data the accompanies a prim.
306 /// </summary>
307 /// <param name="primName"></param>
308 /// <param name="primShape"></param>
309 /// <param name="size"></param>
310 /// <param name="coords">Coords are added to this list by the method.</param>
311 /// <param name="faces">Faces are added to this list by the method.</param>
312 /// <returns>true if coords and faces were successfully generated, false if not</returns>
313 private bool GenerateCoordsAndFacesFromPrimMeshData(
314 string primName, PrimitiveBaseShape primShape, Vector3 size, out List<Coord> coords, out List<Face> faces)
315 {
316// m_log.DebugFormat("[MESH]: experimental mesh proxy generation for {0}", primName);
317
318 coords = new List<Coord>();
319 faces = new List<Face>();
320 OSD meshOsd = null;
321
322 if (primShape.SculptData.Length <= 0)
323 {
324 // XXX: At the moment we can not log here since ODEPrim, for instance, ends up triggering this
325 // method twice - once before it has loaded sculpt data from the asset service and once afterwards.
326 // The first time will always call with unloaded SculptData if this needs to be uploaded.
327// m_log.ErrorFormat("[MESH]: asset data for {0} is zero length", primName);
328 return false;
329 }
330
331 long start = 0;
332 using (MemoryStream data = new MemoryStream(primShape.SculptData))
333 {
334 try
335 {
336 OSD osd = OSDParser.DeserializeLLSDBinary(data);
337 if (osd is OSDMap)
338 meshOsd = (OSDMap)osd;
339 else
340 {
341 m_log.Warn("[Mesh}: unable to cast mesh asset to OSDMap");
342 return false;
343 }
344 }
345 catch (Exception e)
346 {
347 m_log.Error("[MESH]: Exception deserializing mesh asset header:" + e.ToString());
348 }
349
350 start = data.Position;
351 }
352
353 if (meshOsd is OSDMap)
354 {
355 OSDMap physicsParms = null;
356 OSDMap map = (OSDMap)meshOsd;
357 if (map.ContainsKey("physics_shape"))
358 physicsParms = (OSDMap)map["physics_shape"]; // old asset format
359 else if (map.ContainsKey("physics_mesh"))
360 physicsParms = (OSDMap)map["physics_mesh"]; // new asset format
361
362 if (physicsParms == null)
363 {
364 m_log.WarnFormat("[MESH]: No recognized physics mesh found in mesh asset for {0}", primName);
365 return false;
366 }
367
368 int physOffset = physicsParms["offset"].AsInteger() + (int)start;
369 int physSize = physicsParms["size"].AsInteger();
370
371 if (physOffset < 0 || physSize == 0)
372 return false; // no mesh data in asset
373
374 OSD decodedMeshOsd = new OSD();
375 byte[] meshBytes = new byte[physSize];
376 System.Buffer.BlockCopy(primShape.SculptData, physOffset, meshBytes, 0, physSize);
377// byte[] decompressed = new byte[physSize * 5];
378 try
379 {
380 using (MemoryStream inMs = new MemoryStream(meshBytes))
381 {
382 using (MemoryStream outMs = new MemoryStream())
383 {
384 using (ZOutputStream zOut = new ZOutputStream(outMs))
385 {
386 byte[] readBuffer = new byte[2048];
387 int readLen = 0;
388 while ((readLen = inMs.Read(readBuffer, 0, readBuffer.Length)) > 0)
389 {
390 zOut.Write(readBuffer, 0, readLen);
391 }
392 zOut.Flush();
393 outMs.Seek(0, SeekOrigin.Begin);
394
395 byte[] decompressedBuf = outMs.GetBuffer();
396
397 decodedMeshOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf);
398 }
399 }
400 }
401 }
402 catch (Exception e)
403 {
404 m_log.Error("[MESH]: exception decoding physical mesh: " + e.ToString());
405 return false;
406 }
407
408 OSDArray decodedMeshOsdArray = null;
409
410 // physics_shape is an array of OSDMaps, one for each submesh
411 if (decodedMeshOsd is OSDArray)
412 {
413// Console.WriteLine("decodedMeshOsd for {0} - {1}", primName, Util.GetFormattedXml(decodedMeshOsd));
414
415 decodedMeshOsdArray = (OSDArray)decodedMeshOsd;
416 foreach (OSD subMeshOsd in decodedMeshOsdArray)
417 {
418 if (subMeshOsd is OSDMap)
419 AddSubMesh(subMeshOsd as OSDMap, size, coords, faces);
420 }
421 }
422 }
423
424 return true;
425 }
426
427 /// <summary>
428 /// Generate the co-ords and faces necessary to construct a mesh from the sculpt data the accompanies a prim.
429 /// </summary>
430 /// <param name="primName"></param>
431 /// <param name="primShape"></param>
432 /// <param name="size"></param>
433 /// <param name="lod"></param>
434 /// <param name="coords">Coords are added to this list by the method.</param>
435 /// <param name="faces">Faces are added to this list by the method.</param>
436 /// <returns>true if coords and faces were successfully generated, false if not</returns>
437 private bool GenerateCoordsAndFacesFromPrimSculptData(
438 string primName, PrimitiveBaseShape primShape, Vector3 size, float lod, out List<Coord> coords, out List<Face> faces)
439 {
440 coords = new List<Coord>();
441 faces = new List<Face>();
442 PrimMesher.SculptMesh sculptMesh;
443 Image idata = null;
444 string decodedSculptFileName = "";
445
446 if (cacheSculptMaps && primShape.SculptTexture != UUID.Zero)
447 {
448 decodedSculptFileName = System.IO.Path.Combine(decodedSculptMapPath, "smap_" + primShape.SculptTexture.ToString());
449 try
450 {
451 if (File.Exists(decodedSculptFileName))
452 {
453 idata = Image.FromFile(decodedSculptFileName);
454 }
455 }
456 catch (Exception e)
457 {
458 m_log.Error("[SCULPT]: unable to load cached sculpt map " + decodedSculptFileName + " " + e.Message);
459
460 }
461 //if (idata != null)
462 // m_log.Debug("[SCULPT]: loaded cached map asset for map ID: " + primShape.SculptTexture.ToString());
463 }
464
465 if (idata == null)
466 {
467 if (primShape.SculptData == null || primShape.SculptData.Length == 0)
468 return false;
469
470 try
471 {
472 OpenMetaverse.Imaging.ManagedImage unusedData;
473 OpenMetaverse.Imaging.OpenJPEG.DecodeToImage(primShape.SculptData, out unusedData, out idata);
474
475 if (idata == null)
476 {
477 // In some cases it seems that the decode can return a null bitmap without throwing
478 // an exception
479 m_log.WarnFormat("[PHYSICS]: OpenJPEG decoded sculpt data for {0} to a null bitmap. Ignoring.", primName);
480
481 return false;
482 }
483
484 unusedData = null;
485
486 //idata = CSJ2K.J2kImage.FromBytes(primShape.SculptData);
487
488 if (cacheSculptMaps)
489 {
490 try { idata.Save(decodedSculptFileName, ImageFormat.MemoryBmp); }
491 catch (Exception e) { m_log.Error("[SCULPT]: unable to cache sculpt map " + decodedSculptFileName + " " + e.Message); }
492 }
493 }
494 catch (DllNotFoundException)
495 {
496 m_log.Error("[PHYSICS]: OpenJpeg is not installed correctly on this system. Physics Proxy generation failed. Often times this is because of an old version of GLIBC. You must have version 2.4 or above!");
497 return false;
498 }
499 catch (IndexOutOfRangeException)
500 {
501 m_log.Error("[PHYSICS]: OpenJpeg was unable to decode this. Physics Proxy generation failed");
502 return false;
503 }
504 catch (Exception ex)
505 {
506 m_log.Error("[PHYSICS]: Unable to generate a Sculpty physics proxy. Sculpty texture decode failed: " + ex.Message);
507 return false;
508 }
509 }
510
511 PrimMesher.SculptMesh.SculptType sculptType;
512 switch ((OpenMetaverse.SculptType)primShape.SculptType)
513 {
514 case OpenMetaverse.SculptType.Cylinder:
515 sculptType = PrimMesher.SculptMesh.SculptType.cylinder;
516 break;
517 case OpenMetaverse.SculptType.Plane:
518 sculptType = PrimMesher.SculptMesh.SculptType.plane;
519 break;
520 case OpenMetaverse.SculptType.Torus:
521 sculptType = PrimMesher.SculptMesh.SculptType.torus;
522 break;
523 case OpenMetaverse.SculptType.Sphere:
524 sculptType = PrimMesher.SculptMesh.SculptType.sphere;
525 break;
526 default:
527 sculptType = PrimMesher.SculptMesh.SculptType.plane;
528 break;
529 }
530
531 bool mirror = ((primShape.SculptType & 128) != 0);
532 bool invert = ((primShape.SculptType & 64) != 0);
533
534 sculptMesh = new PrimMesher.SculptMesh((Bitmap)idata, sculptType, (int)lod, false, mirror, invert);
535
536 idata.Dispose();
537
538 sculptMesh.DumpRaw(baseDir, primName, "primMesh");
539
540 sculptMesh.Scale(size.X, size.Y, size.Z);
541
542 coords = sculptMesh.coords;
543 faces = sculptMesh.faces;
544
545 return true;
546 }
547
548 /// <summary>
549 /// Generate the co-ords and faces necessary to construct a mesh from the shape data the accompanies a prim.
550 /// </summary>
551 /// <param name="primName"></param>
552 /// <param name="primShape"></param>
553 /// <param name="size"></param>
554 /// <param name="coords">Coords are added to this list by the method.</param>
555 /// <param name="faces">Faces are added to this list by the method.</param>
556 /// <returns>true if coords and faces were successfully generated, false if not</returns>
557 private bool GenerateCoordsAndFacesFromPrimShapeData(
558 string primName, PrimitiveBaseShape primShape, Vector3 size, float lod, out List<Coord> coords, out List<Face> faces)
559 {
560 PrimMesh primMesh;
561 coords = new List<Coord>();
562 faces = new List<Face>();
563
564 float pathShearX = primShape.PathShearX < 128 ? (float)primShape.PathShearX * 0.01f : (float)(primShape.PathShearX - 256) * 0.01f;
565 float pathShearY = primShape.PathShearY < 128 ? (float)primShape.PathShearY * 0.01f : (float)(primShape.PathShearY - 256) * 0.01f;
566 float pathBegin = (float)primShape.PathBegin * 2.0e-5f;
567 float pathEnd = 1.0f - (float)primShape.PathEnd * 2.0e-5f;
568 float pathScaleX = (float)(primShape.PathScaleX - 100) * 0.01f;
569 float pathScaleY = (float)(primShape.PathScaleY - 100) * 0.01f;
570
571 float profileBegin = (float)primShape.ProfileBegin * 2.0e-5f;
572 float profileEnd = 1.0f - (float)primShape.ProfileEnd * 2.0e-5f;
573 float profileHollow = (float)primShape.ProfileHollow * 2.0e-5f;
574 if (profileHollow > 0.95f)
575 profileHollow = 0.95f;
576
577 int sides = 4;
578 LevelOfDetail iLOD = (LevelOfDetail)lod;
579 if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle)
580 sides = 3;
581 else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.Circle)
582 {
583 switch (iLOD)
584 {
585 case LevelOfDetail.High: sides = 24; break;
586 case LevelOfDetail.Medium: sides = 12; break;
587 case LevelOfDetail.Low: sides = 6; break;
588 case LevelOfDetail.VeryLow: sides = 3; break;
589 default: sides = 24; break;
590 }
591 }
592 else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle)
593 { // half circle, prim is a sphere
594 switch (iLOD)
595 {
596 case LevelOfDetail.High: sides = 24; break;
597 case LevelOfDetail.Medium: sides = 12; break;
598 case LevelOfDetail.Low: sides = 6; break;
599 case LevelOfDetail.VeryLow: sides = 3; break;
600 default: sides = 24; break;
601 }
602
603 profileBegin = 0.5f * profileBegin + 0.5f;
604 profileEnd = 0.5f * profileEnd + 0.5f;
605 }
606
607 int hollowSides = sides;
608 if (primShape.HollowShape == HollowShape.Circle)
609 {
610 switch (iLOD)
611 {
612 case LevelOfDetail.High: hollowSides = 24; break;
613 case LevelOfDetail.Medium: hollowSides = 12; break;
614 case LevelOfDetail.Low: hollowSides = 6; break;
615 case LevelOfDetail.VeryLow: hollowSides = 3; break;
616 default: hollowSides = 24; break;
617 }
618 }
619 else if (primShape.HollowShape == HollowShape.Square)
620 hollowSides = 4;
621 else if (primShape.HollowShape == HollowShape.Triangle)
622 hollowSides = 3;
623
624 primMesh = new PrimMesh(sides, profileBegin, profileEnd, profileHollow, hollowSides);
625
626 if (primMesh.errorMessage != null)
627 if (primMesh.errorMessage.Length > 0)
628 m_log.Error("[ERROR] " + primMesh.errorMessage);
629
630 primMesh.topShearX = pathShearX;
631 primMesh.topShearY = pathShearY;
632 primMesh.pathCutBegin = pathBegin;
633 primMesh.pathCutEnd = pathEnd;
634
635 if (primShape.PathCurve == (byte)Extrusion.Straight || primShape.PathCurve == (byte) Extrusion.Flexible)
636 {
637 primMesh.twistBegin = primShape.PathTwistBegin * 18 / 10;
638 primMesh.twistEnd = primShape.PathTwist * 18 / 10;
639 primMesh.taperX = pathScaleX;
640 primMesh.taperY = pathScaleY;
641
642 if (profileBegin < 0.0f || profileBegin >= profileEnd || profileEnd > 1.0f)
643 {
644 ReportPrimError("*** CORRUPT PRIM!! ***", primName, primMesh);
645 if (profileBegin < 0.0f) profileBegin = 0.0f;
646 if (profileEnd > 1.0f) profileEnd = 1.0f;
647 }
648#if SPAM
649 m_log.Debug("****** PrimMesh Parameters (Linear) ******\n" + primMesh.ParamsToDisplayString());
650#endif
651 try
652 {
653 primMesh.ExtrudeLinear();
654 }
655 catch (Exception ex)
656 {
657 ReportPrimError("Extrusion failure: exception: " + ex.ToString(), primName, primMesh);
658 return false;
659 }
660 }
661 else
662 {
663 primMesh.holeSizeX = (200 - primShape.PathScaleX) * 0.01f;
664 primMesh.holeSizeY = (200 - primShape.PathScaleY) * 0.01f;
665 primMesh.radius = 0.01f * primShape.PathRadiusOffset;
666 primMesh.revolutions = 1.0f + 0.015f * primShape.PathRevolutions;
667 primMesh.skew = 0.01f * primShape.PathSkew;
668 primMesh.twistBegin = primShape.PathTwistBegin * 36 / 10;
669 primMesh.twistEnd = primShape.PathTwist * 36 / 10;
670 primMesh.taperX = primShape.PathTaperX * 0.01f;
671 primMesh.taperY = primShape.PathTaperY * 0.01f;
672
673 if (profileBegin < 0.0f || profileBegin >= profileEnd || profileEnd > 1.0f)
674 {
675 ReportPrimError("*** CORRUPT PRIM!! ***", primName, primMesh);
676 if (profileBegin < 0.0f) profileBegin = 0.0f;
677 if (profileEnd > 1.0f) profileEnd = 1.0f;
678 }
679#if SPAM
680 m_log.Debug("****** PrimMesh Parameters (Circular) ******\n" + primMesh.ParamsToDisplayString());
681#endif
682 try
683 {
684 primMesh.ExtrudeCircular();
685 }
686 catch (Exception ex)
687 {
688 ReportPrimError("Extrusion failure: exception: " + ex.ToString(), primName, primMesh);
689 return false;
690 }
691 }
692
693 primMesh.DumpRaw(baseDir, primName, "primMesh");
694
695 primMesh.Scale(size.X, size.Y, size.Z);
696
697 coords = primMesh.coords;
698 faces = primMesh.faces;
699
700 return true;
701 }
702
703 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod)
704 {
705 return CreateMesh(primName, primShape, size, lod, false, true);
706 }
707
708 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical)
709 {
710 return CreateMesh(primName, primShape, size, lod, isPhysical, true);
711 }
712
713 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache)
714 {
715#if SPAM
716 m_log.DebugFormat("[MESH]: Creating mesh for {0}", primName);
717#endif
718
719 Mesh mesh = null;
720 ulong key = 0;
721
722 // If this mesh has been created already, return it instead of creating another copy
723 // For large regions with 100k+ prims and hundreds of copies of each, this can save a GB or more of memory
724 if (shouldCache)
725 {
726 key = primShape.GetMeshKey(size, lod);
727 if (m_uniqueMeshes.TryGetValue(key, out mesh))
728 return mesh;
729 }
730
731 if (size.X < 0.01f) size.X = 0.01f;
732 if (size.Y < 0.01f) size.Y = 0.01f;
733 if (size.Z < 0.01f) size.Z = 0.01f;
734
735 mesh = CreateMeshFromPrimMesher(primName, primShape, size, lod);
736
737 if (mesh != null)
738 {
739 if ((!isPhysical) && size.X < minSizeForComplexMesh && size.Y < minSizeForComplexMesh && size.Z < minSizeForComplexMesh)
740 {
741#if SPAM
742 m_log.Debug("Meshmerizer: prim " + primName + " has a size of " + size.ToString() + " which is below threshold of " +
743 minSizeForComplexMesh.ToString() + " - creating simple bounding box");
744#endif
745 mesh = CreateBoundingBoxMesh(mesh);
746 mesh.DumpRaw(baseDir, primName, "Z extruded");
747 }
748
749 // trim the vertex and triangle lists to free up memory
750 mesh.TrimExcess();
751
752 if (shouldCache)
753 {
754 m_uniqueMeshes.Add(key, mesh);
755 }
756 }
757
758 return mesh;
759 }
760 }
761}