aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/UbitOdePlugin/ODEMeshWorker.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Physics/UbitOdePlugin/ODEMeshWorker.cs')
-rw-r--r--OpenSim/Region/Physics/UbitOdePlugin/ODEMeshWorker.cs753
1 files changed, 753 insertions, 0 deletions
diff --git a/OpenSim/Region/Physics/UbitOdePlugin/ODEMeshWorker.cs b/OpenSim/Region/Physics/UbitOdePlugin/ODEMeshWorker.cs
new file mode 100644
index 0000000..9bf3667
--- /dev/null
+++ b/OpenSim/Region/Physics/UbitOdePlugin/ODEMeshWorker.cs
@@ -0,0 +1,753 @@
1/*
2 * AJLDuarte 2012
3 */
4
5using System;
6using System.Threading;
7using System.Collections.Generic;
8using System.IO;
9using System.Reflection;
10using System.Runtime.InteropServices;
11using System.Text;
12using OpenSim.Framework;
13using OpenSim.Region.Physics.Manager;
14using OdeAPI;
15using log4net;
16using Nini.Config;
17using OpenMetaverse;
18
19namespace OpenSim.Region.Physics.OdePlugin
20{
21 public class ODEMeshWorker
22 {
23 private ILog m_log;
24 private OdeScene m_scene;
25 private IMesher m_mesher;
26
27
28 public bool meshSculptedPrim = true;
29 public bool forceSimplePrimMeshing = false;
30 public float meshSculptLOD = 32;
31 public float MeshSculptphysicalLOD = 32;
32
33 private IntPtr m_workODEspace = IntPtr.Zero;
34
35 public ODEMeshWorker(OdeScene pScene, ILog pLog, IMesher pMesher, IntPtr pWorkSpace, IConfig pConfig)
36 {
37 m_scene = pScene;
38 m_log = pLog;
39 m_mesher = pMesher;
40 m_workODEspace = pWorkSpace;
41
42 if (pConfig != null)
43 {
44 forceSimplePrimMeshing = pConfig.GetBoolean("force_simple_prim_meshing", forceSimplePrimMeshing);
45 meshSculptedPrim = pConfig.GetBoolean("mesh_sculpted_prim", meshSculptedPrim);
46 meshSculptLOD = pConfig.GetFloat("mesh_lod", meshSculptLOD);
47 MeshSculptphysicalLOD = pConfig.GetFloat("mesh_physical_lod", MeshSculptphysicalLOD);
48 }
49 }
50
51 /// <summary>
52 /// Routine to figure out if we need to mesh this prim with our mesher
53 /// </summary>
54 /// <param name="pbs"></param>
55 /// <returns></returns>
56 public bool needsMeshing(PrimitiveBaseShape pbs)
57 {
58 // check sculpts or meshs
59 if (pbs.SculptEntry)
60 {
61 if (meshSculptedPrim)
62 return true;
63
64 if (pbs.SculptType == (byte)SculptType.Mesh) // always do meshs
65 return true;
66
67 return false;
68 }
69
70 if (forceSimplePrimMeshing)
71 return true;
72
73 // if it's a standard box or sphere with no cuts, hollows, twist or top shear, return false since ODE can use an internal representation for the prim
74
75 if ((pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
76 || (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1
77 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z))
78 {
79
80 if (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
81 && pbs.ProfileHollow == 0
82 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
83 && pbs.PathBegin == 0 && pbs.PathEnd == 0
84 && pbs.PathTaperX == 0 && pbs.PathTaperY == 0
85 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
86 && pbs.PathShearX == 0 && pbs.PathShearY == 0)
87 {
88 return false;
89 }
90 }
91
92 // following code doesn't give meshs to boxes and spheres ever
93 // and it's odd.. so for now just return true if asked to force meshs
94 // hopefully mesher will fail if doesn't suport so things still get basic boxes
95
96 int iPropertiesNotSupportedDefault = 0;
97
98 if (pbs.ProfileHollow != 0)
99 iPropertiesNotSupportedDefault++;
100
101 if ((pbs.PathBegin != 0) || pbs.PathEnd != 0)
102 iPropertiesNotSupportedDefault++;
103
104 if ((pbs.PathTwistBegin != 0) || (pbs.PathTwist != 0))
105 iPropertiesNotSupportedDefault++;
106
107 if ((pbs.ProfileBegin != 0) || pbs.ProfileEnd != 0)
108 iPropertiesNotSupportedDefault++;
109
110 if ((pbs.PathScaleX != 100) || (pbs.PathScaleY != 100))
111 iPropertiesNotSupportedDefault++;
112
113 if ((pbs.PathShearX != 0) || (pbs.PathShearY != 0))
114 iPropertiesNotSupportedDefault++;
115
116 if (pbs.ProfileShape == ProfileShape.Circle && pbs.PathCurve == (byte)Extrusion.Straight)
117 iPropertiesNotSupportedDefault++;
118
119 if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1 && (pbs.Scale.X != pbs.Scale.Y || pbs.Scale.Y != pbs.Scale.Z || pbs.Scale.Z != pbs.Scale.X))
120 iPropertiesNotSupportedDefault++;
121
122 if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1)
123 iPropertiesNotSupportedDefault++;
124
125 // test for torus
126 if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Square)
127 {
128 if (pbs.PathCurve == (byte)Extrusion.Curve1)
129 {
130 iPropertiesNotSupportedDefault++;
131 }
132 }
133 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Circle)
134 {
135 if (pbs.PathCurve == (byte)Extrusion.Straight)
136 {
137 iPropertiesNotSupportedDefault++;
138 }
139
140 // ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits
141 else if (pbs.PathCurve == (byte)Extrusion.Curve1)
142 {
143 iPropertiesNotSupportedDefault++;
144 }
145 }
146 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle)
147 {
148 if (pbs.PathCurve == (byte)Extrusion.Curve1 || pbs.PathCurve == (byte)Extrusion.Curve2)
149 {
150 iPropertiesNotSupportedDefault++;
151 }
152 }
153 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle)
154 {
155 if (pbs.PathCurve == (byte)Extrusion.Straight)
156 {
157 iPropertiesNotSupportedDefault++;
158 }
159 else if (pbs.PathCurve == (byte)Extrusion.Curve1)
160 {
161 iPropertiesNotSupportedDefault++;
162 }
163 }
164
165 if (iPropertiesNotSupportedDefault == 0)
166 {
167 return false;
168 }
169 return true;
170 }
171
172 public IMesh getMesh(PhysicsActor actor, PrimitiveBaseShape ppbs, Vector3 psize, byte pshapetype)
173 {
174 if (!(actor is OdePrim))
175 return null;
176
177 IMesh mesh = null;
178 PrimitiveBaseShape pbs = ppbs;
179 Vector3 size = psize;
180 byte shapetype = pshapetype;
181
182 if (needsMeshing(pbs))
183 {
184 bool convex;
185 int clod = (int)LevelOfDetail.High;
186 if (shapetype == 0)
187 convex = false;
188 else
189 {
190 convex = true;
191 if (pbs.SculptType != (byte)SculptType.Mesh)
192 clod = (int)LevelOfDetail.Low;
193 }
194 mesh = m_mesher.GetMesh(actor.Name, pbs, size, clod, true, convex);
195 if (mesh == null)
196 {
197 if (!pbs.SculptEntry)
198 return m_mesher.CreateMesh(actor.Name, pbs, size, clod, true, convex);
199
200 if (pbs.SculptTexture == UUID.Zero)
201 return null;
202
203 if (pbs.SculptType != (byte)SculptType.Mesh)
204 { // check for sculpt decoded image on cache)
205 if (File.Exists(System.IO.Path.Combine("j2kDecodeCache", "smap_" + pbs.SculptTexture.ToString())))
206 return m_mesher.CreateMesh(actor.Name, pbs, size, clod, true, convex);
207 }
208
209 if (pbs.SculptData != null && pbs.SculptData.Length > 0)
210 return m_mesher.CreateMesh(actor.Name, pbs, size, clod, true, convex);
211
212 ODEAssetRequest asr;
213 RequestAssetDelegate assetProvider = m_scene.RequestAssetMethod;
214 if (assetProvider != null)
215 asr = new ODEAssetRequest(this, assetProvider, actor, pbs, m_log);
216
217 return null;
218 }
219 }
220 return mesh;
221 }
222
223 private bool GetTriMeshGeo(ODEPhysRepData repData)
224 {
225 IntPtr vertices, indices;
226 IntPtr triMeshData = IntPtr.Zero;
227 IntPtr geo = IntPtr.Zero;
228 int vertexCount, indexCount;
229 int vertexStride, triStride;
230
231 PhysicsActor actor = repData.actor;
232
233 IMesh mesh = repData.mesh;
234
235 if (mesh == null)
236 {
237 mesh = getMesh(repData.actor, repData.pbs, repData.size, repData.shapetype);
238 }
239
240 if (mesh == null)
241 return false;
242
243 mesh.getVertexListAsPtrToFloatArray(out vertices, out vertexStride, out vertexCount); // Note, that vertices are fixed in unmanaged heap
244 mesh.getIndexListAsPtrToIntArray(out indices, out triStride, out indexCount); // Also fixed, needs release after usage
245
246 if (vertexCount == 0 || indexCount == 0)
247 {
248 m_log.WarnFormat("[PHYSICS]: Invalid mesh data on prim {0} mesh UUID {1}",
249 actor.Name, repData.pbs.SculptTexture.ToString());
250 mesh.releaseSourceMeshData();
251 return false;
252 }
253
254 repData.OBBOffset = mesh.GetCentroid();
255 repData.OBB = mesh.GetOBB();
256 repData.hasOBB = true;
257 repData.physCost = 0.0013f * (float)indexCount;
258
259 mesh.releaseSourceMeshData();
260
261 try
262 {
263 triMeshData = d.GeomTriMeshDataCreate();
264
265 d.GeomTriMeshDataBuildSimple(triMeshData, vertices, vertexStride, vertexCount, indices, indexCount, triStride);
266 d.GeomTriMeshDataPreprocess(triMeshData);
267
268 m_scene.waitForSpaceUnlock(m_workODEspace);
269 geo = d.CreateTriMesh(m_workODEspace, triMeshData, null, null, null);
270 }
271
272 catch (Exception e)
273 {
274 m_log.ErrorFormat("[PHYSICS]: SetGeom Mesh failed for {0} exception: {1}", actor.Name, e);
275 if (triMeshData != IntPtr.Zero)
276 {
277 d.GeomTriMeshDataDestroy(triMeshData);
278 repData.triMeshData = IntPtr.Zero;
279 }
280 repData.geo = IntPtr.Zero;
281 return false;
282 }
283
284 repData.geo = geo;
285 repData.triMeshData = triMeshData;
286 repData.curSpace = m_workODEspace;
287 return true;
288 }
289
290 public ODEPhysRepData CreateActorPhysRep(PhysicsActor actor, PrimitiveBaseShape pbs, IMesh pMesh, Vector3 size, byte shapetype)
291 {
292 ODEPhysRepData repData = new ODEPhysRepData();
293
294 repData.actor = actor;
295 repData.pbs = pbs;
296 repData.mesh = pMesh;
297 repData.size = size;
298 repData.shapetype = shapetype;
299
300 IntPtr geo = IntPtr.Zero;
301 bool hasMesh = false;
302 if (needsMeshing(pbs))
303 {
304 if (GetTriMeshGeo(repData))
305 hasMesh = true;
306 else
307 repData.canColide = false;
308 }
309
310 if (!hasMesh)
311 {
312 if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1
313 && size.X == size.Y && size.Y == size.Z)
314 { // it's a sphere
315 m_scene.waitForSpaceUnlock(m_workODEspace);
316 try
317 {
318 geo = d.CreateSphere(m_workODEspace, size.X * 0.5f);
319 }
320 catch (Exception e)
321 {
322 m_log.WarnFormat("[PHYSICS]: Create sphere failed: {0}", e);
323 return null;
324 }
325 }
326 else
327 {// do it as a box
328 m_scene.waitForSpaceUnlock(m_workODEspace);
329 try
330 {
331 //Console.WriteLine(" CreateGeom 4");
332 geo = d.CreateBox(m_workODEspace, size.X, size.Y, size.Z);
333 }
334 catch (Exception e)
335 {
336 m_log.Warn("[PHYSICS]: Create box failed: {0}", e);
337 return null;
338 }
339 }
340
341 repData.physCost = 0.1f;
342 repData.streamCost = 1.0f;
343 repData.geo = geo;
344 }
345
346 repData.curSpace = m_workODEspace;
347
348 CalcVolumeData(repData);
349
350 return repData;
351 }
352
353 private void CalculateBasicPrimVolume(ODEPhysRepData repData)
354 {
355 PrimitiveBaseShape _pbs = repData.pbs;
356 Vector3 _size = repData.size;
357
358 float volume = _size.X * _size.Y * _size.Z; // default
359 float tmp;
360
361 float hollowAmount = (float)_pbs.ProfileHollow * 2.0e-5f;
362 float hollowVolume = hollowAmount * hollowAmount;
363
364 switch (_pbs.ProfileShape)
365 {
366 case ProfileShape.Square:
367 // default box
368
369 if (_pbs.PathCurve == (byte)Extrusion.Straight)
370 {
371 if (hollowAmount > 0.0)
372 {
373 switch (_pbs.HollowShape)
374 {
375 case HollowShape.Square:
376 case HollowShape.Same:
377 break;
378
379 case HollowShape.Circle:
380
381 hollowVolume *= 0.78539816339f;
382 break;
383
384 case HollowShape.Triangle:
385
386 hollowVolume *= (0.5f * .5f);
387 break;
388
389 default:
390 hollowVolume = 0;
391 break;
392 }
393 volume *= (1.0f - hollowVolume);
394 }
395 }
396
397 else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
398 {
399 //a tube
400
401 volume *= 0.78539816339e-2f * (float)(200 - _pbs.PathScaleX);
402 tmp = 1.0f - 2.0e-2f * (float)(200 - _pbs.PathScaleY);
403 volume -= volume * tmp * tmp;
404
405 if (hollowAmount > 0.0)
406 {
407 hollowVolume *= hollowAmount;
408
409 switch (_pbs.HollowShape)
410 {
411 case HollowShape.Square:
412 case HollowShape.Same:
413 break;
414
415 case HollowShape.Circle:
416 hollowVolume *= 0.78539816339f;
417 break;
418
419 case HollowShape.Triangle:
420 hollowVolume *= 0.5f * 0.5f;
421 break;
422 default:
423 hollowVolume = 0;
424 break;
425 }
426 volume *= (1.0f - hollowVolume);
427 }
428 }
429
430 break;
431
432 case ProfileShape.Circle:
433
434 if (_pbs.PathCurve == (byte)Extrusion.Straight)
435 {
436 volume *= 0.78539816339f; // elipse base
437
438 if (hollowAmount > 0.0)
439 {
440 switch (_pbs.HollowShape)
441 {
442 case HollowShape.Same:
443 case HollowShape.Circle:
444 break;
445
446 case HollowShape.Square:
447 hollowVolume *= 0.5f * 2.5984480504799f;
448 break;
449
450 case HollowShape.Triangle:
451 hollowVolume *= .5f * 1.27323954473516f;
452 break;
453
454 default:
455 hollowVolume = 0;
456 break;
457 }
458 volume *= (1.0f - hollowVolume);
459 }
460 }
461
462 else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
463 {
464 volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - _pbs.PathScaleX);
465 tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY);
466 volume *= (1.0f - tmp * tmp);
467
468 if (hollowAmount > 0.0)
469 {
470
471 // calculate the hollow volume by it's shape compared to the prim shape
472 hollowVolume *= hollowAmount;
473
474 switch (_pbs.HollowShape)
475 {
476 case HollowShape.Same:
477 case HollowShape.Circle:
478 break;
479
480 case HollowShape.Square:
481 hollowVolume *= 0.5f * 2.5984480504799f;
482 break;
483
484 case HollowShape.Triangle:
485 hollowVolume *= .5f * 1.27323954473516f;
486 break;
487
488 default:
489 hollowVolume = 0;
490 break;
491 }
492 volume *= (1.0f - hollowVolume);
493 }
494 }
495 break;
496
497 case ProfileShape.HalfCircle:
498 if (_pbs.PathCurve == (byte)Extrusion.Curve1)
499 {
500 volume *= 0.5236f;
501
502 if (hollowAmount > 0.0)
503 {
504 hollowVolume *= hollowAmount;
505
506 switch (_pbs.HollowShape)
507 {
508 case HollowShape.Circle:
509 case HollowShape.Triangle: // diference in sl is minor and odd
510 case HollowShape.Same:
511 break;
512
513 case HollowShape.Square:
514 hollowVolume *= 0.909f;
515 break;
516
517 // case HollowShape.Triangle:
518 // hollowVolume *= .827f;
519 // break;
520 default:
521 hollowVolume = 0;
522 break;
523 }
524 volume *= (1.0f - hollowVolume);
525 }
526
527 }
528 break;
529
530 case ProfileShape.EquilateralTriangle:
531
532 if (_pbs.PathCurve == (byte)Extrusion.Straight)
533 {
534 volume *= 0.32475953f;
535
536 if (hollowAmount > 0.0)
537 {
538
539 // calculate the hollow volume by it's shape compared to the prim shape
540 switch (_pbs.HollowShape)
541 {
542 case HollowShape.Same:
543 case HollowShape.Triangle:
544 hollowVolume *= .25f;
545 break;
546
547 case HollowShape.Square:
548 hollowVolume *= 0.499849f * 3.07920140172638f;
549 break;
550
551 case HollowShape.Circle:
552 // Hollow shape is a perfect cyllinder in respect to the cube's scale
553 // Cyllinder hollow volume calculation
554
555 hollowVolume *= 0.1963495f * 3.07920140172638f;
556 break;
557
558 default:
559 hollowVolume = 0;
560 break;
561 }
562 volume *= (1.0f - hollowVolume);
563 }
564 }
565 else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
566 {
567 volume *= 0.32475953f;
568 volume *= 0.01f * (float)(200 - _pbs.PathScaleX);
569 tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY);
570 volume *= (1.0f - tmp * tmp);
571
572 if (hollowAmount > 0.0)
573 {
574
575 hollowVolume *= hollowAmount;
576
577 switch (_pbs.HollowShape)
578 {
579 case HollowShape.Same:
580 case HollowShape.Triangle:
581 hollowVolume *= .25f;
582 break;
583
584 case HollowShape.Square:
585 hollowVolume *= 0.499849f * 3.07920140172638f;
586 break;
587
588 case HollowShape.Circle:
589
590 hollowVolume *= 0.1963495f * 3.07920140172638f;
591 break;
592
593 default:
594 hollowVolume = 0;
595 break;
596 }
597 volume *= (1.0f - hollowVolume);
598 }
599 }
600 break;
601
602 default:
603 break;
604 }
605
606 float taperX1;
607 float taperY1;
608 float taperX;
609 float taperY;
610 float pathBegin;
611 float pathEnd;
612 float profileBegin;
613 float profileEnd;
614
615 if (_pbs.PathCurve == (byte)Extrusion.Straight || _pbs.PathCurve == (byte)Extrusion.Flexible)
616 {
617 taperX1 = _pbs.PathScaleX * 0.01f;
618 if (taperX1 > 1.0f)
619 taperX1 = 2.0f - taperX1;
620 taperX = 1.0f - taperX1;
621
622 taperY1 = _pbs.PathScaleY * 0.01f;
623 if (taperY1 > 1.0f)
624 taperY1 = 2.0f - taperY1;
625 taperY = 1.0f - taperY1;
626 }
627 else
628 {
629 taperX = _pbs.PathTaperX * 0.01f;
630 if (taperX < 0.0f)
631 taperX = -taperX;
632 taperX1 = 1.0f - taperX;
633
634 taperY = _pbs.PathTaperY * 0.01f;
635 if (taperY < 0.0f)
636 taperY = -taperY;
637 taperY1 = 1.0f - taperY;
638 }
639
640 volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY);
641
642 pathBegin = (float)_pbs.PathBegin * 2.0e-5f;
643 pathEnd = 1.0f - (float)_pbs.PathEnd * 2.0e-5f;
644 volume *= (pathEnd - pathBegin);
645
646 // this is crude aproximation
647 profileBegin = (float)_pbs.ProfileBegin * 2.0e-5f;
648 profileEnd = 1.0f - (float)_pbs.ProfileEnd * 2.0e-5f;
649 volume *= (profileEnd - profileBegin);
650
651 repData.volume = volume;
652 }
653
654 private void CalcVolumeData(ODEPhysRepData repData)
655 {
656 float volume;
657 Vector3 OBB = repData.size;
658 Vector3 OBBoffset;
659 IntPtr geo = repData.geo;
660
661 if (geo == IntPtr.Zero || repData.triMeshData == IntPtr.Zero)
662 {
663 OBB.X *= 0.5f;
664 OBB.Y *= 0.5f;
665 OBB.Z *= 0.5f;
666
667 repData.OBB = OBB;
668 repData.OBBOffset = Vector3.Zero;
669 }
670 else if (!repData.hasOBB) // should this happen?
671 {
672 d.AABB AABB;
673 d.GeomGetAABB(geo, out AABB); // get the AABB from engine geom
674
675 OBB.X = (AABB.MaxX - AABB.MinX) * 0.5f;
676 OBB.Y = (AABB.MaxY - AABB.MinY) * 0.5f;
677 OBB.Z = (AABB.MaxZ - AABB.MinZ) * 0.5f;
678 repData.OBB = OBB;
679 OBBoffset.X = (AABB.MaxX + AABB.MinX) * 0.5f;
680 OBBoffset.Y = (AABB.MaxY + AABB.MinY) * 0.5f;
681 OBBoffset.Z = (AABB.MaxZ + AABB.MinZ) * 0.5f;
682 repData.OBBOffset = Vector3.Zero;
683 }
684
685 // also its own inertia and mass
686 // keep using basic shape mass for now
687 CalculateBasicPrimVolume(repData);
688
689 if (repData.hasOBB)
690 {
691 OBB = repData.OBB;
692 float pc = repData.physCost;
693 float psf = OBB.X * (OBB.Y + OBB.Z) + OBB.Y * OBB.Z;
694 psf *= 1.33f * .2f;
695
696 pc *= psf;
697 if (pc < 0.1f)
698 pc = 0.1f;
699
700 repData.physCost = pc;
701 }
702 else
703 repData.physCost = 0.1f;
704 }
705 }
706
707 public class ODEAssetRequest
708 {
709 PhysicsActor m_actor;
710 ODEMeshWorker m_worker;
711 PrimitiveBaseShape m_pbs;
712 private ILog m_log;
713
714 public ODEAssetRequest(ODEMeshWorker pWorker, RequestAssetDelegate provider,
715 PhysicsActor pActor, PrimitiveBaseShape ppbs, ILog plog)
716 {
717 m_actor = pActor;
718 m_worker = pWorker;
719 m_pbs = ppbs;
720 m_log = plog;
721
722 if (provider == null)
723 return;
724
725 UUID assetID = m_pbs.SculptTexture;
726 if (assetID == UUID.Zero)
727 return;
728
729 provider(assetID, ODEassetReceived);
730 }
731
732 void ODEassetReceived(AssetBase asset)
733 {
734 if (m_actor != null && m_pbs != null)
735 {
736 if (asset != null)
737 {
738 if (asset.Data != null && asset.Data.Length > 0)
739 {
740 m_pbs.SculptData = asset.Data;
741 m_actor.Shape = m_pbs;
742 }
743 else
744 m_log.WarnFormat("[PHYSICS]: asset provider returned invalid mesh data for prim {0} asset UUID {1}.",
745 m_actor.Name, asset.ID.ToString());
746 }
747 else
748 m_log.WarnFormat("[PHYSICS]: asset provider returned null asset fo mesh of prim {0}.",
749 m_actor.Name);
750 }
751 }
752 }
753} \ No newline at end of file