aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/Meshing/PrimMesher.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Physics/Meshing/PrimMesher.cs')
-rw-r--r--OpenSim/Region/Physics/Meshing/PrimMesher.cs673
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
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using OpenSim.Framework; 30using System.IO;
31using OpenSim.Region.Physics.Manager; 31using OpenSim.Region.Physics.Manager;
32 32
33namespace OpenSim.Region.Physics.Meshing 33namespace 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}