diff options
Diffstat (limited to 'OpenSim/Region')
-rw-r--r-- | OpenSim/Region/Physics/Meshing/PrimMesher.cs | 673 |
1 files changed, 604 insertions, 69 deletions
diff --git a/OpenSim/Region/Physics/Meshing/PrimMesher.cs b/OpenSim/Region/Physics/Meshing/PrimMesher.cs index d7621d3..168a3bb 100644 --- a/OpenSim/Region/Physics/Meshing/PrimMesher.cs +++ b/OpenSim/Region/Physics/Meshing/PrimMesher.cs | |||
@@ -27,32 +27,37 @@ | |||
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using OpenSim.Framework; | 30 | using System.IO; |
31 | using OpenSim.Region.Physics.Manager; | 31 | using OpenSim.Region.Physics.Manager; |
32 | 32 | ||
33 | namespace OpenSim.Region.Physics.Meshing | 33 | namespace OpenSim.Region.Physics.Meshing |
34 | { | 34 | { |
35 | public struct vertex | 35 | public struct Coord |
36 | { | 36 | { |
37 | public float X; | 37 | public float X; |
38 | public float Y; | 38 | public float Y; |
39 | public float Z; | 39 | public float Z; |
40 | 40 | ||
41 | public vertex(float x, float y, float z) | 41 | public Coord(float x, float y, float z) |
42 | { | 42 | { |
43 | this.X = x; | 43 | this.X = x; |
44 | this.Y = y; | 44 | this.Y = y; |
45 | this.Z = z; | 45 | this.Z = z; |
46 | } | 46 | } |
47 | |||
48 | public override string ToString() | ||
49 | { | ||
50 | return this.X.ToString() + " " + this.Y.ToString() + " " + this.Z.ToString(); | ||
51 | } | ||
47 | } | 52 | } |
48 | 53 | ||
49 | public struct face | 54 | public struct Face |
50 | { | 55 | { |
51 | public int v1; | 56 | public int v1; |
52 | public int v2; | 57 | public int v2; |
53 | public int v3; | 58 | public int v3; |
54 | 59 | ||
55 | public face(int v1, int v2, int v3) | 60 | public Face(int v1, int v2, int v3) |
56 | { | 61 | { |
57 | this.v1 = v1; | 62 | this.v1 = v1; |
58 | this.v2 = v2; | 63 | this.v2 = v2; |
@@ -77,16 +82,17 @@ namespace OpenSim.Region.Physics.Meshing | |||
77 | internal class AngleList | 82 | internal class AngleList |
78 | { | 83 | { |
79 | private float iX, iY; // intersection point | 84 | private float iX, iY; // intersection point |
80 | private void intersection( float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4) | 85 | |
86 | private void intersection(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) | ||
81 | { // ref: http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline2d/ | 87 | { // ref: http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline2d/ |
82 | float denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1); | 88 | double denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1); |
83 | float uaNumerator = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3); | 89 | double uaNumerator = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3); |
84 | 90 | ||
85 | if (denom != 0.0) | 91 | if (denom != 0.0) |
86 | { | 92 | { |
87 | float ua = uaNumerator / denom; | 93 | double ua = uaNumerator / denom; |
88 | iX = x1 + ua * (x2 - x1); | 94 | iX = (float)(x1 + ua * (x2 - x1)); |
89 | iY = y1 + ua * (y2 - y1); | 95 | iY = (float)(y1 + ua * (y2 - y1)); |
90 | } | 96 | } |
91 | } | 97 | } |
92 | 98 | ||
@@ -107,14 +113,14 @@ namespace OpenSim.Region.Physics.Meshing | |||
107 | double stopAngleTest = stopAngle; | 113 | double stopAngleTest = stopAngle; |
108 | if (stopAngle < twoPi) | 114 | if (stopAngle < twoPi) |
109 | { | 115 | { |
110 | stopAngleTest = stepSize * (int)(stopAngle / stepSize) + 1; | 116 | stopAngleTest = stepSize * ((int)(stopAngle / stepSize) + 1); |
111 | if (stopAngleTest < stopAngle) | 117 | if (stopAngleTest < stopAngle) |
112 | stopAngleTest += stepSize; | 118 | stopAngleTest += stepSize; |
113 | if (stopAngleTest > twoPi) | 119 | if (stopAngleTest > twoPi) |
114 | stopAngleTest = twoPi; | 120 | stopAngleTest = twoPi; |
115 | } | 121 | } |
116 | 122 | ||
117 | while (angle <= stopAngleTest) | 123 | while (angle <= stopAngleTest) |
118 | { | 124 | { |
119 | Angle newAngle; | 125 | Angle newAngle; |
120 | newAngle.angle = (float) angle; | 126 | newAngle.angle = (float) angle; |
@@ -148,19 +154,28 @@ namespace OpenSim.Region.Physics.Meshing | |||
148 | } | 154 | } |
149 | } | 155 | } |
150 | 156 | ||
151 | internal class makeProfile | 157 | /// <summary> |
158 | /// generates a profile for extrusion | ||
159 | /// </summary> | ||
160 | public class Profile | ||
152 | { | 161 | { |
153 | private float twoPi = 2.0f * (float)Math.PI; | 162 | private const float twoPi = 2.0f * (float)Math.PI; |
154 | 163 | ||
155 | internal List<vertex> coords; | 164 | internal List<Coord> coords; |
156 | internal List<face> faces; | 165 | internal List<Face> faces; |
157 | 166 | ||
158 | internal makeProfile(int sides, float profileStart, float profileEnd, float hollow, int hollowSides) | 167 | internal Profile() |
159 | { | 168 | { |
160 | this.coords = new List<vertex>(); | 169 | this.coords = new List<Coord>(); |
161 | List<vertex> hollowCoords = new List<vertex>(); | 170 | this.faces = new List<Face>(); |
162 | this.faces = new List<face>(); | 171 | } |
163 | vertex center = new vertex(0.0f, 0.0f, 0.0f); | 172 | |
173 | public Profile(int sides, float profileStart, float profileEnd, float hollow, int hollowSides) | ||
174 | { | ||
175 | this.coords = new List<Coord>(); | ||
176 | this.faces = new List<Face>(); | ||
177 | Coord center = new Coord(0.0f, 0.0f, 0.0f); | ||
178 | List<Coord> hollowCoords = new List<Coord>(); | ||
164 | 179 | ||
165 | AngleList angles = new AngleList(); | 180 | AngleList angles = new AngleList(); |
166 | AngleList hollowAngles = new AngleList(); | 181 | AngleList hollowAngles = new AngleList(); |
@@ -184,17 +199,15 @@ namespace OpenSim.Region.Physics.Meshing | |||
184 | if (sides == hollowSides) | 199 | if (sides == hollowSides) |
185 | hollowAngles = angles; | 200 | hollowAngles = angles; |
186 | else | 201 | else |
187 | { | ||
188 | hollowAngles = new AngleList(); | ||
189 | hollowAngles.makeAngles(hollowSides, startAngle, stopAngle); | 202 | hollowAngles.makeAngles(hollowSides, startAngle, stopAngle); |
190 | } | ||
191 | } | 203 | } |
192 | else | 204 | else |
193 | this.coords.Add(center); | 205 | this.coords.Add(center); |
194 | 206 | ||
195 | Angle angle; | 207 | float z = 0.0f; |
196 | vertex newVert = new vertex(); | ||
197 | 208 | ||
209 | Angle angle; | ||
210 | Coord newVert = new Coord(); | ||
198 | if (hollow > 0.001f && hollowSides != sides) | 211 | if (hollow > 0.001f && hollowSides != sides) |
199 | { | 212 | { |
200 | int numHollowAngles = hollowAngles.angles.Count; | 213 | int numHollowAngles = hollowAngles.angles.Count; |
@@ -203,40 +216,44 @@ namespace OpenSim.Region.Physics.Meshing | |||
203 | angle = hollowAngles.angles[i]; | 216 | angle = hollowAngles.angles[i]; |
204 | newVert.X = hollow * xScale * angle.X; | 217 | newVert.X = hollow * xScale * angle.X; |
205 | newVert.Y = hollow * yScale * angle.Y; | 218 | newVert.Y = hollow * yScale * angle.Y; |
206 | newVert.Z = 0.0f; | 219 | newVert.Z = z; |
207 | 220 | ||
208 | hollowCoords.Add(newVert); | 221 | hollowCoords.Add(newVert); |
209 | } | 222 | } |
210 | } | 223 | } |
211 | 224 | ||
225 | int index = 0; | ||
212 | int numAngles = angles.angles.Count; | 226 | int numAngles = angles.angles.Count; |
213 | int index; | 227 | for (int i = 0; i < numAngles; i++) |
214 | for (index = 0; index < numAngles; index++) | ||
215 | { | 228 | { |
216 | angle = angles.angles[index]; | 229 | angle = angles.angles[i]; |
217 | newVert.X = angle.X * xScale; | 230 | newVert.X = angle.X * xScale; |
218 | newVert.Y = angle.Y * yScale; | 231 | newVert.Y = angle.Y * yScale; |
219 | newVert.Z = 0.0f; | 232 | newVert.Z = z; |
220 | this.coords.Add(newVert); | 233 | this.coords.Add(newVert); |
221 | 234 | ||
222 | if (hollow > 0.0f) | 235 | if (hollow > 0.0f) |
223 | { | 236 | { |
224 | newVert.X = angle.X *= hollow; | 237 | if (hollowSides == sides) |
225 | newVert.Y = angle.Y *= hollow; | 238 | { |
226 | newVert.Z = 0.0f; | 239 | newVert.X *= hollow; |
227 | hollowCoords.Add(newVert); | 240 | newVert.Y *= hollow; |
241 | newVert.Z = z; | ||
242 | hollowCoords.Add(newVert); | ||
243 | } | ||
228 | } | 244 | } |
229 | else if (angle.angle > 0.0001f) | 245 | else if (angle.angle > 0.0001f) |
230 | { | 246 | { |
231 | face newFace = new face(); | 247 | Face newFace = new Face(); |
232 | newFace.v1 = 0; | 248 | newFace.v1 = 0; |
233 | newFace.v2 = index; | 249 | newFace.v2 = index; |
234 | newFace.v3 = index; | 250 | newFace.v3 = index + 1; |
235 | this.faces.Add(newFace); | 251 | this.faces.Add(newFace); |
236 | } | 252 | } |
253 | index += 1; | ||
237 | } | 254 | } |
238 | 255 | ||
239 | if (hollow > 0.0) | 256 | if (hollow > 0.0f) |
240 | { | 257 | { |
241 | hollowCoords.Reverse(); | 258 | hollowCoords.Reverse(); |
242 | 259 | ||
@@ -246,29 +263,26 @@ namespace OpenSim.Region.Physics.Meshing | |||
246 | 263 | ||
247 | if (numOuterVerts == numHollowVerts) | 264 | if (numOuterVerts == numHollowVerts) |
248 | { | 265 | { |
249 | face newFace = new face(); | 266 | Face newFace = new Face(); |
250 | 267 | ||
251 | for (int coordIndex = 0; coordIndex < numOuterVerts - 1; coordIndex++) | 268 | for (int coordIndex = 0; coordIndex < numOuterVerts - 1; coordIndex++) |
252 | { | 269 | { |
253 | newFace.v1 = coordIndex; | 270 | newFace.v1 = coordIndex; |
254 | newFace.v2 = coordIndex + 1; | 271 | newFace.v2 = coordIndex + 1; |
255 | newFace.v3 = numTotalVerts - coordIndex - 1; | 272 | newFace.v3 = numTotalVerts - coordIndex - 1; |
256 | |||
257 | this.faces.Add(newFace); | 273 | this.faces.Add(newFace); |
258 | 274 | ||
259 | newFace.v1 = coordIndex + 1; | 275 | newFace.v1 = coordIndex + 1; |
260 | newFace.v2 = numTotalVerts - coordIndex - 2; | 276 | newFace.v2 = numTotalVerts - coordIndex - 2; |
261 | newFace.v3 = numTotalVerts - coordIndex - 1; | 277 | newFace.v3 = numTotalVerts - coordIndex - 1; |
262 | |||
263 | this.faces.Add(newFace); | 278 | this.faces.Add(newFace); |
264 | } | 279 | } |
265 | } | 280 | } |
266 | |||
267 | else | 281 | else |
268 | { | 282 | { |
269 | if (numOuterVerts < numHollowVerts) | 283 | if (numOuterVerts < numHollowVerts) |
270 | { | 284 | { |
271 | face newFace = new face(); | 285 | Face newFace = new Face(); |
272 | int j = 0; // j is the index for outer vertices | 286 | int j = 0; // j is the index for outer vertices |
273 | int maxJ = numOuterVerts - 1; | 287 | int maxJ = numOuterVerts - 1; |
274 | for (int i = 0; i < numHollowVerts; i++) // i is the index for inner vertices | 288 | for (int i = 0; i < numHollowVerts; i++) // i is the index for inner vertices |
@@ -276,7 +290,7 @@ namespace OpenSim.Region.Physics.Meshing | |||
276 | if (j < maxJ) | 290 | if (j < maxJ) |
277 | if (angles.angles[j + 1].angle - hollowAngles.angles[i].angle <= hollowAngles.angles[i].angle - angles.angles[j].angle) | 291 | if (angles.angles[j + 1].angle - hollowAngles.angles[i].angle <= hollowAngles.angles[i].angle - angles.angles[j].angle) |
278 | { | 292 | { |
279 | newFace.v1 = numTotalVerts - i - 2; | 293 | newFace.v1 = numTotalVerts - i - 1; |
280 | newFace.v2 = j; | 294 | newFace.v2 = j; |
281 | newFace.v3 = j + 1; | 295 | newFace.v3 = j + 1; |
282 | 296 | ||
@@ -293,7 +307,7 @@ namespace OpenSim.Region.Physics.Meshing | |||
293 | } | 307 | } |
294 | else // numHollowVerts < numOuterVerts | 308 | else // numHollowVerts < numOuterVerts |
295 | { | 309 | { |
296 | face newFace = new face(); | 310 | Face newFace = new Face(); |
297 | int j = 0; // j is the index for inner vertices | 311 | int j = 0; // j is the index for inner vertices |
298 | int maxJ = numHollowVerts - 1; | 312 | int maxJ = numHollowVerts - 1; |
299 | for (int i = 0; i < numOuterVerts; i++) | 313 | for (int i = 0; i < numOuterVerts; i++) |
@@ -316,23 +330,32 @@ namespace OpenSim.Region.Physics.Meshing | |||
316 | this.faces.Add(newFace); | 330 | this.faces.Add(newFace); |
317 | } | 331 | } |
318 | } | 332 | } |
319 | |||
320 | } | 333 | } |
321 | 334 | ||
322 | this.coords.AddRange(hollowCoords); | 335 | this.coords.AddRange(hollowCoords); |
323 | } | 336 | } |
324 | } | 337 | } |
325 | 338 | ||
326 | internal void addPos(vertex v) | 339 | public Profile Clone() |
340 | { | ||
341 | Profile clone = new Profile(); | ||
342 | |||
343 | clone.coords.AddRange(this.coords); | ||
344 | clone.faces.AddRange(this.faces); | ||
345 | |||
346 | return clone; | ||
347 | } | ||
348 | |||
349 | public void AddPos(Coord v) | ||
327 | { | 350 | { |
328 | this.addPos(v.X, v.Y, v.Z); | 351 | this.AddPos(v.X, v.Y, v.Z); |
329 | } | 352 | } |
330 | 353 | ||
331 | internal void addPos(float x, float y, float z) | 354 | public void AddPos(float x, float y, float z) |
332 | { | 355 | { |
333 | int i; | 356 | int i; |
334 | int numVerts = this.coords.Count; | 357 | int numVerts = this.coords.Count; |
335 | vertex vert; | 358 | Coord vert; |
336 | 359 | ||
337 | for (i = 0; i < numVerts; i++) | 360 | for (i = 0; i < numVerts; i++) |
338 | { | 361 | { |
@@ -340,49 +363,48 @@ namespace OpenSim.Region.Physics.Meshing | |||
340 | vert.X += x; | 363 | vert.X += x; |
341 | vert.Y += y; | 364 | vert.Y += y; |
342 | vert.Z += z; | 365 | vert.Z += z; |
366 | this.coords[i] = vert; | ||
343 | } | 367 | } |
344 | } | 368 | } |
345 | 369 | ||
346 | internal void addRot(Quaternion q) | 370 | public void AddRot(Quaternion q) |
347 | { | 371 | { |
348 | int i; | 372 | int i; |
349 | int numVerts = this.coords.Count; | 373 | int numVerts = this.coords.Count; |
350 | vertex vert; | 374 | Coord vert; |
351 | 375 | ||
352 | for (i = 0; i < numVerts; i++) | 376 | for (i = 0; i < numVerts; i++) |
353 | { | 377 | { |
354 | vert = this.coords[i]; | 378 | vert = this.coords[i]; |
355 | Vertex v = new Vertex(vert.X, vert.Y, vert.Z); | 379 | Vertex v = new Vertex(vert.X, vert.Y, vert.Z) * q; |
356 | |||
357 | v = v * q; | ||
358 | 380 | ||
359 | vert.X = v.X; | 381 | vert.X = v.X; |
360 | vert.Y = v.Y; | 382 | vert.Y = v.Y; |
361 | vert.Z = v.Z; | 383 | vert.Z = v.Z; |
384 | this.coords[i] = vert; | ||
362 | } | 385 | } |
363 | } | 386 | } |
364 | 387 | ||
365 | internal void scale(float x, float y, float z) | 388 | public void Scale(float x, float y) |
366 | { | 389 | { |
367 | int i; | 390 | int i; |
368 | int numVerts = this.coords.Count; | 391 | int numVerts = this.coords.Count; |
369 | vertex vert; | 392 | Coord vert; |
370 | 393 | ||
371 | for (i = 0; i < numVerts; i++) | 394 | for (i = 0; i < numVerts; i++) |
372 | { | 395 | { |
373 | vert = this.coords[i]; | 396 | vert = this.coords[i]; |
374 | |||
375 | vert.X *= x; | 397 | vert.X *= x; |
376 | vert.Y *= y; | 398 | vert.Y *= y; |
377 | vert.Z *= z; | 399 | this.coords[i] = vert; |
378 | } | 400 | } |
379 | } | 401 | } |
380 | 402 | ||
381 | internal void flipNormals() | 403 | public void FlipNormals() |
382 | { | 404 | { |
383 | int i; | 405 | int i; |
384 | int numFaces = this.faces.Count; | 406 | int numFaces = this.faces.Count; |
385 | face tmpFace; | 407 | Face tmpFace; |
386 | int tmp; | 408 | int tmp; |
387 | 409 | ||
388 | for (i = 0; i < numFaces; i++) | 410 | for (i = 0; i < numFaces; i++) |
@@ -391,21 +413,534 @@ namespace OpenSim.Region.Physics.Meshing | |||
391 | tmp = tmpFace.v3; | 413 | tmp = tmpFace.v3; |
392 | tmpFace.v3 = tmpFace.v1; | 414 | tmpFace.v3 = tmpFace.v1; |
393 | tmpFace.v1 = tmp; | 415 | tmpFace.v1 = tmp; |
416 | this.faces[i] = tmpFace; | ||
417 | } | ||
418 | } | ||
419 | |||
420 | public void AddValue2Faces(int num) | ||
421 | { | ||
422 | int numFaces = this.faces.Count; | ||
423 | Face tmpFace; | ||
424 | for (int i = 0; i < numFaces; i++) | ||
425 | { | ||
426 | tmpFace = this.faces[i]; | ||
427 | tmpFace.v1 += num; | ||
428 | tmpFace.v2 += num; | ||
429 | tmpFace.v3 += num; | ||
430 | this.faces[i] = tmpFace; | ||
431 | } | ||
432 | } | ||
433 | |||
434 | public void DumpRaw(String path, String name, String title) | ||
435 | { | ||
436 | if (path == null) | ||
437 | return; | ||
438 | String fileName = name + "_" + title + ".raw"; | ||
439 | String completePath = Path.Combine(path, fileName); | ||
440 | StreamWriter sw = new StreamWriter(completePath); | ||
441 | |||
442 | for (int i = 0; i < this.faces.Count; i++) | ||
443 | { | ||
444 | string s = this.coords[this.faces[i].v1].ToString(); | ||
445 | s += " " + this.coords[this.faces[i].v2].ToString(); | ||
446 | s += " " + this.coords[this.faces[i].v3].ToString(); | ||
447 | |||
448 | sw.WriteLine(s); | ||
394 | } | 449 | } |
450 | |||
451 | sw.Close(); | ||
395 | } | 452 | } |
396 | } | 453 | } |
397 | 454 | ||
398 | public class PrimMesher | 455 | public class PrimMesh |
399 | { | 456 | { |
400 | public List<vertex> vertices; | 457 | private const float twoPi = 2.0f * (float)Math.PI; |
401 | public List<face> faces; | 458 | |
459 | public List<Coord> coords; | ||
460 | public List<Face> faces; | ||
461 | |||
462 | public int sides = 4; | ||
463 | public int hollowSides = 4; | ||
464 | public float profileStart = 0.0f; | ||
465 | public float profileEnd = 1.0f; | ||
466 | public float hollow = 0.0f; | ||
467 | public int twistBegin = 0; | ||
468 | public int twistEnd = 0; | ||
469 | public float topShearX = 0.0f; | ||
470 | public float topShearY = 0.0f; | ||
471 | public float pathCutBegin = 0.0f; | ||
472 | public float pathCutEnd = 1.0f; | ||
473 | public float dimpleBegin = 0.0f; | ||
474 | public float dimpleEnd = 1.0f; | ||
475 | public float skew = 0.0f; | ||
476 | public float holeSizeX = 1.0f; // called pathScaleX in pbs | ||
477 | public float holeSizeY = 0.25f; | ||
478 | public float taperX = 0.0f; | ||
479 | public float taperY = 0.0f; | ||
480 | public float radius = 0.0f; | ||
481 | public float revolutions = 1.0f; | ||
482 | public int stepsPerRevolution = 24; | ||
483 | |||
484 | public string ParamsToDisplayString() | ||
485 | { | ||
486 | string s = ""; | ||
487 | s += "sides..................: " + this.sides.ToString(); | ||
488 | s += "\nhollowSides..........: " + this.hollowSides.ToString(); | ||
489 | s += "\nprofileStart.........: " + this.profileStart.ToString(); | ||
490 | s += "\nprofileEnd...........: " + this.profileEnd.ToString(); | ||
491 | s += "\nhollow...............: " + this.hollow.ToString(); | ||
492 | s += "\ntwistBegin...........: " + this.twistBegin.ToString(); | ||
493 | s += "\ntwistEnd.............: " + this.twistEnd.ToString(); | ||
494 | s += "\ntopShearX............: " + this.topShearX.ToString(); | ||
495 | s += "\ntopShearY............: " + this.topShearY.ToString(); | ||
496 | s += "\npathCutBegin.........: " + this.pathCutBegin.ToString(); | ||
497 | s += "\npathCutEnd...........: " + this.pathCutEnd.ToString(); | ||
498 | s += "\ndimpleBegin..........: " + this.dimpleBegin.ToString(); | ||
499 | s += "\ndimpleEnd............: " + this.dimpleEnd.ToString(); | ||
500 | s += "\nskew.................: " + this.skew.ToString(); | ||
501 | s += "\nholeSizeX............: " + this.holeSizeX.ToString(); | ||
502 | s += "\nholeSizeY............: " + this.holeSizeY.ToString(); | ||
503 | s += "\ntaperX...............: " + this.taperX.ToString(); | ||
504 | s += "\ntaperY...............: " + this.taperY.ToString(); | ||
505 | s += "\nradius...............: " + this.radius.ToString(); | ||
506 | s += "\nrevolutions..........: " + this.revolutions.ToString(); | ||
507 | s += "\nstepsPerRevolution...: " + this.stepsPerRevolution.ToString(); | ||
508 | |||
509 | return s; | ||
510 | } | ||
511 | |||
512 | |||
513 | public PrimMesh(int sides, float profileStart, float profileEnd, float hollow, int hollowSides) | ||
514 | { | ||
515 | this.coords = new List<Coord>(); | ||
516 | this.faces = new List<Face>(); | ||
517 | |||
518 | this.sides = sides; | ||
519 | this.profileStart = profileStart; | ||
520 | this.profileEnd = profileEnd; | ||
521 | this.hollow = hollow; | ||
522 | this.hollowSides = hollowSides; | ||
523 | |||
524 | if (sides < 3) | ||
525 | this.sides = 3; | ||
526 | if ( hollowSides < 3) | ||
527 | this.hollowSides = 3; | ||
528 | if (profileStart < 0.0f) | ||
529 | this.profileStart = 0.0f; | ||
530 | if (profileEnd > 1.0f) | ||
531 | this.profileEnd = 1.0f; | ||
532 | if (profileEnd < 0.02f) | ||
533 | this.profileEnd = 0.02f; | ||
534 | if (profileStart >= profileEnd) | ||
535 | this.profileStart = profileEnd - 0.02f; | ||
536 | if (hollow > 1.0f) | ||
537 | this.hollow = 1.0f; | ||
538 | if (hollow < 0.0f) | ||
539 | this.hollow = 0.0f; | ||
540 | } | ||
541 | |||
542 | public void ExtrudeLinear() | ||
543 | { | ||
544 | this.coords = new List<Coord>(); | ||
545 | this.faces = new List<Face>(); | ||
546 | |||
547 | int step = 0; | ||
548 | int steps = 1; | ||
549 | |||
550 | float length = this.pathCutEnd - this.pathCutBegin; | ||
551 | |||
552 | #if VIEWER | ||
553 | if (this.sides == 3) | ||
554 | { | ||
555 | // prisms don't taper well so add some vertical resolution | ||
556 | // other prims may benefit from this but just do prisms for now | ||
557 | if (Math.Abs(this.taperX) > 0.01 || Math.Abs(this.taperY) > 0.01) | ||
558 | steps = (int)(steps * 4.5 * length); | ||
559 | } | ||
560 | #endif | ||
561 | |||
562 | float twistBegin = this.twistBegin / 360.0f * twoPi; | ||
563 | float twistEnd = this.twistEnd / 360.0f * twoPi; | ||
564 | float twistTotal = twistEnd - twistBegin; | ||
565 | float twistTotalAbs = Math.Abs(twistTotal); | ||
566 | if (twistTotalAbs > 0.01f) | ||
567 | steps += (int)(twistTotalAbs * 3.66); // dahlia's magic number | ||
568 | |||
569 | float start = -0.5f; | ||
570 | float stepSize = length / (float)steps; | ||
571 | float percentOfPathMultiplier = stepSize; | ||
572 | float xProfileScale = 1.0f; | ||
573 | float yProfileScale = 1.0f; | ||
574 | float xOffset = 0.0f; | ||
575 | float yOffset = 0.0f; | ||
576 | float zOffset = start; | ||
577 | float xOffsetStepIncrement = this.topShearX / steps; | ||
578 | float yOffsetStepIncrement = this.topShearY / steps; | ||
579 | |||
580 | float percentOfPath = this.pathCutBegin; | ||
581 | zOffset += percentOfPath; | ||
582 | |||
583 | float hollow = this.hollow; | ||
584 | |||
585 | // sanity checks | ||
586 | float initialProfileRot = 0.0f; | ||
587 | if (this.sides == 3) | ||
588 | { | ||
589 | if (this.hollowSides == 4) | ||
590 | { | ||
591 | if (hollow > 0.7f) | ||
592 | hollow = 0.7f; | ||
593 | hollow *= 0.707f; | ||
594 | } | ||
595 | else hollow *= 0.5f; | ||
596 | } | ||
597 | else if (this.sides == 4) | ||
598 | { | ||
599 | initialProfileRot = 1.25f * (float)Math.PI; | ||
600 | if (this.hollowSides != 4) | ||
601 | hollow *= 0.707f; | ||
602 | } | ||
603 | |||
604 | Profile profile = new Profile(this.sides, this.profileStart, this.profileEnd, hollow, this.hollowSides); | ||
605 | |||
606 | if (initialProfileRot != 0.0f) | ||
607 | profile.AddRot(new Quaternion(new Vertex(0.0f, 0.0f, 1.0f), initialProfileRot)); | ||
608 | |||
609 | bool done = false; | ||
610 | while (!done) | ||
611 | { | ||
612 | Profile newLayer = profile.Clone(); | ||
613 | |||
614 | if (this.taperX == 0.0f) | ||
615 | xProfileScale = 1.0f; | ||
616 | else if (this.taperX > 0.0f) | ||
617 | xProfileScale = 1.0f - percentOfPath * this.taperX; | ||
618 | else xProfileScale = 1.0f + (1.0f - percentOfPath) * this.taperX; | ||
619 | |||
620 | if (this.taperY == 0.0f) | ||
621 | yProfileScale = 1.0f; | ||
622 | else if (this.taperY > 0.0f) | ||
623 | yProfileScale = 1.0f - percentOfPath * this.taperY; | ||
624 | else yProfileScale = 1.0f + (1.0f - percentOfPath) * this.taperY; | ||
625 | |||
626 | if (xProfileScale != 1.0f || yProfileScale != 1.0f) | ||
627 | newLayer.Scale(xProfileScale, yProfileScale); | ||
628 | |||
629 | float twist = twistBegin + twistTotal * percentOfPath; | ||
630 | if (twist != 0.0f) | ||
631 | newLayer.AddRot(new Quaternion(new Vertex(0.0f, 0.0f, 1.0f), twist)); | ||
632 | |||
633 | newLayer.AddPos(xOffset, yOffset, zOffset); | ||
634 | |||
635 | if (step == 0) | ||
636 | newLayer.FlipNormals(); | ||
637 | |||
638 | // append this layer | ||
639 | |||
640 | int coordsLen = this.coords.Count; | ||
641 | newLayer.AddValue2Faces(coordsLen); | ||
642 | |||
643 | this.coords.AddRange(newLayer.coords); | ||
644 | this.faces.AddRange(newLayer.faces); | ||
645 | |||
646 | // fill faces between layers | ||
647 | |||
648 | int numVerts = newLayer.coords.Count; | ||
649 | Face newFace = new Face(); | ||
650 | if (step > 0) | ||
651 | { | ||
652 | for (int i = coordsLen; i < this.coords.Count - 1; i++) | ||
653 | { | ||
654 | newFace.v1 = i; | ||
655 | newFace.v2 = i - numVerts; | ||
656 | newFace.v3 = i - numVerts + 1; | ||
657 | this.faces.Add(newFace); | ||
658 | |||
659 | newFace.v2 = i - numVerts + 1; | ||
660 | newFace.v3 = i + 1; | ||
661 | this.faces.Add(newFace); | ||
662 | } | ||
663 | |||
664 | newFace.v1 = coordsLen - 1; | ||
665 | newFace.v2 = coordsLen - numVerts; | ||
666 | newFace.v3 = coordsLen; | ||
667 | this.faces.Add(newFace); | ||
668 | |||
669 | newFace.v1 = coordsLen + numVerts - 1; | ||
670 | newFace.v2 = coordsLen - 1; | ||
671 | newFace.v3 = coordsLen; | ||
672 | this.faces.Add(newFace); | ||
673 | } | ||
674 | |||
675 | // calc the step for the next iteration of the loop | ||
676 | |||
677 | if (step < steps) | ||
678 | { | ||
679 | step += 1; | ||
680 | percentOfPath += percentOfPathMultiplier; | ||
681 | xOffset += xOffsetStepIncrement; | ||
682 | yOffset += yOffsetStepIncrement; | ||
683 | zOffset += stepSize; | ||
684 | if (percentOfPath > this.pathCutEnd) | ||
685 | done = true; | ||
686 | } | ||
687 | else done = true; | ||
688 | } | ||
689 | } | ||
690 | |||
691 | |||
692 | public void ExtrudeCircular() | ||
693 | { | ||
694 | this.coords = new List<Coord>(); | ||
695 | this.faces = new List<Face>(); | ||
696 | |||
697 | int step = 0; | ||
698 | int steps = 24; | ||
699 | |||
700 | float twistBegin = this.twistBegin / 360.0f * twoPi; | ||
701 | float twistEnd = this.twistEnd / 360.0f * twoPi; | ||
702 | float twistTotal = twistEnd - twistBegin; | ||
402 | 703 | ||
403 | PrimMesher() | 704 | // if the profile has a lot of twist, add more layers otherwise the layers may overlap |
705 | // and the resulting mesh may be quite inaccurate. This method is arbitrary and doesn't | ||
706 | // accurately match the viewer | ||
707 | float twistTotalAbs = Math.Abs(twistTotal); | ||
708 | if (twistTotalAbs > 0.01f) | ||
709 | { | ||
710 | if (twistTotalAbs > Math.PI * 1.5f) | ||
711 | steps *= 2; | ||
712 | if (twistTotalAbs > Math.PI * 3.0f) | ||
713 | steps *= 2; | ||
714 | } | ||
715 | |||
716 | float yPathScale = this.holeSizeY * 0.5f; | ||
717 | float pathLength = this.pathCutEnd - this.pathCutBegin; | ||
718 | float totalSkew = this.skew * 2.0f * pathLength; | ||
719 | float skewStart = this.pathCutBegin * 2.0f * this.skew - this.skew; | ||
720 | |||
721 | // It's not quite clear what pushY (Y top shear) does, but subtracting it from the start and end | ||
722 | // angles appears to approximate it's effects on path cut. Likewise, adding it to the angle used | ||
723 | // to calculate the sine for generating the path radius appears to approximate it's effects there | ||
724 | // too, but there are some subtle differences in the radius which are noticeable as the prim size | ||
725 | // increases and it may affect megaprims quite a bit. The effect of the Y top shear parameter on | ||
726 | // the meshes generated with this technique appear nearly identical in shape to the same prims when | ||
727 | // displayed by the viewer. | ||
728 | |||
729 | float startAngle = (twoPi * this.pathCutBegin * this.revolutions) - this.topShearY * 0.9f; | ||
730 | float endAngle = (twoPi * this.pathCutEnd * this.revolutions) - this.topShearY * 0.9f; | ||
731 | float stepSize = twoPi / this.stepsPerRevolution; | ||
732 | |||
733 | step = (int)(startAngle / stepSize); | ||
734 | int firstStep = step; | ||
735 | float angle = startAngle; | ||
736 | float hollow = this.hollow; | ||
737 | |||
738 | // sanity checks | ||
739 | float initialProfileRot = 0.0f; | ||
740 | if (this.sides == 3) | ||
741 | { | ||
742 | initialProfileRot = (float)Math.PI; | ||
743 | if (this.hollowSides == 4) | ||
744 | { | ||
745 | if (hollow > 0.7f) | ||
746 | hollow = 0.7f; | ||
747 | hollow *= 0.707f; | ||
748 | } | ||
749 | else hollow *= 0.5f; | ||
750 | } | ||
751 | else if (this.sides == 4) | ||
752 | { | ||
753 | initialProfileRot = 0.25f * (float)Math.PI; | ||
754 | if (this.hollowSides != 4) | ||
755 | hollow *= 0.707f; | ||
756 | } | ||
757 | else if (this.sides > 4) | ||
758 | { | ||
759 | initialProfileRot = (float)Math.PI; | ||
760 | if (this.hollowSides == 4) | ||
761 | { | ||
762 | if (hollow > 0.7f) | ||
763 | hollow = 0.7f; | ||
764 | hollow /= 0.7f; | ||
765 | } | ||
766 | } | ||
767 | |||
768 | Profile profile = new Profile(this.sides, this.profileStart, this.profileEnd, hollow, this.hollowSides); | ||
769 | |||
770 | if (initialProfileRot != 0.0f) | ||
771 | profile.AddRot(new Quaternion(new Vertex(0.0f, 0.0f, 1.0f), initialProfileRot)); | ||
772 | |||
773 | bool done = false; | ||
774 | while (!done) // loop through the length of the path and add the layers | ||
775 | { | ||
776 | Profile newLayer = profile.Clone(); | ||
777 | |||
778 | float xProfileScale = (1.0f - Math.Abs(this.skew)) * this.holeSizeX; | ||
779 | float yProfileScale = this.holeSizeY; | ||
780 | |||
781 | float percentOfPath = angle / (twoPi * this.revolutions); | ||
782 | float percentOfAngles = (angle - startAngle) / (endAngle - startAngle); | ||
783 | |||
784 | if (this.taperX > 0.01f) | ||
785 | xProfileScale *= 1.0f - percentOfPath * this.taperX; | ||
786 | else if (this.taperX < -0.01f) | ||
787 | xProfileScale *= 1.0f + (1.0f - percentOfPath) * this.taperX; | ||
788 | |||
789 | if (this.taperY > 0.01f) | ||
790 | yProfileScale *= 1.0f - percentOfPath * this.taperY; | ||
791 | else if (this.taperY < -0.01f) | ||
792 | yProfileScale *= 1.0f + (1.0f - percentOfPath) * this.taperY; | ||
793 | |||
794 | if (xProfileScale != 1.0f || yProfileScale != 1.0f) | ||
795 | newLayer.Scale(xProfileScale, yProfileScale); | ||
796 | |||
797 | float radiusScale = 1.0f; | ||
798 | if (this.radius > 0.001f) | ||
799 | radiusScale = 1.0f - this.radius * percentOfPath; | ||
800 | else if (this.radius < 0.001f) | ||
801 | radiusScale = 1.0f + this.radius * (1.0f - percentOfPath); | ||
802 | |||
803 | float twist = twistBegin + twistTotal * percentOfPath; | ||
804 | |||
805 | float xOffset = 0.5f * (skewStart + totalSkew * percentOfAngles); | ||
806 | |||
807 | xOffset += (float)Math.Sin(angle) * this.topShearX * 0.45f; | ||
808 | float yOffset = (float)Math.Cos(angle) * (0.5f - yPathScale) * radiusScale; | ||
809 | |||
810 | float zOffset = (float)Math.Sin(angle + this.topShearY * 0.9f) * (0.5f - yPathScale) * radiusScale; | ||
811 | |||
812 | // next apply twist rotation to the profile layer | ||
813 | if (twistTotal != 0.0f || twistBegin != 0.0f) | ||
814 | newLayer.AddRot(new Quaternion(new Vertex(0.0f, 0.0f, 1.0f), twist)); | ||
815 | |||
816 | // now orient the rotation of the profile layer relative to it's position on the path | ||
817 | // adding taperY to the angle used to generate the quat appears to approximate the viewer | ||
818 | newLayer.AddRot(new Quaternion(new Vertex(1.0f, 0.0f, 0.0f), angle + this.topShearY * 0.9f)); | ||
819 | newLayer.AddPos(xOffset, yOffset, zOffset); | ||
820 | |||
821 | if (angle == startAngle) | ||
822 | newLayer.FlipNormals(); | ||
823 | |||
824 | // append the layer and fill in the sides | ||
825 | |||
826 | int coordsLen = this.coords.Count; | ||
827 | newLayer.AddValue2Faces(coordsLen); | ||
828 | |||
829 | this.coords.AddRange(newLayer.coords); | ||
830 | this.faces.AddRange(newLayer.faces); | ||
831 | |||
832 | // fill faces between layers | ||
833 | |||
834 | int numVerts = newLayer.coords.Count; | ||
835 | Face newFace = new Face(); | ||
836 | if (step > firstStep) | ||
837 | { | ||
838 | for (int i = coordsLen; i < this.coords.Count - 1; i++) | ||
839 | { | ||
840 | newFace.v1 = i; | ||
841 | newFace.v2 = i - numVerts; | ||
842 | newFace.v3 = i - numVerts + 1; | ||
843 | this.faces.Add(newFace); | ||
844 | |||
845 | newFace.v2 = i - numVerts + 1; | ||
846 | newFace.v3 = i + 1; | ||
847 | this.faces.Add(newFace); | ||
848 | } | ||
849 | |||
850 | newFace.v1 = coordsLen - 1; | ||
851 | newFace.v2 = coordsLen - numVerts; | ||
852 | newFace.v3 = coordsLen; | ||
853 | this.faces.Add(newFace); | ||
854 | |||
855 | newFace.v1 = coordsLen + numVerts - 1; | ||
856 | newFace.v2 = coordsLen - 1; | ||
857 | newFace.v3 = coordsLen; | ||
858 | this.faces.Add(newFace); | ||
859 | } | ||
860 | |||
861 | // calculate terms for next iteration | ||
862 | // calculate the angle for the next iteration of the loop | ||
863 | |||
864 | if (angle >= endAngle) | ||
865 | done = true; | ||
866 | else | ||
867 | { | ||
868 | step += 1; | ||
869 | angle = stepSize * step; | ||
870 | if (angle > endAngle) | ||
871 | angle = endAngle; | ||
872 | } | ||
873 | } | ||
874 | } | ||
875 | |||
876 | public void AddPos(float x, float y, float z) | ||
877 | { | ||
878 | int i; | ||
879 | int numVerts = this.coords.Count; | ||
880 | Coord vert; | ||
881 | |||
882 | for (i = 0; i < numVerts; i++) | ||
883 | { | ||
884 | vert = this.coords[i]; | ||
885 | vert.X += x; | ||
886 | vert.Y += y; | ||
887 | vert.Z += z; | ||
888 | this.coords[i] = vert; | ||
889 | } | ||
890 | } | ||
891 | |||
892 | public void AddRot(Quaternion q) | ||
893 | { | ||
894 | int i; | ||
895 | int numVerts = this.coords.Count; | ||
896 | Coord vert; | ||
897 | |||
898 | for (i = 0; i < numVerts; i++) | ||
899 | { | ||
900 | vert = this.coords[i]; | ||
901 | Vertex v = new Vertex(vert.X, vert.Y, vert.Z) * q; | ||
902 | |||
903 | vert.X = v.X; | ||
904 | vert.Y = v.Y; | ||
905 | vert.Z = v.Z; | ||
906 | this.coords[i] = vert; | ||
907 | } | ||
908 | } | ||
909 | |||
910 | public void Scale(float x, float y, float z) | ||
911 | { | ||
912 | int i; | ||
913 | int numVerts = this.coords.Count; | ||
914 | Coord vert; | ||
915 | |||
916 | for (i = 0; i < numVerts; i++) | ||
917 | { | ||
918 | vert = this.coords[i]; | ||
919 | vert.X *= x; | ||
920 | vert.Y *= y; | ||
921 | vert.Z *= z; | ||
922 | this.coords[i] = vert; | ||
923 | } | ||
924 | } | ||
925 | |||
926 | public void DumpRaw(String path, String name, String title) | ||
404 | { | 927 | { |
405 | vertices = new List<vertex>(); | 928 | if (path == null) |
406 | faces = new List<face>(); | 929 | return; |
930 | String fileName = name + "_" + title + ".raw"; | ||
931 | String completePath = Path.Combine(path, fileName); | ||
932 | StreamWriter sw = new StreamWriter(completePath); | ||
407 | 933 | ||
934 | for (int i = 0; i < this.faces.Count; i++) | ||
935 | { | ||
936 | string s = this.coords[this.faces[i].v1].ToString(); | ||
937 | s += " " + this.coords[this.faces[i].v2].ToString(); | ||
938 | s += " " + this.coords[this.faces[i].v3].ToString(); | ||
408 | 939 | ||
940 | sw.WriteLine(s); | ||
941 | } | ||
942 | |||
943 | sw.Close(); | ||
409 | } | 944 | } |
410 | } | 945 | } |
411 | } | 946 | } |