aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/Physics/Meshing/Meshmerizer.cs1761
1 files changed, 131 insertions, 1630 deletions
diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
index 6955aa0..a65d0f4 100644
--- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
+++ b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
@@ -31,6 +31,9 @@ using System.Collections.Generic;
31using OpenSim.Framework; 31using OpenSim.Framework;
32using OpenSim.Region.Physics.Manager; 32using OpenSim.Region.Physics.Manager;
33using OpenMetaverse; 33using OpenMetaverse;
34using OpenMetaverse.Imaging;
35using System.Drawing;
36using System.Drawing.Imaging;
34using PrimMesher; 37using PrimMesher;
35 38
36namespace OpenSim.Region.Physics.Meshing 39namespace OpenSim.Region.Physics.Meshing
@@ -54,8 +57,6 @@ namespace OpenSim.Region.Physics.Meshing
54 57
55 public class Meshmerizer : IMesher 58 public class Meshmerizer : IMesher
56 { 59 {
57 private bool usePrimMesher = true;
58
59 //private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 60 //private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
60 61
61 // Setting baseDir to a path will enable the dumping of raw files 62 // Setting baseDir to a path will enable the dumping of raw files
@@ -65,277 +66,9 @@ namespace OpenSim.Region.Physics.Meshing
65#else 66#else
66 private const string baseDir = null; //"rawFiles"; 67 private const string baseDir = null; //"rawFiles";
67#endif 68#endif
68 private const float DEG_TO_RAD = 0.01745329238f;
69 69
70 private float minSizeForComplexMesh = 0.2f; // prims with all dimensions smaller than this will have a bounding box mesh 70 private float minSizeForComplexMesh = 0.2f; // prims with all dimensions smaller than this will have a bounding box mesh
71 71
72// private static void IntersectionParameterPD(PhysicsVector p1, PhysicsVector r1, PhysicsVector p2,
73// PhysicsVector r2, ref float lambda, ref float mu)
74// {
75 // p1, p2, points on the straight
76 // r1, r2, directional vectors of the straight. Not necessarily of length 1!
77 // note, that l, m can be scaled such, that the range 0..1 is mapped to the area between two points,
78 // thus allowing to decide whether an intersection is between two points
79
80// float r1x = r1.X;
81// float r1y = r1.Y;
82// float r2x = r2.X;
83// float r2y = r2.Y;
84//
85// float denom = r1y * r2x - r1x * r2y;
86//
87// if (denom == 0.0)
88// {
89// lambda = Single.NaN;
90// mu = Single.NaN;
91// return;
92// }
93//
94// float p1x = p1.X;
95// float p1y = p1.Y;
96// float p2x = p2.X;
97// float p2y = p2.Y;
98// lambda = (-p2x * r2y + p1x * r2y + (p2y - p1y) * r2x) / denom;
99// mu = (-p2x * r1y + p1x * r1y + (p2y - p1y) * r1x) / denom;
100// }
101
102 private static List<Triangle> FindInfluencedTriangles(List<Triangle> triangles, Vertex v)
103 {
104 List<Triangle> influenced = new List<Triangle>();
105 foreach (Triangle t in triangles)
106 {
107 if (t.isInCircle(v.X, v.Y))
108 {
109 influenced.Add(t);
110 }
111 }
112 return influenced;
113 }
114
115 private static void InsertVertices(List<Vertex> vertices, int usedForSeed, List<Triangle> triangles)
116 {
117 // This is a variant of the delaunay algorithm
118 // each time a new vertex is inserted, all triangles that are influenced by it are deleted
119 // and replaced by new ones including the new vertex
120 // It is not very time efficient but easy to implement.
121
122 int iCurrentVertex;
123 int iMaxVertex = vertices.Count;
124 for (iCurrentVertex = usedForSeed; iCurrentVertex < iMaxVertex; iCurrentVertex++)
125 {
126 // Background: A triangle mesh fulfills the delaunay condition if (iff!)
127 // each circumlocutory circle (i.e. the circle that touches all three corners)
128 // of each triangle is empty of other vertices.
129 // Obviously a single (seeding) triangle fulfills this condition.
130 // If we now add one vertex, we need to reconstruct all triangles, that
131 // do not fulfill this condition with respect to the new triangle
132
133 // Find the triangles that are influenced by the new vertex
134 Vertex v = vertices[iCurrentVertex];
135 if (v == null)
136 continue; // Null is polygon stop marker. Ignore it
137 List<Triangle> influencedTriangles = FindInfluencedTriangles(triangles, v);
138
139 List<Simplex> simplices = new List<Simplex>();
140
141 // Reconstruction phase. First step, dissolve each triangle into it's simplices,
142 // i.e. it's "border lines"
143 // Goal is to find "inner" borders and delete them, while the hull gets conserved.
144 // Inner borders are special in the way that they always come twice, which is how we detect them
145 foreach (Triangle t in influencedTriangles)
146 {
147 List<Simplex> newSimplices = t.GetSimplices();
148 simplices.AddRange(newSimplices);
149 triangles.Remove(t);
150 }
151 // Now sort the simplices. That will make identical ones reside side by side in the list
152 simplices.Sort();
153
154 // Look for duplicate simplices here.
155 // Remember, they are directly side by side in the list right now,
156 // So we only check directly neighbours
157 int iSimplex;
158 List<Simplex> innerSimplices = new List<Simplex>();
159 for (iSimplex = 1; iSimplex < simplices.Count; iSimplex++) // Startindex=1, so we can refer backwards
160 {
161 if (simplices[iSimplex - 1].CompareTo(simplices[iSimplex]) == 0)
162 {
163 innerSimplices.Add(simplices[iSimplex - 1]);
164 innerSimplices.Add(simplices[iSimplex]);
165 }
166 }
167
168 foreach (Simplex s in innerSimplices)
169 {
170 simplices.Remove(s);
171 }
172
173 // each simplex still in the list belongs to the hull of the region in question
174 // The new vertex (yes, we still deal with verices here :-)) forms a triangle
175 // with each of these simplices. Build the new triangles and add them to the list
176 foreach (Simplex s in simplices)
177 {
178 Triangle t = new Triangle(s.v1, s.v2, vertices[iCurrentVertex]);
179 if (!t.isDegraded())
180 {
181 triangles.Add(t);
182 }
183 }
184 }
185 }
186
187 private static SimpleHull BuildHoleHull(PrimitiveBaseShape pbs, ProfileShape pshape, HollowShape hshape, UInt16 hollowFactor)
188 {
189 // Tackle HollowShape.Same
190 float fhollowFactor = (float)hollowFactor;
191
192 switch (pshape)
193 {
194 case ProfileShape.Square:
195 if (hshape == HollowShape.Same)
196 hshape= HollowShape.Square;
197 break;
198 case ProfileShape.EquilateralTriangle:
199 fhollowFactor = ((float)hollowFactor / 1.9f);
200 if (hshape == HollowShape.Same)
201 {
202 hshape = HollowShape.Triangle;
203 }
204
205 break;
206
207 case ProfileShape.HalfCircle:
208 case ProfileShape.Circle:
209 if (pbs.PathCurve == (byte)Extrusion.Straight)
210 {
211 if (hshape == HollowShape.Same)
212 {
213 hshape = HollowShape.Circle;
214 }
215 }
216 break;
217
218
219 default:
220 if (hshape == HollowShape.Same)
221 hshape= HollowShape.Square;
222 break;
223 }
224
225
226 SimpleHull holeHull = null;
227
228 if (hshape == HollowShape.Square)
229 {
230 float hollowFactorF = (float)fhollowFactor / (float)50000;
231 Vertex IMM;
232 Vertex IPM;
233 Vertex IPP;
234 Vertex IMP;
235
236 if (pshape == ProfileShape.Circle)
237 { // square cutout in cylinder is 45 degress rotated
238 IMM = new Vertex(0.0f, -0.707f * hollowFactorF, 0.0f);
239 IPM = new Vertex(0.707f * hollowFactorF, 0.0f, 0.0f);
240 IPP = new Vertex(0.0f, 0.707f * hollowFactorF, 0.0f);
241 IMP = new Vertex(-0.707f * hollowFactorF, 0.0f, 0.0f);
242 }
243 else if (pshape == ProfileShape.EquilateralTriangle)
244 {
245 IMM = new Vertex(0.0f, -0.667f * hollowFactorF, 0.0f);
246 IPM = new Vertex(0.667f * hollowFactorF, 0.0f, 0.0f);
247 IPP = new Vertex(0.0f, 0.667f * hollowFactorF, 0.0f);
248 IMP = new Vertex(-0.667f * hollowFactorF, 0.0f, 0.0f);
249 }
250 else
251 {
252 IMM = new Vertex(-0.5f * hollowFactorF, -0.5f * hollowFactorF, 0.0f);
253 IPM = new Vertex(+0.5f * hollowFactorF, -0.5f * hollowFactorF, 0.0f);
254 IPP = new Vertex(+0.5f * hollowFactorF, +0.5f * hollowFactorF, 0.0f);
255 IMP = new Vertex(-0.5f * hollowFactorF, +0.5f * hollowFactorF, 0.0f);
256 }
257
258 holeHull = new SimpleHull();
259
260 holeHull.AddVertex(IMM);
261 holeHull.AddVertex(IMP);
262 holeHull.AddVertex(IPP);
263 holeHull.AddVertex(IPM);
264 }
265 //if (hshape == HollowShape.Circle && pbs.PathCurve == (byte)Extrusion.Straight)
266 if (hshape == HollowShape.Circle)
267 {
268 float hollowFactorF = (float)fhollowFactor / (float)50000;
269
270 //Counter clockwise around the quadrants
271 holeHull = new SimpleHull();
272
273 holeHull.AddVertex(new Vertex(0.353553f * hollowFactorF, 0.353553f * hollowFactorF, 0.0f)); // 45 degrees
274 holeHull.AddVertex(new Vertex(0.433013f * hollowFactorF, 0.250000f * hollowFactorF, 0.0f)); // 30 degrees
275 holeHull.AddVertex(new Vertex(0.482963f * hollowFactorF, 0.129410f * hollowFactorF, 0.0f)); // 15 degrees
276 holeHull.AddVertex(new Vertex(0.500000f * hollowFactorF, 0.000000f * hollowFactorF, 0.0f)); // 0 degrees
277 holeHull.AddVertex(new Vertex(0.482963f * hollowFactorF, -0.129410f * hollowFactorF, 0.0f)); // 345 degrees
278 holeHull.AddVertex(new Vertex(0.433013f * hollowFactorF, -0.250000f * hollowFactorF, 0.0f)); // 330 degrees
279 holeHull.AddVertex(new Vertex(0.353553f * hollowFactorF, -0.353553f * hollowFactorF, 0.0f)); // 315 degrees
280 holeHull.AddVertex(new Vertex(0.250000f * hollowFactorF, -0.433013f * hollowFactorF, 0.0f)); // 300 degrees
281 holeHull.AddVertex(new Vertex(0.129410f * hollowFactorF, -0.482963f * hollowFactorF, 0.0f)); // 285 degrees
282 holeHull.AddVertex(new Vertex(0.000000f * hollowFactorF, -0.500000f * hollowFactorF, 0.0f)); // 270 degrees
283 holeHull.AddVertex(new Vertex(-0.129410f * hollowFactorF, -0.482963f * hollowFactorF, 0.0f)); // 255 degrees
284 holeHull.AddVertex(new Vertex(-0.250000f * hollowFactorF, -0.433013f * hollowFactorF, 0.0f)); // 240 degrees
285 holeHull.AddVertex(new Vertex(-0.353553f * hollowFactorF, -0.353553f * hollowFactorF, 0.0f)); // 225 degrees
286 holeHull.AddVertex(new Vertex(-0.433013f * hollowFactorF, -0.250000f * hollowFactorF, 0.0f)); // 210 degrees
287 holeHull.AddVertex(new Vertex(-0.482963f * hollowFactorF, -0.129410f * hollowFactorF, 0.0f)); // 195 degrees
288 holeHull.AddVertex(new Vertex(-0.500000f * hollowFactorF, 0.000000f * hollowFactorF, 0.0f)); // 180 degrees
289 holeHull.AddVertex(new Vertex(-0.482963f * hollowFactorF, 0.129410f * hollowFactorF, 0.0f)); // 165 degrees
290 holeHull.AddVertex(new Vertex(-0.433013f * hollowFactorF, 0.250000f * hollowFactorF, 0.0f)); // 150 degrees
291 holeHull.AddVertex(new Vertex(-0.353553f * hollowFactorF, 0.353553f * hollowFactorF, 0.0f)); // 135 degrees
292 holeHull.AddVertex(new Vertex(-0.250000f * hollowFactorF, 0.433013f * hollowFactorF, 0.0f)); // 120 degrees
293 holeHull.AddVertex(new Vertex(-0.129410f * hollowFactorF, 0.482963f * hollowFactorF, 0.0f)); // 105 degrees
294 holeHull.AddVertex(new Vertex(0.000000f * hollowFactorF, 0.500000f * hollowFactorF, 0.0f)); // 90 degrees
295 holeHull.AddVertex(new Vertex(0.129410f * hollowFactorF, 0.482963f * hollowFactorF, 0.0f)); // 75 degrees
296 holeHull.AddVertex(new Vertex(0.250000f * hollowFactorF, 0.433013f * hollowFactorF, 0.0f)); // 60 degrees
297 holeHull.AddVertex(new Vertex(0.353553f * hollowFactorF, 0.353553f * hollowFactorF, 0.0f)); // 45 degrees
298
299 }
300 if (hshape == HollowShape.Triangle)
301 {
302 float hollowFactorF = (float)fhollowFactor / (float)50000;
303 Vertex IMM;
304 Vertex IPM;
305 Vertex IPP;
306
307 if (pshape == ProfileShape.Square)
308 {
309 // corner points are at 345, 105, and 225 degrees for the triangle within a box
310
311 //IMM = new Vertex(((float)Math.Cos(345.0 * DEG_TO_RAD) * 0.5f) * hollowFactorF, ((float)Math.Sin(345.0 * DEG_TO_RAD) * 0.5f) * hollowFactorF, 0.0f);
312 //IPM = new Vertex(((float)Math.Cos(105.0 * DEG_TO_RAD) * 0.5f) * hollowFactorF, ((float)Math.Sin(105.0 * DEG_TO_RAD) * 0.5f) * hollowFactorF, 0.0f);
313 //IPP = new Vertex(((float)Math.Cos(225.0 * DEG_TO_RAD) * 0.5f) * hollowFactorF, ((float)Math.Sin(225.0 * DEG_TO_RAD) * 0.5f) * hollowFactorF, 0.0f);
314
315 // hard coded here for speed, the equations are in the commented out lines above
316 IMM = new Vertex(0.48296f * hollowFactorF, -0.12941f * hollowFactorF, 0.0f);
317 IPM = new Vertex(-0.12941f * hollowFactorF, 0.48296f * hollowFactorF, 0.0f);
318 IPP = new Vertex(-0.35355f * hollowFactorF, -0.35355f * hollowFactorF, 0.0f);
319 }
320 else
321 {
322 IMM = new Vertex(-0.25f * hollowFactorF, -0.45f * hollowFactorF, 0.0f);
323 IPM = new Vertex(+0.5f * hollowFactorF, +0f * hollowFactorF, 0.0f);
324 IPP = new Vertex(-0.25f * hollowFactorF, +0.45f * hollowFactorF, 0.0f);
325 }
326
327 holeHull = new SimpleHull();
328
329 holeHull.AddVertex(IMM);
330 holeHull.AddVertex(IPP);
331 holeHull.AddVertex(IPM);
332
333 }
334
335 return holeHull;
336
337
338 }
339 72
340 /// <summary> 73 /// <summary>
341 /// creates a simple box mesh of the specified size 74 /// creates a simple box mesh of the specified size
@@ -420,1364 +153,197 @@ namespace OpenSim.Region.Physics.Meshing
420 return CreateSimpleBoxMesh(minX, maxX, minY, maxY, minZ, maxZ); 153 return CreateSimpleBoxMesh(minX, maxX, minY, maxY, minZ, maxZ);
421 } 154 }
422 155
423 156 private void ReportPrimError(string message, string primName, PrimMesh primMesh)
424 private static Mesh CreateBoxMesh(String primName, PrimitiveBaseShape primShape, PhysicsVector size)
425 // Builds the z (+ and -) surfaces of a box shaped prim
426 {
427 UInt16 hollowFactor = primShape.ProfileHollow;
428 UInt16 profileBegin = primShape.ProfileBegin;
429 UInt16 profileEnd = primShape.ProfileEnd;
430 UInt16 taperX = primShape.PathScaleX;
431 UInt16 taperY = primShape.PathScaleY;
432 UInt16 pathShearX = primShape.PathShearX;
433 UInt16 pathShearY = primShape.PathShearY;
434
435#if SPAM
436 reportPrimParams("[BOX] " + primName, primShape);
437#endif
438
439 // Procedure: This is based on the fact that the upper (plus) and lower (minus) Z-surface
440 // of a block are basically the same
441 // They may be warped differently but the shape is identical
442 // So we only create one surface as a model and derive both plus and minus surface of the block from it
443 // This is done in a model space where the block spans from -.5 to +.5 in X and Y
444 // The mapping to Scene space is done later during the "extrusion" phase
445
446 // Base
447 Vertex MM = new Vertex(-0.5f, -0.5f, 0.0f);
448 Vertex PM = new Vertex(+0.5f, -0.5f, 0.0f);
449 Vertex PP = new Vertex(+0.5f, +0.5f, 0.0f);
450 Vertex MP = new Vertex(-0.5f, +0.5f, 0.0f);
451
452 SimpleHull outerHull = new SimpleHull();
453
454 outerHull.AddVertex(PP);
455 outerHull.AddVertex(MP);
456 outerHull.AddVertex(MM);
457 outerHull.AddVertex(PM);
458
459 // Deal with cuts now
460 if ((profileBegin != 0) || (profileEnd != 0))
461 {
462 double fProfileBeginAngle = profileBegin / 50000.0*360.0;
463 // In degree, for easier debugging and understanding
464 fProfileBeginAngle -= (90.0 + 45.0); // for some reasons, the SL client counts from the corner -X/-Y
465 double fProfileEndAngle = 360.0 - profileEnd / 50000.0*360.0; // Pathend comes as complement to 1.0
466 fProfileEndAngle -= (90.0 + 45.0);
467
468 // avoid some problem angles until the hull subtraction routine is fixed
469 if ((fProfileBeginAngle + 45.0f) % 90.0f == 0.0f)
470 fProfileBeginAngle += 5.0f;
471 if ((fProfileEndAngle + 45.0f) % 90.0f == 0.0f)
472 fProfileEndAngle -= 5.0f;
473 if (fProfileBeginAngle % 90.0f == 0.0f)
474 fProfileBeginAngle += 1.0f;
475 if (fProfileEndAngle % 90.0f == 0.0f)
476 fProfileEndAngle -= 1.0f;
477
478 if (fProfileBeginAngle < fProfileEndAngle)
479 fProfileEndAngle -= 360.0;
480
481#if SPAM
482 Console.WriteLine("Meshmerizer: fProfileBeginAngle: " + fProfileBeginAngle.ToString() + " fProfileEndAngle: " + fProfileEndAngle.ToString());
483#endif
484
485 // Note, that we don't want to cut out a triangle, even if this is a
486 // good approximation for small cuts. Indeed we want to cut out an arc
487 // and we approximate this arc by a polygon chain
488 // Also note, that these vectors are of length 1.0 and thus their endpoints lay outside the model space
489 // So it can easily be subtracted from the outer hull
490 int iSteps = (int) (((fProfileBeginAngle - fProfileEndAngle)/45.0) + .5);
491 // how many steps do we need with approximately 45 degree
492 double dStepWidth = (fProfileBeginAngle - fProfileEndAngle)/iSteps;
493
494 Vertex origin = new Vertex(0.0f, 0.0f, 0.0f);
495
496 // Note the sequence of vertices here. It's important to have the other rotational sense than in outerHull
497 SimpleHull cutHull = new SimpleHull();
498 cutHull.AddVertex(origin);
499 for (int i = 0; i < iSteps; i++)
500 {
501 double angle = fProfileBeginAngle - i*dStepWidth; // we count against the angle orientation!!!!
502 Vertex v = Vertex.FromAngle(angle*Math.PI/180.0);
503 cutHull.AddVertex(v);
504 }
505 Vertex legEnd = Vertex.FromAngle(fProfileEndAngle*Math.PI/180.0);
506 // Calculated separately to avoid errors
507 cutHull.AddVertex(legEnd);
508
509 //m_log.DebugFormat("Starting cutting of the hollow shape from the prim {1}", 0, primName);
510 SimpleHull cuttedHull = SimpleHull.SubtractHull(outerHull, cutHull);
511
512 outerHull = cuttedHull;
513 }
514
515 // Deal with the hole here
516 if (hollowFactor > 0)
517 {
518 if (hollowFactor < 1000)
519 hollowFactor = 1000; // some sane minimum for our beloved SimpleHull routines
520
521 SimpleHull holeHull = BuildHoleHull(primShape, primShape.ProfileShape, primShape.HollowShape, hollowFactor);
522 if (holeHull != null)
523 {
524 SimpleHull hollowedHull = SimpleHull.SubtractHull(outerHull, holeHull);
525
526 outerHull = hollowedHull;
527 }
528 }
529
530 Mesh m = new Mesh();
531
532 Vertex Seed1 = new Vertex(0.0f, -10.0f, 0.0f);
533 Vertex Seed2 = new Vertex(-10.0f, 10.0f, 0.0f);
534 Vertex Seed3 = new Vertex(10.0f, 10.0f, 0.0f);
535
536 m.Add(Seed1);
537 m.Add(Seed2);
538 m.Add(Seed3);
539
540 m.Add(new Triangle(Seed1, Seed2, Seed3));
541 m.Add(outerHull.getVertices());
542
543 InsertVertices(m.vertices, 3, m.triangles);
544 m.DumpRaw(baseDir, primName, "Proto first Mesh");
545
546 m.Remove(Seed1);
547 m.Remove(Seed2);
548 m.Remove(Seed3);
549 m.DumpRaw(baseDir, primName, "Proto seeds removed");
550
551 m.RemoveTrianglesOutside(outerHull);
552 m.DumpRaw(baseDir, primName, "Proto outsides removed");
553
554 foreach (Triangle t in m.triangles)
555 {
556 PhysicsVector n = t.getNormal();
557 if (n.Z < 0.0)
558 t.invertNormal();
559 }
560
561 Extruder extr = new Extruder();
562
563 extr.size = size;
564
565 if (taperX != 100)
566 {
567 if (taperX > 100)
568 {
569 extr.taperTopFactorX = 1.0f - ((float)(taperX - 100) / 100);
570 }
571 else
572 {
573 extr.taperBotFactorX = 1.0f - ((100 - (float)taperX) / 100);
574 }
575
576 }
577
578 if (taperY != 100)
579 {
580 if (taperY > 100)
581 {
582 extr.taperTopFactorY = 1.0f - ((float)(taperY - 100) / 100);
583 }
584 else
585 {
586 extr.taperBotFactorY = 1.0f - ((100 - (float)taperY) / 100);
587 }
588 }
589
590 if (pathShearX != 0)
591 {
592 if (pathShearX > 50)
593 {
594 // Complimentary byte. Negative values wrap around the byte. Positive values go up to 50
595 extr.pushX = (((float)(256 - pathShearX) / 100) * -1f);
596 }
597 else
598 {
599 extr.pushX = (float)pathShearX / 100;
600 }
601 }
602
603 if (pathShearY != 0)
604 {
605 if (pathShearY > 50)
606 {
607 // Complimentary byte. Negative values wrap around the byte. Positive values go up to 50
608 extr.pushY = (((float)(256 - pathShearY) / 100) * -1f);
609 }
610 else
611 {
612 extr.pushY = (float)pathShearY / 100;
613 }
614 }
615
616 extr.twistTop = (float)primShape.PathTwist * (float)Math.PI * 0.01f;
617 extr.twistBot = (float)primShape.PathTwistBegin * (float)Math.PI * 0.01f;
618 extr.pathBegin = primShape.PathBegin;
619 extr.pathEnd = primShape.PathEnd;
620
621 Mesh result = extr.ExtrudeLinearPath(m);
622 result.DumpRaw(baseDir, primName, "Z extruded");
623#if SPAM
624 int vCount = 0;
625
626 foreach (Vertex v in result.vertices)
627 if (v != null)
628 vCount++;
629 System.Console.WriteLine("Mesh vertex count: " + vCount.ToString());
630#endif
631 return result;
632 }
633
634 private static Mesh CreateCylinderMesh(String primName, PrimitiveBaseShape primShape, PhysicsVector size)
635 // Builds the z (+ and -) surfaces of a box shaped prim
636 { 157 {
158 Console.WriteLine(message);
159 Console.WriteLine("\nPrim Name: " + primName);
160 Console.WriteLine("****** PrimMesh Parameters ******\n" + primMesh.ParamsToDisplayString());
637 161
638 UInt16 hollowFactor = primShape.ProfileHollow;
639 UInt16 profileBegin = primShape.ProfileBegin;
640 UInt16 profileEnd = primShape.ProfileEnd;
641 UInt16 taperX = primShape.PathScaleX;
642 UInt16 taperY = primShape.PathScaleY;
643 UInt16 pathShearX = primShape.PathShearX;
644 UInt16 pathShearY = primShape.PathShearY;
645
646#if SPAM
647 reportPrimParams("[CYLINDER] " + primName, primShape);
648#endif
649
650
651 // Procedure: This is based on the fact that the upper (plus) and lower (minus) Z-surface
652 // of a block are basically the same
653 // They may be warped differently but the shape is identical
654 // So we only create one surface as a model and derive both plus and minus surface of the block from it
655 // This is done in a model space where the block spans from -.5 to +.5 in X and Y
656 // The mapping to Scene space is done later during the "extrusion" phase
657
658 // Base
659
660 SimpleHull outerHull = new SimpleHull();
661
662 // counter-clockwise around the quadrants, start at 45 degrees
663
664 outerHull.AddVertex(new Vertex(0.353553f, 0.353553f, 0.0f)); // 45 degrees
665 outerHull.AddVertex(new Vertex(0.250000f, 0.433013f, 0.0f)); // 60 degrees
666 outerHull.AddVertex(new Vertex(0.129410f, 0.482963f, 0.0f)); // 75 degrees
667 outerHull.AddVertex(new Vertex(0.000000f, 0.500000f, 0.0f)); // 90 degrees
668 outerHull.AddVertex(new Vertex(-0.129410f, 0.482963f, 0.0f)); // 105 degrees
669 outerHull.AddVertex(new Vertex(-0.250000f, 0.433013f, 0.0f)); // 120 degrees
670 outerHull.AddVertex(new Vertex(-0.353553f, 0.353553f, 0.0f)); // 135 degrees
671 outerHull.AddVertex(new Vertex(-0.433013f, 0.250000f, 0.0f)); // 150 degrees
672 outerHull.AddVertex(new Vertex(-0.482963f, 0.129410f, 0.0f)); // 165 degrees
673 outerHull.AddVertex(new Vertex(-0.500000f, 0.000000f, 0.0f)); // 180 degrees
674 outerHull.AddVertex(new Vertex(-0.482963f, -0.129410f, 0.0f)); // 195 degrees
675 outerHull.AddVertex(new Vertex(-0.433013f, -0.250000f, 0.0f)); // 210 degrees
676 outerHull.AddVertex(new Vertex(-0.353553f, -0.353553f, 0.0f)); // 225 degrees
677 outerHull.AddVertex(new Vertex(-0.250000f, -0.433013f, 0.0f)); // 240 degrees
678 outerHull.AddVertex(new Vertex(-0.129410f, -0.482963f, 0.0f)); // 255 degrees
679 outerHull.AddVertex(new Vertex(0.000000f, -0.500000f, 0.0f)); // 270 degrees
680 outerHull.AddVertex(new Vertex(0.129410f, -0.482963f, 0.0f)); // 285 degrees
681 outerHull.AddVertex(new Vertex(0.250000f, -0.433013f, 0.0f)); // 300 degrees
682 outerHull.AddVertex(new Vertex(0.353553f, -0.353553f, 0.0f)); // 315 degrees
683 outerHull.AddVertex(new Vertex(0.433013f, -0.250000f, 0.0f)); // 330 degrees
684 outerHull.AddVertex(new Vertex(0.482963f, -0.129410f, 0.0f)); // 345 degrees
685 outerHull.AddVertex(new Vertex(0.500000f, 0.000000f, 0.0f)); // 0 degrees
686 outerHull.AddVertex(new Vertex(0.482963f, 0.129410f, 0.0f)); // 15 degrees
687 outerHull.AddVertex(new Vertex(0.433013f, 0.250000f, 0.0f)); // 30 degrees
688
689
690
691 // Deal with cuts now
692 if ((profileBegin != 0) || (profileEnd != 0))
693 {
694 double fProfileBeginAngle = profileBegin / 50000.0 * 360.0;
695 // In degree, for easier debugging and understanding
696 double fProfileEndAngle = 360.0 - profileEnd / 50000.0 * 360.0; // Pathend comes as complement to 1.0
697
698#if SPAM
699 Console.WriteLine("Extruder: Cylinder fProfileBeginAngle: " + fProfileBeginAngle.ToString() + " fProfileEndAngle: " + fProfileEndAngle.ToString());
700#endif
701 if (fProfileBeginAngle > 270.0f && fProfileBeginAngle < 271.8f) // a problem angle for the hull subtract routine :(
702 fProfileBeginAngle = 271.8f; // workaround - use the smaller slice
703
704 if (fProfileBeginAngle < fProfileEndAngle)
705 fProfileEndAngle -= 360.0;
706#if SPAM
707 Console.WriteLine("Extruder: Cylinder fProfileBeginAngle: " + fProfileBeginAngle.ToString() + " fProfileEndAngle: " + fProfileEndAngle.ToString());
708#endif
709
710 // Note, that we don't want to cut out a triangle, even if this is a
711 // good approximation for small cuts. Indeed we want to cut out an arc
712 // and we approximate this arc by a polygon chain
713 // Also note, that these vectors are of length 1.0 and thus their endpoints lay outside the model space
714 // So it can easily be subtracted from the outer hull
715 int iSteps = (int)(((fProfileBeginAngle - fProfileEndAngle) / 45.0) + .5);
716 // how many steps do we need with approximately 45 degree
717 double dStepWidth = (fProfileBeginAngle - fProfileEndAngle) / iSteps;
718
719 Vertex origin = new Vertex(0.0f, 0.0f, 0.0f);
720
721 // Note the sequence of vertices here. It's important to have the other rotational sense than in outerHull
722 SimpleHull cutHull = new SimpleHull();
723 cutHull.AddVertex(origin);
724 for (int i = 0; i < iSteps; i++)
725 {
726 double angle = fProfileBeginAngle - i * dStepWidth; // we count against the angle orientation!!!!
727 Vertex v = Vertex.FromAngle(angle * Math.PI / 180.0);
728 cutHull.AddVertex(v);
729 }
730 Vertex legEnd = Vertex.FromAngle(fProfileEndAngle * Math.PI / 180.0);
731 // Calculated separately to avoid errors
732 cutHull.AddVertex(legEnd);
733
734 SimpleHull cuttedHull = SimpleHull.SubtractHull(outerHull, cutHull);
735
736 outerHull = cuttedHull;
737 }
738
739 // Deal with the hole here
740 if (hollowFactor > 0)
741 {
742 if (hollowFactor < 1000)
743 hollowFactor = 1000; // some sane minimum for our beloved SimpleHull routines
744
745 SimpleHull holeHull = BuildHoleHull(primShape, primShape.ProfileShape, primShape.HollowShape, hollowFactor);
746 if (holeHull != null)
747 {
748 SimpleHull hollowedHull = SimpleHull.SubtractHull(outerHull, holeHull);
749
750 outerHull = hollowedHull;
751 }
752 }
753
754 Mesh m = new Mesh();
755
756 Vertex Seed1 = new Vertex(0.0f, -10.0f, 0.0f);
757 Vertex Seed2 = new Vertex(-10.0f, 10.0f, 0.0f);
758 Vertex Seed3 = new Vertex(10.0f, 10.0f, 0.0f);
759
760 m.Add(Seed1);
761 m.Add(Seed2);
762 m.Add(Seed3);
763
764 m.Add(new Triangle(Seed1, Seed2, Seed3));
765 m.Add(outerHull.getVertices());
766
767 InsertVertices(m.vertices, 3, m.triangles);
768 m.DumpRaw(baseDir, primName, "Proto first Mesh");
769
770 m.Remove(Seed1);
771 m.Remove(Seed2);
772 m.Remove(Seed3);
773 m.DumpRaw(baseDir, primName, "Proto seeds removed");
774
775 m.RemoveTrianglesOutside(outerHull);
776 m.DumpRaw(baseDir, primName, "Proto outsides removed");
777
778 foreach (Triangle t in m.triangles)
779 {
780 PhysicsVector n = t.getNormal();
781 if (n.Z < 0.0)
782 t.invertNormal();
783 }
784
785 Extruder extr = new Extruder();
786
787 extr.size = size;
788
789 if (taperX != 100)
790 {
791 if (taperX > 100)
792 {
793 extr.taperTopFactorX = 1.0f - ((float)(taperX - 100) / 100); }
794 else
795 {
796 extr.taperBotFactorX = 1.0f - ((100 - (float)taperX) / 100);
797 }
798
799 }
800
801 if (taperY != 100)
802 {
803 if (taperY > 100)
804 {
805 extr.taperTopFactorY = 1.0f - ((float)(taperY - 100) / 100);
806 }
807 else
808 {
809 extr.taperBotFactorY = 1.0f - ((100 - (float)taperY) / 100);
810 }
811 }
812
813 if (pathShearX != 0)
814 {
815 if (pathShearX > 50)
816 {
817 // Complimentary byte. Negative values wrap around the byte. Positive values go up to 50
818 extr.pushX = (((float)(256 - pathShearX) / 100) * -1f);
819 }
820 else
821 {
822 extr.pushX = (float)pathShearX / 100;
823 }
824 }
825
826 if (pathShearY != 0)
827 {
828 if (pathShearY > 50)
829 {
830 // Complimentary byte. Negative values wrap around the byte. Positive values go up to 50
831 extr.pushY = (((float)(256 - pathShearY) / 100) * -1f);
832 }
833 else
834 {
835 extr.pushY = (float)pathShearY / 100;
836 }
837
838 }
839
840 extr.twistTop = (float)primShape.PathTwist * (float)Math.PI * 0.01f;
841 extr.twistBot = (float)primShape.PathTwistBegin * (float)Math.PI * 0.01f;
842 extr.pathBegin = primShape.PathBegin;
843 extr.pathEnd = primShape.PathEnd;
844
845 Mesh result = extr.ExtrudeLinearPath(m);
846 result.DumpRaw(baseDir, primName, "Z extruded");
847#if SPAM
848 int vCount = 0;
849
850 foreach (Vertex v in result.vertices)
851 if (v != null)
852 vCount++;
853 System.Console.WriteLine("Mesh vertex count: " + vCount.ToString());
854#endif
855 return result;
856 } 162 }
857 163
858 private static Mesh CreatePrismMesh(String primName, PrimitiveBaseShape primShape, PhysicsVector size) 164 public Mesh CreateMeshFromPrimMesher(string primName, PrimitiveBaseShape primShape, PhysicsVector size, float lod)
859 // Builds the z (+ and -) surfaces of a box shaped prim
860 { 165 {
861 UInt16 hollowFactor = primShape.ProfileHollow; 166 Mesh mesh = new Mesh();
862 UInt16 profileBegin = primShape.ProfileBegin; 167 PrimMesh primMesh;
863 UInt16 profileEnd = primShape.ProfileEnd; 168 PrimMesher.SculptMesh sculptMesh;
864 UInt16 taperX = primShape.PathScaleX;
865 UInt16 taperY = primShape.PathScaleY;
866 UInt16 pathShearX = primShape.PathShearX;
867 UInt16 pathShearY = primShape.PathShearY;
868
869
870#if SPAM
871 reportPrimParams("[PRISM] " + primName, primShape);
872#endif
873 // Procedure: This is based on the fact that the upper (plus) and lower (minus) Z-surface
874 // of a block are basically the same
875 // They may be warped differently but the shape is identical
876 // So we only create one surface as a model and derive both plus and minus surface of the block from it
877 // This is done in a model space where the block spans from -.5 to +.5 in X and Y
878 // The mapping to Scene space is done later during the "extrusion" phase
879
880 // Base
881 Vertex MM = new Vertex(-0.25f, -0.45f, 0.0f);
882 Vertex PM = new Vertex(+0.5f, 0f, 0.0f);
883 Vertex PP = new Vertex(-0.25f, +0.45f, 0.0f);
884
885
886 SimpleHull outerHull = new SimpleHull();
887
888 outerHull.AddVertex(PP);
889 outerHull.AddVertex(MM);
890 outerHull.AddVertex(PM);
891
892 // Deal with cuts now
893 if ((profileBegin != 0) || (profileEnd != 0))
894 {
895 double fProfileBeginAngle = profileBegin / 50000.0 * 360.0;
896 // In degree, for easier debugging and understanding
897 double fProfileEndAngle = 360.0 - profileEnd / 50000.0 * 360.0; // Pathend comes as complement to 1.0
898
899 if (fProfileBeginAngle < fProfileEndAngle)
900 fProfileEndAngle -= 360.0;
901
902 // Note, that we don't want to cut out a triangle, even if this is a
903 // good approximation for small cuts. Indeed we want to cut out an arc
904 // and we approximate this arc by a polygon chain
905 // Also note, that these vectors are of length 1.0 and thus their endpoints lay outside the model space
906 // So it can easily be subtracted from the outer hull
907 int iSteps = (int)(((fProfileBeginAngle - fProfileEndAngle) / 45.0) + .5);
908 // how many steps do we need with approximately 45 degree
909 double dStepWidth = (fProfileBeginAngle - fProfileEndAngle) / iSteps;
910
911 Vertex origin = new Vertex(0.0f, 0.0f, 0.0f);
912
913 // Note the sequence of vertices here. It's important to have the other rotational sense than in outerHull
914 SimpleHull cutHull = new SimpleHull();
915 cutHull.AddVertex(origin);
916 for (int i = 0; i < iSteps; i++)
917 {
918 double angle = fProfileBeginAngle - i * dStepWidth; // we count against the angle orientation!!!!
919 Vertex v = Vertex.FromAngle(angle * Math.PI / 180.0);
920 cutHull.AddVertex(v);
921 }
922 Vertex legEnd = Vertex.FromAngle(fProfileEndAngle * Math.PI / 180.0);
923 // Calculated separately to avoid errors
924 cutHull.AddVertex(legEnd);
925
926 SimpleHull cuttedHull = SimpleHull.SubtractHull(outerHull, cutHull);
927
928 outerHull = cuttedHull;
929 }
930
931 // Deal with the hole here
932 if (hollowFactor > 0)
933 {
934 if (hollowFactor < 1000)
935 hollowFactor = 1000; // some sane minimum for our beloved SimpleHull routines
936
937 SimpleHull holeHull = BuildHoleHull(primShape, primShape.ProfileShape, primShape.HollowShape, hollowFactor);
938 if (holeHull != null)
939 {
940 SimpleHull hollowedHull = SimpleHull.SubtractHull(outerHull, holeHull);
941
942 outerHull = hollowedHull;
943 }
944 }
945
946 Mesh m = new Mesh();
947
948 Vertex Seed1 = new Vertex(0.0f, -10.0f, 0.0f);
949 Vertex Seed2 = new Vertex(-10.0f, 10.0f, 0.0f);
950 Vertex Seed3 = new Vertex(10.0f, 10.0f, 0.0f);
951
952 m.Add(Seed1);
953 m.Add(Seed2);
954 m.Add(Seed3);
955
956 m.Add(new Triangle(Seed1, Seed2, Seed3));
957 m.Add(outerHull.getVertices());
958
959 InsertVertices(m.vertices, 3, m.triangles);
960 m.DumpRaw(baseDir, primName, "Proto first Mesh");
961
962 m.Remove(Seed1);
963 m.Remove(Seed2);
964 m.Remove(Seed3);
965 m.DumpRaw(baseDir, primName, "Proto seeds removed");
966
967 m.RemoveTrianglesOutside(outerHull);
968 m.DumpRaw(baseDir, primName, "Proto outsides removed");
969
970 foreach (Triangle t in m.triangles)
971 {
972 PhysicsVector n = t.getNormal();
973 if (n.Z < 0.0)
974 t.invertNormal();
975 }
976 169
977 Extruder extr = new Extruder(); 170 List<Coord> coords;
171 List<Face> faces;
978 172
979 extr.size = size; 173 Image idata = null;
980 174
981 if (taperX != 100) 175 if (primShape.SculptEntry)
982 { 176 {
983 if (taperX > 100) 177 if (primShape.SculptData.Length == 0)
984 { 178 return null;
985 extr.taperTopFactorX = 1.0f - ((float)(taperX - 100) / 100);
986 }
987 else
988 {
989 extr.taperBotFactorX = 1.0f - ((100 - (float)taperX) / 100);
990 }
991
992 }
993 179
994 if (taperY != 100) 180 try
995 {
996 if (taperY > 100)
997 { 181 {
998 extr.taperTopFactorY = 1.0f - ((float)(taperY - 100) / 100); 182 ManagedImage managedImage; // we never use this
183 OpenJPEG.DecodeToImage(primShape.SculptData, out managedImage, out idata);
999 } 184 }
1000 else 185 catch (Exception)
1001 { 186 {
1002 extr.taperBotFactorY = 1.0f - ((100 - (float)taperY) / 100); 187 System.Console.WriteLine("[PHYSICS]: Unable to generate a Sculpty physics proxy. Sculpty texture decode failed!");
188 return null;
1003 } 189 }
1004 }
1005 190
1006 if (pathShearX != 0)
1007 {
1008 if (pathShearX > 50)
1009 {
1010 // Complimentary byte. Negative values wrap around the byte. Positive values go up to 50
1011 extr.pushX = (((float)(256 - pathShearX) / 100) * -1f);
1012 }
1013 else
1014 {
1015 extr.pushX = (float)pathShearX / 100;
1016 }
1017 }
1018 191
1019 if (pathShearY != 0) 192 PrimMesher.SculptMesh.SculptType sculptType;
1020 { 193 switch ((OpenMetaverse.SculptType)primShape.SculptType)
1021 if (pathShearY > 50)
1022 {
1023 // Complimentary byte. Negative values wrap around the byte. Positive values go up to 50
1024 extr.pushY = (((float)(256 - pathShearY) / 100) * -1f);
1025 }
1026 else
1027 { 194 {
1028 extr.pushY = (float)pathShearY / 100; 195 case OpenMetaverse.SculptType.Cylinder:
196 sculptType = PrimMesher.SculptMesh.SculptType.cylinder;
197 break;
198 case OpenMetaverse.SculptType.Plane:
199 sculptType = PrimMesher.SculptMesh.SculptType.plane;
200 break;
201 case OpenMetaverse.SculptType.Torus:
202 sculptType = PrimMesher.SculptMesh.SculptType.torus;
203 break;
204 case OpenMetaverse.SculptType.Sphere:
205 default:
206 sculptType = PrimMesher.SculptMesh.SculptType.sphere;
207 break;
1029 } 208 }
1030 } 209 sculptMesh = new PrimMesher.SculptMesh((Bitmap)idata, sculptType, (int)lod, false);
1031
1032 extr.twistTop = (float)primShape.PathTwist * (float)Math.PI * 0.01f;
1033 extr.twistBot = (float)primShape.PathTwistBegin * (float)Math.PI * 0.01f;
1034 extr.pathBegin = primShape.PathBegin;
1035 extr.pathEnd = primShape.PathEnd;
1036
1037 Mesh result = extr.ExtrudeLinearPath(m);
1038 result.DumpRaw(baseDir, primName, "Z extruded");
1039#if SPAM
1040 int vCount = 0;
1041
1042 foreach (Vertex v in result.vertices)
1043 if (v != null)
1044 vCount++;
1045 System.Console.WriteLine("Mesh vertex count: " + vCount.ToString());
1046#endif
1047 return result;
1048 }
1049
1050 /// <summary>
1051 /// builds an icosahedral geodesic sphere - used as default in place of problem meshes
1052 /// </summary>
1053 /// <param name="primName"></param>
1054 /// <param name="primShape"></param>
1055 /// <param name="size"></param>
1056 /// <returns></returns>
1057 private static Mesh CreateSphereMesh(String primName, PrimitiveBaseShape primShape, PhysicsVector size)
1058 {
1059 // Builds an icosahedral geodesic sphere
1060 // based on an article by Paul Bourke
1061 // http://local.wasp.uwa.edu.au/~pbourke/
1062 // articles:
1063 // http://local.wasp.uwa.edu.au/~pbourke/geometry/polygonmesh/
1064 // and
1065 // http://local.wasp.uwa.edu.au/~pbourke/geometry/polyhedra/index.html
1066
1067 // Still have more to do here.
1068
1069 Mesh m = new Mesh();
1070
1071#if SPAM
1072 reportPrimParams("[SPHERE] " + primName, primShape);
1073#endif
1074
1075 float LOD = 0.2f;
1076 float diameter = 0.5f;// Our object will result in -0.5 to 0.5
1077 float sq5 = (float) Math.Sqrt(5.0);
1078 float phi = (1 + sq5) * 0.5f;
1079 float rat = (float) Math.Sqrt(10f + (2f * sq5)) / (4f * phi);
1080 float a = (diameter / rat) * 0.5f;
1081 float b = (diameter / rat) / (2.0f * phi);
1082
1083
1084 // 12 Icosahedron vertexes
1085 Vertex v1 = new Vertex(0f, b, -a);
1086 Vertex v2 = new Vertex(b, a, 0f);
1087 Vertex v3 = new Vertex(-b, a, 0f);
1088 Vertex v4 = new Vertex(0f, b, a);
1089 Vertex v5 = new Vertex(0f, -b, a);
1090 Vertex v6 = new Vertex(-a, 0f, b);
1091 Vertex v7 = new Vertex(0f, -b, -a);
1092 Vertex v8 = new Vertex(a, 0f, -b);
1093 Vertex v9 = new Vertex(a, 0f, b);
1094 Vertex v10 = new Vertex(-a, 0f, -b);
1095 Vertex v11 = new Vertex(b, -a, 0);
1096 Vertex v12 = new Vertex(-b, -a, 0);
1097
1098
1099
1100 // Base Faces of the Icosahedron (20)
1101 SphereLODTriangle(v1, v2, v3, diameter, LOD, m);
1102 SphereLODTriangle(v4, v3, v2, diameter, LOD, m);
1103 SphereLODTriangle(v4, v5, v6, diameter, LOD, m);
1104 SphereLODTriangle(v4, v9, v5, diameter, LOD, m);
1105 SphereLODTriangle(v1, v7, v8, diameter, LOD, m);
1106 SphereLODTriangle(v1, v10, v7, diameter, LOD, m);
1107 SphereLODTriangle(v5, v11, v12, diameter, LOD, m);
1108 SphereLODTriangle(v7, v12, v11, diameter, LOD, m);
1109 SphereLODTriangle(v3, v6, v10, diameter, LOD, m);
1110 SphereLODTriangle(v12, v10, v6, diameter, LOD, m);
1111 SphereLODTriangle(v2, v8, v9, diameter, LOD, m);
1112 SphereLODTriangle(v11, v9, v8, diameter, LOD, m);
1113 SphereLODTriangle(v4, v6, v3, diameter, LOD, m);
1114 SphereLODTriangle(v4, v2, v9, diameter, LOD, m);
1115 SphereLODTriangle(v1, v3, v10, diameter, LOD, m);
1116 SphereLODTriangle(v1, v8, v2, diameter, LOD, m);
1117 SphereLODTriangle(v7, v10, v12, diameter, LOD, m);
1118 SphereLODTriangle(v7, v11, v8, diameter, LOD, m);
1119 SphereLODTriangle(v5, v12, v6, diameter, LOD, m);
1120 SphereLODTriangle(v5, v9, v11, diameter, LOD, m);
1121
1122 // Scale the mesh based on our prim scale
1123 foreach (Vertex v in m.vertices)
1124 {
1125 v.X *= size.X;
1126 v.Y *= size.Y;
1127 v.Z *= size.Z;
1128 }
1129
1130 // This was built with the normals pointing inside..
1131 // therefore we have to invert the normals
1132 foreach (Triangle t in m.triangles)
1133 {
1134 t.invertNormal();
1135 }
1136 // Dump the faces for visualization in blender.
1137 m.DumpRaw(baseDir, primName, "Icosahedron");
1138#if SPAM
1139 int vCount = 0;
1140
1141 foreach (Vertex v in m.vertices)
1142 if (v != null)
1143 vCount++;
1144 System.Console.WriteLine("Mesh vertex count: " + vCount.ToString());
1145#endif
1146
1147 return m;
1148 }
1149 private SculptMesh CreateSculptMesh(string primName, PrimitiveBaseShape primShape, PhysicsVector size, float lod)
1150 {
1151
1152#if SPAM
1153 reportPrimParams("[SCULPT] " + primName, primShape);
1154#endif
1155
1156 SculptMesh sm = new SculptMesh(primShape.SculptData, lod);
1157 // Scale the mesh based on our prim scale
1158 foreach (Vertex v in sm.vertices)
1159 {
1160 v.X *= 0.5f;
1161 v.Y *= 0.5f;
1162 v.Z *= 0.5f;
1163 v.X *= size.X;
1164 v.Y *= size.Y;
1165 v.Z *= size.Z;
1166 }
1167 // This was built with the normals pointing inside..
1168 // therefore we have to invert the normals
1169 foreach (Triangle t in sm.triangles)
1170 {
1171 t.invertNormal();
1172 }
1173 sm.DumpRaw(baseDir, primName, "Sculpt");
1174 return sm;
1175
1176 }
1177
1178 /// <summary>
1179 /// Creates a mesh for prim types torus, ring, tube, and sphere
1180 /// </summary>
1181 /// <param name="primName"></param>
1182 /// <param name="primShape"></param>
1183 /// <param name="size"></param>
1184 /// <returns></returns>
1185 private static Mesh CreateCircularPathMesh(String primName, PrimitiveBaseShape primShape, PhysicsVector size)
1186 {
1187
1188 UInt16 hollowFactor = primShape.ProfileHollow;
1189 UInt16 profileBegin = primShape.ProfileBegin;
1190 UInt16 profileEnd = primShape.ProfileEnd;
1191 UInt16 pathShearX = primShape.PathShearX;
1192 UInt16 pathShearY = primShape.PathShearY;
1193 HollowShape hollowShape = primShape.HollowShape;
1194
1195#if SPAM
1196 reportPrimParams("[CIRCULAR PATH PRIM] " + primName, primShape);
1197 Console.WriteLine("pathTwist: " + primShape.PathTwist.ToString() + " pathTwistBegin: " + primShape.PathTwistBegin.ToString());
1198 Console.WriteLine("primShape.ProfileCurve & 0x07: " + Convert.ToString(primShape.ProfileCurve & 0x07));
1199
1200#endif
1201
1202 SimpleHull outerHull = new SimpleHull();
1203
1204 if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.Circle)
1205 {
1206#if SPAM
1207 Console.WriteLine("Meshmerizer thinks " + primName + " is a TORUS");
1208#endif
1209 if (hollowShape == HollowShape.Same)
1210 hollowShape = HollowShape.Circle;
1211
1212 // build the profile shape
1213 // counter-clockwise around the quadrants, start at 45 degrees
1214
1215 outerHull.AddVertex(new Vertex(0.353553f, 0.353553f, 0.0f)); // 45 degrees
1216 outerHull.AddVertex(new Vertex(0.250000f, 0.433013f, 0.0f)); // 60 degrees
1217 outerHull.AddVertex(new Vertex(0.129410f, 0.482963f, 0.0f)); // 75 degrees
1218 outerHull.AddVertex(new Vertex(0.000000f, 0.500000f, 0.0f)); // 90 degrees
1219 outerHull.AddVertex(new Vertex(-0.129410f, 0.482963f, 0.0f)); // 105 degrees
1220 outerHull.AddVertex(new Vertex(-0.250000f, 0.433013f, 0.0f)); // 120 degrees
1221 outerHull.AddVertex(new Vertex(-0.353553f, 0.353553f, 0.0f)); // 135 degrees
1222 outerHull.AddVertex(new Vertex(-0.433013f, 0.250000f, 0.0f)); // 150 degrees
1223 outerHull.AddVertex(new Vertex(-0.482963f, 0.129410f, 0.0f)); // 165 degrees
1224 outerHull.AddVertex(new Vertex(-0.500000f, 0.000000f, 0.0f)); // 180 degrees
1225 outerHull.AddVertex(new Vertex(-0.482963f, -0.129410f, 0.0f)); // 195 degrees
1226 outerHull.AddVertex(new Vertex(-0.433013f, -0.250000f, 0.0f)); // 210 degrees
1227 outerHull.AddVertex(new Vertex(-0.353553f, -0.353553f, 0.0f)); // 225 degrees
1228 outerHull.AddVertex(new Vertex(-0.250000f, -0.433013f, 0.0f)); // 240 degrees
1229 outerHull.AddVertex(new Vertex(-0.129410f, -0.482963f, 0.0f)); // 255 degrees
1230 outerHull.AddVertex(new Vertex(0.000000f, -0.500000f, 0.0f)); // 270 degrees
1231 outerHull.AddVertex(new Vertex(0.129410f, -0.482963f, 0.0f)); // 285 degrees
1232 outerHull.AddVertex(new Vertex(0.250000f, -0.433013f, 0.0f)); // 300 degrees
1233 outerHull.AddVertex(new Vertex(0.353553f, -0.353553f, 0.0f)); // 315 degrees
1234 outerHull.AddVertex(new Vertex(0.433013f, -0.250000f, 0.0f)); // 330 degrees
1235 outerHull.AddVertex(new Vertex(0.482963f, -0.129410f, 0.0f)); // 345 degrees
1236 outerHull.AddVertex(new Vertex(0.500000f, 0.000000f, 0.0f)); // 0 degrees
1237 outerHull.AddVertex(new Vertex(0.482963f, 0.129410f, 0.0f)); // 15 degrees
1238 outerHull.AddVertex(new Vertex(0.433013f, 0.250000f, 0.0f)); // 30 degrees
1239 }
1240
1241 else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.Square) // a ring
1242 {
1243#if SPAM
1244 Console.WriteLine("Meshmerizer thinks " + primName + " is a TUBE");
1245#endif
1246 if (hollowShape == HollowShape.Same)
1247 hollowShape = HollowShape.Square;
1248 210
1249 outerHull.AddVertex(new Vertex(+0.5f, +0.5f, 0.0f)); 211 idata.Dispose();
1250 outerHull.AddVertex(new Vertex(-0.5f, +0.5f, 0.0f));
1251 outerHull.AddVertex(new Vertex(-0.5f, -0.5f, 0.0f));
1252 outerHull.AddVertex(new Vertex(+0.5f, -0.5f, 0.0f));
1253 }
1254 212
1255 else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle) 213 sculptMesh.DumpRaw(baseDir, primName, "primMesh");
1256 {
1257#if SPAM
1258 Console.WriteLine("Meshmerizer thinks " + primName + " is a RING");
1259#endif
1260 if (hollowShape == HollowShape.Same)
1261 hollowShape = HollowShape.Triangle;
1262 214
1263 outerHull.AddVertex(new Vertex(+0.255f, -0.375f, 0.0f)); 215 sculptMesh.Scale(size.X, size.Y, size.Z);
1264 outerHull.AddVertex(new Vertex(+0.25f, +0.375f, 0.0f));
1265 outerHull.AddVertex(new Vertex(-0.5f, +0.0f, 0.0f));
1266 216
217 coords = sculptMesh.coords;
218 faces = sculptMesh.faces;
1267 } 219 }
1268 220
1269 else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle) 221 else
1270 { 222 {
1271#if SPAM 223 float pathShearX = primShape.PathShearX < 128 ? (float)primShape.PathShearX * 0.01f : (float)(primShape.PathShearX - 256) * 0.01f;
1272 Console.WriteLine("Meshmerizer thinks " + primName + " is a SPHERE"); 224 float pathShearY = primShape.PathShearY < 128 ? (float)primShape.PathShearY * 0.01f : (float)(primShape.PathShearY - 256) * 0.01f;
1273#endif 225 float pathBegin = (float)primShape.PathBegin * 2.0e-5f;
1274 226 float pathEnd = 1.0f - (float)primShape.PathEnd * 2.0e-5f;
1275 // sanity check here... some spheres have inverted normals which can trap avatars 227 float pathScaleX = (float)(primShape.PathScaleX - 100) * 0.01f;
1276 // so for now if the shape parameters are such that this may happen, revert to the 228 float pathScaleY = (float)(primShape.PathScaleY - 100) * 0.01f;
1277 // geodesic sphere mesh.. the threshold is arbitrary as it seems any twist on a sphere
1278 // will create some inverted normals
1279 if (
1280 (System.Math.Abs(primShape.PathTwist - primShape.PathTwistBegin) > 65)
1281 || (primShape.PathBegin == 0
1282 && primShape.PathEnd == 0
1283 && primShape.PathTwist == 0
1284 && primShape.PathTwistBegin == 0
1285 && primShape.ProfileBegin == 0
1286 && primShape.ProfileEnd == 0
1287 && hollowFactor == 0
1288 ) // simple sphere, revert to geodesic shape
1289
1290 )
1291 {
1292#if SPAM
1293 System.Console.WriteLine("reverting to geodesic sphere for prim: " + primName);
1294#endif
1295 return CreateSphereMesh(primName, primShape, size);
1296 }
1297 229
1298 if (hollowFactor == 0) 230 float profileBegin = (float)primShape.ProfileBegin * 2.0e-5f;
1299 { 231 float profileEnd = 1.0f - (float)primShape.ProfileEnd * 2.0e-5f;
1300 // the hull triangulator is happier with a minimal hollow 232 float profileHollow = (float)primShape.ProfileHollow * 2.0e-5f;
1301 hollowFactor = 2000;
1302 }
1303 233
1304 if (hollowShape == HollowShape.Same) 234 int sides = 4;
1305 hollowShape = HollowShape.Circle; 235 if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle)
1306 236 sides = 3;
1307 outerHull.AddVertex(new Vertex(0.250000f, 0.433013f, 0.0f)); // 60 degrees 237 else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.Circle)
1308 outerHull.AddVertex(new Vertex(0.129410f, 0.482963f, 0.0f)); // 75 degrees 238 sides = 24;
1309 outerHull.AddVertex(new Vertex(0.000000f, 0.500000f, 0.0f)); // 90 degrees 239 else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle)
1310 outerHull.AddVertex(new Vertex(-0.129410f, 0.482963f, 0.0f)); // 105 degrees 240 { // half circle, prim is a sphere
1311 outerHull.AddVertex(new Vertex(-0.250000f, 0.433013f, 0.0f)); // 120 degrees 241 sides = 24;
1312 outerHull.AddVertex(new Vertex(-0.353553f, 0.353553f, 0.0f)); // 135 degrees
1313 outerHull.AddVertex(new Vertex(-0.433013f, 0.250000f, 0.0f)); // 150 degrees
1314 outerHull.AddVertex(new Vertex(-0.482963f, 0.129410f, 0.0f)); // 165 degrees
1315 outerHull.AddVertex(new Vertex(-0.500000f, 0.000000f, 0.0f)); // 180 degrees
1316
1317 outerHull.AddVertex(new Vertex(0.500000f, 0.000000f, 0.0f)); // 0 degrees
1318 outerHull.AddVertex(new Vertex(0.482963f, 0.129410f, 0.0f)); // 15 degrees
1319 outerHull.AddVertex(new Vertex(0.433013f, 0.250000f, 0.0f)); // 30 degrees
1320 outerHull.AddVertex(new Vertex(0.353553f, 0.353553f, 0.0f)); // 45 degrees
1321 }
1322 242
1323 // Deal with cuts now 243 profileBegin = 0.5f * profileBegin + 0.5f;
1324 if ((profileBegin != 0) || (profileEnd != 0)) 244 profileEnd = 0.5f * profileEnd + 0.5f;
1325 {
1326 double fProfileBeginAngle = profileBegin / 50000.0 * 360.0;
1327 // In degree, for easier debugging and understanding
1328 double fProfileEndAngle = 360.0 - profileEnd / 50000.0 * 360.0; // Pathend comes as complement to 1.0
1329
1330 if (fProfileBeginAngle < fProfileEndAngle)
1331 fProfileEndAngle -= 360.0;
1332
1333 if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle)
1334 { // dimpled sphere uses profile cut but since it's a half circle the angles are smaller
1335 fProfileBeginAngle = 0.0036f * (float)primShape.ProfileBegin;
1336 fProfileEndAngle = 180.0f - 0.0036f * (float)primShape.ProfileEnd;
1337 if (fProfileBeginAngle < fProfileEndAngle)
1338 fProfileEndAngle -= 360.0f;
1339 // a cut starting at 0 degrees with a hollow causes an infinite loop so move the start angle
1340 // past it into the empty part of the circle to avoid this condition
1341 if (fProfileBeginAngle == 0.0f) fProfileBeginAngle = -10.0f;
1342 245
1343#if SPAM
1344 Console.WriteLine("Sphere dimple: fProfileBeginAngle: " + fProfileBeginAngle.ToString() + " fProfileEndAngle: " + fProfileEndAngle.ToString());
1345#endif
1346 }
1347 else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.Square)
1348 { // tube profile cut is offset 45 degrees from other prim types
1349 fProfileBeginAngle += 45.0f;
1350 fProfileEndAngle += 45.0f;
1351 if (fProfileBeginAngle < fProfileEndAngle)
1352 fProfileEndAngle -= 360.0;
1353 }
1354 else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle)
1355 { // ring profile cut is offset 180 degrees from other prim types
1356 fProfileBeginAngle += 180.0f;
1357 fProfileEndAngle += 180.0f;
1358 if (fProfileBeginAngle < fProfileEndAngle)
1359 fProfileEndAngle -= 360.0;
1360 } 246 }
1361 247
1362 // Note, that we don't want to cut out a triangle, even if this is a 248 int hollowSides = sides;
1363 // good approximation for small cuts. Indeed we want to cut out an arc 249 if (primShape.HollowShape == HollowShape.Circle)
1364 // and we approximate this arc by a polygon chain 250 hollowSides = 24;
1365 // Also note, that these vectors are of length 1.0 and thus their endpoints lay outside the model space 251 else if (primShape.HollowShape == HollowShape.Square)
1366 // So it can easily be subtracted from the outer hull 252 hollowSides = 4;
1367 int iSteps = (int)(((fProfileBeginAngle - fProfileEndAngle) / 45.0) + .5); 253 else if (primShape.HollowShape == HollowShape.Triangle)
1368 // how many steps do we need with approximately 45 degree 254 hollowSides = 3;
1369 double dStepWidth = (fProfileBeginAngle - fProfileEndAngle) / iSteps;
1370
1371 Vertex origin = new Vertex(0.0f, 0.0f, 0.0f);
1372
1373 // Note the sequence of vertices here. It's important to have the other rotational sense than in outerHull
1374 SimpleHull cutHull = new SimpleHull();
1375 cutHull.AddVertex(origin);
1376 for (int i = 0; i < iSteps; i++)
1377 {
1378 double angle = fProfileBeginAngle - i * dStepWidth; // we count against the angle orientation!!!!
1379 Vertex v = Vertex.FromAngle(angle * Math.PI / 180.0);
1380 cutHull.AddVertex(v);
1381 }
1382 Vertex legEnd = Vertex.FromAngle(fProfileEndAngle * Math.PI / 180.0);
1383 // Calculated separately to avoid errors
1384 cutHull.AddVertex(legEnd);
1385 255
1386 // m_log.DebugFormat("Starting cutting of the hollow shape from the prim {1}", 0, primName); 256 primMesh = new PrimMesh(sides, profileBegin, profileEnd, profileHollow, hollowSides);
1387 SimpleHull cuttedHull = SimpleHull.SubtractHull(outerHull, cutHull);
1388 257
1389 if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.Circle) 258 primMesh.topShearX = pathShearX;
1390 { 259 primMesh.topShearY = pathShearY;
1391 Quaternion zFlip = Quaternion.CreateFromAxisAngle(new Vector3(0.0f, 0.0f, 1.0f), (float)Math.PI); 260 primMesh.pathCutBegin = pathBegin;
1392 Vertex vTmp = new Vertex(0.0f, 0.0f, 0.0f); 261 primMesh.pathCutEnd = pathEnd;
1393 foreach (Vertex v in cuttedHull.getVertices())
1394 if (v != null)
1395 {
1396 vTmp = v * zFlip;
1397 v.X = vTmp.X;
1398 v.Y = vTmp.Y;
1399 v.Z = vTmp.Z;
1400 }
1401 }
1402
1403 outerHull = cuttedHull;
1404 }
1405 262
1406 // Deal with the hole here 263 if (primShape.PathCurve == (byte)Extrusion.Straight)
1407 if (hollowFactor > 0)
1408 {
1409 SimpleHull holeHull;
1410
1411 if (hollowShape == HollowShape.Triangle)
1412 { 264 {
1413 holeHull = new SimpleHull(); 265 primMesh.twistBegin = primShape.PathTwistBegin * 18 / 10;
266 primMesh.twistEnd = primShape.PathTwist * 18 / 10;
267 primMesh.taperX = pathScaleX;
268 primMesh.taperY = pathScaleY;
1414 269
1415 float hollowFactorF = (float)hollowFactor * 2.0e-5f; 270 if (profileBegin < 0.0f || profileBegin >= profileEnd || profileEnd > 1.0f)
1416
1417 if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle)
1418 { 271 {
1419 holeHull.AddVertex(new Vertex(+0.125f * hollowFactorF, -0.1875f * hollowFactorF, 0.0f)); 272 ReportPrimError("*** CORRUPT PRIM!! ***", primName, primMesh);
1420 holeHull.AddVertex(new Vertex(-0.25f * hollowFactorF, -0f * hollowFactorF, 0.0f)); 273 if (profileBegin < 0.0f) profileBegin = 0.0f;
1421 holeHull.AddVertex(new Vertex(+0.125f * hollowFactorF, +0.1875f * hollowFactorF, 0.0f)); 274 if (profileEnd > 1.0f) profileEnd = 1.0f;
1422 } 275 }
1423 else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle) 276#if SPAM
277 Console.WriteLine("****** PrimMesh Parameters (Linear) ******\n" + primMesh.ParamsToDisplayString());
278#endif
279 try
1424 { 280 {
1425 holeHull.AddVertex(new Vertex(-0.500000f * hollowFactorF, 0.000000f * hollowFactorF, 0.0f)); // 180 degrees 281 primMesh.ExtrudeLinear();
1426 holeHull.AddVertex(new Vertex(-0.250000f * hollowFactorF, 0.433013f * hollowFactorF, 0.0f)); // 120 degrees
1427 holeHull.AddVertex(new Vertex(0.250000f * hollowFactorF, 0.433013f * hollowFactorF, 0.0f)); // 60 degrees
1428 holeHull.AddVertex(new Vertex(0.500000f * hollowFactorF, 0.000000f * hollowFactorF, 0.0f)); // 0 degrees
1429 } 282 }
1430 else 283 catch (Exception ex)
1431 { 284 {
1432 holeHull.AddVertex(new Vertex(+0.25f * hollowFactorF, -0.45f * hollowFactorF, 0.0f)); 285 ReportPrimError("Extrusion failure: exception: " + ex.ToString(), primName, primMesh);
1433 holeHull.AddVertex(new Vertex(-0.5f * hollowFactorF, -0f * hollowFactorF, 0.0f)); 286 return null;
1434 holeHull.AddVertex(new Vertex(+0.25f * hollowFactorF, +0.45f * hollowFactorF, 0.0f));
1435 } 287 }
1436 } 288 }
1437 else if (hollowShape == HollowShape.Square && (primShape.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle)
1438 {
1439 holeHull = new SimpleHull();
1440
1441 float hollowFactorF = (float)hollowFactor * 2.0e-5f;
1442
1443 holeHull.AddVertex(new Vertex(-0.707f * hollowFactorF, 0.0f, 0.0f)); // 180 degrees
1444 holeHull.AddVertex(new Vertex(0.0f, 0.707f * hollowFactorF, 0.0f)); // 120 degrees
1445 holeHull.AddVertex(new Vertex(0.707f * hollowFactorF, 0.0f, 0.0f)); // 60 degrees
1446 }
1447 else 289 else
1448 { 290 {
1449 holeHull = BuildHoleHull(primShape, primShape.ProfileShape, hollowShape, hollowFactor); 291 primMesh.holeSizeX = (200 - primShape.PathScaleX) * 0.01f;
1450 } 292 primMesh.holeSizeY = (200 - primShape.PathScaleY) * 0.01f;
1451 293 primMesh.radius = 0.01f * primShape.PathRadiusOffset;
1452 if (holeHull != null) 294 primMesh.revolutions = 1.0f + 0.015f * primShape.PathRevolutions;
1453 { 295 primMesh.skew = 0.01f * primShape.PathSkew;
1454 SimpleHull hollowedHull = SimpleHull.SubtractHull(outerHull, holeHull); 296 primMesh.twistBegin = primShape.PathTwistBegin * 36 / 10;
1455 297 primMesh.twistEnd = primShape.PathTwist * 36 / 10;
1456 outerHull = hollowedHull; 298 primMesh.taperX = primShape.PathTaperX * 0.01f;
1457 } 299 primMesh.taperY = primShape.PathTaperY * 0.01f;
1458 } 300
1459 301 if (profileBegin < 0.0f || profileBegin >= profileEnd || profileEnd > 1.0f)
1460 Mesh m = new Mesh(); 302 {
1461 303 ReportPrimError("*** CORRUPT PRIM!! ***", primName, primMesh);
1462 Vertex Seed1 = new Vertex(0.0f, -10.0f, 0.0f); 304 if (profileBegin < 0.0f) profileBegin = 0.0f;
1463 Vertex Seed2 = new Vertex(-10.0f, 10.0f, 0.0f); 305 if (profileEnd > 1.0f) profileEnd = 1.0f;
1464 Vertex Seed3 = new Vertex(10.0f, 10.0f, 0.0f); 306 }
1465
1466 m.Add(Seed1);
1467 m.Add(Seed2);
1468 m.Add(Seed3);
1469
1470 m.Add(new Triangle(Seed1, Seed2, Seed3));
1471 m.Add(outerHull.getVertices());
1472
1473 InsertVertices(m.vertices, 3, m.triangles);
1474 m.DumpRaw(baseDir, primName, "Proto first Mesh");
1475
1476 m.Remove(Seed1);
1477 m.Remove(Seed2);
1478 m.Remove(Seed3);
1479 m.DumpRaw(baseDir, primName, "Proto seeds removed");
1480
1481 m.RemoveTrianglesOutside(outerHull);
1482 m.DumpRaw(baseDir, primName, "Proto outsides removed");
1483
1484 foreach (Triangle t in m.triangles)
1485 t.invertNormal();
1486
1487
1488 float skew = primShape.PathSkew * 0.01f;
1489 float pathScaleX = (float)(200 - primShape.PathScaleX) * 0.01f;
1490 float pathScaleY = (float)(200 - primShape.PathScaleY) * 0.01f;
1491 float profileXComp = pathScaleX * (1.0f - Math.Abs(skew));
1492
1493#if SPAM
1494 //Console.WriteLine("primShape.PathScaleX: " + primShape.PathScaleX.ToString() + " primShape.PathScaleY: " + primShape.PathScaleY.ToString());
1495 //Console.WriteLine("primShape.PathSkew: " + primShape.PathSkew.ToString() + " primShape.PathRadiusOffset: " + primShape.PathRadiusOffset.ToString() + " primShape.pathRevolutions: " + primShape.PathRevolutions.ToString());
1496 Console.WriteLine("PathScaleX: " + pathScaleX.ToString() + " pathScaleY: " + pathScaleY.ToString());
1497 Console.WriteLine("skew: " + skew.ToString() + " profileXComp: " + profileXComp.ToString());
1498#endif
1499
1500 foreach (Vertex v in m.vertices)
1501 if (v != null)
1502 {
1503 v.X *= profileXComp;
1504 v.Y *= pathScaleY;
1505 }
1506
1507 Extruder extr = new Extruder();
1508
1509 extr.size = size;
1510 extr.pathScaleX = pathScaleX;
1511 extr.pathScaleY = pathScaleY;
1512 extr.pathCutBegin = 0.00002f * primShape.PathBegin;
1513 extr.pathCutEnd = 0.00002f * (50000 - primShape.PathEnd);
1514 extr.pathBegin = primShape.PathBegin;
1515 extr.pathEnd = primShape.PathEnd;
1516 extr.skew = skew;
1517 extr.revolutions = 1.0f + (float)primShape.PathRevolutions * 3.0f / 200.0f;
1518 extr.pathTaperX = 0.01f * (float)primShape.PathTaperX;
1519 extr.pathTaperY = 0.01f * (float)primShape.PathTaperY;
1520
1521 extr.radius = 0.01f * (float)primShape.PathRadiusOffset;
1522
1523#if SPAM 307#if SPAM
1524 //System.Console.WriteLine("primShape.PathBegin: " + primShape.PathBegin.ToString() + " primShape.PathEnd: " + primShape.PathEnd.ToString()); 308 Console.WriteLine("****** PrimMesh Parameters (Circular) ******\n" + primMesh.ParamsToDisplayString());
1525 System.Console.WriteLine("extr.pathCutBegin: " + extr.pathCutBegin.ToString() + " extr.pathCutEnd: " + extr.pathCutEnd.ToString());
1526 System.Console.WriteLine("extr.revolutions: " + extr.revolutions.ToString());
1527
1528 //System.Console.WriteLine("primShape.PathTaperX: " + primShape.PathTaperX.ToString());
1529 //System.Console.WriteLine("primShape.PathTaperY: " + primShape.PathTaperY.ToString());
1530
1531
1532 //System.Console.WriteLine("primShape.PathRadiusOffset: " + primShape.PathRadiusOffset.ToString());
1533#endif 309#endif
1534 310 try
1535 311 {
1536 312 primMesh.ExtrudeCircular();
1537 313 }
1538 if (pathShearX != 0) 314 catch (Exception ex)
1539 { 315 {
1540 if (pathShearX > 50) 316 ReportPrimError("Extrusion failure: exception: " + ex.ToString(), primName, primMesh);
1541 { 317 return null;
1542 // Complimentary byte. Negative values wrap around the byte. Positive values go up to 50 318 }
1543 extr.pushX = (((float)(256 - pathShearX) / 100) * -1f);
1544 }
1545 else
1546 {
1547 extr.pushX = (float)pathShearX / 100;
1548 }
1549 }
1550
1551 if (pathShearY != 0)
1552 {
1553 if (pathShearY > 50)
1554 {
1555 // Complimentary byte. Negative values wrap around the byte. Positive values go up to 50
1556 extr.pushY = (((float)(256 - pathShearY) / 100) * -1f);
1557 }
1558 else
1559 {
1560 extr.pushY = (float)pathShearY / 100;
1561 } 319 }
1562 320
1563 } 321 primMesh.DumpRaw(baseDir, primName, "primMesh");
1564
1565 extr.twistTop = (float)primShape.PathTwist * (float)Math.PI * 0.02f;
1566 extr.twistBot = (float)primShape.PathTwistBegin * (float)Math.PI * 0.02f;
1567
1568 Mesh result = extr.ExtrudeCircularPath(m);
1569 result.DumpRaw(baseDir, primName, "Z extruded");
1570
1571#if SPAM
1572 int vCount = 0;
1573
1574 foreach (Vertex v in result.vertices)
1575 {
1576 if (v != null)
1577 vCount++;
1578 }
1579
1580 System.Console.WriteLine("Mesh vertex count: " + vCount.ToString());
1581#endif
1582
1583 return result;
1584 }
1585
1586 public static Vertex midUnitRadialPoint(Vertex a, Vertex b, float radius)
1587 {
1588 Vertex midpoint = new Vertex(a + b) * 0.5f;
1589 return (midpoint.normalize() * radius);
1590 }
1591
1592 public static void SphereLODTriangle(Vertex a, Vertex b, Vertex c, float diameter, float LOD, Mesh m)
1593 {
1594 Vertex aa = a - b;
1595 Vertex ba = b - c;
1596 Vertex da = c - a;
1597
1598 if (((aa.length() < LOD) && (ba.length() < LOD) && (da.length() < LOD)))
1599 {
1600 // We don't want duplicate verticies. Duplicates cause the scale algorithm to produce a spikeball
1601 // spikes are novel, but we want ellipsoids.
1602
1603 if (!m.vertices.Contains(a))
1604 m.Add(a);
1605 if (!m.vertices.Contains(b))
1606 m.Add(b);
1607 if (!m.vertices.Contains(c))
1608 m.Add(c);
1609
1610 // Add the triangle to the mesh
1611 Triangle t = new Triangle(a, b, c);
1612 m.Add(t);
1613 }
1614 else
1615 {
1616 Vertex ab = midUnitRadialPoint(a, b, diameter);
1617 Vertex bc = midUnitRadialPoint(b, c, diameter);
1618 Vertex ca = midUnitRadialPoint(c, a, diameter);
1619
1620 // Recursive! Splits the triangle up into 4 smaller triangles
1621 SphereLODTriangle(a, ab, ca, diameter, LOD, m);
1622 SphereLODTriangle(ab, b, bc, diameter, LOD, m);
1623 SphereLODTriangle(ca, bc, c, diameter, LOD, m);
1624 SphereLODTriangle(ab, bc, ca, diameter, LOD, m);
1625
1626 }
1627 }
1628
1629 private void ReportPrimError(string message, string primName, PrimMesh primMesh)
1630 {
1631 Console.WriteLine(message);
1632 Console.WriteLine("\nPrim Name: " + primName);
1633 Console.WriteLine("****** PrimMesh Parameters (Linear) ******\n" + primMesh.ParamsToDisplayString());
1634
1635 }
1636
1637 public Mesh CreateMeshFromPrimMesher(string primName, PrimitiveBaseShape primShape, PhysicsVector size, float lod)
1638 {
1639 Mesh mesh = new Mesh();
1640
1641 float pathShearX = primShape.PathShearX < 128 ? (float)primShape.PathShearX * 0.01f : (float)(primShape.PathShearX - 256) * 0.01f;
1642 float pathShearY = primShape.PathShearY < 128 ? (float)primShape.PathShearY * 0.01f : (float)(primShape.PathShearY - 256) * 0.01f;
1643 float pathBegin = (float)primShape.PathBegin * 2.0e-5f;
1644 float pathEnd = 1.0f - (float)primShape.PathEnd * 2.0e-5f;
1645 float pathScaleX = (float)(primShape.PathScaleX - 100) * 0.01f;
1646 float pathScaleY = (float)(primShape.PathScaleY - 100) * 0.01f;
1647
1648 float profileBegin = (float)primShape.ProfileBegin * 2.0e-5f;
1649 float profileEnd = 1.0f - (float)primShape.ProfileEnd * 2.0e-5f;
1650 float profileHollow = (float)primShape.ProfileHollow * 2.0e-5f;
1651
1652 int sides = 4;
1653 if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle)
1654 sides = 3;
1655 else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.Circle)
1656 sides = 24;
1657 else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle)
1658 { // half circle, prim is a sphere
1659 sides = 24;
1660
1661 profileBegin = 0.5f * profileBegin + 0.5f;
1662 profileEnd = 0.5f * profileEnd + 0.5f;
1663
1664 }
1665
1666 int hollowSides = sides;
1667 if (primShape.HollowShape == HollowShape.Circle)
1668 hollowSides = 24;
1669 else if (primShape.HollowShape == HollowShape.Square)
1670 hollowSides = 4;
1671 else if (primShape.HollowShape == HollowShape.Triangle)
1672 hollowSides = 3;
1673 322
1674 PrimMesh primMesh = new PrimMesh(sides, profileBegin, profileEnd, profileHollow, hollowSides); 323 primMesh.Scale(size.X, size.Y, size.Z);
1675 324
1676 primMesh.topShearX = pathShearX; 325 coords = primMesh.coords;
1677 primMesh.topShearY = pathShearY; 326 faces = primMesh.faces;
1678 primMesh.pathCutBegin = pathBegin;
1679 primMesh.pathCutEnd = pathEnd;
1680 327
1681 if (primShape.PathCurve == (byte)Extrusion.Straight)
1682 {
1683 primMesh.twistBegin = primShape.PathTwistBegin * 18 / 10;
1684 primMesh.twistEnd = primShape.PathTwist * 18 / 10;
1685 primMesh.taperX = pathScaleX;
1686 primMesh.taperY = pathScaleY;
1687
1688 if (profileBegin < 0.0f || profileBegin >= profileEnd || profileEnd > 1.0f)
1689 {
1690 ReportPrimError("*** CORRUPT PRIM!! ***", primName, primMesh);
1691 if (profileBegin < 0.0f) profileBegin = 0.0f;
1692 if (profileEnd > 1.0f) profileEnd = 1.0f;
1693 }
1694#if SPAM
1695 Console.WriteLine("****** PrimMesh Parameters (Linear) ******\n" + primMesh.ParamsToDisplayString());
1696#endif
1697 try
1698 {
1699 primMesh.ExtrudeLinear();
1700 }
1701 catch (Exception ex)
1702 {
1703 ReportPrimError("Extrusion failure: exception: " + ex.ToString(), primName, primMesh);
1704 return null;
1705 }
1706 } 328 }
1707 else
1708 {
1709 primMesh.holeSizeX = (200 - primShape.PathScaleX) * 0.01f;
1710 primMesh.holeSizeY = (200 - primShape.PathScaleY) * 0.01f;
1711 primMesh.radius = 0.01f * primShape.PathRadiusOffset;
1712 primMesh.revolutions = 1.0f + 0.015f * primShape.PathRevolutions;
1713 primMesh.skew = 0.01f * primShape.PathSkew;
1714 primMesh.twistBegin = primShape.PathTwistBegin * 36 / 10;
1715 primMesh.twistEnd = primShape.PathTwist * 36 / 10;
1716 primMesh.taperX = primShape.PathTaperX * 0.01f;
1717 primMesh.taperY = primShape.PathTaperY * 0.01f;
1718
1719 if (profileBegin < 0.0f || profileBegin >= profileEnd || profileEnd > 1.0f)
1720 {
1721 ReportPrimError("*** CORRUPT PRIM!! ***", primName, primMesh);
1722 if (profileBegin < 0.0f) profileBegin = 0.0f;
1723 if (profileEnd > 1.0f) profileEnd = 1.0f;
1724 }
1725#if SPAM
1726 Console.WriteLine("****** PrimMesh Parameters (Circular) ******\n" + primMesh.ParamsToDisplayString());
1727#endif
1728 try
1729 {
1730 primMesh.ExtrudeCircular();
1731 }
1732 catch (Exception ex)
1733 {
1734 ReportPrimError("Extrusion failure: exception: " + ex.ToString(), primName, primMesh);
1735 return null;
1736 }
1737 }
1738
1739 primMesh.DumpRaw(baseDir, primName, "primMesh");
1740 329
1741 primMesh.Scale(size.X, size.Y, size.Z);
1742 330
1743 int numCoords = primMesh.coords.Count; 331 int numCoords = coords.Count;
1744 int numFaces = primMesh.faces.Count; 332 int numFaces = faces.Count;
1745 333
1746 List<Coord> coords = primMesh.coords;
1747 for (int i = 0; i < numCoords; i++) 334 for (int i = 0; i < numCoords; i++)
1748 { 335 {
1749 Coord c = coords[i]; 336 Coord c = coords[i];
1750 mesh.vertices.Add(new Vertex(c.X, c.Y, c.Z)); 337 mesh.vertices.Add(new Vertex(c.X, c.Y, c.Z));
1751 } 338 }
1752 339
1753 List<Face> faces = primMesh.faces;
1754 List<Vertex> vertices = mesh.vertices; 340 List<Vertex> vertices = mesh.vertices;
1755
1756 for (int i = 0; i < numFaces; i++) 341 for (int i = 0; i < numFaces; i++)
1757 { 342 {
1758 Face f = faces[i]; 343 Face f = faces[i];
1759 mesh.triangles.Add(new Triangle(vertices[f.v1], vertices[f.v2], vertices[f.v3])); 344 mesh.triangles.Add(new Triangle(vertices[f.v1], vertices[f.v2], vertices[f.v3]));
1760 } 345 }
1761 346
1762 //for (int i = 0; i < numFaces; i++)
1763 //{
1764 // Face f = primMesh.faces[i];
1765 // Coord vert = primMesh.coords[f.v1];
1766 // Vertex v1 = new Vertex(vert.X, vert.Y, vert.Z);
1767 // mesh.vertices.Add(v1);
1768 // vert = primMesh.coords[f.v2];
1769 // Vertex v2 = new Vertex(vert.X, vert.Y, vert.Z);
1770 // mesh.vertices.Add(v2);
1771 // vert = primMesh.coords[f.v3];
1772 // Vertex v3 = new Vertex(vert.X, vert.Y, vert.Z);
1773 // mesh.vertices.Add(v3);
1774 // mesh.triangles.Add(new Triangle(v1, v2, v3));
1775 //}
1776
1777 //mesh.DumpRaw(baseDir, primName, "Mesh");
1778
1779 //mesh.primMesh = primMesh;
1780
1781 return mesh; 347 return mesh;
1782 } 348 }
1783 349
@@ -1794,83 +360,16 @@ namespace OpenSim.Region.Physics.Meshing
1794 if (size.Y < 0.01f) size.Y = 0.01f; 360 if (size.Y < 0.01f) size.Y = 0.01f;
1795 if (size.Z < 0.01f) size.Z = 0.01f; 361 if (size.Z < 0.01f) size.Z = 0.01f;
1796 362
1797#if SPAM 363 mesh = CreateMeshFromPrimMesher(primName, primShape, size, lod);
1798 reportPrimParams(primName, primShape);
1799#endif
1800
1801 if (primShape.SculptEntry && primShape.SculptType != (byte)0 && primShape.SculptData.Length > 0)
1802 {
1803 SculptMesh smesh = CreateSculptMesh(primName, primShape, size, lod);
1804 mesh = (Mesh)smesh;
1805 }
1806
1807 else if (usePrimMesher)
1808 {
1809 mesh = CreateMeshFromPrimMesher(primName, primShape, size, lod);
1810 }
1811 else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.Square)
1812 {
1813 if (primShape.PathCurve == (byte)Extrusion.Straight)
1814 { // its a box
1815 mesh = CreateBoxMesh(primName, primShape, size);
1816 //mesh = CreateMeshFromPrimMesher(primName, primShape, size, lod);
1817 }
1818 else if (primShape.PathCurve == (byte)Extrusion.Curve1)
1819 { // tube
1820 // do a cylinder for now
1821 mesh = CreateCylinderMesh(primName, primShape, size);
1822 //mesh = CreateMeshFromPrimMesher(primName, primShape, size, lod);
1823 }
1824 }
1825 else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.Circle)
1826 {
1827 if (primShape.PathCurve == (byte)Extrusion.Straight)
1828 {
1829 mesh = CreateCylinderMesh(primName, primShape, size);
1830 //mesh = CreateMeshFromPrimMesher(primName, primShape, size, lod);
1831 }
1832
1833 // ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits
1834 else if (primShape.PathCurve == (byte) Extrusion.Curve1)
1835 { // dahlia's favorite, a torus :)
1836 mesh = CreateCircularPathMesh(primName, primShape, size);
1837 //mesh = CreateMeshFromPrimMesher(primName, primShape, size, lod);\
1838 }
1839 }
1840 else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle)
1841 {
1842 if (primShape.PathCurve == (byte)Extrusion.Curve1 || primShape.PathCurve == (byte) Extrusion.Curve2)
1843 {
1844 //mesh = CreateSphereMesh(primName, primShape, size);
1845 mesh = CreateCircularPathMesh(primName, primShape, size);
1846 //mesh = CreateMeshFromPrimMesher(primName, primShape, size, lod);
1847 }
1848 }
1849 else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle)
1850 {
1851 if (primShape.PathCurve == (byte)Extrusion.Straight)
1852 {
1853 mesh = CreatePrismMesh(primName, primShape, size);
1854 //mesh = CreateMeshFromPrimMesher(primName, primShape, size, lod);
1855 }
1856 else if (primShape.PathCurve == (byte) Extrusion.Curve1)
1857 { // a ring - do a cylinder for now
1858 //mesh = CreateCylinderMesh(primName, primShape, size);
1859 mesh = CreateCircularPathMesh(primName, primShape, size);
1860 //mesh = CreateMeshFromPrimMesher(primName, primShape, size, lod);
1861 }
1862 }
1863 else // just do a box
1864 {
1865 mesh = CreateBoxMesh(primName, primShape, size);
1866 }
1867 364
1868 if (mesh != null) 365 if (mesh != null)
1869 { 366 {
1870 if ((!isPhysical) && size.X < minSizeForComplexMesh && size.Y < minSizeForComplexMesh && size.Z < minSizeForComplexMesh) 367 if ((!isPhysical) && size.X < minSizeForComplexMesh && size.Y < minSizeForComplexMesh && size.Z < minSizeForComplexMesh)
1871 { 368 {
1872#if SPAM 369#if SPAM
1873 Console.WriteLine("Meshmerizer: prim " + primName + " has a size of " + size.ToString() + " which is below threshold of " + minSizeForComplexMesh.ToString() + " - creating simple bounding box" ); 370 Console.WriteLine("Meshmerizer: prim " + primName + " has a size of " + size.ToString() + " which is below threshold of " +
371
372minSizeForComplexMesh.ToString() + " - creating simple bounding box" );
1874#endif 373#endif
1875 mesh = CreateBoundingBoxMesh(mesh); 374 mesh = CreateBoundingBoxMesh(mesh);
1876 mesh.DumpRaw(baseDir, primName, "Z extruded"); 375 mesh.DumpRaw(baseDir, primName, "Z extruded");
@@ -1884,6 +383,8 @@ namespace OpenSim.Region.Physics.Meshing
1884 return mesh; 383 return mesh;
1885 } 384 }
1886 385
386
387
1887#if SPAM 388#if SPAM
1888 // please dont comment this out until I'm done with this module - dahlia 389 // please dont comment this out until I'm done with this module - dahlia
1889 private static void reportPrimParams(string name, PrimitiveBaseShape primShape) 390 private static void reportPrimParams(string name, PrimitiveBaseShape primShape)