diff options
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Region/Physics/Meshing/Meshmerizer.cs | 641 |
1 files changed, 360 insertions, 281 deletions
diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs index 5413aa8..e81b982 100644 --- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs +++ b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs | |||
@@ -301,20 +301,22 @@ namespace OpenSim.Region.Physics.Meshing | |||
301 | } | 301 | } |
302 | } | 302 | } |
303 | 303 | ||
304 | /// <summary> | ||
305 | /// Create a physics mesh from data that comes with the prim. The actual data used depends on the prim type. | ||
306 | /// </summary> | ||
307 | /// <param name="primName"></param> | ||
308 | /// <param name="primShape"></param> | ||
309 | /// <param name="size"></param> | ||
310 | /// <param name="lod"></param> | ||
311 | /// <returns></returns> | ||
304 | private Mesh CreateMeshFromPrimMesher(string primName, PrimitiveBaseShape primShape, Vector3 size, float lod) | 312 | private Mesh CreateMeshFromPrimMesher(string primName, PrimitiveBaseShape primShape, Vector3 size, float lod) |
305 | { | 313 | { |
306 | // m_log.DebugFormat( | 314 | // m_log.DebugFormat( |
307 | // "[MESH]: Creating physics proxy for {0}, shape {1}", | 315 | // "[MESH]: Creating physics proxy for {0}, shape {1}", |
308 | // primName, (OpenMetaverse.SculptType)primShape.SculptType); | 316 | // primName, (OpenMetaverse.SculptType)primShape.SculptType); |
309 | 317 | ||
310 | PrimMesh primMesh; | 318 | List<Coord> coords; |
311 | PrimMesher.SculptMesh sculptMesh; | 319 | List<Face> faces; |
312 | |||
313 | List<Coord> coords = new List<Coord>(); | ||
314 | List<Face> faces = new List<Face>(); | ||
315 | |||
316 | Image idata = null; | ||
317 | string decodedSculptFileName = ""; | ||
318 | 320 | ||
319 | if (primShape.SculptEntry) | 321 | if (primShape.SculptEntry) |
320 | { | 322 | { |
@@ -323,337 +325,414 @@ namespace OpenSim.Region.Physics.Meshing | |||
323 | if (!useMeshiesPhysicsMesh) | 325 | if (!useMeshiesPhysicsMesh) |
324 | return null; | 326 | return null; |
325 | 327 | ||
326 | m_log.DebugFormat("[MESH]: experimental mesh proxy generation for {0}", primName); | 328 | if (!GenerateCoordsAndFacesFromPrimMeshData(primName, primShape, size, out coords, out faces)) |
329 | return null; | ||
330 | } | ||
331 | else | ||
332 | { | ||
333 | if (!GenerateCoordsAndFacesFromPrimSculptData(primName, primShape, size, lod, out coords, out faces)) | ||
334 | return null; | ||
335 | } | ||
336 | } | ||
337 | else | ||
338 | { | ||
339 | if (!GenerateCoordsAndFacesFromPrimShapeData(primName, primShape, size, out coords, out faces)) | ||
340 | return null; | ||
341 | } | ||
327 | 342 | ||
328 | OSD meshOsd = null; | 343 | // Remove the reference to any JPEG2000 sculpt data so it can be GCed |
344 | primShape.SculptData = Utils.EmptyBytes; | ||
329 | 345 | ||
330 | if (primShape.SculptData.Length <= 0) | 346 | int numCoords = coords.Count; |
331 | { | 347 | int numFaces = faces.Count; |
332 | m_log.Error("[MESH]: asset data is zero length"); | ||
333 | return null; | ||
334 | } | ||
335 | 348 | ||
336 | long start = 0; | 349 | // Create the list of vertices |
337 | using (MemoryStream data = new MemoryStream(primShape.SculptData)) | 350 | List<Vertex> vertices = new List<Vertex>(); |
338 | { | 351 | for (int i = 0; i < numCoords; i++) |
339 | try | 352 | { |
340 | { | 353 | Coord c = coords[i]; |
341 | OSD osd = OSDParser.DeserializeLLSDBinary(data); | 354 | vertices.Add(new Vertex(c.X, c.Y, c.Z)); |
342 | if (osd is OSDMap) | 355 | } |
343 | meshOsd = (OSDMap)osd; | ||
344 | else | ||
345 | { | ||
346 | m_log.Warn("[Mesh}: unable to cast mesh asset to OSDMap"); | ||
347 | return null; | ||
348 | } | ||
349 | } | ||
350 | catch (Exception e) | ||
351 | { | ||
352 | m_log.Error("[MESH]: Exception deserializing mesh asset header:" + e.ToString()); | ||
353 | } | ||
354 | 356 | ||
355 | start = data.Position; | 357 | Mesh mesh = new Mesh(); |
356 | } | 358 | // Add the corresponding triangles to the mesh |
359 | for (int i = 0; i < numFaces; i++) | ||
360 | { | ||
361 | Face f = faces[i]; | ||
362 | mesh.Add(new Triangle(vertices[f.v1], vertices[f.v2], vertices[f.v3])); | ||
363 | } | ||
364 | |||
365 | return mesh; | ||
366 | } | ||
357 | 367 | ||
358 | if (meshOsd is OSDMap) | 368 | /// <summary> |
369 | /// Generate the co-ords and faces necessary to construct a mesh from the mesh data the accompanies a prim. | ||
370 | /// </summary> | ||
371 | /// <param name="primName"></param> | ||
372 | /// <param name="primShape"></param> | ||
373 | /// <param name="size"></param> | ||
374 | /// <param name="coords">Coords are added to this list by the method.</param> | ||
375 | /// <param name="faces">Faces are added to this list by the method.</param> | ||
376 | /// <returns>true if coords and faces were successfully generated, false if not</returns> | ||
377 | private bool GenerateCoordsAndFacesFromPrimMeshData( | ||
378 | string primName, PrimitiveBaseShape primShape, Vector3 size, out List<Coord> coords, out List<Face> faces) | ||
379 | { | ||
380 | m_log.DebugFormat("[MESH]: experimental mesh proxy generation for {0}", primName); | ||
381 | |||
382 | coords = new List<Coord>(); | ||
383 | faces = new List<Face>(); | ||
384 | OSD meshOsd = null; | ||
385 | |||
386 | if (primShape.SculptData.Length <= 0) | ||
387 | { | ||
388 | m_log.Error("[MESH]: asset data is zero length"); | ||
389 | return false; | ||
390 | } | ||
391 | |||
392 | long start = 0; | ||
393 | using (MemoryStream data = new MemoryStream(primShape.SculptData)) | ||
394 | { | ||
395 | try | ||
396 | { | ||
397 | OSD osd = OSDParser.DeserializeLLSDBinary(data); | ||
398 | if (osd is OSDMap) | ||
399 | meshOsd = (OSDMap)osd; | ||
400 | else | ||
359 | { | 401 | { |
360 | OSDMap physicsParms = null; | 402 | m_log.Warn("[Mesh}: unable to cast mesh asset to OSDMap"); |
361 | OSDMap map = (OSDMap)meshOsd; | 403 | return false; |
362 | if (map.ContainsKey("physics_shape")) | 404 | } |
363 | physicsParms = (OSDMap)map["physics_shape"]; // old asset format | 405 | } |
364 | else if (map.ContainsKey("physics_mesh")) | 406 | catch (Exception e) |
365 | physicsParms = (OSDMap)map["physics_mesh"]; // new asset format | 407 | { |
366 | 408 | m_log.Error("[MESH]: Exception deserializing mesh asset header:" + e.ToString()); | |
367 | if (physicsParms == null) | 409 | } |
368 | { | 410 | |
369 | m_log.Warn("[MESH]: no recognized physics mesh found in mesh asset"); | 411 | start = data.Position; |
370 | return null; | 412 | } |
371 | } | ||
372 | 413 | ||
373 | int physOffset = physicsParms["offset"].AsInteger() + (int)start; | 414 | if (meshOsd is OSDMap) |
374 | int physSize = physicsParms["size"].AsInteger(); | 415 | { |
416 | OSDMap physicsParms = null; | ||
417 | OSDMap map = (OSDMap)meshOsd; | ||
418 | if (map.ContainsKey("physics_shape")) | ||
419 | physicsParms = (OSDMap)map["physics_shape"]; // old asset format | ||
420 | else if (map.ContainsKey("physics_mesh")) | ||
421 | physicsParms = (OSDMap)map["physics_mesh"]; // new asset format | ||
422 | |||
423 | if (physicsParms == null) | ||
424 | { | ||
425 | m_log.Warn("[MESH]: no recognized physics mesh found in mesh asset"); | ||
426 | return false; | ||
427 | } | ||
375 | 428 | ||
376 | if (physOffset < 0 || physSize == 0) | 429 | int physOffset = physicsParms["offset"].AsInteger() + (int)start; |
377 | return null; // no mesh data in asset | 430 | int physSize = physicsParms["size"].AsInteger(); |
378 | 431 | ||
379 | OSD decodedMeshOsd = new OSD(); | 432 | if (physOffset < 0 || physSize == 0) |
380 | byte[] meshBytes = new byte[physSize]; | 433 | return false; // no mesh data in asset |
381 | System.Buffer.BlockCopy(primShape.SculptData, physOffset, meshBytes, 0, physSize); | 434 | |
435 | OSD decodedMeshOsd = new OSD(); | ||
436 | byte[] meshBytes = new byte[physSize]; | ||
437 | System.Buffer.BlockCopy(primShape.SculptData, physOffset, meshBytes, 0, physSize); | ||
382 | // byte[] decompressed = new byte[physSize * 5]; | 438 | // byte[] decompressed = new byte[physSize * 5]; |
383 | try | 439 | try |
440 | { | ||
441 | using (MemoryStream inMs = new MemoryStream(meshBytes)) | ||
442 | { | ||
443 | using (MemoryStream outMs = new MemoryStream()) | ||
384 | { | 444 | { |
385 | using (MemoryStream inMs = new MemoryStream(meshBytes)) | 445 | using (ZOutputStream zOut = new ZOutputStream(outMs)) |
386 | { | 446 | { |
387 | using (MemoryStream outMs = new MemoryStream()) | 447 | byte[] readBuffer = new byte[2048]; |
448 | int readLen = 0; | ||
449 | while ((readLen = inMs.Read(readBuffer, 0, readBuffer.Length)) > 0) | ||
388 | { | 450 | { |
389 | using (ZOutputStream zOut = new ZOutputStream(outMs)) | 451 | zOut.Write(readBuffer, 0, readLen); |
390 | { | ||
391 | byte[] readBuffer = new byte[2048]; | ||
392 | int readLen = 0; | ||
393 | while ((readLen = inMs.Read(readBuffer, 0, readBuffer.Length)) > 0) | ||
394 | { | ||
395 | zOut.Write(readBuffer, 0, readLen); | ||
396 | } | ||
397 | zOut.Flush(); | ||
398 | outMs.Seek(0, SeekOrigin.Begin); | ||
399 | |||
400 | byte[] decompressedBuf = outMs.GetBuffer(); | ||
401 | |||
402 | decodedMeshOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf); | ||
403 | } | ||
404 | } | 452 | } |
453 | zOut.Flush(); | ||
454 | outMs.Seek(0, SeekOrigin.Begin); | ||
455 | |||
456 | byte[] decompressedBuf = outMs.GetBuffer(); | ||
457 | |||
458 | decodedMeshOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf); | ||
405 | } | 459 | } |
406 | } | 460 | } |
407 | catch (Exception e) | 461 | } |
408 | { | 462 | } |
409 | m_log.Error("[MESH]: exception decoding physical mesh: " + e.ToString()); | 463 | catch (Exception e) |
410 | return null; | 464 | { |
411 | } | 465 | m_log.Error("[MESH]: exception decoding physical mesh: " + e.ToString()); |
466 | return false; | ||
467 | } | ||
412 | 468 | ||
413 | OSDArray decodedMeshOsdArray = null; | 469 | OSDArray decodedMeshOsdArray = null; |
414 | 470 | ||
415 | // physics_shape is an array of OSDMaps, one for each submesh | 471 | // physics_shape is an array of OSDMaps, one for each submesh |
416 | if (decodedMeshOsd is OSDArray) | 472 | if (decodedMeshOsd is OSDArray) |
417 | { | 473 | { |
418 | // Console.WriteLine("decodedMeshOsd for {0} - {1}", primName, Util.GetFormattedXml(decodedMeshOsd)); | 474 | // Console.WriteLine("decodedMeshOsd for {0} - {1}", primName, Util.GetFormattedXml(decodedMeshOsd)); |
419 | 475 | ||
420 | decodedMeshOsdArray = (OSDArray)decodedMeshOsd; | 476 | decodedMeshOsdArray = (OSDArray)decodedMeshOsd; |
421 | foreach (OSD subMeshOsd in decodedMeshOsdArray) | 477 | foreach (OSD subMeshOsd in decodedMeshOsdArray) |
422 | { | 478 | { |
423 | if (subMeshOsd is OSDMap) | 479 | if (subMeshOsd is OSDMap) |
424 | AddSubMesh(subMeshOsd as OSDMap, size, coords, faces); | 480 | AddSubMesh(subMeshOsd as OSDMap, size, coords, faces); |
425 | } | ||
426 | } | ||
427 | } | 481 | } |
428 | } | 482 | } |
429 | else | 483 | } |
484 | |||
485 | return true; | ||
486 | } | ||
487 | |||
488 | /// <summary> | ||
489 | /// Generate the co-ords and faces necessary to construct a mesh from the sculpt data the accompanies a prim. | ||
490 | /// </summary> | ||
491 | /// <param name="primName"></param> | ||
492 | /// <param name="primShape"></param> | ||
493 | /// <param name="size"></param> | ||
494 | /// <param name="lod"></param> | ||
495 | /// <param name="coords">Coords are added to this list by the method.</param> | ||
496 | /// <param name="faces">Faces are added to this list by the method.</param> | ||
497 | /// <returns>true if coords and faces were successfully generated, false if not</returns> | ||
498 | private bool GenerateCoordsAndFacesFromPrimSculptData( | ||
499 | string primName, PrimitiveBaseShape primShape, Vector3 size, float lod, out List<Coord> coords, out List<Face> faces) | ||
500 | { | ||
501 | coords = new List<Coord>(); | ||
502 | faces = new List<Face>(); | ||
503 | PrimMesher.SculptMesh sculptMesh; | ||
504 | Image idata = null; | ||
505 | string decodedSculptFileName = ""; | ||
506 | |||
507 | if (cacheSculptMaps && primShape.SculptTexture != UUID.Zero) | ||
508 | { | ||
509 | decodedSculptFileName = System.IO.Path.Combine(decodedSculptMapPath, "smap_" + primShape.SculptTexture.ToString()); | ||
510 | try | ||
430 | { | 511 | { |
431 | if (cacheSculptMaps && primShape.SculptTexture != UUID.Zero) | 512 | if (File.Exists(decodedSculptFileName)) |
432 | { | 513 | { |
433 | decodedSculptFileName = System.IO.Path.Combine(decodedSculptMapPath, "smap_" + primShape.SculptTexture.ToString()); | 514 | idata = Image.FromFile(decodedSculptFileName); |
434 | try | ||
435 | { | ||
436 | if (File.Exists(decodedSculptFileName)) | ||
437 | { | ||
438 | idata = Image.FromFile(decodedSculptFileName); | ||
439 | } | ||
440 | } | ||
441 | catch (Exception e) | ||
442 | { | ||
443 | m_log.Error("[SCULPT]: unable to load cached sculpt map " + decodedSculptFileName + " " + e.Message); | ||
444 | |||
445 | } | ||
446 | //if (idata != null) | ||
447 | // m_log.Debug("[SCULPT]: loaded cached map asset for map ID: " + primShape.SculptTexture.ToString()); | ||
448 | } | 515 | } |
516 | } | ||
517 | catch (Exception e) | ||
518 | { | ||
519 | m_log.Error("[SCULPT]: unable to load cached sculpt map " + decodedSculptFileName + " " + e.Message); | ||
520 | |||
521 | } | ||
522 | //if (idata != null) | ||
523 | // m_log.Debug("[SCULPT]: loaded cached map asset for map ID: " + primShape.SculptTexture.ToString()); | ||
524 | } | ||
525 | |||
526 | if (idata == null) | ||
527 | { | ||
528 | if (primShape.SculptData == null || primShape.SculptData.Length == 0) | ||
529 | return false; | ||
530 | |||
531 | try | ||
532 | { | ||
533 | OpenMetaverse.Imaging.ManagedImage unusedData; | ||
534 | OpenMetaverse.Imaging.OpenJPEG.DecodeToImage(primShape.SculptData, out unusedData, out idata); | ||
449 | 535 | ||
450 | if (idata == null) | 536 | if (idata == null) |
451 | { | 537 | { |
452 | if (primShape.SculptData == null || primShape.SculptData.Length == 0) | 538 | // In some cases it seems that the decode can return a null bitmap without throwing |
453 | return null; | 539 | // an exception |
540 | m_log.WarnFormat("[PHYSICS]: OpenJPEG decoded sculpt data for {0} to a null bitmap. Ignoring.", primName); | ||
454 | 541 | ||
455 | try | 542 | return false; |
456 | { | 543 | } |
457 | OpenMetaverse.Imaging.ManagedImage unusedData; | ||
458 | OpenMetaverse.Imaging.OpenJPEG.DecodeToImage(primShape.SculptData, out unusedData, out idata); | ||
459 | unusedData = null; | ||
460 | 544 | ||
461 | //idata = CSJ2K.J2kImage.FromBytes(primShape.SculptData); | 545 | unusedData = null; |
462 | 546 | ||
463 | if (cacheSculptMaps && idata != null) | 547 | //idata = CSJ2K.J2kImage.FromBytes(primShape.SculptData); |
464 | { | ||
465 | try { idata.Save(decodedSculptFileName, ImageFormat.MemoryBmp); } | ||
466 | catch (Exception e) { m_log.Error("[SCULPT]: unable to cache sculpt map " + decodedSculptFileName + " " + e.Message); } | ||
467 | } | ||
468 | } | ||
469 | catch (DllNotFoundException) | ||
470 | { | ||
471 | 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!"); | ||
472 | return null; | ||
473 | } | ||
474 | catch (IndexOutOfRangeException) | ||
475 | { | ||
476 | m_log.Error("[PHYSICS]: OpenJpeg was unable to decode this. Physics Proxy generation failed"); | ||
477 | return null; | ||
478 | } | ||
479 | catch (Exception ex) | ||
480 | { | ||
481 | m_log.Error("[PHYSICS]: Unable to generate a Sculpty physics proxy. Sculpty texture decode failed: " + ex.Message); | ||
482 | return null; | ||
483 | } | ||
484 | } | ||
485 | 548 | ||
486 | PrimMesher.SculptMesh.SculptType sculptType; | 549 | if (cacheSculptMaps) |
487 | switch ((OpenMetaverse.SculptType)primShape.SculptType) | ||
488 | { | 550 | { |
489 | case OpenMetaverse.SculptType.Cylinder: | 551 | try { idata.Save(decodedSculptFileName, ImageFormat.MemoryBmp); } |
490 | sculptType = PrimMesher.SculptMesh.SculptType.cylinder; | 552 | catch (Exception e) { m_log.Error("[SCULPT]: unable to cache sculpt map " + decodedSculptFileName + " " + e.Message); } |
491 | break; | ||
492 | case OpenMetaverse.SculptType.Plane: | ||
493 | sculptType = PrimMesher.SculptMesh.SculptType.plane; | ||
494 | break; | ||
495 | case OpenMetaverse.SculptType.Torus: | ||
496 | sculptType = PrimMesher.SculptMesh.SculptType.torus; | ||
497 | break; | ||
498 | case OpenMetaverse.SculptType.Sphere: | ||
499 | sculptType = PrimMesher.SculptMesh.SculptType.sphere; | ||
500 | break; | ||
501 | default: | ||
502 | sculptType = PrimMesher.SculptMesh.SculptType.plane; | ||
503 | break; | ||
504 | } | 553 | } |
554 | } | ||
555 | catch (DllNotFoundException) | ||
556 | { | ||
557 | 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!"); | ||
558 | return false; | ||
559 | } | ||
560 | catch (IndexOutOfRangeException) | ||
561 | { | ||
562 | m_log.Error("[PHYSICS]: OpenJpeg was unable to decode this. Physics Proxy generation failed"); | ||
563 | return false; | ||
564 | } | ||
565 | catch (Exception ex) | ||
566 | { | ||
567 | m_log.Error("[PHYSICS]: Unable to generate a Sculpty physics proxy. Sculpty texture decode failed: " + ex.Message); | ||
568 | return false; | ||
569 | } | ||
570 | } | ||
571 | |||
572 | PrimMesher.SculptMesh.SculptType sculptType; | ||
573 | switch ((OpenMetaverse.SculptType)primShape.SculptType) | ||
574 | { | ||
575 | case OpenMetaverse.SculptType.Cylinder: | ||
576 | sculptType = PrimMesher.SculptMesh.SculptType.cylinder; | ||
577 | break; | ||
578 | case OpenMetaverse.SculptType.Plane: | ||
579 | sculptType = PrimMesher.SculptMesh.SculptType.plane; | ||
580 | break; | ||
581 | case OpenMetaverse.SculptType.Torus: | ||
582 | sculptType = PrimMesher.SculptMesh.SculptType.torus; | ||
583 | break; | ||
584 | case OpenMetaverse.SculptType.Sphere: | ||
585 | sculptType = PrimMesher.SculptMesh.SculptType.sphere; | ||
586 | break; | ||
587 | default: | ||
588 | sculptType = PrimMesher.SculptMesh.SculptType.plane; | ||
589 | break; | ||
590 | } | ||
505 | 591 | ||
506 | bool mirror = ((primShape.SculptType & 128) != 0); | 592 | bool mirror = ((primShape.SculptType & 128) != 0); |
507 | bool invert = ((primShape.SculptType & 64) != 0); | 593 | bool invert = ((primShape.SculptType & 64) != 0); |
508 | 594 | ||
509 | sculptMesh = new PrimMesher.SculptMesh((Bitmap)idata, sculptType, (int)lod, false, mirror, invert); | 595 | sculptMesh = new PrimMesher.SculptMesh((Bitmap)idata, sculptType, (int)lod, false, mirror, invert); |
510 | |||
511 | idata.Dispose(); | ||
512 | 596 | ||
513 | sculptMesh.DumpRaw(baseDir, primName, "primMesh"); | 597 | idata.Dispose(); |
514 | 598 | ||
515 | sculptMesh.Scale(size.X, size.Y, size.Z); | 599 | sculptMesh.DumpRaw(baseDir, primName, "primMesh"); |
516 | 600 | ||
517 | coords = sculptMesh.coords; | 601 | sculptMesh.Scale(size.X, size.Y, size.Z); |
518 | faces = sculptMesh.faces; | 602 | |
519 | } | 603 | coords = sculptMesh.coords; |
604 | faces = sculptMesh.faces; | ||
605 | |||
606 | return true; | ||
607 | } | ||
608 | |||
609 | /// <summary> | ||
610 | /// Generate the co-ords and faces necessary to construct a mesh from the shape data the accompanies a prim. | ||
611 | /// </summary> | ||
612 | /// <param name="primName"></param> | ||
613 | /// <param name="primShape"></param> | ||
614 | /// <param name="size"></param> | ||
615 | /// <param name="coords">Coords are added to this list by the method.</param> | ||
616 | /// <param name="faces">Faces are added to this list by the method.</param> | ||
617 | /// <returns>true if coords and faces were successfully generated, false if not</returns> | ||
618 | private bool GenerateCoordsAndFacesFromPrimShapeData( | ||
619 | string primName, PrimitiveBaseShape primShape, Vector3 size, out List<Coord> coords, out List<Face> faces) | ||
620 | { | ||
621 | PrimMesh primMesh; | ||
622 | coords = new List<Coord>(); | ||
623 | faces = new List<Face>(); | ||
624 | |||
625 | float pathShearX = primShape.PathShearX < 128 ? (float)primShape.PathShearX * 0.01f : (float)(primShape.PathShearX - 256) * 0.01f; | ||
626 | float pathShearY = primShape.PathShearY < 128 ? (float)primShape.PathShearY * 0.01f : (float)(primShape.PathShearY - 256) * 0.01f; | ||
627 | float pathBegin = (float)primShape.PathBegin * 2.0e-5f; | ||
628 | float pathEnd = 1.0f - (float)primShape.PathEnd * 2.0e-5f; | ||
629 | float pathScaleX = (float)(primShape.PathScaleX - 100) * 0.01f; | ||
630 | float pathScaleY = (float)(primShape.PathScaleY - 100) * 0.01f; | ||
631 | |||
632 | float profileBegin = (float)primShape.ProfileBegin * 2.0e-5f; | ||
633 | float profileEnd = 1.0f - (float)primShape.ProfileEnd * 2.0e-5f; | ||
634 | float profileHollow = (float)primShape.ProfileHollow * 2.0e-5f; | ||
635 | if (profileHollow > 0.95f) | ||
636 | profileHollow = 0.95f; | ||
637 | |||
638 | int sides = 4; | ||
639 | if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle) | ||
640 | sides = 3; | ||
641 | else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.Circle) | ||
642 | sides = 24; | ||
643 | else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle) | ||
644 | { // half circle, prim is a sphere | ||
645 | sides = 24; | ||
646 | |||
647 | profileBegin = 0.5f * profileBegin + 0.5f; | ||
648 | profileEnd = 0.5f * profileEnd + 0.5f; | ||
520 | } | 649 | } |
521 | else | ||
522 | { | ||
523 | float pathShearX = primShape.PathShearX < 128 ? (float)primShape.PathShearX * 0.01f : (float)(primShape.PathShearX - 256) * 0.01f; | ||
524 | float pathShearY = primShape.PathShearY < 128 ? (float)primShape.PathShearY * 0.01f : (float)(primShape.PathShearY - 256) * 0.01f; | ||
525 | float pathBegin = (float)primShape.PathBegin * 2.0e-5f; | ||
526 | float pathEnd = 1.0f - (float)primShape.PathEnd * 2.0e-5f; | ||
527 | float pathScaleX = (float)(primShape.PathScaleX - 100) * 0.01f; | ||
528 | float pathScaleY = (float)(primShape.PathScaleY - 100) * 0.01f; | ||
529 | |||
530 | float profileBegin = (float)primShape.ProfileBegin * 2.0e-5f; | ||
531 | float profileEnd = 1.0f - (float)primShape.ProfileEnd * 2.0e-5f; | ||
532 | float profileHollow = (float)primShape.ProfileHollow * 2.0e-5f; | ||
533 | if (profileHollow > 0.95f) | ||
534 | profileHollow = 0.95f; | ||
535 | |||
536 | int sides = 4; | ||
537 | if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle) | ||
538 | sides = 3; | ||
539 | else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.Circle) | ||
540 | sides = 24; | ||
541 | else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle) | ||
542 | { // half circle, prim is a sphere | ||
543 | sides = 24; | ||
544 | |||
545 | profileBegin = 0.5f * profileBegin + 0.5f; | ||
546 | profileEnd = 0.5f * profileEnd + 0.5f; | ||
547 | } | ||
548 | 650 | ||
549 | int hollowSides = sides; | 651 | int hollowSides = sides; |
550 | if (primShape.HollowShape == HollowShape.Circle) | 652 | if (primShape.HollowShape == HollowShape.Circle) |
551 | hollowSides = 24; | 653 | hollowSides = 24; |
552 | else if (primShape.HollowShape == HollowShape.Square) | 654 | else if (primShape.HollowShape == HollowShape.Square) |
553 | hollowSides = 4; | 655 | hollowSides = 4; |
554 | else if (primShape.HollowShape == HollowShape.Triangle) | 656 | else if (primShape.HollowShape == HollowShape.Triangle) |
555 | hollowSides = 3; | 657 | hollowSides = 3; |
556 | 658 | ||
557 | primMesh = new PrimMesh(sides, profileBegin, profileEnd, profileHollow, hollowSides); | 659 | primMesh = new PrimMesh(sides, profileBegin, profileEnd, profileHollow, hollowSides); |
558 | 660 | ||
559 | if (primMesh.errorMessage != null) | 661 | if (primMesh.errorMessage != null) |
560 | if (primMesh.errorMessage.Length > 0) | 662 | if (primMesh.errorMessage.Length > 0) |
561 | m_log.Error("[ERROR] " + primMesh.errorMessage); | 663 | m_log.Error("[ERROR] " + primMesh.errorMessage); |
562 | 664 | ||
563 | primMesh.topShearX = pathShearX; | 665 | primMesh.topShearX = pathShearX; |
564 | primMesh.topShearY = pathShearY; | 666 | primMesh.topShearY = pathShearY; |
565 | primMesh.pathCutBegin = pathBegin; | 667 | primMesh.pathCutBegin = pathBegin; |
566 | primMesh.pathCutEnd = pathEnd; | 668 | primMesh.pathCutEnd = pathEnd; |
567 | 669 | ||
568 | if (primShape.PathCurve == (byte)Extrusion.Straight || primShape.PathCurve == (byte) Extrusion.Flexible) | 670 | if (primShape.PathCurve == (byte)Extrusion.Straight || primShape.PathCurve == (byte) Extrusion.Flexible) |
569 | { | 671 | { |
570 | primMesh.twistBegin = primShape.PathTwistBegin * 18 / 10; | 672 | primMesh.twistBegin = primShape.PathTwistBegin * 18 / 10; |
571 | primMesh.twistEnd = primShape.PathTwist * 18 / 10; | 673 | primMesh.twistEnd = primShape.PathTwist * 18 / 10; |
572 | primMesh.taperX = pathScaleX; | 674 | primMesh.taperX = pathScaleX; |
573 | primMesh.taperY = pathScaleY; | 675 | primMesh.taperY = pathScaleY; |
574 | 676 | ||
575 | if (profileBegin < 0.0f || profileBegin >= profileEnd || profileEnd > 1.0f) | 677 | if (profileBegin < 0.0f || profileBegin >= profileEnd || profileEnd > 1.0f) |
576 | { | 678 | { |
577 | ReportPrimError("*** CORRUPT PRIM!! ***", primName, primMesh); | 679 | ReportPrimError("*** CORRUPT PRIM!! ***", primName, primMesh); |
578 | if (profileBegin < 0.0f) profileBegin = 0.0f; | 680 | if (profileBegin < 0.0f) profileBegin = 0.0f; |
579 | if (profileEnd > 1.0f) profileEnd = 1.0f; | 681 | if (profileEnd > 1.0f) profileEnd = 1.0f; |
580 | } | 682 | } |
581 | #if SPAM | 683 | #if SPAM |
582 | m_log.Debug("****** PrimMesh Parameters (Linear) ******\n" + primMesh.ParamsToDisplayString()); | 684 | m_log.Debug("****** PrimMesh Parameters (Linear) ******\n" + primMesh.ParamsToDisplayString()); |
583 | #endif | 685 | #endif |
584 | try | 686 | try |
585 | { | 687 | { |
586 | primMesh.ExtrudeLinear(); | 688 | primMesh.ExtrudeLinear(); |
587 | } | ||
588 | catch (Exception ex) | ||
589 | { | ||
590 | ReportPrimError("Extrusion failure: exception: " + ex.ToString(), primName, primMesh); | ||
591 | return null; | ||
592 | } | ||
593 | } | 689 | } |
594 | else | 690 | catch (Exception ex) |
595 | { | 691 | { |
596 | primMesh.holeSizeX = (200 - primShape.PathScaleX) * 0.01f; | 692 | ReportPrimError("Extrusion failure: exception: " + ex.ToString(), primName, primMesh); |
597 | primMesh.holeSizeY = (200 - primShape.PathScaleY) * 0.01f; | 693 | return false; |
598 | primMesh.radius = 0.01f * primShape.PathRadiusOffset; | 694 | } |
599 | primMesh.revolutions = 1.0f + 0.015f * primShape.PathRevolutions; | 695 | } |
600 | primMesh.skew = 0.01f * primShape.PathSkew; | 696 | else |
601 | primMesh.twistBegin = primShape.PathTwistBegin * 36 / 10; | 697 | { |
602 | primMesh.twistEnd = primShape.PathTwist * 36 / 10; | 698 | primMesh.holeSizeX = (200 - primShape.PathScaleX) * 0.01f; |
603 | primMesh.taperX = primShape.PathTaperX * 0.01f; | 699 | primMesh.holeSizeY = (200 - primShape.PathScaleY) * 0.01f; |
604 | primMesh.taperY = primShape.PathTaperY * 0.01f; | 700 | primMesh.radius = 0.01f * primShape.PathRadiusOffset; |
605 | 701 | primMesh.revolutions = 1.0f + 0.015f * primShape.PathRevolutions; | |
606 | if (profileBegin < 0.0f || profileBegin >= profileEnd || profileEnd > 1.0f) | 702 | primMesh.skew = 0.01f * primShape.PathSkew; |
607 | { | 703 | primMesh.twistBegin = primShape.PathTwistBegin * 36 / 10; |
608 | ReportPrimError("*** CORRUPT PRIM!! ***", primName, primMesh); | 704 | primMesh.twistEnd = primShape.PathTwist * 36 / 10; |
609 | if (profileBegin < 0.0f) profileBegin = 0.0f; | 705 | primMesh.taperX = primShape.PathTaperX * 0.01f; |
610 | if (profileEnd > 1.0f) profileEnd = 1.0f; | 706 | primMesh.taperY = primShape.PathTaperY * 0.01f; |
611 | } | 707 | |
708 | if (profileBegin < 0.0f || profileBegin >= profileEnd || profileEnd > 1.0f) | ||
709 | { | ||
710 | ReportPrimError("*** CORRUPT PRIM!! ***", primName, primMesh); | ||
711 | if (profileBegin < 0.0f) profileBegin = 0.0f; | ||
712 | if (profileEnd > 1.0f) profileEnd = 1.0f; | ||
713 | } | ||
612 | #if SPAM | 714 | #if SPAM |
613 | m_log.Debug("****** PrimMesh Parameters (Circular) ******\n" + primMesh.ParamsToDisplayString()); | 715 | m_log.Debug("****** PrimMesh Parameters (Circular) ******\n" + primMesh.ParamsToDisplayString()); |
614 | #endif | 716 | #endif |
615 | try | 717 | try |
616 | { | 718 | { |
617 | primMesh.ExtrudeCircular(); | 719 | primMesh.ExtrudeCircular(); |
618 | } | 720 | } |
619 | catch (Exception ex) | 721 | catch (Exception ex) |
620 | { | 722 | { |
621 | ReportPrimError("Extrusion failure: exception: " + ex.ToString(), primName, primMesh); | 723 | ReportPrimError("Extrusion failure: exception: " + ex.ToString(), primName, primMesh); |
622 | return null; | 724 | return false; |
623 | } | ||
624 | } | 725 | } |
625 | |||
626 | primMesh.DumpRaw(baseDir, primName, "primMesh"); | ||
627 | |||
628 | primMesh.Scale(size.X, size.Y, size.Z); | ||
629 | |||
630 | coords = primMesh.coords; | ||
631 | faces = primMesh.faces; | ||
632 | } | 726 | } |
633 | 727 | ||
634 | // Remove the reference to any JPEG2000 sculpt data so it can be GCed | 728 | primMesh.DumpRaw(baseDir, primName, "primMesh"); |
635 | primShape.SculptData = Utils.EmptyBytes; | ||
636 | 729 | ||
637 | int numCoords = coords.Count; | 730 | primMesh.Scale(size.X, size.Y, size.Z); |
638 | int numFaces = faces.Count; | ||
639 | 731 | ||
640 | // Create the list of vertices | 732 | coords = primMesh.coords; |
641 | List<Vertex> vertices = new List<Vertex>(); | 733 | faces = primMesh.faces; |
642 | for (int i = 0; i < numCoords; i++) | ||
643 | { | ||
644 | Coord c = coords[i]; | ||
645 | vertices.Add(new Vertex(c.X, c.Y, c.Z)); | ||
646 | } | ||
647 | |||
648 | Mesh mesh = new Mesh(); | ||
649 | // Add the corresponding triangles to the mesh | ||
650 | for (int i = 0; i < numFaces; i++) | ||
651 | { | ||
652 | Face f = faces[i]; | ||
653 | mesh.Add(new Triangle(vertices[f.v1], vertices[f.v2], vertices[f.v3])); | ||
654 | } | ||
655 | 734 | ||
656 | return mesh; | 735 | return true; |
657 | } | 736 | } |
658 | 737 | ||
659 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) | 738 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) |