aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/Meshing
diff options
context:
space:
mode:
authorDahlia Trimble2008-11-29 11:02:14 +0000
committerDahlia Trimble2008-11-29 11:02:14 +0000
commitfdd238833163eb947986bfcdd09da82f6949a5f2 (patch)
tree6b90177758405f6106f4f5d4d75e3b98bf08053c /OpenSim/Region/Physics/Meshing
parentComment the ScriptSponsor and restore the indefinite lifetime for (diff)
downloadopensim-SC-fdd238833163eb947986bfcdd09da82f6949a5f2.zip
opensim-SC-fdd238833163eb947986bfcdd09da82f6949a5f2.tar.gz
opensim-SC-fdd238833163eb947986bfcdd09da82f6949a5f2.tar.bz2
opensim-SC-fdd238833163eb947986bfcdd09da82f6949a5f2.tar.xz
Update meshing code to sync with current PrimMesher.cs on forge.
Migrate sculpt meshing code to primMesher version. This should result in more accurate physical sculpted prim proxies. Remove much obsolete code from Region/Physics/Meshing
Diffstat (limited to 'OpenSim/Region/Physics/Meshing')
-rw-r--r--OpenSim/Region/Physics/Meshing/Extruder.cs472
-rw-r--r--OpenSim/Region/Physics/Meshing/HelperTypes.cs14
-rw-r--r--OpenSim/Region/Physics/Meshing/Mesh.cs20
-rw-r--r--OpenSim/Region/Physics/Meshing/Meshmerizer.cs1761
-rw-r--r--OpenSim/Region/Physics/Meshing/PrimMesher.cs163
-rw-r--r--OpenSim/Region/Physics/Meshing/SculptMesh.cs523
-rw-r--r--OpenSim/Region/Physics/Meshing/SimpleHull.cs394
-rw-r--r--OpenSim/Region/Physics/Meshing/Simplex.cs220
8 files changed, 525 insertions, 3042 deletions
diff --git a/OpenSim/Region/Physics/Meshing/Extruder.cs b/OpenSim/Region/Physics/Meshing/Extruder.cs
deleted file mode 100644
index 1fc65e3..0000000
--- a/OpenSim/Region/Physics/Meshing/Extruder.cs
+++ /dev/null
@@ -1,472 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27//#define SPAM
28
29using OpenMetaverse;
30using OpenSim.Region.Physics.Manager;
31
32namespace OpenSim.Region.Physics.Meshing
33{
34 internal class Extruder
35 {
36 //public float startParameter;
37 //public float stopParameter;
38 public PhysicsVector size;
39
40 public float taperTopFactorX = 1f;
41 public float taperTopFactorY = 1f;
42 public float taperBotFactorX = 1f;
43 public float taperBotFactorY = 1f;
44
45 public float pushX = 0f;
46 public float pushY = 0f;
47
48 // twist amount in radians. NOT DEGREES.
49 public float twistTop = 0;
50 public float twistBot = 0;
51 public float twistMid = 0;
52 public float pathScaleX = 1.0f;
53 public float pathScaleY = 0.5f;
54 public float skew = 0.0f;
55 public float radius = 0.0f;
56 public float revolutions = 1.0f;
57
58 public float pathCutBegin = 0.0f;
59 public float pathCutEnd = 1.0f;
60
61 public ushort pathBegin = 0;
62 public ushort pathEnd = 0;
63
64 public float pathTaperX = 0.0f;
65 public float pathTaperY = 0.0f;
66
67 /// <summary>
68 /// Creates an extrusion of a profile along a linear path. Used to create prim types box, cylinder, and prism.
69 /// </summary>
70 /// <param name="m"></param>
71 /// <returns>A mesh of the extruded shape</returns>
72 public Mesh ExtrudeLinearPath(Mesh m)
73 {
74 Mesh result = new Mesh();
75
76 Mesh newLayer;
77 Mesh lastLayer = null;
78
79 int step = 0;
80 int steps = 1;
81
82 float twistTotal = twistTop - twistBot;
83 // if the profile has a lot of twist, add more layers otherwise the layers may overlap
84 // and the resulting mesh may be quite inaccurate. This method is arbitrary and may not
85 // accurately match the viewer
86 float twistTotalAbs = System.Math.Abs(twistTotal);
87 if (twistTotalAbs > 0.01)
88 steps += (int)(twistTotalAbs * 3.66f); // dahlia's magic number ;)
89
90#if SPAM
91 System.Console.WriteLine("ExtrudeLinearPath: twistTotalAbs: " + twistTotalAbs.ToString() + " steps: " + steps.ToString());
92#endif
93
94 double percentOfPathMultiplier = 1.0 / steps;
95
96 float start = -0.5f;
97
98 float stepSize = 1.0f / (float)steps;
99
100 float xProfileScale = 1.0f;
101 float yProfileScale = 1.0f;
102
103 float xOffset = 0.0f;
104 float yOffset = 0.0f;
105 float zOffset = start;
106
107 float xOffsetStepIncrement = pushX / steps;
108 float yOffsetStepIncrement = pushY / steps;
109
110#if SPAM
111 System.Console.WriteLine("Extruder: twistTop: " + twistTop.ToString() + " twistbot: " + twistBot.ToString() + " twisttotal: " + twistTotal.ToString());
112 System.Console.WriteLine("Extruder: taperBotFactorX: " + taperBotFactorX.ToString() + " taperBotFactorY: " + taperBotFactorY.ToString()
113 + " taperTopFactorX: " + taperTopFactorX.ToString() + " taperTopFactorY: " + taperTopFactorY.ToString());
114 System.Console.WriteLine("Extruder: PathScaleX: " + pathScaleX.ToString() + " pathScaleY: " + pathScaleY.ToString());
115#endif
116
117 //float percentOfPath = 0.0f;
118 float percentOfPath = (float)pathBegin * 2.0e-5f;
119 zOffset += percentOfPath;
120 bool done = false;
121 do // loop through the length of the path and add the layers
122 {
123 newLayer = m.Clone();
124
125 if (taperBotFactorX < 1.0f)
126 xProfileScale = 1.0f - (1.0f - percentOfPath) * (1.0f - taperBotFactorX);
127 else if (taperTopFactorX < 1.0f)
128 xProfileScale = 1.0f - percentOfPath * (1.0f - taperTopFactorX);
129 else xProfileScale = 1.0f;
130
131 if (taperBotFactorY < 1.0f)
132 yProfileScale = 1.0f - (1.0f - percentOfPath) * (1.0f - taperBotFactorY);
133 else if (taperTopFactorY < 1.0f)
134 yProfileScale = 1.0f - percentOfPath * (1.0f - taperTopFactorY);
135 else yProfileScale = 1.0f;
136
137#if SPAM
138 //System.Console.WriteLine("xProfileScale: " + xProfileScale.ToString() + " yProfileScale: " + yProfileScale.ToString());
139#endif
140 Vertex vTemp = new Vertex(0.0f, 0.0f, 0.0f);
141
142 // apply the taper to the profile before any rotations
143 if (xProfileScale != 1.0f || yProfileScale != 1.0f)
144 {
145 foreach (Vertex v in newLayer.vertices)
146 {
147 if (v != null)
148 {
149 v.X *= xProfileScale;
150 v.Y *= yProfileScale;
151 }
152 }
153 }
154
155
156 float twist = twistBot + (twistTotal * (float)percentOfPath);
157#if SPAM
158 System.Console.WriteLine("Extruder: percentOfPath: " + percentOfPath.ToString() + " zOffset: " + zOffset.ToString()
159 + " xProfileScale: " + xProfileScale.ToString() + " yProfileScale: " + yProfileScale.ToString());
160#endif
161
162 // apply twist rotation to the profile layer and position the layer in the prim
163
164 Quaternion profileRot = Quaternion.CreateFromAxisAngle(new Vector3(0.0f, 0.0f, 1.0f), twist);
165 foreach (Vertex v in newLayer.vertices)
166 {
167 if (v != null)
168 {
169 vTemp = v * profileRot;
170 v.X = vTemp.X + xOffset;
171 v.Y = vTemp.Y + yOffset;
172 v.Z = vTemp.Z + zOffset;
173 }
174 }
175
176 if (step == 0) // the first layer, invert normals
177 {
178 foreach (Triangle t in newLayer.triangles)
179 {
180 t.invertNormal();
181 }
182 }
183
184 result.Append(newLayer);
185
186 int iLastNull = 0;
187
188 if (lastLayer != null)
189 {
190 int i, count = newLayer.vertices.Count;
191
192 for (i = 0; i < count; i++)
193 {
194 int iNext = (i + 1);
195
196 if (lastLayer.vertices[i] == null) // cant make a simplex here
197 {
198 iLastNull = i + 1;
199 }
200 else
201 {
202 if (i == count - 1) // End of list
203 iNext = iLastNull;
204
205 if (lastLayer.vertices[iNext] == null) // Null means wrap to begin of last segment
206 iNext = iLastNull;
207
208 result.Add(new Triangle(newLayer.vertices[i], lastLayer.vertices[i], newLayer.vertices[iNext]));
209 result.Add(new Triangle(newLayer.vertices[iNext], lastLayer.vertices[i], lastLayer.vertices[iNext]));
210 }
211 }
212 }
213 lastLayer = newLayer;
214
215 // calc the step for the next interation of the loop
216
217 if (step < steps)
218 {
219 step++;
220 percentOfPath += (float)percentOfPathMultiplier;
221
222 xOffset += xOffsetStepIncrement;
223 yOffset += yOffsetStepIncrement;
224 zOffset += stepSize;
225
226 if (percentOfPath > 1.0f - (float)pathEnd * 2.0e-5f)
227 done = true;
228 }
229 else done = true;
230
231 } while (!done); // loop until all the layers in the path are completed
232
233 // scale the mesh to the desired size
234 float xScale = size.X;
235 float yScale = size.Y;
236 float zScale = size.Z;
237
238 foreach (Vertex v in result.vertices)
239 {
240 if (v != null)
241 {
242 v.X *= xScale;
243 v.Y *= yScale;
244 v.Z *= zScale;
245 }
246 }
247
248 return result;
249 }
250
251 /// <summary>
252 /// Extrudes a shape around a circular path. Used to create prim types torus, ring, and tube.
253 /// </summary>
254 /// <param name="m"></param>
255 /// <returns>a mesh of the extruded shape</returns>
256 public Mesh ExtrudeCircularPath(Mesh m)
257 {
258 Mesh result = new Mesh();
259
260 Mesh newLayer;
261 Mesh lastLayer = null;
262
263 int step;
264 int steps = 24;
265
266 float twistTotal = twistTop - twistBot;
267 // if the profile has a lot of twist, add more layers otherwise the layers may overlap
268 // and the resulting mesh may be quite inaccurate. This method is arbitrary and doesn't
269 // accurately match the viewer
270 if (System.Math.Abs(twistTotal) > (float)System.Math.PI * 1.5f) steps *= 2;
271 if (System.Math.Abs(twistTotal) > (float)System.Math.PI * 3.0f) steps *= 2;
272
273 // double percentOfPathMultiplier = 1.0 / steps;
274 // double angleStepMultiplier = System.Math.PI * 2.0 / steps;
275
276 float yPathScale = pathScaleY * 0.5f;
277 float pathLength = pathCutEnd - pathCutBegin;
278 float totalSkew = skew * 2.0f * pathLength;
279 float skewStart = (-skew) + pathCutBegin * 2.0f * skew;
280
281 // It's not quite clear what pushY (Y top shear) does, but subtracting it from the start and end
282 // angles appears to approximate it's effects on path cut. Likewise, adding it to the angle used
283 // to calculate the sine for generating the path radius appears to approximate it's effects there
284 // too, but there are some subtle differences in the radius which are noticeable as the prim size
285 // increases and it may affect megaprims quite a bit. The effect of the Y top shear parameter on
286 // the meshes generated with this technique appear nearly identical in shape to the same prims when
287 // displayed by the viewer.
288
289
290 float startAngle = (float)(System.Math.PI * 2.0 * pathCutBegin * revolutions) - pushY * 0.9f;
291 float endAngle = (float)(System.Math.PI * 2.0 * pathCutEnd * revolutions) - pushY * 0.9f;
292 float stepSize = (float)0.2617993878; // 2*PI / 24 segments per revolution
293
294 step = (int)(startAngle / stepSize);
295 float angle = startAngle;
296
297 float xProfileScale = 1.0f;
298 float yProfileScale = 1.0f;
299
300
301#if SPAM
302 System.Console.WriteLine("Extruder: twistTop: " + twistTop.ToString() + " twistbot: " + twistBot.ToString() + " twisttotal: " + twistTotal.ToString());
303 System.Console.WriteLine("Extruder: startAngle: " + startAngle.ToString() + " endAngle: " + endAngle.ToString() + " step: " + step.ToString());
304 System.Console.WriteLine("Extruder: taperBotFactorX: " + taperBotFactorX.ToString() + " taperBotFactorY: " + taperBotFactorY.ToString()
305 + " taperTopFactorX: " + taperTopFactorX.ToString() + " taperTopFactorY: " + taperTopFactorY.ToString());
306 System.Console.WriteLine("Extruder: PathScaleX: " + pathScaleX.ToString() + " pathScaleY: " + pathScaleY.ToString());
307#endif
308
309 bool done = false;
310 do // loop through the length of the path and add the layers
311 {
312 newLayer = m.Clone();
313
314 float percentOfPath = (angle - startAngle) / (endAngle - startAngle); // endAngle should always be larger than startAngle
315
316 if (pathTaperX > 0.001f) // can't really compare to 0.0f as the value passed is never exactly zero
317 xProfileScale = 1.0f - percentOfPath * pathTaperX;
318 else if (pathTaperX < -0.001f)
319 xProfileScale = 1.0f + (1.0f - percentOfPath) * pathTaperX;
320 else xProfileScale = 1.0f;
321
322 if (pathTaperY > 0.001f)
323 yProfileScale = 1.0f - percentOfPath * pathTaperY;
324 else if (pathTaperY < -0.001f)
325 yProfileScale = 1.0f + (1.0f - percentOfPath) * pathTaperY;
326 else yProfileScale = 1.0f;
327
328#if SPAM
329 //System.Console.WriteLine("xProfileScale: " + xProfileScale.ToString() + " yProfileScale: " + yProfileScale.ToString());
330#endif
331 Vertex vTemp = new Vertex(0.0f, 0.0f, 0.0f);
332
333 // apply the taper to the profile before any rotations
334 if (xProfileScale != 1.0f || yProfileScale != 1.0f)
335 {
336 foreach (Vertex v in newLayer.vertices)
337 {
338 if (v != null)
339 {
340 v.X *= xProfileScale;
341 v.Y *= yProfileScale;
342 }
343 }
344 }
345
346 float radiusScale;
347
348 if (radius > 0.001f)
349 radiusScale = 1.0f - radius * percentOfPath;
350 else if (radius < 0.001f)
351 radiusScale = 1.0f + radius * (1.0f - percentOfPath);
352 else
353 radiusScale = 1.0f;
354
355#if SPAM
356 System.Console.WriteLine("Extruder: angle: " + angle.ToString() + " percentOfPath: " + percentOfPath.ToString()
357 + " radius: " + radius.ToString() + " radiusScale: " + radiusScale.ToString()
358 + " xProfileScale: " + xProfileScale.ToString() + " yProfileScale: " + yProfileScale.ToString());
359#endif
360
361 float twist = twistBot + (twistTotal * (float)percentOfPath);
362
363 float xOffset;
364 float yOffset;
365 float zOffset;
366
367 xOffset = 0.5f * (skewStart + totalSkew * (float)percentOfPath);
368 xOffset += (float) System.Math.Sin(angle) * pushX * 0.45f;
369 yOffset = (float)(System.Math.Cos(angle) * (0.5f - yPathScale)) * radiusScale;
370 zOffset = (float)(System.Math.Sin(angle + pushY * 0.9f) * (0.5f - yPathScale)) * radiusScale;
371
372 // next apply twist rotation to the profile layer
373 if (twistTotal != 0.0f || twistBot != 0.0f)
374 {
375 Quaternion profileRot = new Quaternion(new Vector3(0.0f, 0.0f, 1.0f), twist);
376 foreach (Vertex v in newLayer.vertices)
377 {
378 if (v != null)
379 {
380 vTemp = v * profileRot;
381 v.X = vTemp.X;
382 v.Y = vTemp.Y;
383 v.Z = vTemp.Z;
384 }
385 }
386 }
387
388 // now orient the rotation of the profile layer relative to it's position on the path
389 // adding pushY to the angle used to generate the quat appears to approximate the viewer
390 Quaternion layerRot = Quaternion.CreateFromAxisAngle(new Vector3(1.0f, 0.0f, 0.0f), (float)angle + pushY * 0.9f);
391 foreach (Vertex v in newLayer.vertices)
392 {
393 if (v != null)
394 {
395 vTemp = v * layerRot;
396 v.X = vTemp.X + xOffset;
397 v.Y = vTemp.Y + yOffset;
398 v.Z = vTemp.Z + zOffset;
399 }
400 }
401
402 if (angle == startAngle) // the first layer, invert normals
403 {
404 foreach (Triangle t in newLayer.triangles)
405 {
406 t.invertNormal();
407 }
408 }
409
410 result.Append(newLayer);
411
412 int iLastNull = 0;
413
414 if (lastLayer != null)
415 {
416 int i, count = newLayer.vertices.Count;
417
418 for (i = 0; i < count; i++)
419 {
420 int iNext = (i + 1);
421
422 if (lastLayer.vertices[i] == null) // cant make a simplex here
423 {
424 iLastNull = i + 1;
425 }
426 else
427 {
428 if (i == count - 1) // End of list
429 iNext = iLastNull;
430
431 if (lastLayer.vertices[iNext] == null) // Null means wrap to begin of last segment
432 iNext = iLastNull;
433
434 result.Add(new Triangle(newLayer.vertices[i], lastLayer.vertices[i], newLayer.vertices[iNext]));
435 result.Add(new Triangle(newLayer.vertices[iNext], lastLayer.vertices[i], lastLayer.vertices[iNext]));
436 }
437 }
438 }
439 lastLayer = newLayer;
440
441 // calc the angle for the next interation of the loop
442 if (angle >= endAngle)
443 {
444 done = true;
445 }
446 else
447 {
448 angle = stepSize * ++step;
449 if (angle > endAngle)
450 angle = endAngle;
451 }
452 } while (!done); // loop until all the layers in the path are completed
453
454 // scale the mesh to the desired size
455 float xScale = size.X;
456 float yScale = size.Y;
457 float zScale = size.Z;
458
459 foreach (Vertex v in result.vertices)
460 {
461 if (v != null)
462 {
463 v.X *= xScale;
464 v.Y *= yScale;
465 v.Z *= zScale;
466 }
467 }
468
469 return result;
470 }
471 }
472}
diff --git a/OpenSim/Region/Physics/Meshing/HelperTypes.cs b/OpenSim/Region/Physics/Meshing/HelperTypes.cs
index 7491782..7198cae 100644
--- a/OpenSim/Region/Physics/Meshing/HelperTypes.cs
+++ b/OpenSim/Region/Physics/Meshing/HelperTypes.cs
@@ -356,20 +356,6 @@ public class Triangle
356 radius_square = (float) (rx*rx + ry*ry); 356 radius_square = (float) (rx*rx + ry*ry);
357 } 357 }
358 358
359 public List<Simplex> GetSimplices()
360 {
361 List<Simplex> result = new List<Simplex>();
362 Simplex s1 = new Simplex(v1, v2);
363 Simplex s2 = new Simplex(v2, v3);
364 Simplex s3 = new Simplex(v3, v1);
365
366 result.Add(s1);
367 result.Add(s2);
368 result.Add(s3);
369
370 return result;
371 }
372
373 public override String ToString() 359 public override String ToString()
374 { 360 {
375 NumberFormatInfo nfi = new NumberFormatInfo(); 361 NumberFormatInfo nfi = new NumberFormatInfo();
diff --git a/OpenSim/Region/Physics/Meshing/Mesh.cs b/OpenSim/Region/Physics/Meshing/Mesh.cs
index 583b485..5a565ff 100644
--- a/OpenSim/Region/Physics/Meshing/Mesh.cs
+++ b/OpenSim/Region/Physics/Meshing/Mesh.cs
@@ -115,26 +115,6 @@ namespace OpenSim.Region.Physics.Meshing
115 vertices.Remove(v); 115 vertices.Remove(v);
116 } 116 }
117 117
118 public void RemoveTrianglesOutside(SimpleHull hull)
119 {
120 int i;
121
122 for (i = 0; i < triangles.Count; i++)
123 {
124 Triangle t = triangles[i];
125 Vertex v1 = t.v1;
126 Vertex v2 = t.v2;
127 Vertex v3 = t.v3;
128 PhysicsVector m = v1 + v2 + v3;
129 m /= 3.0f;
130 if (!hull.IsPointIn(new Vertex(m)))
131 {
132 triangles.RemoveAt(i);
133 i--;
134 }
135 }
136 }
137
138 public void Add(List<Vertex> lv) 118 public void Add(List<Vertex> lv)
139 { 119 {
140 foreach (Vertex v in lv) 120 foreach (Vertex v in lv)
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)
diff --git a/OpenSim/Region/Physics/Meshing/PrimMesher.cs b/OpenSim/Region/Physics/Meshing/PrimMesher.cs
index 282bbd5..d79a480 100644
--- a/OpenSim/Region/Physics/Meshing/PrimMesher.cs
+++ b/OpenSim/Region/Physics/Meshing/PrimMesher.cs
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (c) Contributors, http://opensimulator.org/ 2 * Copyright (c) Contributors
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
@@ -243,10 +243,11 @@ namespace PrimMesher
243 public int n2; 243 public int n2;
244 public int n3; 244 public int n3;
245 245
246 //// UVs 246 // uvs
247 //public int uv1; 247 public int uv1;
248 //public int uv2; 248 public int uv2;
249 //public int uv3; 249 public int uv3;
250
250 251
251 public Face(int v1, int v2, int v3) 252 public Face(int v1, int v2, int v3)
252 { 253 {
@@ -260,9 +261,10 @@ namespace PrimMesher
260 this.n2 = 0; 261 this.n2 = 0;
261 this.n3 = 0; 262 this.n3 = 0;
262 263
263 //this.uv1 = 0; 264 this.uv1 = 0;
264 //this.uv2 = 0; 265 this.uv2 = 0;
265 //this.uv3 = 0; 266 this.uv3 = 0;
267
266 } 268 }
267 269
268 public Face(int v1, int v2, int v3, int n1, int n2, int n3) 270 public Face(int v1, int v2, int v3, int n1, int n2, int n3)
@@ -277,9 +279,21 @@ namespace PrimMesher
277 this.n2 = n2; 279 this.n2 = n2;
278 this.n3 = n3; 280 this.n3 = n3;
279 281
280 //this.uv1 = 0; 282 this.uv1 = 0;
281 //this.uv2 = 0; 283 this.uv2 = 0;
282 //this.uv3 = 0; 284 this.uv3 = 0;
285 }
286
287 public Coord SurfaceNormal(List<Coord> coordList)
288 {
289 Coord c1 = coordList[this.v1];
290 Coord c2 = coordList[this.v2];
291 Coord c3 = coordList[this.v3];
292
293 Coord edge1 = new Coord(c2.X - c1.X, c2.Y - c1.Y, c2.Z - c1.Z);
294 Coord edge2 = new Coord(c3.X - c1.X, c3.Y - c1.Y, c3.Z - c1.Z);
295
296 return Coord.Cross(edge1, edge2).Normalize();
283 } 297 }
284 } 298 }
285 299
@@ -560,7 +574,7 @@ namespace PrimMesher
560 /// <summary> 574 /// <summary>
561 /// generates a profile for extrusion 575 /// generates a profile for extrusion
562 /// </summary> 576 /// </summary>
563 public class Profile 577 internal class Profile
564 { 578 {
565 private const float twoPi = 2.0f * (float)Math.PI; 579 private const float twoPi = 2.0f * (float)Math.PI;
566 580
@@ -569,6 +583,7 @@ namespace PrimMesher
569 internal List<Coord> vertexNormals; 583 internal List<Coord> vertexNormals;
570 internal List<float> us; 584 internal List<float> us;
571 internal List<UVCoord> faceUVs; 585 internal List<UVCoord> faceUVs;
586 internal List<int> faceNumbers;
572 587
573 internal Coord faceNormal = new Coord(0.0f, 0.0f, 1.0f); 588 internal Coord faceNormal = new Coord(0.0f, 0.0f, 1.0f);
574 internal Coord cutNormal1 = new Coord(); 589 internal Coord cutNormal1 = new Coord();
@@ -578,6 +593,8 @@ namespace PrimMesher
578 internal int numHollowVerts = 0; 593 internal int numHollowVerts = 0;
579 594
580 internal bool calcVertexNormals = false; 595 internal bool calcVertexNormals = false;
596 internal int bottomFaceNumber = 0;
597 internal int numPrimFaces = 0;
581 598
582 internal Profile() 599 internal Profile()
583 { 600 {
@@ -586,9 +603,10 @@ namespace PrimMesher
586 this.vertexNormals = new List<Coord>(); 603 this.vertexNormals = new List<Coord>();
587 this.us = new List<float>(); 604 this.us = new List<float>();
588 this.faceUVs = new List<UVCoord>(); 605 this.faceUVs = new List<UVCoord>();
606 this.faceNumbers = new List<int>();
589 } 607 }
590 608
591 public Profile(int sides, float profileStart, float profileEnd, float hollow, int hollowSides, bool createFaces, bool calcVertexNormals) 609 internal Profile(int sides, float profileStart, float profileEnd, float hollow, int hollowSides, bool createFaces, bool calcVertexNormals)
592 { 610 {
593 this.calcVertexNormals = calcVertexNormals; 611 this.calcVertexNormals = calcVertexNormals;
594 this.coords = new List<Coord>(); 612 this.coords = new List<Coord>();
@@ -596,6 +614,8 @@ namespace PrimMesher
596 this.vertexNormals = new List<Coord>(); 614 this.vertexNormals = new List<Coord>();
597 this.us = new List<float>(); 615 this.us = new List<float>();
598 this.faceUVs = new List<UVCoord>(); 616 this.faceUVs = new List<UVCoord>();
617 this.faceNumbers = new List<int>();
618
599 Coord center = new Coord(0.0f, 0.0f, 0.0f); 619 Coord center = new Coord(0.0f, 0.0f, 0.0f);
600 620
601 List<Coord> hollowCoords = new List<Coord>(); 621 List<Coord> hollowCoords = new List<Coord>();
@@ -674,7 +694,7 @@ namespace PrimMesher
674 hollowCoords.Add(newVert); 694 hollowCoords.Add(newVert);
675 if (this.calcVertexNormals) 695 if (this.calcVertexNormals)
676 { 696 {
677 if (sides < 5) 697 if (hollowSides < 5)
678 hollowNormals.Add(hollowAngles.normals[i].Invert()); 698 hollowNormals.Add(hollowAngles.normals[i].Invert());
679 else 699 else
680 hollowNormals.Add(new Coord(-angle.X, -angle.Y, 0.0f)); 700 hollowNormals.Add(new Coord(-angle.X, -angle.Y, 0.0f));
@@ -689,7 +709,7 @@ namespace PrimMesher
689 709
690 for (int i = 0; i < numAngles; i++) 710 for (int i = 0; i < numAngles; i++)
691 { 711 {
692 //int iNext = i == numAngles ? i + 1 : 0; 712 int iNext = i == numAngles ? i + 1 : 0;
693 angle = angles.angles[i]; 713 angle = angles.angles[i];
694 newVert.X = angle.X * xScale; 714 newVert.X = angle.X * xScale;
695 newVert.Y = angle.Y * yScale; 715 newVert.Y = angle.Y * yScale;
@@ -884,21 +904,46 @@ namespace PrimMesher
884 hollowNormals = null; 904 hollowNormals = null;
885 hollowUs = null; 905 hollowUs = null;
886 906
907 if (calcVertexNormals)
908 { // calculate prim face numbers
909 // I know it's ugly but so is the whole concept of prim face numbers
910 int faceNum = 1;
911 int startVert = hasProfileCut && !hasHollow ? 1 : 0;
912 if (startVert > 0)
913 this.faceNumbers.Add(0);
914 for (int i = 0; i < numOuterVerts; i++)
915 this.faceNumbers.Add(sides < 5 ? faceNum++ : faceNum);
916 if (sides > 4)
917 faceNum++;
918 if (hasProfileCut)
919 this.faceNumbers.Add(0);
920 for (int i = 0; i < numHollowVerts; i++)
921 this.faceNumbers.Add(faceNum++);
922 this.bottomFaceNumber = faceNum++;
923 if (hasHollow && hasProfileCut)
924 this.faceNumbers.Add(faceNum++);
925 for (int i = 0; i < this.faceNumbers.Count; i++)
926 if (this.faceNumbers[i] == 0)
927 this.faceNumbers[i] = faceNum++;
928
929 this.numPrimFaces = faceNum;
930 }
931
887 } 932 }
888 933
889 public void MakeFaceUVs() 934 internal void MakeFaceUVs()
890 { 935 {
891 this.faceUVs = new List<UVCoord>(); 936 this.faceUVs = new List<UVCoord>();
892 foreach (Coord c in this.coords) 937 foreach (Coord c in this.coords)
893 this.faceUVs.Add(new UVCoord(1.0f - (0.5f + c.X), 1.0f - (0.5f - c.Y))); 938 this.faceUVs.Add(new UVCoord(1.0f - (0.5f + c.X), 1.0f - (0.5f - c.Y)));
894 } 939 }
895 940
896 public Profile Clone() 941 internal Profile Clone()
897 { 942 {
898 return this.Clone(true); 943 return this.Clone(true);
899 } 944 }
900 945
901 public Profile Clone(bool needFaces) 946 internal Profile Clone(bool needFaces)
902 { 947 {
903 Profile clone = new Profile(); 948 Profile clone = new Profile();
904 949
@@ -914,6 +959,7 @@ namespace PrimMesher
914 clone.cutNormal1 = this.cutNormal1; 959 clone.cutNormal1 = this.cutNormal1;
915 clone.cutNormal2 = this.cutNormal2; 960 clone.cutNormal2 = this.cutNormal2;
916 clone.us.AddRange(this.us); 961 clone.us.AddRange(this.us);
962 clone.faceNumbers.AddRange(this.faceNumbers);
917 } 963 }
918 clone.numOuterVerts = this.numOuterVerts; 964 clone.numOuterVerts = this.numOuterVerts;
919 clone.numHollowVerts = this.numHollowVerts; 965 clone.numHollowVerts = this.numHollowVerts;
@@ -921,12 +967,12 @@ namespace PrimMesher
921 return clone; 967 return clone;
922 } 968 }
923 969
924 public void AddPos(Coord v) 970 internal void AddPos(Coord v)
925 { 971 {
926 this.AddPos(v.X, v.Y, v.Z); 972 this.AddPos(v.X, v.Y, v.Z);
927 } 973 }
928 974
929 public void AddPos(float x, float y, float z) 975 internal void AddPos(float x, float y, float z)
930 { 976 {
931 int i; 977 int i;
932 int numVerts = this.coords.Count; 978 int numVerts = this.coords.Count;
@@ -942,7 +988,7 @@ namespace PrimMesher
942 } 988 }
943 } 989 }
944 990
945 public void AddRot(Quat q) 991 internal void AddRot(Quat q)
946 { 992 {
947 int i; 993 int i;
948 int numVerts = this.coords.Count; 994 int numVerts = this.coords.Count;
@@ -963,7 +1009,7 @@ namespace PrimMesher
963 } 1009 }
964 } 1010 }
965 1011
966 public void Scale(float x, float y) 1012 internal void Scale(float x, float y)
967 { 1013 {
968 int i; 1014 int i;
969 int numVerts = this.coords.Count; 1015 int numVerts = this.coords.Count;
@@ -981,7 +1027,7 @@ namespace PrimMesher
981 /// <summary> 1027 /// <summary>
982 /// Changes order of the vertex indices and negates the center vertex normal. Does not alter vertex normals of radial vertices 1028 /// Changes order of the vertex indices and negates the center vertex normal. Does not alter vertex normals of radial vertices
983 /// </summary> 1029 /// </summary>
984 public void FlipNormals() 1030 internal void FlipNormals()
985 { 1031 {
986 int i; 1032 int i;
987 int numFaces = this.faces.Count; 1033 int numFaces = this.faces.Count;
@@ -1021,7 +1067,7 @@ namespace PrimMesher
1021 } 1067 }
1022 } 1068 }
1023 1069
1024 public void AddValue2FaceVertexIndices(int num) 1070 internal void AddValue2FaceVertexIndices(int num)
1025 { 1071 {
1026 int numFaces = this.faces.Count; 1072 int numFaces = this.faces.Count;
1027 Face tmpFace; 1073 Face tmpFace;
@@ -1036,7 +1082,7 @@ namespace PrimMesher
1036 } 1082 }
1037 } 1083 }
1038 1084
1039 public void AddValue2FaceNormalIndices(int num) 1085 internal void AddValue2FaceNormalIndices(int num)
1040 { 1086 {
1041 if (this.calcVertexNormals) 1087 if (this.calcVertexNormals)
1042 { 1088 {
@@ -1054,7 +1100,7 @@ namespace PrimMesher
1054 } 1100 }
1055 } 1101 }
1056 1102
1057 public void DumpRaw(String path, String name, String title) 1103 internal void DumpRaw(String path, String name, String title)
1058 { 1104 {
1059 if (path == null) 1105 if (path == null)
1060 return; 1106 return;
@@ -1113,6 +1159,12 @@ namespace PrimMesher
1113 private bool normalsProcessed = false; 1159 private bool normalsProcessed = false;
1114 public bool viewerMode = false; 1160 public bool viewerMode = false;
1115 1161
1162 public int numPrimFaces = 0;
1163
1164 /// <summary>
1165 /// Human readable string representation of the parameters used to create a mesh.
1166 /// </summary>
1167 /// <returns></returns>
1116 public string ParamsToDisplayString() 1168 public string ParamsToDisplayString()
1117 { 1169 {
1118 string s = ""; 1170 string s = "";
@@ -1141,7 +1193,14 @@ namespace PrimMesher
1141 return s; 1193 return s;
1142 } 1194 }
1143 1195
1144 1196 /// <summary>
1197 /// Constructs a PrimMesh object and creates the profile for extrusion.
1198 /// </summary>
1199 /// <param name="sides"></param>
1200 /// <param name="profileStart"></param>
1201 /// <param name="profileEnd"></param>
1202 /// <param name="hollow"></param>
1203 /// <param name="hollowSides"></param>
1145 public PrimMesh(int sides, float profileStart, float profileEnd, float hollow, int hollowSides) 1204 public PrimMesh(int sides, float profileStart, float profileEnd, float hollow, int hollowSides)
1146 { 1205 {
1147 this.coords = new List<Coord>(); 1206 this.coords = new List<Coord>();
@@ -1174,6 +1233,9 @@ namespace PrimMesher
1174 this.hasHollow = (this.hollow > 0.001f); 1233 this.hasHollow = (this.hollow > 0.001f);
1175 } 1234 }
1176 1235
1236 /// <summary>
1237 /// Extrudes a profile along a straight line path. Used for prim types box, cylinder, and prism.
1238 /// </summary>
1177 public void ExtrudeLinear() 1239 public void ExtrudeLinear()
1178 { 1240 {
1179 this.coords = new List<Coord>(); 1241 this.coords = new List<Coord>();
@@ -1248,6 +1310,7 @@ namespace PrimMesher
1248 hollow *= 1.414f; 1310 hollow *= 1.414f;
1249 1311
1250 Profile profile = new Profile(this.sides, this.profileStart, this.profileEnd, hollow, this.hollowSides, true, calcVertexNormals); 1312 Profile profile = new Profile(this.sides, this.profileStart, this.profileEnd, hollow, this.hollowSides, true, calcVertexNormals);
1313 this.numPrimFaces = profile.numPrimFaces;
1251 1314
1252 int cut1Vert = -1; 1315 int cut1Vert = -1;
1253 int cut2Vert = -1; 1316 int cut2Vert = -1;
@@ -1398,7 +1461,7 @@ namespace PrimMesher
1398 if (u2 < 0.1f) 1461 if (u2 < 0.1f)
1399 u2 = 1.0f; 1462 u2 = 1.0f;
1400 1463
1401 newViewerFace2.primFaceNumber = newViewerFace1.primFaceNumber = whichVert + 1; 1464 //newViewerFace2.primFaceNumber = newViewerFace1.primFaceNumber = whichVert + 1;
1402 } 1465 }
1403 1466
1404 newViewerFace1.uv1.U = u1; 1467 newViewerFace1.uv1.U = u1;
@@ -1462,6 +1525,8 @@ namespace PrimMesher
1462 } 1525 }
1463 } 1526 }
1464 1527
1528 newViewerFace2.primFaceNumber = newViewerFace1.primFaceNumber = newLayer.faceNumbers[whichVert];
1529
1465 this.viewerFaces.Add(newViewerFace1); 1530 this.viewerFaces.Add(newViewerFace1);
1466 this.viewerFaces.Add(newViewerFace2); 1531 this.viewerFaces.Add(newViewerFace2);
1467 1532
@@ -1492,7 +1557,7 @@ namespace PrimMesher
1492 // add the top faces to the viewerFaces list here 1557 // add the top faces to the viewerFaces list here
1493 Coord faceNormal = newLayer.faceNormal; 1558 Coord faceNormal = newLayer.faceNormal;
1494 ViewerFace newViewerFace = new ViewerFace(); 1559 ViewerFace newViewerFace = new ViewerFace();
1495 newViewerFace.primFaceNumber = 0; 1560 newViewerFace.primFaceNumber = newLayer.bottomFaceNumber;
1496 foreach (Face face in newLayer.faces) 1561 foreach (Face face in newLayer.faces)
1497 { 1562 {
1498 newViewerFace.v1 = newLayer.coords[face.v1 - coordsLen]; 1563 newViewerFace.v1 = newLayer.coords[face.v1 - coordsLen];
@@ -1513,6 +1578,9 @@ namespace PrimMesher
1513 } 1578 }
1514 } 1579 }
1515 1580
1581 /// <summary>
1582 /// Extrude a profile into a circular path prim mesh. Used for prim types torus, tube, and ring.
1583 /// </summary>
1516 public void ExtrudeCircular() 1584 public void ExtrudeCircular()
1517 { 1585 {
1518 this.coords = new List<Coord>(); 1586 this.coords = new List<Coord>();
@@ -1615,6 +1683,7 @@ namespace PrimMesher
1615 needEndFaces = true; 1683 needEndFaces = true;
1616 1684
1617 Profile profile = new Profile(this.sides, this.profileStart, this.profileEnd, hollow, this.hollowSides, needEndFaces, calcVertexNormals); 1685 Profile profile = new Profile(this.sides, this.profileStart, this.profileEnd, hollow, this.hollowSides, needEndFaces, calcVertexNormals);
1686 this.numPrimFaces = profile.numPrimFaces;
1618 1687
1619 int cut1Vert = -1; 1688 int cut1Vert = -1;
1620 int cut2Vert = -1; 1689 int cut2Vert = -1;
@@ -1787,7 +1856,7 @@ namespace PrimMesher
1787 if (u2 < 0.1f) 1856 if (u2 < 0.1f)
1788 u2 = 1.0f; 1857 u2 = 1.0f;
1789 1858
1790 newViewerFace2.primFaceNumber = newViewerFace1.primFaceNumber = whichVert + 1; 1859 //newViewerFace2.primFaceNumber = newViewerFace1.primFaceNumber = whichVert + 1;
1791 } 1860 }
1792 1861
1793 newViewerFace1.uv1.U = u1; 1862 newViewerFace1.uv1.U = u1;
@@ -1865,6 +1934,7 @@ namespace PrimMesher
1865 } 1934 }
1866 } 1935 }
1867 1936
1937 newViewerFace1.primFaceNumber = newViewerFace2.primFaceNumber = newLayer.faceNumbers[whichVert];
1868 this.viewerFaces.Add(newViewerFace1); 1938 this.viewerFaces.Add(newViewerFace1);
1869 this.viewerFaces.Add(newViewerFace2); 1939 this.viewerFaces.Add(newViewerFace2);
1870 1940
@@ -1894,7 +1964,7 @@ namespace PrimMesher
1894 // add the bottom faces to the viewerFaces list here 1964 // add the bottom faces to the viewerFaces list here
1895 Coord faceNormal = newLayer.faceNormal; 1965 Coord faceNormal = newLayer.faceNormal;
1896 ViewerFace newViewerFace = new ViewerFace(); 1966 ViewerFace newViewerFace = new ViewerFace();
1897 newViewerFace.primFaceNumber = 0; 1967 newViewerFace.primFaceNumber = newLayer.bottomFaceNumber;
1898 foreach (Face face in newLayer.faces) 1968 foreach (Face face in newLayer.faces)
1899 { 1969 {
1900 newViewerFace.v1 = newLayer.coords[face.v1 - coordsLen]; 1970 newViewerFace.v1 = newLayer.coords[face.v1 - coordsLen];
@@ -1932,6 +2002,11 @@ namespace PrimMesher
1932 return SurfaceNormal(this.coords[face.v1], this.coords[face.v2], this.coords[face.v3]); 2002 return SurfaceNormal(this.coords[face.v1], this.coords[face.v2], this.coords[face.v3]);
1933 } 2003 }
1934 2004
2005 /// <summary>
2006 /// Calculate the surface normal for a face in the list of faces
2007 /// </summary>
2008 /// <param name="faceIndex"></param>
2009 /// <returns></returns>
1935 public Coord SurfaceNormal(int faceIndex) 2010 public Coord SurfaceNormal(int faceIndex)
1936 { 2011 {
1937 int numFaces = this.faces.Count; 2012 int numFaces = this.faces.Count;
@@ -1941,6 +2016,9 @@ namespace PrimMesher
1941 return SurfaceNormal(this.faces[faceIndex]); 2016 return SurfaceNormal(this.faces[faceIndex]);
1942 } 2017 }
1943 2018
2019 /// <summary>
2020 /// Calculate surface normals for all of the faces in the list of faces in this mesh
2021 /// </summary>
1944 public void CalcNormals() 2022 public void CalcNormals()
1945 { 2023 {
1946 if (normalsProcessed) 2024 if (normalsProcessed)
@@ -1968,6 +2046,12 @@ namespace PrimMesher
1968 } 2046 }
1969 } 2047 }
1970 2048
2049 /// <summary>
2050 /// Adds a value to each XYZ vertex coordinate in the mesh
2051 /// </summary>
2052 /// <param name="x"></param>
2053 /// <param name="y"></param>
2054 /// <param name="z"></param>
1971 public void AddPos(float x, float y, float z) 2055 public void AddPos(float x, float y, float z)
1972 { 2056 {
1973 int i; 2057 int i;
@@ -1984,9 +2068,12 @@ namespace PrimMesher
1984 } 2068 }
1985 } 2069 }
1986 2070
2071 /// <summary>
2072 /// Rotates the mesh
2073 /// </summary>
2074 /// <param name="q"></param>
1987 public void AddRot(Quat q) 2075 public void AddRot(Quat q)
1988 { 2076 {
1989 Console.WriteLine("AddRot(" + q.ToString() + ")");
1990 int i; 2077 int i;
1991 int numVerts = this.coords.Count; 2078 int numVerts = this.coords.Count;
1992 2079
@@ -2020,6 +2107,12 @@ namespace PrimMesher
2020 2107
2021 } 2108 }
2022 2109
2110 /// <summary>
2111 /// Scales the mesh
2112 /// </summary>
2113 /// <param name="x"></param>
2114 /// <param name="y"></param>
2115 /// <param name="z"></param>
2023 public void Scale(float x, float y, float z) 2116 public void Scale(float x, float y, float z)
2024 { 2117 {
2025 int i; 2118 int i;
@@ -2046,6 +2139,12 @@ namespace PrimMesher
2046 2139
2047 } 2140 }
2048 2141
2142 /// <summary>
2143 /// Dumps the mesh to a Blender compatible "Raw" format file
2144 /// </summary>
2145 /// <param name="path"></param>
2146 /// <param name="name"></param>
2147 /// <param name="title"></param>
2049 public void DumpRaw(String path, String name, String title) 2148 public void DumpRaw(String path, String name, String title)
2050 { 2149 {
2051 if (path == null) 2150 if (path == null)
diff --git a/OpenSim/Region/Physics/Meshing/SculptMesh.cs b/OpenSim/Region/Physics/Meshing/SculptMesh.cs
index 0dc7ef2..826030b 100644
--- a/OpenSim/Region/Physics/Meshing/SculptMesh.cs
+++ b/OpenSim/Region/Physics/Meshing/SculptMesh.cs
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (c) Contributors, http://opensimulator.org/ 2 * Copyright (c) Contributors
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
@@ -27,314 +27,317 @@
27 27
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Text;
31using System.IO;
30using System.Drawing; 32using System.Drawing;
31using System.Drawing.Imaging; 33using System.Drawing.Imaging;
32using System.Text;
33using OpenMetaverse.Imaging;
34 34
35namespace OpenSim.Region.Physics.Meshing 35namespace PrimMesher
36{ 36{
37 // This functionality based on the XNA SculptPreview by John Hurliman.
38 public class SculptMesh : Mesh
39 {
40 Image idata = null;
41 Bitmap bLOD = null;
42 Bitmap bBitmap = null;
43 37
44 Vertex northpole = new Vertex(0, 0, 0); 38 public class SculptMesh
45 Vertex southpole = new Vertex(0, 0, 0); 39 {
40 public List<Coord> coords;
41 public List<Face> faces;
46 42
47 private int lod = 32; 43 public List<ViewerFace> viewerFaces;
48 private const float RANGE = 128.0f; 44 public List<Coord> normals;
45 public List<UVCoord> uvs;
49 46
50 public SculptMesh(byte[] jpegData, float _lod) 47 public enum SculptType { sphere = 1, torus = 2, plane = 3, cylinder = 4 };
48 private const float pixScale = 0.00390625f; // 1.0 / 256
49
50 private Bitmap ScaleImage(Bitmap srcImage, float scale)
51 { 51 {
52 if (_lod == 2f || _lod == 4f || _lod == 8f || _lod == 16f || _lod == 32f || _lod == 64f) 52 int sourceWidth = srcImage.Width;
53 lod = (int)_lod; 53 int sourceHeight = srcImage.Height;
54 int sourceX = 0;
55 int sourceY = 0;
56
57 int destX = 0;
58 int destY = 0;
59 int destWidth = (int)(sourceWidth * scale);
60 int destHeight = (int)(sourceHeight * scale);
61
62 Bitmap scaledImage = new Bitmap(destWidth, destHeight,
63 PixelFormat.Format24bppRgb);
64 scaledImage.SetResolution(srcImage.HorizontalResolution,
65 srcImage.VerticalResolution);
66
67 Graphics grPhoto = Graphics.FromImage(scaledImage);
68 grPhoto.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Bilinear;
69
70 grPhoto.DrawImage(srcImage,
71 new Rectangle(destX, destY, destWidth, destHeight),
72 new Rectangle(sourceX, sourceY, sourceWidth, sourceHeight),
73 GraphicsUnit.Pixel);
74
75 grPhoto.Dispose();
76 return scaledImage;
77 }
54 78
55 try 79 public SculptMesh SculptMeshFromFile(string fileName, SculptType sculptType, int lod, bool viewerMode)
56 { 80 {
57 ManagedImage managedImage; // we never use this 81 Bitmap bitmap = (Bitmap)Bitmap.FromFile(fileName);
58 OpenJPEG.DecodeToImage(jpegData, out managedImage, out idata); 82 SculptMesh sculptMesh = new SculptMesh(bitmap, sculptType, lod, viewerMode);
59 //int i = 0; 83 bitmap.Dispose();
60 //i = i / i; 84 return sculptMesh;
61 } 85 }
62 catch (Exception)
63 {
64 System.Console.WriteLine("[PHYSICS]: Unable to generate a Sculpty physics proxy. Sculpty texture decode failed!");
65 return;
66 }
67 86
68 if (idata != null) 87 public SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode)
69 { 88 {
70 bBitmap = new Bitmap(idata); 89 coords = new List<Coord>();
71 if (bBitmap.Width == bBitmap.Height) 90 faces = new List<Face>();
72 { 91 normals = new List<Coord>();
73 DoLOD(); 92 uvs = new List<UVCoord>();
74 93
75 LoadPoles(); 94 float sourceScaleFactor = (float)lod / (float)Math.Max(sculptBitmap.Width, sculptBitmap.Height);
95 bool scaleSourceImage = sourceScaleFactor < 1.0f ? true : false;
76 96
77 processSculptTexture(); 97 Bitmap bitmap;
98 if (scaleSourceImage)
99 bitmap = ScaleImage(sculptBitmap, sourceScaleFactor);
100 else
101 bitmap = sculptBitmap;
78 102
79 bLOD.Dispose(); 103 viewerFaces = new List<ViewerFace>();
80 bBitmap.Dispose();
81 idata.Dispose();
82 }
83 }
84 }
85
86 private Vertex ColorToVertex(Color input)
87 {
88 return new Vertex(
89 ((float)input.R - 128) / RANGE,
90 ((float)input.G - 128) / RANGE,
91 ((float)input.B - 128) / RANGE);
92 }
93
94 private void LoadPoles()
95 {
96 northpole = new Vertex(0, 0, 0);
97 for (int x = 0; x < bLOD.Width; x++)
98 {
99 northpole += ColorToVertex(GetPixel(0, 0));
100 }
101 northpole /= bLOD.Width;
102 104
103 southpole = new Vertex(0, 0, 0); 105 int width = bitmap.Width;
104 for (int x = 0; x < bLOD.Width; x++) 106 int height = bitmap.Height;
105 {
106 //System.Console.WriteLine("Height: " + bLOD.Height.ToString());
107 southpole += ColorToVertex(GetPixel(bLOD.Height - 1, (bLOD.Height - 1)));
108 }
109 southpole /= bBitmap.Width;
110 }
111 107
112 private Color GetPixel(int x, int y) 108 float widthUnit = 1.0f / width;
113 { 109 float heightUnit = 1.0f / (height - 1);
114 return bLOD.GetPixel(x, y);
115 }
116 110
117 public int LOD 111 int p1, p2, p3, p4;
118 { 112 Color color;
119 get 113 float x, y, z;
120 {
121 return (int)Math.Log(Scale, 2);
122 }
123 set
124 {
125 int power = value;
126 if (power == 0)
127 power = 6;
128 if (power < 2)
129 power = 2;
130 if (power > 9)
131 power = 9;
132 int t = (int)Math.Pow(2, power);
133 if (t != Scale)
134 {
135 lod = t;
136 }
137 }
138 }
139 114
140 public int Scale 115 int imageX, imageY;
141 {
142 get
143 {
144 return lod;
145 }
146 }
147
148 private void DoLOD()
149 {
150 int x_max = Math.Min(Scale, bBitmap.Width);
151 int y_max = Math.Min(Scale, bBitmap.Height);
152 if (bBitmap.Width == x_max && bBitmap.Height == y_max)
153 bLOD = bBitmap;
154 116
155 else if (bLOD == null || x_max != bLOD.Width || y_max != bLOD.Height)//don't resize if you don't need to. 117 if (sculptType == SculptType.sphere)
156 { 118 { // average the top and bottom row pixel values so the resulting vertices appear to converge
157 System.Drawing.Bitmap tile = new System.Drawing.Bitmap(bBitmap.Width * 2, bBitmap.Height, PixelFormat.Format24bppRgb); 119 int lastRow = height - 1;
158 System.Drawing.Bitmap tile_LOD = new System.Drawing.Bitmap(x_max * 2, y_max, PixelFormat.Format24bppRgb); 120 int r1 = 0, g1 = 0, b1 = 0;
159 121 int r2 = 0, g2 = 0, b2 = 0;
160 bLOD = new System.Drawing.Bitmap(x_max, y_max, PixelFormat.Format24bppRgb); 122 for (imageX = 0; imageX < width; imageX++)
161 bLOD.SetResolution(bBitmap.HorizontalResolution, bBitmap.VerticalResolution); 123 {
162 124 Color c1 = bitmap.GetPixel(imageX, 0);
163 System.Drawing.Graphics grPhoto = System.Drawing.Graphics.FromImage(tile); 125 Color c2 = bitmap.GetPixel(imageX, lastRow);
164 grPhoto.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
165
166 grPhoto.DrawImage(bBitmap,
167 new System.Drawing.Rectangle(0, 0, bBitmap.Width / 2, bBitmap.Height),
168 new System.Drawing.Rectangle(bBitmap.Width / 2, 0, bBitmap.Width / 2, bBitmap.Height),
169 System.Drawing.GraphicsUnit.Pixel);
170
171 grPhoto.DrawImage(bBitmap,
172 new System.Drawing.Rectangle((3 * bBitmap.Width) / 2, 0, bBitmap.Width / 2, bBitmap.Height),
173 new System.Drawing.Rectangle(0, 0, bBitmap.Width / 2, bBitmap.Height),
174 System.Drawing.GraphicsUnit.Pixel);
175
176 grPhoto.DrawImage(bBitmap,
177 new System.Drawing.Rectangle(bBitmap.Width / 2, 0, bBitmap.Width, bBitmap.Height),
178 new System.Drawing.Rectangle(0, 0, bBitmap.Width, bBitmap.Height),
179 System.Drawing.GraphicsUnit.Pixel);
180
181 grPhoto = System.Drawing.Graphics.FromImage(tile_LOD);
182 //grPhoto.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear;
183 grPhoto.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Bilinear;
184
185 grPhoto.DrawImage(tile,
186 new System.Drawing.Rectangle(0, 0, tile_LOD.Width, tile_LOD.Height),
187 new System.Drawing.Rectangle(0, 0, tile.Width, tile.Height),
188 System.Drawing.GraphicsUnit.Pixel);
189
190 grPhoto = System.Drawing.Graphics.FromImage(bLOD);
191 grPhoto.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
192
193 grPhoto.DrawImage(tile_LOD,
194 new System.Drawing.Rectangle(0, 0, bLOD.Width, bLOD.Height),
195 new System.Drawing.Rectangle(tile_LOD.Width / 4, 0, tile_LOD.Width / 2, tile_LOD.Height),
196 System.Drawing.GraphicsUnit.Pixel);
197
198 grPhoto.Dispose();
199 tile_LOD.Dispose();
200 tile.Dispose();
201 }
202 126
203 } 127 r1 += c1.R;
204 128 g1 += c1.G;
205 public void clearStuff() 129 b1 += c1.B;
206 {
207 this.triangles.Clear();
208 this.vertices.Clear();
209 //normals = new float[0];
210 }
211
212 public void processSculptTexture()
213 {
214 int x_max = Math.Min(Scale, bBitmap.Width);
215 int y_max = Math.Min(Scale, bBitmap.Height);
216 130
217 int COLUMNS = x_max + 1; 131 r2 += c2.R;
132 g2 += c2.G;
133 b2 += c2.B;
134 }
218 135
219 Vertex[] sVertices = new Vertex[COLUMNS * y_max]; 136 Color newC1 = Color.FromArgb(r1 / width, g1 / width, b1 / width);
220 //float[] indices = new float[COLUMNS * (y_max - 1) * 6]; 137 Color newC2 = Color.FromArgb(r2 / width, g2 / width, b2 / width);
221 138
222 for (int y = 0; y < y_max; y++) 139 for (imageX = 0; imageX < width; imageX++)
223 {
224 for (int x = 0; x < x_max; x++)
225 { 140 {
226 // Create the vertex 141 bitmap.SetPixel(imageX, 0, newC1);
227 Vertex v1 = new Vertex(0,0,0); 142 bitmap.SetPixel(imageX, lastRow, newC2);
143 }
144 }
228 145
229 // Create a vertex position from the RGB channels in the current pixel
230 // int ypos = y * bLOD.Width;
231 146
147 int pixelsAcross = sculptType == SculptType.plane ? width : width + 1;
148 int pixelsDown = sculptType == SculptType.sphere || sculptType == SculptType.cylinder ? height + 1 : height;
232 149
233 if (y == 0) 150 for (imageY = 0; imageY < pixelsDown; imageY++)
234 { 151 {
235 v1 = northpole; 152 int rowOffset = imageY * width;
236 } 153
237 else if (y == y_max - 1) 154 for (imageX = 0; imageX < pixelsAcross; imageX++)
155 {
156 /*
157 * p1-----p2
158 * | \ f2 |
159 * | \ |
160 * | f1 \|
161 * p3-----p4
162 */
163
164 if (imageX < width)
238 { 165 {
239 v1 = southpole; 166 p4 = rowOffset + imageX;
167 p3 = p4 - 1;
240 } 168 }
241 else 169 else
242 { 170 {
243 v1 = ColorToVertex(GetPixel(x, y)); 171 p4 = rowOffset; // wrap around to beginning
172 p3 = rowOffset + imageX - 1;
244 } 173 }
245 174
246 // Add the vertex for use later 175 p2 = p4 - width;
247 if (!vertices.Contains(v1)) 176 p1 = p3 - width;
248 Add(v1);
249 177
250 sVertices[y * COLUMNS + x] = v1; 178 color = bitmap.GetPixel(imageX == width ? 0 : imageX, imageY == height ? height - 1 : imageY);
251 //System.Console.WriteLine("adding: " + v1.ToString());
252 }
253 //Vertex tempVertex = vertices[y * COLUMNS];
254 // sVertices[y * COLUMNS + x_max] = tempVertex;
255 }
256 179
257 // Create the Triangles 180 x = (color.R - 128) * pixScale;
258 //int i = 0; 181 y = (color.G - 128) * pixScale;
182 z = (color.B - 128) * pixScale;
259 183
260 for (int y = 0; y < y_max - 1; y++) 184 Coord c = new Coord(x, y, z);
261 { 185 this.coords.Add(c);
262 int x; 186 if (viewerMode)
263
264 for (x = 0; x < x_max; x++)
265 {
266 Vertex vt11 = sVertices[(y * COLUMNS + x)];
267 Vertex vt12 = sVertices[(y * COLUMNS + (x + 1))];
268 Vertex vt13 = sVertices[((y + 1) * COLUMNS + (x + 1))];
269 if (vt11 != null && vt12 != null && vt13 != null)
270 { 187 {
271 if (vt11 != vt12 && vt11 != vt13 && vt12 != vt13) 188 this.normals.Add(new Coord());
272 { 189 this.uvs.Add(new UVCoord(widthUnit * imageX, heightUnit * imageY));
273 Triangle tri1 = new Triangle(vt11, vt12, vt13);
274 //indices[i++] = (ushort)(y * COLUMNS + x);
275 //indices[i++] = (ushort)(y * COLUMNS + (x + 1));
276 //indices[i++] = (ushort)((y + 1) * COLUMNS + (x + 1));
277 Add(tri1);
278 }
279 } 190 }
280 191
281 Vertex vt21 = sVertices[(y * COLUMNS + x)]; 192 if (imageY > 0 && imageX > 0)
282 Vertex vt22 = sVertices[((y + 1) * COLUMNS + (x + 1))];
283 Vertex vt23 = sVertices[((y + 1) * COLUMNS + x)];
284 if (vt21 != null && vt22 != null && vt23 != null)
285 { 193 {
286 if (vt21.Equals(vt22, 0.022f) || vt21.Equals(vt23, 0.022f) || vt22.Equals(vt23, 0.022f)) 194 Face f1, f2;
195
196 if (viewerMode)
287 { 197 {
198 f1 = new Face(p1, p3, p4, p1, p3, p4);
199 f1.uv1 = p1;
200 f1.uv2 = p3;
201 f1.uv3 = p4;
202
203 f2 = new Face(p1, p4, p2, p1, p4, p2);
204 f2.uv1 = p1;
205 f2.uv2 = p4;
206 f2.uv3 = p2;
288 } 207 }
289 else 208 else
290 { 209 {
291 Triangle tri2 = new Triangle(vt21, vt22, vt23); 210 f1 = new Face(p1, p3, p4);
292 //indices[i++] = (ushort)(y * COLUMNS + x); 211 f2 = new Face(p1, p4, p2);
293 //indices[i++] = (ushort)((y + 1) * COLUMNS + (x + 1));
294 //indices[i++] = (ushort)((y + 1) * COLUMNS + x);
295 Add(tri2);
296 } 212 }
213
214 this.faces.Add(f1);
215 this.faces.Add(f2);
297 } 216 }
217 }
218 }
219
220 if (scaleSourceImage)
221 bitmap.Dispose();
222
223 if (viewerMode)
224 { // compute vertex normals by summing all the surface normals of all the triangles sharing
225 // each vertex and then normalizing
226 int numFaces = this.faces.Count;
227 for (int i = 0; i < numFaces; i++)
228 {
229 Face face = this.faces[i];
230 Coord surfaceNormal = face.SurfaceNormal(this.coords);
231 this.normals[face.v1] += surfaceNormal;
232 this.normals[face.v2] += surfaceNormal;
233 this.normals[face.v3] += surfaceNormal;
234 }
298 235
236 int numCoords = this.coords.Count;
237 for (int i = 0; i < numCoords; i++)
238 this.coords[i].Normalize();
239
240 if (sculptType != SculptType.plane)
241 { // blend the vertex normals at the cylinder seam
242 pixelsAcross = width + 1;
243 for (imageY = 0; imageY < height; imageY++)
244 {
245 int rowOffset = imageY * pixelsAcross;
246
247 this.normals[rowOffset] = this.normals[rowOffset + width - 1] = (this.normals[rowOffset] + this.normals[rowOffset + width - 1]).Normalize();
248 }
299 } 249 }
300 //Vertex vt31 = sVertices[(y * x_max + x)];
301 //Vertex vt32 = sVertices[(y * x_max + 0)];
302 //Vertex vt33 = sVertices[((y + 1) * x_max + 0)];
303 //if (vt31 != null && vt32 != null && vt33 != null)
304 //{
305 //if (vt31.Equals(vt32, 0.022f) || vt31.Equals(vt33, 0.022f) || vt32.Equals(vt33, 0.022f))
306 //{
307 //}
308 //else
309 //{
310 //Triangle tri3 = new Triangle(vt31, vt32, vt33);
311 // Wrap the last cell in the row around
312 //indices[i++] = (ushort)(y * x_max + x); //a
313 //indices[i++] = (ushort)(y * x_max + 0); //b
314 //indices[i++] = (ushort)((y + 1) * x_max + 0); //c
315 //Add(tri3);
316 // }
317 //}
318
319 //Vertex vt41 = sVertices[(y * x_max + x)];
320 //Vertex vt42 = sVertices[((y + 1) * x_max + 0)];
321 //Vertex vt43 = sVertices[((y + 1) * x_max + x)];
322 //if (vt41 != null && vt42 != null && vt43 != null)
323 //{
324 //if (vt41.Equals(vt42, 0.022f) || vt31.Equals(vt43, 0.022f) || vt32.Equals(vt43, 0.022f))
325 //{
326 //}
327 // else
328 // {
329 //Triangle tri4 = new Triangle(vt41, vt42, vt43);
330 //indices[i++] = (ushort)(y * x_max + x); //a
331 //indices[i++] = (ushort)((y + 1) * x_max + 0); //b
332 //indices[i++] = (ushort)((y + 1) * x_max + x); //c
333 //Add(tri4);
334 //}
335 //}
336 250
251 foreach (Face face in this.faces)
252 {
253 ViewerFace vf = new ViewerFace(0);
254 vf.v1 = this.coords[face.v1];
255 vf.v2 = this.coords[face.v2];
256 vf.v3 = this.coords[face.v3];
257
258 vf.n1 = this.normals[face.n1];
259 vf.n2 = this.normals[face.n2];
260 vf.n3 = this.normals[face.n3];
261
262 vf.uv1 = this.uvs[face.uv1];
263 vf.uv2 = this.uvs[face.uv2];
264 vf.uv3 = this.uvs[face.uv3];
265
266 this.viewerFaces.Add(vf);
267 }
337 } 268 }
338 } 269 }
270
271 public void AddRot(Quat q)
272 {
273 int i;
274 int numVerts = this.coords.Count;
275
276 for (i = 0; i < numVerts; i++)
277 this.coords[i] *= q;
278
279 if (this.viewerFaces != null)
280 {
281 int numViewerFaces = this.viewerFaces.Count;
282
283 for (i = 0; i < numViewerFaces; i++)
284 {
285 ViewerFace v = this.viewerFaces[i];
286 v.v1 *= q;
287 v.v2 *= q;
288 v.v3 *= q;
289
290 v.n1 *= q;
291 v.n2 *= q;
292 v.n3 *= q;
293
294 this.viewerFaces[i] = v;
295 }
296 }
297 }
298
299 public void Scale(float x, float y, float z)
300 {
301 int i;
302 int numVerts = this.coords.Count;
303 //Coord vert;
304
305 Coord m = new Coord(x, y, z);
306 for (i = 0; i < numVerts; i++)
307 this.coords[i] *= m;
308
309 if (this.viewerFaces != null)
310 {
311 int numViewerFaces = this.viewerFaces.Count;
312 for (i = 0; i < numViewerFaces; i++)
313 {
314 ViewerFace v = this.viewerFaces[i];
315 v.v1 *= m;
316 v.v2 *= m;
317 v.v3 *= m;
318 this.viewerFaces[i] = v;
319 }
320 }
321 }
322
323 public void DumpRaw(String path, String name, String title)
324 {
325 if (path == null)
326 return;
327 String fileName = name + "_" + title + ".raw";
328 String completePath = Path.Combine(path, fileName);
329 StreamWriter sw = new StreamWriter(completePath);
330
331 for (int i = 0; i < this.faces.Count; i++)
332 {
333 string s = this.coords[this.faces[i].v1].ToString();
334 s += " " + this.coords[this.faces[i].v2].ToString();
335 s += " " + this.coords[this.faces[i].v3].ToString();
336
337 sw.WriteLine(s);
338 }
339
340 sw.Close();
341 }
339 } 342 }
340} 343}
diff --git a/OpenSim/Region/Physics/Meshing/SimpleHull.cs b/OpenSim/Region/Physics/Meshing/SimpleHull.cs
deleted file mode 100644
index 5eeadae..0000000
--- a/OpenSim/Region/Physics/Meshing/SimpleHull.cs
+++ /dev/null
@@ -1,394 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using OpenSim.Region.Physics.Manager;
31
32namespace OpenSim.Region.Physics.Meshing
33{
34 // A simple hull is a set of vertices building up to simplices that border a region
35 // The word simple referes to the fact, that this class assumes, that all simplices
36 // do not intersect
37 // Simple hulls can be added and subtracted.
38 // Vertices can be checked to lie inside a hull
39 // Also note, that the sequence of the vertices is important and defines if the region that
40 // is defined by the hull lies inside or outside the simplex chain
41 public class SimpleHull
42 {
43 //private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
44
45 private List<Vertex> vertices = new List<Vertex>();
46 private List<Vertex> holeVertices = new List<Vertex>(); // Only used, when the hull is hollow
47
48 // Adds a vertex to the end of the list
49 public void AddVertex(Vertex v)
50 {
51 vertices.Add(v);
52 }
53
54 public override String ToString()
55 {
56 String result = String.Empty;
57 foreach (Vertex v in vertices)
58 {
59 result += "b:" + v.ToString() + "\n";
60 }
61
62 return result;
63 }
64
65
66 public List<Vertex> getVertices()
67 {
68 List<Vertex> newVertices = new List<Vertex>();
69
70 newVertices.AddRange(vertices);
71 newVertices.Add(null);
72 newVertices.AddRange(holeVertices);
73
74 return newVertices;
75 }
76
77 public SimpleHull Clone()
78 {
79 SimpleHull result = new SimpleHull();
80 foreach (Vertex v in vertices)
81 {
82 result.AddVertex(v.Clone());
83 }
84
85 foreach (Vertex v in holeVertices)
86 {
87 result.holeVertices.Add(v.Clone());
88 }
89
90 return result;
91 }
92
93 public bool IsPointIn(Vertex v1)
94 {
95 int iCounter = 0;
96 List<Simplex> simplices = buildSimplexList();
97 foreach (Simplex s in simplices)
98 {
99 // Send a ray along the positive X-Direction
100 // Note, that this direction must correlate with the "below" interpretation
101 // of handling for the special cases below
102 PhysicsVector intersection = s.RayIntersect(v1, new PhysicsVector(1.0f, 0.0f, 0.0f), true);
103
104 if (intersection == null)
105 continue; // No intersection. Done. More tests to follow otherwise
106
107 // Did we hit the end of a simplex?
108 // Then this can be one of two special cases:
109 // 1. we go through a border exactly at a joint
110 // 2. we have just marginally touched a corner
111 // 3. we can slide along a border
112 // Solution: If the other vertex is "below" the ray, we don't count it
113 // Thus corners pointing down are counted twice, corners pointing up are not counted
114 // borders are counted once
115 if (intersection.IsIdentical(s.v1, 0.001f))
116 {
117 if (s.v2.Y < v1.Y)
118 continue;
119 }
120 // Do this for the other vertex two
121 if (intersection.IsIdentical(s.v2, 0.001f))
122 {
123 if (s.v1.Y < v1.Y)
124 continue;
125 }
126 iCounter++;
127 }
128
129 return iCounter%2 == 1; // Point is inside if the number of intersections is odd
130 }
131
132 public bool containsPointsFrom(SimpleHull otherHull)
133 {
134 foreach (Vertex v in otherHull.vertices)
135 {
136 if (IsPointIn(v))
137 return true;
138 }
139
140 return false;
141 }
142
143
144 private List<Simplex> buildSimplexList()
145 {
146 List<Simplex> result = new List<Simplex>();
147
148 // Not asserted but assumed: at least three vertices
149 for (int i = 0; i < vertices.Count - 1; i++)
150 {
151 Simplex s = new Simplex(vertices[i], vertices[i + 1]);
152 result.Add(s);
153 }
154 Simplex s1 = new Simplex(vertices[vertices.Count - 1], vertices[0]);
155 result.Add(s1);
156
157 if (holeVertices.Count == 0)
158 return result;
159
160 // Same here. At least three vertices in hole assumed
161 for (int i = 0; i < holeVertices.Count - 1; i++)
162 {
163 Simplex s = new Simplex(holeVertices[i], holeVertices[i + 1]);
164 result.Add(s);
165 }
166
167 s1 = new Simplex(holeVertices[holeVertices.Count - 1], holeVertices[0]);
168 result.Add(s1);
169 return result;
170 }
171
172// TODO: unused
173// private bool InsertVertex(Vertex v, int iAfter)
174// {
175// vertices.Insert(iAfter + 1, v);
176// return true;
177// }
178
179 private Vertex getNextVertex(Vertex currentVertex)
180 {
181 int iCurrentIndex;
182 iCurrentIndex = vertices.IndexOf(currentVertex);
183
184 // Error handling for iCurrentIndex==-1 should go here (and probably never will)
185
186 iCurrentIndex++;
187 if (iCurrentIndex == vertices.Count)
188 iCurrentIndex = 0;
189
190 return vertices[iCurrentIndex];
191 }
192
193 public Vertex FindVertex(Vertex vBase, float tolerance)
194 {
195 foreach (Vertex v in vertices)
196 {
197 if (v.IsIdentical(vBase, tolerance))
198 return v;
199 }
200
201 return null;
202 }
203
204 public void FindIntersection(Simplex s, ref Vertex Intersection, ref Vertex nextVertex)
205 {
206 Vertex bestIntersection = null;
207 float distToV1 = Single.PositiveInfinity;
208 Simplex bestIntersectingSimplex = null;
209
210 List<Simplex> simple = buildSimplexList();
211 foreach (Simplex sTest in simple)
212 {
213 PhysicsVector vvTemp = Simplex.Intersect(sTest, s, -.001f, -.001f, 0.999f, .999f);
214
215 Vertex vTemp = null;
216 if (vvTemp != null)
217 vTemp = new Vertex(vvTemp);
218
219 if (vTemp != null)
220 {
221 PhysicsVector diff = (s.v1 - vTemp);
222 float distTemp = diff.length();
223
224 if (bestIntersection == null || distTemp < distToV1)
225 {
226 bestIntersection = vTemp;
227 distToV1 = distTemp;
228 bestIntersectingSimplex = sTest;
229 }
230 }
231 }
232
233 Intersection = bestIntersection;
234 if (bestIntersectingSimplex != null)
235 nextVertex = bestIntersectingSimplex.v2;
236 else
237 nextVertex = null;
238 }
239
240
241 public static SimpleHull SubtractHull(SimpleHull baseHull, SimpleHull otherHull)
242 {
243 SimpleHull baseHullClone = baseHull.Clone();
244 SimpleHull otherHullClone = otherHull.Clone();
245 bool intersects = false;
246
247 //m_log.Debug("State before intersection detection");
248 //m_log.DebugFormat("The baseHull is:\n{1}", 0, baseHullClone.ToString());
249 //m_log.DebugFormat("The otherHull is:\n{1}", 0, otherHullClone.ToString());
250
251 {
252 int iBase, iOther;
253
254 // Insert into baseHull
255 for (iBase = 0; iBase < baseHullClone.vertices.Count; iBase++)
256 {
257 int iBaseNext = (iBase + 1)%baseHullClone.vertices.Count;
258 Simplex sBase = new Simplex(baseHullClone.vertices[iBase], baseHullClone.vertices[iBaseNext]);
259
260 for (iOther = 0; iOther < otherHullClone.vertices.Count; iOther++)
261 {
262 int iOtherNext = (iOther + 1)%otherHullClone.vertices.Count;
263 Simplex sOther =
264 new Simplex(otherHullClone.vertices[iOther], otherHullClone.vertices[iOtherNext]);
265
266 PhysicsVector intersect = Simplex.Intersect(sBase, sOther, 0.001f, -.001f, 0.999f, 1.001f);
267 if (intersect != null)
268 {
269 Vertex vIntersect = new Vertex(intersect);
270 baseHullClone.vertices.Insert(iBase + 1, vIntersect);
271 sBase.v2 = vIntersect;
272 intersects = true;
273 }
274 }
275 }
276 }
277
278 //m_log.Debug("State after intersection detection for the base hull");
279 //m_log.DebugFormat("The baseHull is:\n{1}", 0, baseHullClone.ToString());
280
281 {
282 int iOther, iBase;
283
284 // Insert into otherHull
285 for (iOther = 0; iOther < otherHullClone.vertices.Count; iOther++)
286 {
287 int iOtherNext = (iOther + 1)%otherHullClone.vertices.Count;
288 Simplex sOther = new Simplex(otherHullClone.vertices[iOther], otherHullClone.vertices[iOtherNext]);
289
290 for (iBase = 0; iBase < baseHullClone.vertices.Count; iBase++)
291 {
292 int iBaseNext = (iBase + 1)%baseHullClone.vertices.Count;
293 Simplex sBase = new Simplex(baseHullClone.vertices[iBase], baseHullClone.vertices[iBaseNext]);
294
295 PhysicsVector intersect = Simplex.Intersect(sBase, sOther, -.001f, 0.001f, 1.001f, 0.999f);
296 if (intersect != null)
297 {
298 Vertex vIntersect = new Vertex(intersect);
299 otherHullClone.vertices.Insert(iOther + 1, vIntersect);
300 sOther.v2 = vIntersect;
301 intersects = true;
302 }
303 }
304 }
305 }
306
307 //m_log.Debug("State after intersection detection for the base hull");
308 //m_log.DebugFormat("The otherHull is:\n{1}", 0, otherHullClone.ToString());
309
310 bool otherIsInBase = baseHullClone.containsPointsFrom(otherHullClone);
311 if (!intersects && otherIsInBase)
312 {
313 // We have a hole here
314 baseHullClone.holeVertices = otherHullClone.vertices;
315 return baseHullClone;
316 }
317
318 SimpleHull result = new SimpleHull();
319
320 // Find a good starting Simplex from baseHull
321 // A good starting simplex is one that is outside otherHull
322 // Such a simplex must exist, otherwise the result will be empty
323 Vertex baseStartVertex = null;
324 {
325 int iBase;
326 for (iBase = 0; iBase < baseHullClone.vertices.Count; iBase++)
327 {
328 int iBaseNext = (iBase + 1)%baseHullClone.vertices.Count;
329 Vertex center = new Vertex((baseHullClone.vertices[iBase] + baseHullClone.vertices[iBaseNext])/2.0f);
330 bool isOutside = !otherHullClone.IsPointIn(center);
331 if (isOutside)
332 {
333 baseStartVertex = baseHullClone.vertices[iBaseNext];
334 break;
335 }
336 }
337 }
338
339
340 if (baseStartVertex == null) // i.e. no simplex fulfilled the "outside" condition.
341 // In otherwords, subtractHull completely embraces baseHull
342 {
343 return result;
344 }
345
346 // The simplex that *starts* with baseStartVertex is outside the cutting hull,
347 // so we can start our walk with the next vertex without loosing a branch
348 Vertex V1 = baseStartVertex;
349 bool onBase = true;
350
351 // And here is how we do the magic :-)
352 // Start on the base hull.
353 // Walk the vertices in the positive direction
354 // For each vertex check, whether it is a vertex shared with the other hull
355 // if this is the case, switch over to walking the other vertex list.
356 // Note: The other hull *must* go backwards to our starting point (via several orther vertices)
357 // Thus it is important that the cutting hull has the inverse directional sense than the
358 // base hull!!!!!!!!! (means if base goes CW around it's center cutting hull must go CCW)
359
360 bool done = false;
361 while (!done)
362 {
363 result.AddVertex(V1);
364 Vertex nextVertex = null;
365 if (onBase)
366 {
367 nextVertex = otherHullClone.FindVertex(V1, 0.001f);
368 }
369 else
370 {
371 nextVertex = baseHullClone.FindVertex(V1, 0.001f);
372 }
373
374 if (nextVertex != null) // A node that represents an intersection
375 {
376 V1 = nextVertex; // Needed to find the next vertex on the other hull
377 onBase = !onBase;
378 }
379
380 if (onBase)
381 V1 = baseHullClone.getNextVertex(V1);
382 else
383 V1 = otherHullClone.getNextVertex(V1);
384
385 if (V1 == baseStartVertex)
386 done = true;
387 }
388
389 //m_log.DebugFormat("The resulting Hull is:\n{1}", 0, result.ToString());
390
391 return result;
392 }
393 }
394}
diff --git a/OpenSim/Region/Physics/Meshing/Simplex.cs b/OpenSim/Region/Physics/Meshing/Simplex.cs
deleted file mode 100644
index aeeef11..0000000
--- a/OpenSim/Region/Physics/Meshing/Simplex.cs
+++ /dev/null
@@ -1,220 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using OpenSim.Region.Physics.Manager;
30
31namespace OpenSim.Region.Physics.Meshing
32{
33 // A simplex is a section of a straight line.
34 // It is defined by its endpoints, i.e. by two vertices
35 // Operation on vertices are
36 public class Simplex : IComparable<Simplex>
37 {
38 public Vertex v1;
39 public Vertex v2;
40
41 public Simplex(Vertex _v1, Vertex _v2)
42 {
43 v1 = _v1;
44 v2 = _v2;
45 }
46
47 public int CompareTo(Simplex other)
48 {
49 Vertex lv1, lv2, ov1, ov2, temp;
50
51 lv1 = v1;
52 lv2 = v2;
53 ov1 = other.v1;
54 ov2 = other.v2;
55
56 if (lv1 > lv2)
57 {
58 temp = lv1;
59 lv1 = lv2;
60 lv2 = temp;
61 }
62
63 if (ov1 > ov2)
64 {
65 temp = ov1;
66 ov1 = ov2;
67 ov2 = temp;
68 }
69
70 if (lv1 > ov1)
71 {
72 return 1;
73 }
74 if (lv1 < ov1)
75 {
76 return -1;
77 }
78
79 if (lv2 > ov2)
80 {
81 return 1;
82 }
83 if (lv2 < ov2)
84 {
85 return -1;
86 }
87
88 return 0;
89 }
90
91 private static void intersectParameter(PhysicsVector p1, PhysicsVector r1, PhysicsVector p2, PhysicsVector r2,
92 ref float lambda, ref float mu)
93 {
94 // Intersects two straights
95 // p1, p2, points on the straight
96 // r1, r2, directional vectors of the straight. Not necessarily of length 1!
97 // note, that l, m can be scaled such, that the range 0..1 is mapped to the area between two points,
98 // thus allowing to decide whether an intersection is between two points
99
100 float r1x = r1.X;
101 float r1y = r1.Y;
102 float r2x = r2.X;
103 float r2y = r2.Y;
104
105 float denom = r1y*r2x - r1x*r2y;
106
107 float p1x = p1.X;
108 float p1y = p1.Y;
109 float p2x = p2.X;
110 float p2y = p2.Y;
111
112 float z1 = -p2x*r2y + p1x*r2y + (p2y - p1y)*r2x;
113 float z2 = -p2x*r1y + p1x*r1y + (p2y - p1y)*r1x;
114
115 if (denom == 0.0f) // Means the straights are parallel. Either no intersection or an infinite number of them
116 {
117 if (z1 == 0.0f)
118 {
119// Means they are identical -> many, many intersections
120 lambda = Single.NaN;
121 mu = Single.NaN;
122 }
123 else
124 {
125 lambda = Single.PositiveInfinity;
126 mu = Single.PositiveInfinity;
127 }
128 return;
129 }
130
131
132 lambda = z1/denom;
133 mu = z2/denom;
134 }
135
136
137 // Intersects the simplex with another one.
138 // the borders are used to deal with float inaccuracies
139 // As a rule of thumb, the borders are
140 // lowerBorder1 : 0.0
141 // lowerBorder2 : 0.0
142 // upperBorder1 : 1.0
143 // upperBorder2 : 1.0
144 // Set these to values near the given parameters (e.g. 0.001 instead of 1 to exclude simplex starts safely, or to -0.001 to include them safely)
145 public static PhysicsVector Intersect(
146 Simplex s1,
147 Simplex s2,
148 float lowerBorder1,
149 float lowerBorder2,
150 float upperBorder1,
151 float upperBorder2)
152 {
153 PhysicsVector firstSimplexDirection = s1.v2 - s1.v1;
154 PhysicsVector secondSimplexDirection = s2.v2 - s2.v1;
155
156 float lambda = 0.0f;
157 float mu = 0.0f;
158
159 // Give us the parameters of an intersection. This subroutine does *not* take the constraints
160 // (intersection must be between v1 and v2 and it must be in the positive direction of the ray)
161 // into account. We do that afterwards.
162 intersectParameter(s1.v1, firstSimplexDirection, s2.v1, secondSimplexDirection, ref lambda, ref mu);
163
164 if (Single.IsInfinity(lambda)) // Special case. No intersection at all. directions parallel.
165 return null;
166
167 if (Single.IsNaN(lambda)) // Special case. many, many intersections.
168 return null;
169
170 if (lambda > upperBorder1) // We're behind v2
171 return null;
172
173 if (lambda < lowerBorder1)
174 return null;
175
176 if (mu < lowerBorder2) // outside simplex 2
177 return null;
178
179 if (mu > upperBorder2) // outside simplex 2
180 return null;
181
182 return s1.v1 + lambda*firstSimplexDirection;
183 }
184
185 // Intersects the simplex with a ray. The ray is defined as all p=origin + lambda*direction
186 // where lambda >= 0
187 public PhysicsVector RayIntersect(Vertex origin, PhysicsVector direction, bool bEndsIncluded)
188 {
189 PhysicsVector simplexDirection = v2 - v1;
190
191 float lambda = 0.0f;
192 float mu = 0.0f;
193
194 // Give us the parameters of an intersection. This subroutine does *not* take the constraints
195 // (intersection must be between v1 and v2 and it must be in the positive direction of the ray)
196 // into account. We do that afterwards.
197 intersectParameter(v1, simplexDirection, origin, direction, ref lambda, ref mu);
198
199 if (Single.IsInfinity(lambda)) // Special case. No intersection at all. directions parallel.
200 return null;
201
202 if (Single.IsNaN(lambda)) // Special case. many, many intersections.
203 return null;
204
205 if (mu < 0.0) // We're on the wrong side of the ray
206 return null;
207
208 if (lambda > 1.0) // We're behind v2
209 return null;
210
211 if (lambda == 1.0 && !bEndsIncluded)
212 return null; // The end of the simplices are not included
213
214 if (lambda < 0.0f) // we're before v1;
215 return null;
216
217 return v1 + lambda*simplexDirection;
218 }
219 }
220}