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.cs727
1 files changed, 387 insertions, 340 deletions
diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
index b79e1a1..53d5e4c 100644
--- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
+++ b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
@@ -193,67 +193,6 @@ namespace OpenSim.Region.Physics.Meshing
193 m_log.Error("****** PrimMesh Parameters ******\n" + primMesh.ParamsToDisplayString()); 193 m_log.Error("****** PrimMesh Parameters ******\n" + primMesh.ParamsToDisplayString());
194 } 194 }
195 195
196 private ulong GetMeshKey(PrimitiveBaseShape pbs, Vector3 size, float lod)
197 {
198 ulong hash = 5381;
199
200 hash = djb2(hash, pbs.PathCurve);
201 hash = djb2(hash, (byte)((byte)pbs.HollowShape | (byte)pbs.ProfileShape));
202 hash = djb2(hash, pbs.PathBegin);
203 hash = djb2(hash, pbs.PathEnd);
204 hash = djb2(hash, pbs.PathScaleX);
205 hash = djb2(hash, pbs.PathScaleY);
206 hash = djb2(hash, pbs.PathShearX);
207 hash = djb2(hash, pbs.PathShearY);
208 hash = djb2(hash, (byte)pbs.PathTwist);
209 hash = djb2(hash, (byte)pbs.PathTwistBegin);
210 hash = djb2(hash, (byte)pbs.PathRadiusOffset);
211 hash = djb2(hash, (byte)pbs.PathTaperX);
212 hash = djb2(hash, (byte)pbs.PathTaperY);
213 hash = djb2(hash, pbs.PathRevolutions);
214 hash = djb2(hash, (byte)pbs.PathSkew);
215 hash = djb2(hash, pbs.ProfileBegin);
216 hash = djb2(hash, pbs.ProfileEnd);
217 hash = djb2(hash, pbs.ProfileHollow);
218
219 // TODO: Separate scale out from the primitive shape data (after
220 // scaling is supported at the physics engine level)
221 byte[] scaleBytes = size.GetBytes();
222 for (int i = 0; i < scaleBytes.Length; i++)
223 hash = djb2(hash, scaleBytes[i]);
224
225 // Include LOD in hash, accounting for endianness
226 byte[] lodBytes = new byte[4];
227 Buffer.BlockCopy(BitConverter.GetBytes(lod), 0, lodBytes, 0, 4);
228 if (!BitConverter.IsLittleEndian)
229 {
230 Array.Reverse(lodBytes, 0, 4);
231 }
232 for (int i = 0; i < lodBytes.Length; i++)
233 hash = djb2(hash, lodBytes[i]);
234
235 // include sculpt UUID
236 if (pbs.SculptEntry)
237 {
238 scaleBytes = pbs.SculptTexture.GetBytes();
239 for (int i = 0; i < scaleBytes.Length; i++)
240 hash = djb2(hash, scaleBytes[i]);
241 }
242
243 return hash;
244 }
245
246 private ulong djb2(ulong hash, byte c)
247 {
248 return ((hash << 5) + hash) + (ulong)c;
249 }
250
251 private ulong djb2(ulong hash, ushort c)
252 {
253 hash = ((hash << 5) + hash) + (ulong)((byte)c);
254 return ((hash << 5) + hash) + (ulong)(c >> 8);
255 }
256
257 /// <summary> 196 /// <summary>
258 /// Add a submesh to an existing list of coords and faces. 197 /// Add a submesh to an existing list of coords and faces.
259 /// </summary> 198 /// </summary>
@@ -301,16 +240,22 @@ namespace OpenSim.Region.Physics.Meshing
301 } 240 }
302 } 241 }
303 242
243 /// <summary>
244 /// Create a physics mesh from data that comes with the prim. The actual data used depends on the prim type.
245 /// </summary>
246 /// <param name="primName"></param>
247 /// <param name="primShape"></param>
248 /// <param name="size"></param>
249 /// <param name="lod"></param>
250 /// <returns></returns>
304 private Mesh CreateMeshFromPrimMesher(string primName, PrimitiveBaseShape primShape, Vector3 size, float lod) 251 private Mesh CreateMeshFromPrimMesher(string primName, PrimitiveBaseShape primShape, Vector3 size, float lod)
305 { 252 {
306 PrimMesh primMesh; 253// m_log.DebugFormat(
307 PrimMesher.SculptMesh sculptMesh; 254// "[MESH]: Creating physics proxy for {0}, shape {1}",
308 255// primName, (OpenMetaverse.SculptType)primShape.SculptType);
309 List<Coord> coords = new List<Coord>();
310 List<Face> faces = new List<Face>();
311 256
312 Image idata = null; 257 List<Coord> coords;
313 string decodedSculptFileName = ""; 258 List<Face> faces;
314 259
315 if (primShape.SculptEntry) 260 if (primShape.SculptEntry)
316 { 261 {
@@ -319,337 +264,440 @@ namespace OpenSim.Region.Physics.Meshing
319 if (!useMeshiesPhysicsMesh) 264 if (!useMeshiesPhysicsMesh)
320 return null; 265 return null;
321 266
322 m_log.Debug("[MESH]: experimental mesh proxy generation"); 267 if (!GenerateCoordsAndFacesFromPrimMeshData(primName, primShape, size, out coords, out faces))
268 return null;
269 }
270 else
271 {
272 if (!GenerateCoordsAndFacesFromPrimSculptData(primName, primShape, size, lod, out coords, out faces))
273 return null;
274 }
275 }
276 else
277 {
278 if (!GenerateCoordsAndFacesFromPrimShapeData(primName, primShape, size, lod, out coords, out faces))
279 return null;
280 }
323 281
324 OSD meshOsd = null; 282 // Remove the reference to any JPEG2000 sculpt data so it can be GCed
283 primShape.SculptData = Utils.EmptyBytes;
325 284
326 if (primShape.SculptData.Length <= 0) 285 int numCoords = coords.Count;
327 { 286 int numFaces = faces.Count;
328 m_log.Error("[MESH]: asset data is zero length");
329 return null;
330 }
331 287
332 long start = 0; 288 // Create the list of vertices
333 using (MemoryStream data = new MemoryStream(primShape.SculptData)) 289 List<Vertex> vertices = new List<Vertex>();
334 { 290 for (int i = 0; i < numCoords; i++)
335 try 291 {
336 { 292 Coord c = coords[i];
337 OSD osd = OSDParser.DeserializeLLSDBinary(data); 293 vertices.Add(new Vertex(c.X, c.Y, c.Z));
338 if (osd is OSDMap) 294 }
339 meshOsd = (OSDMap)osd;
340 else
341 {
342 m_log.Warn("[Mesh}: unable to cast mesh asset to OSDMap");
343 return null;
344 }
345 }
346 catch (Exception e)
347 {
348 m_log.Error("[MESH]: Exception deserializing mesh asset header:" + e.ToString());
349 }
350 295
351 start = data.Position; 296 Mesh mesh = new Mesh();
352 } 297 // Add the corresponding triangles to the mesh
298 for (int i = 0; i < numFaces; i++)
299 {
300 Face f = faces[i];
301 mesh.Add(new Triangle(vertices[f.v1], vertices[f.v2], vertices[f.v3]));
302 }
303
304 return mesh;
305 }
306
307 /// <summary>
308 /// Generate the co-ords and faces necessary to construct a mesh from the mesh data the accompanies a prim.
309 /// </summary>
310 /// <param name="primName"></param>
311 /// <param name="primShape"></param>
312 /// <param name="size"></param>
313 /// <param name="coords">Coords are added to this list by the method.</param>
314 /// <param name="faces">Faces are added to this list by the method.</param>
315 /// <returns>true if coords and faces were successfully generated, false if not</returns>
316 private bool GenerateCoordsAndFacesFromPrimMeshData(
317 string primName, PrimitiveBaseShape primShape, Vector3 size, out List<Coord> coords, out List<Face> faces)
318 {
319 m_log.DebugFormat("[MESH]: experimental mesh proxy generation for {0}", primName);
320
321 coords = new List<Coord>();
322 faces = new List<Face>();
323 OSD meshOsd = null;
324
325 if (primShape.SculptData.Length <= 0)
326 {
327 m_log.Error("[MESH]: asset data is zero length");
328 return false;
329 }
353 330
354 if (meshOsd is OSDMap) 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
355 { 340 {
356 OSDMap physicsParms = null; 341 m_log.Warn("[Mesh}: unable to cast mesh asset to OSDMap");
357 OSDMap map = (OSDMap)meshOsd; 342 return false;
358 if (map.ContainsKey("physics_shape")) 343 }
359 physicsParms = (OSDMap)map["physics_shape"]; // old asset format 344 }
360 else if (map.ContainsKey("physics_mesh")) 345 catch (Exception e)
361 physicsParms = (OSDMap)map["physics_mesh"]; // new asset format 346 {
362 347 m_log.Error("[MESH]: Exception deserializing mesh asset header:" + e.ToString());
363 if (physicsParms == null) 348 }
364 { 349
365 m_log.Warn("[MESH]: no recognized physics mesh found in mesh asset"); 350 start = data.Position;
366 return null; 351 }
367 } 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.Warn("[MESH]: no recognized physics mesh found in mesh asset");
365 return false;
366 }
368 367
369 int physOffset = physicsParms["offset"].AsInteger() + (int)start; 368 int physOffset = physicsParms["offset"].AsInteger() + (int)start;
370 int physSize = physicsParms["size"].AsInteger(); 369 int physSize = physicsParms["size"].AsInteger();
371 370
372 if (physOffset < 0 || physSize == 0) 371 if (physOffset < 0 || physSize == 0)
373 return null; // no mesh data in asset 372 return false; // no mesh data in asset
374 373
375 OSD decodedMeshOsd = new OSD(); 374 OSD decodedMeshOsd = new OSD();
376 byte[] meshBytes = new byte[physSize]; 375 byte[] meshBytes = new byte[physSize];
377 System.Buffer.BlockCopy(primShape.SculptData, physOffset, meshBytes, 0, physSize); 376 System.Buffer.BlockCopy(primShape.SculptData, physOffset, meshBytes, 0, physSize);
378// byte[] decompressed = new byte[physSize * 5]; 377// byte[] decompressed = new byte[physSize * 5];
379 try 378 try
379 {
380 using (MemoryStream inMs = new MemoryStream(meshBytes))
381 {
382 using (MemoryStream outMs = new MemoryStream())
380 { 383 {
381 using (MemoryStream inMs = new MemoryStream(meshBytes)) 384 using (ZOutputStream zOut = new ZOutputStream(outMs))
382 { 385 {
383 using (MemoryStream outMs = new MemoryStream()) 386 byte[] readBuffer = new byte[2048];
387 int readLen = 0;
388 while ((readLen = inMs.Read(readBuffer, 0, readBuffer.Length)) > 0)
384 { 389 {
385 using (ZOutputStream zOut = new ZOutputStream(outMs)) 390 zOut.Write(readBuffer, 0, readLen);
386 {
387 byte[] readBuffer = new byte[2048];
388 int readLen = 0;
389 while ((readLen = inMs.Read(readBuffer, 0, readBuffer.Length)) > 0)
390 {
391 zOut.Write(readBuffer, 0, readLen);
392 }
393 zOut.Flush();
394 outMs.Seek(0, SeekOrigin.Begin);
395
396 byte[] decompressedBuf = outMs.GetBuffer();
397
398 decodedMeshOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf);
399 }
400 } 391 }
392 zOut.Flush();
393 outMs.Seek(0, SeekOrigin.Begin);
394
395 byte[] decompressedBuf = outMs.GetBuffer();
396
397 decodedMeshOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf);
401 } 398 }
402 } 399 }
403 catch (Exception e) 400 }
404 { 401 }
405 m_log.Error("[MESH]: exception decoding physical mesh: " + e.ToString()); 402 catch (Exception e)
406 return null; 403 {
407 } 404 m_log.Error("[MESH]: exception decoding physical mesh: " + e.ToString());
405 return false;
406 }
408 407
409 OSDArray decodedMeshOsdArray = null; 408 OSDArray decodedMeshOsdArray = null;
410 409
411 // physics_shape is an array of OSDMaps, one for each submesh 410 // physics_shape is an array of OSDMaps, one for each submesh
412 if (decodedMeshOsd is OSDArray) 411 if (decodedMeshOsd is OSDArray)
413 { 412 {
414// Console.WriteLine("decodedMeshOsd for {0} - {1}", primName, Util.GetFormattedXml(decodedMeshOsd)); 413// Console.WriteLine("decodedMeshOsd for {0} - {1}", primName, Util.GetFormattedXml(decodedMeshOsd));
415 414
416 decodedMeshOsdArray = (OSDArray)decodedMeshOsd; 415 decodedMeshOsdArray = (OSDArray)decodedMeshOsd;
417 foreach (OSD subMeshOsd in decodedMeshOsdArray) 416 foreach (OSD subMeshOsd in decodedMeshOsdArray)
418 { 417 {
419 if (subMeshOsd is OSDMap) 418 if (subMeshOsd is OSDMap)
420 AddSubMesh(subMeshOsd as OSDMap, size, coords, faces); 419 AddSubMesh(subMeshOsd as OSDMap, size, coords, faces);
421 }
422 }
423 } 420 }
424 } 421 }
425 else 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
426 { 450 {
427 if (cacheSculptMaps && primShape.SculptTexture != UUID.Zero) 451 if (File.Exists(decodedSculptFileName))
428 { 452 {
429 decodedSculptFileName = System.IO.Path.Combine(decodedSculptMapPath, "smap_" + primShape.SculptTexture.ToString()); 453 idata = Image.FromFile(decodedSculptFileName);
430 try
431 {
432 if (File.Exists(decodedSculptFileName))
433 {
434 idata = Image.FromFile(decodedSculptFileName);
435 }
436 }
437 catch (Exception e)
438 {
439 m_log.Error("[SCULPT]: unable to load cached sculpt map " + decodedSculptFileName + " " + e.Message);
440
441 }
442 //if (idata != null)
443 // m_log.Debug("[SCULPT]: loaded cached map asset for map ID: " + primShape.SculptTexture.ToString());
444 } 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);
445 474
446 if (idata == null) 475 if (idata == null)
447 { 476 {
448 if (primShape.SculptData == null || primShape.SculptData.Length == 0) 477 // In some cases it seems that the decode can return a null bitmap without throwing
449 return null; 478 // an exception
479 m_log.WarnFormat("[PHYSICS]: OpenJPEG decoded sculpt data for {0} to a null bitmap. Ignoring.", primName);
450 480
451 try 481 return false;
452 { 482 }
453 OpenMetaverse.Imaging.ManagedImage unusedData;
454 OpenMetaverse.Imaging.OpenJPEG.DecodeToImage(primShape.SculptData, out unusedData, out idata);
455 unusedData = null;
456 483
457 //idata = CSJ2K.J2kImage.FromBytes(primShape.SculptData); 484 unusedData = null;
458 485
459 if (cacheSculptMaps && idata != null) 486 //idata = CSJ2K.J2kImage.FromBytes(primShape.SculptData);
460 {
461 try { idata.Save(decodedSculptFileName, ImageFormat.MemoryBmp); }
462 catch (Exception e) { m_log.Error("[SCULPT]: unable to cache sculpt map " + decodedSculptFileName + " " + e.Message); }
463 }
464 }
465 catch (DllNotFoundException)
466 {
467 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!");
468 return null;
469 }
470 catch (IndexOutOfRangeException)
471 {
472 m_log.Error("[PHYSICS]: OpenJpeg was unable to decode this. Physics Proxy generation failed");
473 return null;
474 }
475 catch (Exception ex)
476 {
477 m_log.Error("[PHYSICS]: Unable to generate a Sculpty physics proxy. Sculpty texture decode failed: " + ex.Message);
478 return null;
479 }
480 }
481 487
482 PrimMesher.SculptMesh.SculptType sculptType; 488 if (cacheSculptMaps)
483 switch ((OpenMetaverse.SculptType)primShape.SculptType)
484 { 489 {
485 case OpenMetaverse.SculptType.Cylinder: 490 try { idata.Save(decodedSculptFileName, ImageFormat.MemoryBmp); }
486 sculptType = PrimMesher.SculptMesh.SculptType.cylinder; 491 catch (Exception e) { m_log.Error("[SCULPT]: unable to cache sculpt map " + decodedSculptFileName + " " + e.Message); }
487 break;
488 case OpenMetaverse.SculptType.Plane:
489 sculptType = PrimMesher.SculptMesh.SculptType.plane;
490 break;
491 case OpenMetaverse.SculptType.Torus:
492 sculptType = PrimMesher.SculptMesh.SculptType.torus;
493 break;
494 case OpenMetaverse.SculptType.Sphere:
495 sculptType = PrimMesher.SculptMesh.SculptType.sphere;
496 break;
497 default:
498 sculptType = PrimMesher.SculptMesh.SculptType.plane;
499 break;
500 } 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 }
501 530
502 bool mirror = ((primShape.SculptType & 128) != 0); 531 bool mirror = ((primShape.SculptType & 128) != 0);
503 bool invert = ((primShape.SculptType & 64) != 0); 532 bool invert = ((primShape.SculptType & 64) != 0);
504 533
505 sculptMesh = new PrimMesher.SculptMesh((Bitmap)idata, sculptType, (int)lod, false, mirror, invert); 534 sculptMesh = new PrimMesher.SculptMesh((Bitmap)idata, sculptType, (int)lod, false, mirror, invert);
506
507 idata.Dispose();
508 535
509 sculptMesh.DumpRaw(baseDir, primName, "primMesh"); 536 idata.Dispose();
510 537
511 sculptMesh.Scale(size.X, size.Y, size.Z); 538 sculptMesh.DumpRaw(baseDir, primName, "primMesh");
512 539
513 coords = sculptMesh.coords; 540 sculptMesh.Scale(size.X, size.Y, size.Z);
514 faces = sculptMesh.faces; 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;
515 } 590 }
516 } 591 }
517 else 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)
518 { 609 {
519 float pathShearX = primShape.PathShearX < 128 ? (float)primShape.PathShearX * 0.01f : (float)(primShape.PathShearX - 256) * 0.01f; 610 switch (iLOD)
520 float pathShearY = primShape.PathShearY < 128 ? (float)primShape.PathShearY * 0.01f : (float)(primShape.PathShearY - 256) * 0.01f; 611 {
521 float pathBegin = (float)primShape.PathBegin * 2.0e-5f; 612 case LevelOfDetail.High: hollowSides = 24; break;
522 float pathEnd = 1.0f - (float)primShape.PathEnd * 2.0e-5f; 613 case LevelOfDetail.Medium: hollowSides = 12; break;
523 float pathScaleX = (float)(primShape.PathScaleX - 100) * 0.01f; 614 case LevelOfDetail.Low: hollowSides = 6; break;
524 float pathScaleY = (float)(primShape.PathScaleY - 100) * 0.01f; 615 case LevelOfDetail.VeryLow: hollowSides = 3; break;
525 616 default: hollowSides = 24; break;
526 float profileBegin = (float)primShape.ProfileBegin * 2.0e-5f;
527 float profileEnd = 1.0f - (float)primShape.ProfileEnd * 2.0e-5f;
528 float profileHollow = (float)primShape.ProfileHollow * 2.0e-5f;
529 if (profileHollow > 0.95f)
530 profileHollow = 0.95f;
531
532 int sides = 4;
533 if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle)
534 sides = 3;
535 else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.Circle)
536 sides = 24;
537 else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle)
538 { // half circle, prim is a sphere
539 sides = 24;
540
541 profileBegin = 0.5f * profileBegin + 0.5f;
542 profileEnd = 0.5f * profileEnd + 0.5f;
543 } 617 }
618 }
619 else if (primShape.HollowShape == HollowShape.Square)
620 hollowSides = 4;
621 else if (primShape.HollowShape == HollowShape.Triangle)
622 hollowSides = 3;
544 623
545 int hollowSides = sides; 624 primMesh = new PrimMesh(sides, profileBegin, profileEnd, profileHollow, hollowSides);
546 if (primShape.HollowShape == HollowShape.Circle)
547 hollowSides = 24;
548 else if (primShape.HollowShape == HollowShape.Square)
549 hollowSides = 4;
550 else if (primShape.HollowShape == HollowShape.Triangle)
551 hollowSides = 3;
552 625
553 primMesh = new PrimMesh(sides, profileBegin, profileEnd, profileHollow, hollowSides); 626 if (primMesh.errorMessage != null)
627 if (primMesh.errorMessage.Length > 0)
628 m_log.Error("[ERROR] " + primMesh.errorMessage);
554 629
555 if (primMesh.errorMessage != null) 630 primMesh.topShearX = pathShearX;
556 if (primMesh.errorMessage.Length > 0) 631 primMesh.topShearY = pathShearY;
557 m_log.Error("[ERROR] " + primMesh.errorMessage); 632 primMesh.pathCutBegin = pathBegin;
633 primMesh.pathCutEnd = pathEnd;
558 634
559 primMesh.topShearX = pathShearX; 635 if (primShape.PathCurve == (byte)Extrusion.Straight || primShape.PathCurve == (byte) Extrusion.Flexible)
560 primMesh.topShearY = pathShearY; 636 {
561 primMesh.pathCutBegin = pathBegin; 637 primMesh.twistBegin = primShape.PathTwistBegin * 18 / 10;
562 primMesh.pathCutEnd = pathEnd; 638 primMesh.twistEnd = primShape.PathTwist * 18 / 10;
639 primMesh.taperX = pathScaleX;
640 primMesh.taperY = pathScaleY;
563 641
564 if (primShape.PathCurve == (byte)Extrusion.Straight || primShape.PathCurve == (byte) Extrusion.Flexible) 642 if (profileBegin < 0.0f || profileBegin >= profileEnd || profileEnd > 1.0f)
565 { 643 {
566 primMesh.twistBegin = primShape.PathTwistBegin * 18 / 10; 644 ReportPrimError("*** CORRUPT PRIM!! ***", primName, primMesh);
567 primMesh.twistEnd = primShape.PathTwist * 18 / 10; 645 if (profileBegin < 0.0f) profileBegin = 0.0f;
568 primMesh.taperX = pathScaleX; 646 if (profileEnd > 1.0f) profileEnd = 1.0f;
569 primMesh.taperY = pathScaleY; 647 }
570
571 if (profileBegin < 0.0f || profileBegin >= profileEnd || profileEnd > 1.0f)
572 {
573 ReportPrimError("*** CORRUPT PRIM!! ***", primName, primMesh);
574 if (profileBegin < 0.0f) profileBegin = 0.0f;
575 if (profileEnd > 1.0f) profileEnd = 1.0f;
576 }
577#if SPAM 648#if SPAM
578 m_log.Debug("****** PrimMesh Parameters (Linear) ******\n" + primMesh.ParamsToDisplayString()); 649 m_log.Debug("****** PrimMesh Parameters (Linear) ******\n" + primMesh.ParamsToDisplayString());
579#endif 650#endif
580 try 651 try
581 { 652 {
582 primMesh.ExtrudeLinear(); 653 primMesh.ExtrudeLinear();
583 }
584 catch (Exception ex)
585 {
586 ReportPrimError("Extrusion failure: exception: " + ex.ToString(), primName, primMesh);
587 return null;
588 }
589 } 654 }
590 else 655 catch (Exception ex)
591 { 656 {
592 primMesh.holeSizeX = (200 - primShape.PathScaleX) * 0.01f; 657 ReportPrimError("Extrusion failure: exception: " + ex.ToString(), primName, primMesh);
593 primMesh.holeSizeY = (200 - primShape.PathScaleY) * 0.01f; 658 return false;
594 primMesh.radius = 0.01f * primShape.PathRadiusOffset; 659 }
595 primMesh.revolutions = 1.0f + 0.015f * primShape.PathRevolutions; 660 }
596 primMesh.skew = 0.01f * primShape.PathSkew; 661 else
597 primMesh.twistBegin = primShape.PathTwistBegin * 36 / 10; 662 {
598 primMesh.twistEnd = primShape.PathTwist * 36 / 10; 663 primMesh.holeSizeX = (200 - primShape.PathScaleX) * 0.01f;
599 primMesh.taperX = primShape.PathTaperX * 0.01f; 664 primMesh.holeSizeY = (200 - primShape.PathScaleY) * 0.01f;
600 primMesh.taperY = primShape.PathTaperY * 0.01f; 665 primMesh.radius = 0.01f * primShape.PathRadiusOffset;
601 666 primMesh.revolutions = 1.0f + 0.015f * primShape.PathRevolutions;
602 if (profileBegin < 0.0f || profileBegin >= profileEnd || profileEnd > 1.0f) 667 primMesh.skew = 0.01f * primShape.PathSkew;
603 { 668 primMesh.twistBegin = primShape.PathTwistBegin * 36 / 10;
604 ReportPrimError("*** CORRUPT PRIM!! ***", primName, primMesh); 669 primMesh.twistEnd = primShape.PathTwist * 36 / 10;
605 if (profileBegin < 0.0f) profileBegin = 0.0f; 670 primMesh.taperX = primShape.PathTaperX * 0.01f;
606 if (profileEnd > 1.0f) profileEnd = 1.0f; 671 primMesh.taperY = primShape.PathTaperY * 0.01f;
607 } 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 }
608#if SPAM 679#if SPAM
609 m_log.Debug("****** PrimMesh Parameters (Circular) ******\n" + primMesh.ParamsToDisplayString()); 680 m_log.Debug("****** PrimMesh Parameters (Circular) ******\n" + primMesh.ParamsToDisplayString());
610#endif 681#endif
611 try 682 try
612 { 683 {
613 primMesh.ExtrudeCircular(); 684 primMesh.ExtrudeCircular();
614 } 685 }
615 catch (Exception ex) 686 catch (Exception ex)
616 { 687 {
617 ReportPrimError("Extrusion failure: exception: " + ex.ToString(), primName, primMesh); 688 ReportPrimError("Extrusion failure: exception: " + ex.ToString(), primName, primMesh);
618 return null; 689 return false;
619 }
620 } 690 }
621
622 primMesh.DumpRaw(baseDir, primName, "primMesh");
623
624 primMesh.Scale(size.X, size.Y, size.Z);
625
626 coords = primMesh.coords;
627 faces = primMesh.faces;
628 } 691 }
629 692
630 // Remove the reference to any JPEG2000 sculpt data so it can be GCed 693 primMesh.DumpRaw(baseDir, primName, "primMesh");
631 primShape.SculptData = Utils.EmptyBytes;
632 694
633 int numCoords = coords.Count; 695 primMesh.Scale(size.X, size.Y, size.Z);
634 int numFaces = faces.Count;
635
636 // Create the list of vertices
637 List<Vertex> vertices = new List<Vertex>();
638 for (int i = 0; i < numCoords; i++)
639 {
640 Coord c = coords[i];
641 vertices.Add(new Vertex(c.X, c.Y, c.Z));
642 }
643 696
644 Mesh mesh = new Mesh(); 697 coords = primMesh.coords;
645 // Add the corresponding triangles to the mesh 698 faces = primMesh.faces;
646 for (int i = 0; i < numFaces; i++)
647 {
648 Face f = faces[i];
649 mesh.Add(new Triangle(vertices[f.v1], vertices[f.v2], vertices[f.v3]));
650 }
651 699
652 return mesh; 700 return true;
653 } 701 }
654 702
655 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) 703 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod)
@@ -668,8 +716,7 @@ namespace OpenSim.Region.Physics.Meshing
668 716
669 // If this mesh has been created already, return it instead of creating another copy 717 // If this mesh has been created already, return it instead of creating another copy
670 // For large regions with 100k+ prims and hundreds of copies of each, this can save a GB or more of memory 718 // For large regions with 100k+ prims and hundreds of copies of each, this can save a GB or more of memory
671 719 key = primShape.GetMeshKey(size, lod);
672 key = GetMeshKey(primShape, size, lod);
673 if (m_uniqueMeshes.TryGetValue(key, out mesh)) 720 if (m_uniqueMeshes.TryGetValue(key, out mesh))
674 return mesh; 721 return mesh;
675 722