diff options
author | Robert Adams | 2015-09-08 06:15:46 -0700 |
---|---|---|
committer | Robert Adams | 2015-09-08 06:15:46 -0700 |
commit | 4dd17c4117ea413fb0c4418511956cb3abfe258c (patch) | |
tree | 6f31a583610f8bf074d1f0b4e7ab6ccef37dec9a /OpenSim/Region/PhysicsModules/UbitOdePlugin/ODEMeshWorker.cs | |
parent | Merge of ubitworkvarnew with opensim/master as of 20150905. (diff) | |
download | opensim-SC-4dd17c4117ea413fb0c4418511956cb3abfe258c.zip opensim-SC-4dd17c4117ea413fb0c4418511956cb3abfe258c.tar.gz opensim-SC-4dd17c4117ea413fb0c4418511956cb3abfe258c.tar.bz2 opensim-SC-4dd17c4117ea413fb0c4418511956cb3abfe258c.tar.xz |
More 'everything is a module' merging.
Have most of UbitOde converted.
There are compile errors in OpenSimBase as the new modules stuff is not all there.
Removed ChOdePlugin as it's connection to OdePlugin was tangled.
Diffstat (limited to 'OpenSim/Region/PhysicsModules/UbitOdePlugin/ODEMeshWorker.cs')
-rw-r--r-- | OpenSim/Region/PhysicsModules/UbitOdePlugin/ODEMeshWorker.cs | 933 |
1 files changed, 933 insertions, 0 deletions
diff --git a/OpenSim/Region/PhysicsModules/UbitOdePlugin/ODEMeshWorker.cs b/OpenSim/Region/PhysicsModules/UbitOdePlugin/ODEMeshWorker.cs new file mode 100644 index 0000000..918c9db --- /dev/null +++ b/OpenSim/Region/PhysicsModules/UbitOdePlugin/ODEMeshWorker.cs | |||
@@ -0,0 +1,933 @@ | |||
1 | /* | ||
2 | * AJLDuarte 2012 | ||
3 | */ | ||
4 | |||
5 | using System; | ||
6 | using System.Threading; | ||
7 | using System.Collections.Generic; | ||
8 | using System.IO; | ||
9 | using System.Reflection; | ||
10 | using System.Runtime.InteropServices; | ||
11 | using System.Text; | ||
12 | using OpenSim.Framework; | ||
13 | using OpenSim.Region.PhysicsModules.SharedBase; | ||
14 | using OdeAPI; | ||
15 | using log4net; | ||
16 | using Nini.Config; | ||
17 | using OpenMetaverse; | ||
18 | |||
19 | namespace OpenSim.Region.PhysicsModules.OdePlugin | ||
20 | { | ||
21 | public enum MeshState : byte | ||
22 | { | ||
23 | noNeed = 0, | ||
24 | |||
25 | loadingAsset = 1, | ||
26 | |||
27 | AssetOK = 0x0f, // 00001111 | ||
28 | |||
29 | NeedMask = 0x30, // 00110000 | ||
30 | needMesh = 0x10, // 00010000 | ||
31 | needAsset = 0x20, // 00100000 | ||
32 | |||
33 | FailMask = 0xC0, // 11000000 | ||
34 | AssetFailed = 0x40, // 01000000 | ||
35 | MeshFailed = 0x80, // 10000000 | ||
36 | |||
37 | MeshNoColide = FailMask | needAsset | ||
38 | } | ||
39 | |||
40 | public enum meshWorkerCmnds : byte | ||
41 | { | ||
42 | nop = 0, | ||
43 | addnew, | ||
44 | changefull, | ||
45 | changesize, | ||
46 | changeshapetype, | ||
47 | getmesh, | ||
48 | } | ||
49 | |||
50 | public class ODEPhysRepData | ||
51 | { | ||
52 | public PhysicsActor actor; | ||
53 | public PrimitiveBaseShape pbs; | ||
54 | public IMesh mesh; | ||
55 | |||
56 | public Vector3 size; | ||
57 | public Vector3 OBB; | ||
58 | public Vector3 OBBOffset; | ||
59 | |||
60 | public float volume; | ||
61 | |||
62 | public byte shapetype; | ||
63 | public bool hasOBB; | ||
64 | public bool hasMeshVolume; | ||
65 | public MeshState meshState; | ||
66 | public UUID? assetID; | ||
67 | public meshWorkerCmnds comand; | ||
68 | } | ||
69 | |||
70 | public class ODEMeshWorker | ||
71 | { | ||
72 | |||
73 | private ILog m_log; | ||
74 | private OdeScene m_scene; | ||
75 | private IMesher m_mesher; | ||
76 | |||
77 | public bool meshSculptedPrim = true; | ||
78 | public bool forceSimplePrimMeshing = false; | ||
79 | public float meshSculptLOD = 32; | ||
80 | public float MeshSculptphysicalLOD = 32; | ||
81 | |||
82 | |||
83 | private OpenSim.Framework.BlockingQueue<ODEPhysRepData> createqueue = new OpenSim.Framework.BlockingQueue<ODEPhysRepData>(); | ||
84 | private bool m_running; | ||
85 | |||
86 | private Thread m_thread; | ||
87 | |||
88 | public ODEMeshWorker(OdeScene pScene, ILog pLog, IMesher pMesher, IConfig pConfig) | ||
89 | { | ||
90 | m_scene = pScene; | ||
91 | m_log = pLog; | ||
92 | m_mesher = pMesher; | ||
93 | |||
94 | if (pConfig != null) | ||
95 | { | ||
96 | forceSimplePrimMeshing = pConfig.GetBoolean("force_simple_prim_meshing", forceSimplePrimMeshing); | ||
97 | meshSculptedPrim = pConfig.GetBoolean("mesh_sculpted_prim", meshSculptedPrim); | ||
98 | meshSculptLOD = pConfig.GetFloat("mesh_lod", meshSculptLOD); | ||
99 | MeshSculptphysicalLOD = pConfig.GetFloat("mesh_physical_lod", MeshSculptphysicalLOD); | ||
100 | } | ||
101 | m_running = true; | ||
102 | m_thread = new Thread(DoWork); | ||
103 | m_thread.Name = "OdeMeshWorker"; | ||
104 | m_thread.Start(); | ||
105 | } | ||
106 | |||
107 | private void DoWork() | ||
108 | { | ||
109 | m_mesher.ExpireFileCache(); | ||
110 | |||
111 | while(m_running) | ||
112 | { | ||
113 | ODEPhysRepData nextRep = createqueue.Dequeue(); | ||
114 | if(!m_running) | ||
115 | return; | ||
116 | if (nextRep == null) | ||
117 | continue; | ||
118 | if (m_scene.haveActor(nextRep.actor)) | ||
119 | { | ||
120 | switch (nextRep.comand) | ||
121 | { | ||
122 | case meshWorkerCmnds.changefull: | ||
123 | case meshWorkerCmnds.changeshapetype: | ||
124 | case meshWorkerCmnds.changesize: | ||
125 | GetMesh(nextRep); | ||
126 | if (CreateActorPhysRep(nextRep) && m_scene.haveActor(nextRep.actor)) | ||
127 | m_scene.AddChange(nextRep.actor, changes.PhysRepData, nextRep); | ||
128 | break; | ||
129 | case meshWorkerCmnds.getmesh: | ||
130 | DoRepDataGetMesh(nextRep); | ||
131 | break; | ||
132 | } | ||
133 | } | ||
134 | } | ||
135 | } | ||
136 | |||
137 | public void Stop() | ||
138 | { | ||
139 | try | ||
140 | { | ||
141 | m_thread.Abort(); | ||
142 | createqueue.Clear(); | ||
143 | } | ||
144 | catch | ||
145 | { | ||
146 | } | ||
147 | } | ||
148 | |||
149 | public void ChangeActorPhysRep(PhysicsActor actor, PrimitiveBaseShape pbs, | ||
150 | Vector3 size, byte shapetype) | ||
151 | { | ||
152 | ODEPhysRepData repData = new ODEPhysRepData(); | ||
153 | repData.actor = actor; | ||
154 | repData.pbs = pbs; | ||
155 | repData.size = size; | ||
156 | repData.shapetype = shapetype; | ||
157 | |||
158 | CheckMesh(repData); | ||
159 | CalcVolumeData(repData); | ||
160 | m_scene.AddChange(actor, changes.PhysRepData, repData); | ||
161 | return; | ||
162 | } | ||
163 | |||
164 | public ODEPhysRepData NewActorPhysRep(PhysicsActor actor, PrimitiveBaseShape pbs, | ||
165 | Vector3 size, byte shapetype) | ||
166 | { | ||
167 | ODEPhysRepData repData = new ODEPhysRepData(); | ||
168 | repData.actor = actor; | ||
169 | repData.pbs = pbs; | ||
170 | repData.size = size; | ||
171 | repData.shapetype = shapetype; | ||
172 | |||
173 | CheckMesh(repData); | ||
174 | CalcVolumeData(repData); | ||
175 | m_scene.AddChange(actor, changes.AddPhysRep, repData); | ||
176 | return repData; | ||
177 | } | ||
178 | |||
179 | public void RequestMesh(ODEPhysRepData repData) | ||
180 | { | ||
181 | repData.mesh = null; | ||
182 | |||
183 | if (repData.meshState == MeshState.needAsset) | ||
184 | { | ||
185 | PrimitiveBaseShape pbs = repData.pbs; | ||
186 | |||
187 | // check if we got outdated | ||
188 | |||
189 | if (!pbs.SculptEntry || pbs.SculptTexture == UUID.Zero) | ||
190 | { | ||
191 | repData.meshState = MeshState.noNeed; | ||
192 | return; | ||
193 | } | ||
194 | |||
195 | repData.assetID = pbs.SculptTexture; | ||
196 | repData.meshState = MeshState.loadingAsset; | ||
197 | |||
198 | repData.comand = meshWorkerCmnds.getmesh; | ||
199 | createqueue.Enqueue(repData); | ||
200 | } | ||
201 | } | ||
202 | |||
203 | // creates and prepares a mesh to use and calls parameters estimation | ||
204 | public bool CreateActorPhysRep(ODEPhysRepData repData) | ||
205 | { | ||
206 | IMesh mesh = repData.mesh; | ||
207 | |||
208 | if (mesh != null) | ||
209 | { | ||
210 | IntPtr vertices, indices; | ||
211 | int vertexCount, indexCount; | ||
212 | int vertexStride, triStride; | ||
213 | |||
214 | mesh.getVertexListAsPtrToFloatArray(out vertices, out vertexStride, out vertexCount); | ||
215 | mesh.getIndexListAsPtrToIntArray(out indices, out triStride, out indexCount); | ||
216 | |||
217 | if (vertexCount == 0 || indexCount == 0) | ||
218 | { | ||
219 | m_log.WarnFormat("[PHYSICS]: Invalid mesh data on prim {0} mesh UUID {1}", | ||
220 | repData.actor.Name, repData.pbs.SculptTexture.ToString()); | ||
221 | repData.meshState = MeshState.MeshFailed; | ||
222 | repData.hasOBB = false; | ||
223 | repData.mesh = null; | ||
224 | m_scene.mesher.ReleaseMesh(mesh); | ||
225 | } | ||
226 | else | ||
227 | { | ||
228 | repData.OBBOffset = mesh.GetCentroid(); | ||
229 | repData.OBB = mesh.GetOBB(); | ||
230 | repData.hasOBB = true; | ||
231 | mesh.releaseSourceMeshData(); | ||
232 | } | ||
233 | } | ||
234 | CalcVolumeData(repData); | ||
235 | return true; | ||
236 | } | ||
237 | |||
238 | public void AssetLoaded(ODEPhysRepData repData) | ||
239 | { | ||
240 | if (m_scene.haveActor(repData.actor)) | ||
241 | { | ||
242 | if (needsMeshing(repData.pbs)) // no need for pbs now? | ||
243 | { | ||
244 | repData.comand = meshWorkerCmnds.changefull; | ||
245 | createqueue.Enqueue(repData); | ||
246 | } | ||
247 | } | ||
248 | else | ||
249 | repData.pbs.SculptData = Utils.EmptyBytes; | ||
250 | } | ||
251 | |||
252 | public void DoRepDataGetMesh(ODEPhysRepData repData) | ||
253 | { | ||
254 | if (!repData.pbs.SculptEntry) | ||
255 | return; | ||
256 | |||
257 | if (repData.meshState != MeshState.loadingAsset) | ||
258 | return; | ||
259 | |||
260 | if (repData.assetID == null || repData.assetID == UUID.Zero) | ||
261 | return; | ||
262 | |||
263 | if (repData.assetID != repData.pbs.SculptTexture) | ||
264 | return; | ||
265 | |||
266 | // check if it is in cache | ||
267 | GetMesh(repData); | ||
268 | if (repData.meshState != MeshState.needAsset) | ||
269 | { | ||
270 | CreateActorPhysRep(repData); | ||
271 | m_scene.AddChange(repData.actor, changes.PhysRepData, repData); | ||
272 | return; | ||
273 | } | ||
274 | |||
275 | RequestAssetDelegate assetProvider = m_scene.RequestAssetMethod; | ||
276 | if (assetProvider == null) | ||
277 | return; | ||
278 | ODEAssetRequest asr = new ODEAssetRequest(this, assetProvider, repData, m_log); | ||
279 | } | ||
280 | |||
281 | |||
282 | /// <summary> | ||
283 | /// Routine to figure out if we need to mesh this prim with our mesher | ||
284 | /// </summary> | ||
285 | /// <param name="pbs"></param> | ||
286 | /// <returns></returns> | ||
287 | public bool needsMeshing(PrimitiveBaseShape pbs) | ||
288 | { | ||
289 | // check sculpts or meshs | ||
290 | if (pbs.SculptEntry) | ||
291 | { | ||
292 | if (meshSculptedPrim) | ||
293 | return true; | ||
294 | |||
295 | if (pbs.SculptType == (byte)SculptType.Mesh) // always do meshs | ||
296 | return true; | ||
297 | |||
298 | return false; | ||
299 | } | ||
300 | |||
301 | if (forceSimplePrimMeshing) | ||
302 | return true; | ||
303 | |||
304 | // 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 | ||
305 | |||
306 | if ((pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) | ||
307 | || (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1 | ||
308 | && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z)) | ||
309 | { | ||
310 | |||
311 | if (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 | ||
312 | && pbs.ProfileHollow == 0 | ||
313 | && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0 | ||
314 | && pbs.PathBegin == 0 && pbs.PathEnd == 0 | ||
315 | && pbs.PathTaperX == 0 && pbs.PathTaperY == 0 | ||
316 | && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 | ||
317 | && pbs.PathShearX == 0 && pbs.PathShearY == 0) | ||
318 | { | ||
319 | return false; | ||
320 | } | ||
321 | } | ||
322 | |||
323 | // following code doesn't give meshs to boxes and spheres ever | ||
324 | // and it's odd.. so for now just return true if asked to force meshs | ||
325 | // hopefully mesher will fail if doesn't suport so things still get basic boxes | ||
326 | |||
327 | int iPropertiesNotSupportedDefault = 0; | ||
328 | |||
329 | if (pbs.ProfileHollow != 0) | ||
330 | iPropertiesNotSupportedDefault++; | ||
331 | |||
332 | if ((pbs.PathBegin != 0) || pbs.PathEnd != 0) | ||
333 | iPropertiesNotSupportedDefault++; | ||
334 | |||
335 | if ((pbs.PathTwistBegin != 0) || (pbs.PathTwist != 0)) | ||
336 | iPropertiesNotSupportedDefault++; | ||
337 | |||
338 | if ((pbs.ProfileBegin != 0) || pbs.ProfileEnd != 0) | ||
339 | iPropertiesNotSupportedDefault++; | ||
340 | |||
341 | if ((pbs.PathScaleX != 100) || (pbs.PathScaleY != 100)) | ||
342 | iPropertiesNotSupportedDefault++; | ||
343 | |||
344 | if ((pbs.PathShearX != 0) || (pbs.PathShearY != 0)) | ||
345 | iPropertiesNotSupportedDefault++; | ||
346 | |||
347 | if (pbs.ProfileShape == ProfileShape.Circle && pbs.PathCurve == (byte)Extrusion.Straight) | ||
348 | iPropertiesNotSupportedDefault++; | ||
349 | |||
350 | 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)) | ||
351 | iPropertiesNotSupportedDefault++; | ||
352 | |||
353 | if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) | ||
354 | iPropertiesNotSupportedDefault++; | ||
355 | |||
356 | // test for torus | ||
357 | if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Square) | ||
358 | { | ||
359 | if (pbs.PathCurve == (byte)Extrusion.Curve1) | ||
360 | { | ||
361 | iPropertiesNotSupportedDefault++; | ||
362 | } | ||
363 | } | ||
364 | else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Circle) | ||
365 | { | ||
366 | if (pbs.PathCurve == (byte)Extrusion.Straight) | ||
367 | { | ||
368 | iPropertiesNotSupportedDefault++; | ||
369 | } | ||
370 | |||
371 | // ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits | ||
372 | else if (pbs.PathCurve == (byte)Extrusion.Curve1) | ||
373 | { | ||
374 | iPropertiesNotSupportedDefault++; | ||
375 | } | ||
376 | } | ||
377 | else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle) | ||
378 | { | ||
379 | if (pbs.PathCurve == (byte)Extrusion.Curve1 || pbs.PathCurve == (byte)Extrusion.Curve2) | ||
380 | { | ||
381 | iPropertiesNotSupportedDefault++; | ||
382 | } | ||
383 | } | ||
384 | else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle) | ||
385 | { | ||
386 | if (pbs.PathCurve == (byte)Extrusion.Straight) | ||
387 | { | ||
388 | iPropertiesNotSupportedDefault++; | ||
389 | } | ||
390 | else if (pbs.PathCurve == (byte)Extrusion.Curve1) | ||
391 | { | ||
392 | iPropertiesNotSupportedDefault++; | ||
393 | } | ||
394 | } | ||
395 | |||
396 | if (iPropertiesNotSupportedDefault == 0) | ||
397 | { | ||
398 | return false; | ||
399 | } | ||
400 | return true; | ||
401 | } | ||
402 | |||
403 | // see if we need a mesh and if so if we have a cached one | ||
404 | // called with a new repData | ||
405 | public void CheckMesh(ODEPhysRepData repData) | ||
406 | { | ||
407 | PhysicsActor actor = repData.actor; | ||
408 | PrimitiveBaseShape pbs = repData.pbs; | ||
409 | |||
410 | if (!needsMeshing(pbs)) | ||
411 | { | ||
412 | repData.meshState = MeshState.noNeed; | ||
413 | return; | ||
414 | } | ||
415 | |||
416 | IMesh mesh = null; | ||
417 | |||
418 | Vector3 size = repData.size; | ||
419 | byte shapetype = repData.shapetype; | ||
420 | |||
421 | bool convex; | ||
422 | |||
423 | int clod = (int)LevelOfDetail.High; | ||
424 | if (shapetype == 0) | ||
425 | convex = false; | ||
426 | else | ||
427 | { | ||
428 | convex = true; | ||
429 | if (pbs.SculptType != (byte)SculptType.Mesh) | ||
430 | clod = (int)LevelOfDetail.Low; | ||
431 | } | ||
432 | |||
433 | mesh = m_mesher.GetMesh(actor.Name, pbs, size, clod, true, convex); | ||
434 | |||
435 | if (mesh == null) | ||
436 | { | ||
437 | if (pbs.SculptEntry) | ||
438 | { | ||
439 | if (pbs.SculptTexture != null && pbs.SculptTexture != UUID.Zero) | ||
440 | { | ||
441 | repData.assetID = pbs.SculptTexture; | ||
442 | repData.meshState = MeshState.needAsset; | ||
443 | } | ||
444 | else | ||
445 | repData.meshState = MeshState.MeshFailed; | ||
446 | |||
447 | return; | ||
448 | } | ||
449 | else | ||
450 | { | ||
451 | repData.meshState = MeshState.needMesh; | ||
452 | mesh = m_mesher.CreateMesh(actor.Name, pbs, size, clod, true, convex, true); | ||
453 | if (mesh == null) | ||
454 | { | ||
455 | repData.meshState = MeshState.MeshFailed; | ||
456 | return; | ||
457 | } | ||
458 | } | ||
459 | } | ||
460 | |||
461 | repData.meshState = MeshState.AssetOK; | ||
462 | repData.mesh = mesh; | ||
463 | |||
464 | if (pbs.SculptEntry) | ||
465 | { | ||
466 | repData.assetID = pbs.SculptTexture; | ||
467 | } | ||
468 | |||
469 | pbs.SculptData = Utils.EmptyBytes; | ||
470 | return ; | ||
471 | } | ||
472 | |||
473 | public void GetMesh(ODEPhysRepData repData) | ||
474 | { | ||
475 | PhysicsActor actor = repData.actor; | ||
476 | |||
477 | PrimitiveBaseShape pbs = repData.pbs; | ||
478 | |||
479 | repData.mesh = null; | ||
480 | repData.hasOBB = false; | ||
481 | |||
482 | if (!needsMeshing(pbs)) | ||
483 | { | ||
484 | repData.meshState = MeshState.noNeed; | ||
485 | return; | ||
486 | } | ||
487 | |||
488 | if (repData.meshState == MeshState.MeshFailed) | ||
489 | return; | ||
490 | |||
491 | if (pbs.SculptEntry) | ||
492 | { | ||
493 | if (repData.meshState == MeshState.AssetFailed) | ||
494 | { | ||
495 | if (pbs.SculptTexture == repData.assetID) | ||
496 | return; | ||
497 | } | ||
498 | } | ||
499 | |||
500 | repData.meshState = MeshState.noNeed; | ||
501 | |||
502 | IMesh mesh = null; | ||
503 | Vector3 size = repData.size; | ||
504 | byte shapetype = repData.shapetype; | ||
505 | |||
506 | bool convex; | ||
507 | int clod = (int)LevelOfDetail.High; | ||
508 | if (shapetype == 0) | ||
509 | convex = false; | ||
510 | else | ||
511 | { | ||
512 | convex = true; | ||
513 | if (pbs.SculptType != (byte)SculptType.Mesh) | ||
514 | clod = (int)LevelOfDetail.Low; | ||
515 | } | ||
516 | |||
517 | mesh = m_mesher.CreateMesh(actor.Name, pbs, size, clod, true, convex, true); | ||
518 | |||
519 | if (mesh == null) | ||
520 | { | ||
521 | if (pbs.SculptEntry) | ||
522 | { | ||
523 | if (pbs.SculptTexture == UUID.Zero) | ||
524 | return; | ||
525 | |||
526 | repData.assetID = pbs.SculptTexture; | ||
527 | |||
528 | if (pbs.SculptData == null || pbs.SculptData.Length == 0) | ||
529 | { | ||
530 | repData.meshState = MeshState.needAsset; | ||
531 | return; | ||
532 | } | ||
533 | } | ||
534 | } | ||
535 | |||
536 | repData.mesh = mesh; | ||
537 | repData.pbs.SculptData = Utils.EmptyBytes; | ||
538 | |||
539 | if (mesh == null) | ||
540 | { | ||
541 | if (pbs.SculptEntry) | ||
542 | repData.meshState = MeshState.AssetFailed; | ||
543 | else | ||
544 | repData.meshState = MeshState.MeshFailed; | ||
545 | |||
546 | return; | ||
547 | } | ||
548 | |||
549 | repData.meshState = MeshState.AssetOK; | ||
550 | |||
551 | return; | ||
552 | } | ||
553 | |||
554 | private void CalculateBasicPrimVolume(ODEPhysRepData repData) | ||
555 | { | ||
556 | PrimitiveBaseShape _pbs = repData.pbs; | ||
557 | Vector3 _size = repData.size; | ||
558 | |||
559 | float volume = _size.X * _size.Y * _size.Z; // default | ||
560 | float tmp; | ||
561 | |||
562 | float hollowAmount = (float)_pbs.ProfileHollow * 2.0e-5f; | ||
563 | float hollowVolume = hollowAmount * hollowAmount; | ||
564 | |||
565 | switch (_pbs.ProfileShape) | ||
566 | { | ||
567 | case ProfileShape.Square: | ||
568 | // default box | ||
569 | |||
570 | if (_pbs.PathCurve == (byte)Extrusion.Straight) | ||
571 | { | ||
572 | if (hollowAmount > 0.0) | ||
573 | { | ||
574 | switch (_pbs.HollowShape) | ||
575 | { | ||
576 | case HollowShape.Square: | ||
577 | case HollowShape.Same: | ||
578 | break; | ||
579 | |||
580 | case HollowShape.Circle: | ||
581 | |||
582 | hollowVolume *= 0.78539816339f; | ||
583 | break; | ||
584 | |||
585 | case HollowShape.Triangle: | ||
586 | |||
587 | hollowVolume *= (0.5f * .5f); | ||
588 | break; | ||
589 | |||
590 | default: | ||
591 | hollowVolume = 0; | ||
592 | break; | ||
593 | } | ||
594 | volume *= (1.0f - hollowVolume); | ||
595 | } | ||
596 | } | ||
597 | |||
598 | else if (_pbs.PathCurve == (byte)Extrusion.Curve1) | ||
599 | { | ||
600 | //a tube | ||
601 | |||
602 | volume *= 0.78539816339e-2f * (float)(200 - _pbs.PathScaleX); | ||
603 | tmp = 1.0f - 2.0e-2f * (float)(200 - _pbs.PathScaleY); | ||
604 | volume -= volume * tmp * tmp; | ||
605 | |||
606 | if (hollowAmount > 0.0) | ||
607 | { | ||
608 | hollowVolume *= hollowAmount; | ||
609 | |||
610 | switch (_pbs.HollowShape) | ||
611 | { | ||
612 | case HollowShape.Square: | ||
613 | case HollowShape.Same: | ||
614 | break; | ||
615 | |||
616 | case HollowShape.Circle: | ||
617 | hollowVolume *= 0.78539816339f; | ||
618 | break; | ||
619 | |||
620 | case HollowShape.Triangle: | ||
621 | hollowVolume *= 0.5f * 0.5f; | ||
622 | break; | ||
623 | default: | ||
624 | hollowVolume = 0; | ||
625 | break; | ||
626 | } | ||
627 | volume *= (1.0f - hollowVolume); | ||
628 | } | ||
629 | } | ||
630 | |||
631 | break; | ||
632 | |||
633 | case ProfileShape.Circle: | ||
634 | |||
635 | if (_pbs.PathCurve == (byte)Extrusion.Straight) | ||
636 | { | ||
637 | volume *= 0.78539816339f; // elipse base | ||
638 | |||
639 | if (hollowAmount > 0.0) | ||
640 | { | ||
641 | switch (_pbs.HollowShape) | ||
642 | { | ||
643 | case HollowShape.Same: | ||
644 | case HollowShape.Circle: | ||
645 | break; | ||
646 | |||
647 | case HollowShape.Square: | ||
648 | hollowVolume *= 0.5f * 2.5984480504799f; | ||
649 | break; | ||
650 | |||
651 | case HollowShape.Triangle: | ||
652 | hollowVolume *= .5f * 1.27323954473516f; | ||
653 | break; | ||
654 | |||
655 | default: | ||
656 | hollowVolume = 0; | ||
657 | break; | ||
658 | } | ||
659 | volume *= (1.0f - hollowVolume); | ||
660 | } | ||
661 | } | ||
662 | |||
663 | else if (_pbs.PathCurve == (byte)Extrusion.Curve1) | ||
664 | { | ||
665 | volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - _pbs.PathScaleX); | ||
666 | tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY); | ||
667 | volume *= (1.0f - tmp * tmp); | ||
668 | |||
669 | if (hollowAmount > 0.0) | ||
670 | { | ||
671 | |||
672 | // calculate the hollow volume by it's shape compared to the prim shape | ||
673 | hollowVolume *= hollowAmount; | ||
674 | |||
675 | switch (_pbs.HollowShape) | ||
676 | { | ||
677 | case HollowShape.Same: | ||
678 | case HollowShape.Circle: | ||
679 | break; | ||
680 | |||
681 | case HollowShape.Square: | ||
682 | hollowVolume *= 0.5f * 2.5984480504799f; | ||
683 | break; | ||
684 | |||
685 | case HollowShape.Triangle: | ||
686 | hollowVolume *= .5f * 1.27323954473516f; | ||
687 | break; | ||
688 | |||
689 | default: | ||
690 | hollowVolume = 0; | ||
691 | break; | ||
692 | } | ||
693 | volume *= (1.0f - hollowVolume); | ||
694 | } | ||
695 | } | ||
696 | break; | ||
697 | |||
698 | case ProfileShape.HalfCircle: | ||
699 | if (_pbs.PathCurve == (byte)Extrusion.Curve1) | ||
700 | { | ||
701 | volume *= 0.5236f; | ||
702 | |||
703 | if (hollowAmount > 0.0) | ||
704 | { | ||
705 | hollowVolume *= hollowAmount; | ||
706 | |||
707 | switch (_pbs.HollowShape) | ||
708 | { | ||
709 | case HollowShape.Circle: | ||
710 | case HollowShape.Triangle: // diference in sl is minor and odd | ||
711 | case HollowShape.Same: | ||
712 | break; | ||
713 | |||
714 | case HollowShape.Square: | ||
715 | hollowVolume *= 0.909f; | ||
716 | break; | ||
717 | |||
718 | // case HollowShape.Triangle: | ||
719 | // hollowVolume *= .827f; | ||
720 | // break; | ||
721 | default: | ||
722 | hollowVolume = 0; | ||
723 | break; | ||
724 | } | ||
725 | volume *= (1.0f - hollowVolume); | ||
726 | } | ||
727 | |||
728 | } | ||
729 | break; | ||
730 | |||
731 | case ProfileShape.EquilateralTriangle: | ||
732 | |||
733 | if (_pbs.PathCurve == (byte)Extrusion.Straight) | ||
734 | { | ||
735 | volume *= 0.32475953f; | ||
736 | |||
737 | if (hollowAmount > 0.0) | ||
738 | { | ||
739 | |||
740 | // calculate the hollow volume by it's shape compared to the prim shape | ||
741 | switch (_pbs.HollowShape) | ||
742 | { | ||
743 | case HollowShape.Same: | ||
744 | case HollowShape.Triangle: | ||
745 | hollowVolume *= .25f; | ||
746 | break; | ||
747 | |||
748 | case HollowShape.Square: | ||
749 | hollowVolume *= 0.499849f * 3.07920140172638f; | ||
750 | break; | ||
751 | |||
752 | case HollowShape.Circle: | ||
753 | // Hollow shape is a perfect cyllinder in respect to the cube's scale | ||
754 | // Cyllinder hollow volume calculation | ||
755 | |||
756 | hollowVolume *= 0.1963495f * 3.07920140172638f; | ||
757 | break; | ||
758 | |||
759 | default: | ||
760 | hollowVolume = 0; | ||
761 | break; | ||
762 | } | ||
763 | volume *= (1.0f - hollowVolume); | ||
764 | } | ||
765 | } | ||
766 | else if (_pbs.PathCurve == (byte)Extrusion.Curve1) | ||
767 | { | ||
768 | volume *= 0.32475953f; | ||
769 | volume *= 0.01f * (float)(200 - _pbs.PathScaleX); | ||
770 | tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY); | ||
771 | volume *= (1.0f - tmp * tmp); | ||
772 | |||
773 | if (hollowAmount > 0.0) | ||
774 | { | ||
775 | |||
776 | hollowVolume *= hollowAmount; | ||
777 | |||
778 | switch (_pbs.HollowShape) | ||
779 | { | ||
780 | case HollowShape.Same: | ||
781 | case HollowShape.Triangle: | ||
782 | hollowVolume *= .25f; | ||
783 | break; | ||
784 | |||
785 | case HollowShape.Square: | ||
786 | hollowVolume *= 0.499849f * 3.07920140172638f; | ||
787 | break; | ||
788 | |||
789 | case HollowShape.Circle: | ||
790 | |||
791 | hollowVolume *= 0.1963495f * 3.07920140172638f; | ||
792 | break; | ||
793 | |||
794 | default: | ||
795 | hollowVolume = 0; | ||
796 | break; | ||
797 | } | ||
798 | volume *= (1.0f - hollowVolume); | ||
799 | } | ||
800 | } | ||
801 | break; | ||
802 | |||
803 | default: | ||
804 | break; | ||
805 | } | ||
806 | |||
807 | float taperX1; | ||
808 | float taperY1; | ||
809 | float taperX; | ||
810 | float taperY; | ||
811 | float pathBegin; | ||
812 | float pathEnd; | ||
813 | float profileBegin; | ||
814 | float profileEnd; | ||
815 | |||
816 | if (_pbs.PathCurve == (byte)Extrusion.Straight || _pbs.PathCurve == (byte)Extrusion.Flexible) | ||
817 | { | ||
818 | taperX1 = _pbs.PathScaleX * 0.01f; | ||
819 | if (taperX1 > 1.0f) | ||
820 | taperX1 = 2.0f - taperX1; | ||
821 | taperX = 1.0f - taperX1; | ||
822 | |||
823 | taperY1 = _pbs.PathScaleY * 0.01f; | ||
824 | if (taperY1 > 1.0f) | ||
825 | taperY1 = 2.0f - taperY1; | ||
826 | taperY = 1.0f - taperY1; | ||
827 | } | ||
828 | else | ||
829 | { | ||
830 | taperX = _pbs.PathTaperX * 0.01f; | ||
831 | if (taperX < 0.0f) | ||
832 | taperX = -taperX; | ||
833 | taperX1 = 1.0f - taperX; | ||
834 | |||
835 | taperY = _pbs.PathTaperY * 0.01f; | ||
836 | if (taperY < 0.0f) | ||
837 | taperY = -taperY; | ||
838 | taperY1 = 1.0f - taperY; | ||
839 | } | ||
840 | |||
841 | volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY); | ||
842 | |||
843 | pathBegin = (float)_pbs.PathBegin * 2.0e-5f; | ||
844 | pathEnd = 1.0f - (float)_pbs.PathEnd * 2.0e-5f; | ||
845 | volume *= (pathEnd - pathBegin); | ||
846 | |||
847 | // this is crude aproximation | ||
848 | profileBegin = (float)_pbs.ProfileBegin * 2.0e-5f; | ||
849 | profileEnd = 1.0f - (float)_pbs.ProfileEnd * 2.0e-5f; | ||
850 | volume *= (profileEnd - profileBegin); | ||
851 | |||
852 | repData.volume = volume; | ||
853 | } | ||
854 | |||
855 | private void CalcVolumeData(ODEPhysRepData repData) | ||
856 | { | ||
857 | if (repData.hasOBB) | ||
858 | { | ||
859 | Vector3 OBB = repData.OBB; | ||
860 | } | ||
861 | else | ||
862 | { | ||
863 | Vector3 OBB = repData.size; | ||
864 | OBB.X *= 0.5f; | ||
865 | OBB.Y *= 0.5f; | ||
866 | OBB.Z *= 0.5f; | ||
867 | |||
868 | repData.OBB = OBB; | ||
869 | repData.OBBOffset = Vector3.Zero; | ||
870 | } | ||
871 | |||
872 | CalculateBasicPrimVolume(repData); | ||
873 | } | ||
874 | } | ||
875 | |||
876 | public class ODEAssetRequest | ||
877 | { | ||
878 | ODEMeshWorker m_worker; | ||
879 | private ILog m_log; | ||
880 | ODEPhysRepData repData; | ||
881 | |||
882 | public ODEAssetRequest(ODEMeshWorker pWorker, RequestAssetDelegate provider, | ||
883 | ODEPhysRepData pRepData, ILog plog) | ||
884 | { | ||
885 | m_worker = pWorker; | ||
886 | m_log = plog; | ||
887 | repData = pRepData; | ||
888 | |||
889 | repData.meshState = MeshState.AssetFailed; | ||
890 | if (provider == null) | ||
891 | return; | ||
892 | |||
893 | if (repData.assetID == null) | ||
894 | return; | ||
895 | |||
896 | UUID assetID = (UUID) repData.assetID; | ||
897 | if (assetID == UUID.Zero) | ||
898 | return; | ||
899 | |||
900 | repData.meshState = MeshState.loadingAsset; | ||
901 | provider(assetID, ODEassetReceived); | ||
902 | } | ||
903 | |||
904 | void ODEassetReceived(AssetBase asset) | ||
905 | { | ||
906 | repData.meshState = MeshState.AssetFailed; | ||
907 | if (asset != null) | ||
908 | { | ||
909 | if (asset.Data != null && asset.Data.Length > 0) | ||
910 | { | ||
911 | repData.meshState = MeshState.noNeed; | ||
912 | |||
913 | if (!repData.pbs.SculptEntry) | ||
914 | return; | ||
915 | if (repData.pbs.SculptTexture != repData.assetID) | ||
916 | return; | ||
917 | |||
918 | // repData.pbs.SculptData = new byte[asset.Data.Length]; | ||
919 | // asset.Data.CopyTo(repData.pbs.SculptData,0); | ||
920 | repData.pbs.SculptData = asset.Data; | ||
921 | repData.meshState = MeshState.AssetOK; | ||
922 | m_worker.AssetLoaded(repData); | ||
923 | } | ||
924 | else | ||
925 | m_log.WarnFormat("[PHYSICS]: asset provider returned invalid mesh data for prim {0} asset UUID {1}.", | ||
926 | repData.actor.Name, asset.ID.ToString()); | ||
927 | } | ||
928 | else | ||
929 | m_log.WarnFormat("[PHYSICS]: asset provider returned null asset fo mesh of prim {0}.", | ||
930 | repData.actor.Name); | ||
931 | } | ||
932 | } | ||
933 | } | ||