diff options
author | Dahlia Trimble | 2008-11-29 11:02:14 +0000 |
---|---|---|
committer | Dahlia Trimble | 2008-11-29 11:02:14 +0000 |
commit | fdd238833163eb947986bfcdd09da82f6949a5f2 (patch) | |
tree | 6b90177758405f6106f4f5d4d75e3b98bf08053c /OpenSim/Region | |
parent | Comment the ScriptSponsor and restore the indefinite lifetime for (diff) | |
download | opensim-SC_OLD-fdd238833163eb947986bfcdd09da82f6949a5f2.zip opensim-SC_OLD-fdd238833163eb947986bfcdd09da82f6949a5f2.tar.gz opensim-SC_OLD-fdd238833163eb947986bfcdd09da82f6949a5f2.tar.bz2 opensim-SC_OLD-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 '')
-rw-r--r-- | OpenSim/Region/Physics/Meshing/Extruder.cs | 472 | ||||
-rw-r--r-- | OpenSim/Region/Physics/Meshing/HelperTypes.cs | 14 | ||||
-rw-r--r-- | OpenSim/Region/Physics/Meshing/Mesh.cs | 20 | ||||
-rw-r--r-- | OpenSim/Region/Physics/Meshing/Meshmerizer.cs | 1761 | ||||
-rw-r--r-- | OpenSim/Region/Physics/Meshing/PrimMesher.cs | 163 | ||||
-rw-r--r-- | OpenSim/Region/Physics/Meshing/SculptMesh.cs | 523 | ||||
-rw-r--r-- | OpenSim/Region/Physics/Meshing/SimpleHull.cs | 394 | ||||
-rw-r--r-- | OpenSim/Region/Physics/Meshing/Simplex.cs | 220 |
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 | |||
29 | using OpenMetaverse; | ||
30 | using OpenSim.Region.Physics.Manager; | ||
31 | |||
32 | namespace 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; | |||
31 | using OpenSim.Framework; | 31 | using OpenSim.Framework; |
32 | using OpenSim.Region.Physics.Manager; | 32 | using OpenSim.Region.Physics.Manager; |
33 | using OpenMetaverse; | 33 | using OpenMetaverse; |
34 | using OpenMetaverse.Imaging; | ||
35 | using System.Drawing; | ||
36 | using System.Drawing.Imaging; | ||
34 | using PrimMesher; | 37 | using PrimMesher; |
35 | 38 | ||
36 | namespace OpenSim.Region.Physics.Meshing | 39 | namespace 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 | |||
372 | minSizeForComplexMesh.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 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.Text; | ||
31 | using System.IO; | ||
30 | using System.Drawing; | 32 | using System.Drawing; |
31 | using System.Drawing.Imaging; | 33 | using System.Drawing.Imaging; |
32 | using System.Text; | ||
33 | using OpenMetaverse.Imaging; | ||
34 | 34 | ||
35 | namespace OpenSim.Region.Physics.Meshing | 35 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using OpenSim.Region.Physics.Manager; | ||
31 | |||
32 | namespace 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 | |||
28 | using System; | ||
29 | using OpenSim.Region.Physics.Manager; | ||
30 | |||
31 | namespace 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 | } | ||