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