aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region')
-rw-r--r--OpenSim/Region/Physics/Meshing/PrimMesher.cs4336
-rw-r--r--OpenSim/Region/Physics/Meshing/SculptMesh.cs686
2 files changed, 2511 insertions, 2511 deletions
diff --git a/OpenSim/Region/Physics/Meshing/PrimMesher.cs b/OpenSim/Region/Physics/Meshing/PrimMesher.cs
index 1fed64d..d79a480 100644
--- a/OpenSim/Region/Physics/Meshing/PrimMesher.cs
+++ b/OpenSim/Region/Physics/Meshing/PrimMesher.cs
@@ -1,2168 +1,2168 @@
1/* 1/*
2 * Copyright (c) Contributors 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
6 * modification, are permitted provided that the following conditions are met: 6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright 7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer. 8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright 9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the 10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution. 11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the 12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products 13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission. 14 * derived from this software without specific prior written permission.
15 * 15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY 16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY 19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 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 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 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 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. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Text; 30using System.Text;
31using System.IO; 31using System.IO;
32 32
33namespace PrimMesher 33namespace PrimMesher
34{ 34{
35 public struct Quat 35 public struct Quat
36 { 36 {
37 /// <summary>X value</summary> 37 /// <summary>X value</summary>
38 public float X; 38 public float X;
39 /// <summary>Y value</summary> 39 /// <summary>Y value</summary>
40 public float Y; 40 public float Y;
41 /// <summary>Z value</summary> 41 /// <summary>Z value</summary>
42 public float Z; 42 public float Z;
43 /// <summary>W value</summary> 43 /// <summary>W value</summary>
44 public float W; 44 public float W;
45 45
46 public Quat(float x, float y, float z, float w) 46 public Quat(float x, float y, float z, float w)
47 { 47 {
48 X = x; 48 X = x;
49 Y = y; 49 Y = y;
50 Z = z; 50 Z = z;
51 W = w; 51 W = w;
52 } 52 }
53 53
54 public Quat(Coord axis, float angle) 54 public Quat(Coord axis, float angle)
55 { 55 {
56 axis = axis.Normalize(); 56 axis = axis.Normalize();
57 57
58 angle *= 0.5f; 58 angle *= 0.5f;
59 float c = (float)Math.Cos(angle); 59 float c = (float)Math.Cos(angle);
60 float s = (float)Math.Sin(angle); 60 float s = (float)Math.Sin(angle);
61 61
62 X = axis.X * s; 62 X = axis.X * s;
63 Y = axis.Y * s; 63 Y = axis.Y * s;
64 Z = axis.Z * s; 64 Z = axis.Z * s;
65 W = c; 65 W = c;
66 66
67 Normalize(); 67 Normalize();
68 } 68 }
69 69
70 public float Length() 70 public float Length()
71 { 71 {
72 return (float)Math.Sqrt(X * X + Y * Y + Z * Z + W * W); 72 return (float)Math.Sqrt(X * X + Y * Y + Z * Z + W * W);
73 } 73 }
74 74
75 public Quat Normalize() 75 public Quat Normalize()
76 { 76 {
77 const float MAG_THRESHOLD = 0.0000001f; 77 const float MAG_THRESHOLD = 0.0000001f;
78 float mag = Length(); 78 float mag = Length();
79 79
80 // Catch very small rounding errors when normalizing 80 // Catch very small rounding errors when normalizing
81 if (mag > MAG_THRESHOLD) 81 if (mag > MAG_THRESHOLD)
82 { 82 {
83 float oomag = 1f / mag; 83 float oomag = 1f / mag;
84 X *= oomag; 84 X *= oomag;
85 Y *= oomag; 85 Y *= oomag;
86 Z *= oomag; 86 Z *= oomag;
87 W *= oomag; 87 W *= oomag;
88 } 88 }
89 else 89 else
90 { 90 {
91 X = 0f; 91 X = 0f;
92 Y = 0f; 92 Y = 0f;
93 Z = 0f; 93 Z = 0f;
94 W = 1f; 94 W = 1f;
95 } 95 }
96 96
97 return this; 97 return this;
98 } 98 }
99 99
100 public override string ToString() 100 public override string ToString()
101 { 101 {
102 return "< X: " + this.X.ToString() + ", Y: " + this.Y.ToString() + ", Z: " + this.Z.ToString() + ", W: " + this.W.ToString() + ">"; 102 return "< X: " + this.X.ToString() + ", Y: " + this.Y.ToString() + ", Z: " + this.Z.ToString() + ", W: " + this.W.ToString() + ">";
103 } 103 }
104 } 104 }
105 105
106 public struct Coord 106 public struct Coord
107 { 107 {
108 public float X; 108 public float X;
109 public float Y; 109 public float Y;
110 public float Z; 110 public float Z;
111 111
112 public Coord(float x, float y, float z) 112 public Coord(float x, float y, float z)
113 { 113 {
114 this.X = x; 114 this.X = x;
115 this.Y = y; 115 this.Y = y;
116 this.Z = z; 116 this.Z = z;
117 } 117 }
118 118
119 public float Length() 119 public float Length()
120 { 120 {
121 return (float)Math.Sqrt(this.X * this.X + this.Y * this.Y + this.Z * this.Z); 121 return (float)Math.Sqrt(this.X * this.X + this.Y * this.Y + this.Z * this.Z);
122 } 122 }
123 123
124 public Coord Invert() 124 public Coord Invert()
125 { 125 {
126 this.X = -this.X; 126 this.X = -this.X;
127 this.Y = -this.Y; 127 this.Y = -this.Y;
128 this.Z = -this.Z; 128 this.Z = -this.Z;
129 129
130 return this; 130 return this;
131 } 131 }
132 132
133 public Coord Normalize() 133 public Coord Normalize()
134 { 134 {
135 const float MAG_THRESHOLD = 0.0000001f; 135 const float MAG_THRESHOLD = 0.0000001f;
136 float mag = Length(); 136 float mag = Length();
137 137
138 // Catch very small rounding errors when normalizing 138 // Catch very small rounding errors when normalizing
139 if (mag > MAG_THRESHOLD) 139 if (mag > MAG_THRESHOLD)
140 { 140 {
141 float oomag = 1.0f / mag; 141 float oomag = 1.0f / mag;
142 this.X *= oomag; 142 this.X *= oomag;
143 this.Y *= oomag; 143 this.Y *= oomag;
144 this.Z *= oomag; 144 this.Z *= oomag;
145 } 145 }
146 else 146 else
147 { 147 {
148 this.X = 0.0f; 148 this.X = 0.0f;
149 this.Y = 0.0f; 149 this.Y = 0.0f;
150 this.Z = 0.0f; 150 this.Z = 0.0f;
151 } 151 }
152 152
153 return this; 153 return this;
154 } 154 }
155 155
156 public override string ToString() 156 public override string ToString()
157 { 157 {
158 return this.X.ToString() + " " + this.Y.ToString() + " " + this.Z.ToString(); 158 return this.X.ToString() + " " + this.Y.ToString() + " " + this.Z.ToString();
159 } 159 }
160 160
161 public static Coord Cross(Coord c1, Coord c2) 161 public static Coord Cross(Coord c1, Coord c2)
162 { 162 {
163 return new Coord( 163 return new Coord(
164 c1.Y * c2.Z - c2.Y * c1.Z, 164 c1.Y * c2.Z - c2.Y * c1.Z,
165 c1.Z * c2.X - c2.Z * c1.X, 165 c1.Z * c2.X - c2.Z * c1.X,
166 c1.X * c2.Y - c2.X * c1.Y 166 c1.X * c2.Y - c2.X * c1.Y
167 ); 167 );
168 } 168 }
169 169
170 public static Coord operator +(Coord v, Coord a) 170 public static Coord operator +(Coord v, Coord a)
171 { 171 {
172 return new Coord(v.X + a.X, v.Y + a.Y, v.Z + a.Z); 172 return new Coord(v.X + a.X, v.Y + a.Y, v.Z + a.Z);
173 } 173 }
174 174
175 public static Coord operator *(Coord v, Coord m) 175 public static Coord operator *(Coord v, Coord m)
176 { 176 {
177 return new Coord(v.X * m.X, v.Y * m.Y, v.Z * m.Z); 177 return new Coord(v.X * m.X, v.Y * m.Y, v.Z * m.Z);
178 } 178 }
179 179
180 public static Coord operator *(Coord v, Quat q) 180 public static Coord operator *(Coord v, Quat q)
181 { 181 {
182 // From http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/transforms/ 182 // From http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/transforms/
183 183
184 Coord c2 = new Coord(0.0f, 0.0f, 0.0f); 184 Coord c2 = new Coord(0.0f, 0.0f, 0.0f);
185 185
186 c2.X = q.W * q.W * v.X + 186 c2.X = q.W * q.W * v.X +
187 2f * q.Y * q.W * v.Z - 187 2f * q.Y * q.W * v.Z -
188 2f * q.Z * q.W * v.Y + 188 2f * q.Z * q.W * v.Y +
189 q.X * q.X * v.X + 189 q.X * q.X * v.X +
190 2f * q.Y * q.X * v.Y + 190 2f * q.Y * q.X * v.Y +
191 2f * q.Z * q.X * v.Z - 191 2f * q.Z * q.X * v.Z -
192 q.Z * q.Z * v.X - 192 q.Z * q.Z * v.X -
193 q.Y * q.Y * v.X; 193 q.Y * q.Y * v.X;
194 194
195 c2.Y = 195 c2.Y =
196 2f * q.X * q.Y * v.X + 196 2f * q.X * q.Y * v.X +
197 q.Y * q.Y * v.Y + 197 q.Y * q.Y * v.Y +
198 2f * q.Z * q.Y * v.Z + 198 2f * q.Z * q.Y * v.Z +
199 2f * q.W * q.Z * v.X - 199 2f * q.W * q.Z * v.X -
200 q.Z * q.Z * v.Y + 200 q.Z * q.Z * v.Y +
201 q.W * q.W * v.Y - 201 q.W * q.W * v.Y -
202 2f * q.X * q.W * v.Z - 202 2f * q.X * q.W * v.Z -
203 q.X * q.X * v.Y; 203 q.X * q.X * v.Y;
204 204
205 c2.Z = 205 c2.Z =
206 2f * q.X * q.Z * v.X + 206 2f * q.X * q.Z * v.X +
207 2f * q.Y * q.Z * v.Y + 207 2f * q.Y * q.Z * v.Y +
208 q.Z * q.Z * v.Z - 208 q.Z * q.Z * v.Z -
209 2f * q.W * q.Y * v.X - 209 2f * q.W * q.Y * v.X -
210 q.Y * q.Y * v.Z + 210 q.Y * q.Y * v.Z +
211 2f * q.W * q.X * v.Y - 211 2f * q.W * q.X * v.Y -
212 q.X * q.X * v.Z + 212 q.X * q.X * v.Z +
213 q.W * q.W * v.Z; 213 q.W * q.W * v.Z;
214 214
215 return c2; 215 return c2;
216 } 216 }
217 } 217 }
218 218
219 public struct UVCoord 219 public struct UVCoord
220 { 220 {
221 public float U; 221 public float U;
222 public float V; 222 public float V;
223 223
224 224
225 public UVCoord(float u, float v) 225 public UVCoord(float u, float v)
226 { 226 {
227 this.U = u; 227 this.U = u;
228 this.V = v; 228 this.V = v;
229 } 229 }
230 } 230 }
231 231
232 public struct Face 232 public struct Face
233 { 233 {
234 public int primFace; 234 public int primFace;
235 235
236 // vertices 236 // vertices
237 public int v1; 237 public int v1;
238 public int v2; 238 public int v2;
239 public int v3; 239 public int v3;
240 240
241 //normals 241 //normals
242 public int n1; 242 public int n1;
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
252 public Face(int v1, int v2, int v3) 252 public Face(int v1, int v2, int v3)
253 { 253 {
254 primFace = 0; 254 primFace = 0;
255 255
256 this.v1 = v1; 256 this.v1 = v1;
257 this.v2 = v2; 257 this.v2 = v2;
258 this.v3 = v3; 258 this.v3 = v3;
259 259
260 this.n1 = 0; 260 this.n1 = 0;
261 this.n2 = 0; 261 this.n2 = 0;
262 this.n3 = 0; 262 this.n3 = 0;
263 263
264 this.uv1 = 0; 264 this.uv1 = 0;
265 this.uv2 = 0; 265 this.uv2 = 0;
266 this.uv3 = 0; 266 this.uv3 = 0;
267 267
268 } 268 }
269 269
270 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)
271 { 271 {
272 primFace = 0; 272 primFace = 0;
273 273
274 this.v1 = v1; 274 this.v1 = v1;
275 this.v2 = v2; 275 this.v2 = v2;
276 this.v3 = v3; 276 this.v3 = v3;
277 277
278 this.n1 = n1; 278 this.n1 = n1;
279 this.n2 = n2; 279 this.n2 = n2;
280 this.n3 = n3; 280 this.n3 = n3;
281 281
282 this.uv1 = 0; 282 this.uv1 = 0;
283 this.uv2 = 0; 283 this.uv2 = 0;
284 this.uv3 = 0; 284 this.uv3 = 0;
285 } 285 }
286 286
287 public Coord SurfaceNormal(List<Coord> coordList) 287 public Coord SurfaceNormal(List<Coord> coordList)
288 { 288 {
289 Coord c1 = coordList[this.v1]; 289 Coord c1 = coordList[this.v1];
290 Coord c2 = coordList[this.v2]; 290 Coord c2 = coordList[this.v2];
291 Coord c3 = coordList[this.v3]; 291 Coord c3 = coordList[this.v3];
292 292
293 Coord edge1 = new Coord(c2.X - c1.X, c2.Y - c1.Y, c2.Z - c1.Z); 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); 294 Coord edge2 = new Coord(c3.X - c1.X, c3.Y - c1.Y, c3.Z - c1.Z);
295 295
296 return Coord.Cross(edge1, edge2).Normalize(); 296 return Coord.Cross(edge1, edge2).Normalize();
297 } 297 }
298 } 298 }
299 299
300 public struct ViewerFace 300 public struct ViewerFace
301 { 301 {
302 public int primFaceNumber; 302 public int primFaceNumber;
303 303
304 public Coord v1; 304 public Coord v1;
305 public Coord v2; 305 public Coord v2;
306 public Coord v3; 306 public Coord v3;
307 307
308 public Coord n1; 308 public Coord n1;
309 public Coord n2; 309 public Coord n2;
310 public Coord n3; 310 public Coord n3;
311 311
312 public UVCoord uv1; 312 public UVCoord uv1;
313 public UVCoord uv2; 313 public UVCoord uv2;
314 public UVCoord uv3; 314 public UVCoord uv3;
315 315
316 public ViewerFace(int primFaceNumber) 316 public ViewerFace(int primFaceNumber)
317 { 317 {
318 this.primFaceNumber = primFaceNumber; 318 this.primFaceNumber = primFaceNumber;
319 319
320 this.v1 = new Coord(); 320 this.v1 = new Coord();
321 this.v2 = new Coord(); 321 this.v2 = new Coord();
322 this.v3 = new Coord(); 322 this.v3 = new Coord();
323 323
324 this.n1 = new Coord(); 324 this.n1 = new Coord();
325 this.n2 = new Coord(); 325 this.n2 = new Coord();
326 this.n3 = new Coord(); 326 this.n3 = new Coord();
327 327
328 this.uv1 = new UVCoord(); 328 this.uv1 = new UVCoord();
329 this.uv2 = new UVCoord(); 329 this.uv2 = new UVCoord();
330 this.uv3 = new UVCoord(); 330 this.uv3 = new UVCoord();
331 } 331 }
332 332
333 public void Scale(float x, float y, float z) 333 public void Scale(float x, float y, float z)
334 { 334 {
335 this.v1.X *= x; 335 this.v1.X *= x;
336 this.v1.Y *= y; 336 this.v1.Y *= y;
337 this.v1.Z *= z; 337 this.v1.Z *= z;
338 338
339 this.v2.X *= x; 339 this.v2.X *= x;
340 this.v2.Y *= y; 340 this.v2.Y *= y;
341 this.v2.Z *= z; 341 this.v2.Z *= z;
342 342
343 this.v3.X *= x; 343 this.v3.X *= x;
344 this.v3.Y *= y; 344 this.v3.Y *= y;
345 this.v3.Z *= z; 345 this.v3.Z *= z;
346 } 346 }
347 347
348 public void AddRot(Quat q) 348 public void AddRot(Quat q)
349 { 349 {
350 this.v1 *= q; 350 this.v1 *= q;
351 this.v2 *= q; 351 this.v2 *= q;
352 this.v3 *= q; 352 this.v3 *= q;
353 353
354 this.n1 *= q; 354 this.n1 *= q;
355 this.n2 *= q; 355 this.n2 *= q;
356 this.n3 *= q; 356 this.n3 *= q;
357 } 357 }
358 358
359 public void CalcSurfaceNormal() 359 public void CalcSurfaceNormal()
360 { 360 {
361 361
362 Coord edge1 = new Coord(this.v2.X - this.v1.X, this.v2.Y - this.v1.Y, this.v2.Z - this.v1.Z); 362 Coord edge1 = new Coord(this.v2.X - this.v1.X, this.v2.Y - this.v1.Y, this.v2.Z - this.v1.Z);
363 Coord edge2 = new Coord(this.v3.X - this.v1.X, this.v3.Y - this.v1.Y, this.v3.Z - this.v1.Z); 363 Coord edge2 = new Coord(this.v3.X - this.v1.X, this.v3.Y - this.v1.Y, this.v3.Z - this.v1.Z);
364 364
365 this.n1 = this.n2 = this.n3 = Coord.Cross(edge1, edge2).Normalize(); 365 this.n1 = this.n2 = this.n3 = Coord.Cross(edge1, edge2).Normalize();
366 } 366 }
367 } 367 }
368 368
369 internal struct Angle 369 internal struct Angle
370 { 370 {
371 internal float angle; 371 internal float angle;
372 internal float X; 372 internal float X;
373 internal float Y; 373 internal float Y;
374 374
375 internal Angle(float angle, float x, float y) 375 internal Angle(float angle, float x, float y)
376 { 376 {
377 this.angle = angle; 377 this.angle = angle;
378 this.X = x; 378 this.X = x;
379 this.Y = y; 379 this.Y = y;
380 } 380 }
381 } 381 }
382 382
383 internal class AngleList 383 internal class AngleList
384 { 384 {
385 private float iX, iY; // intersection point 385 private float iX, iY; // intersection point
386 386
387 private Angle[] angles3 = 387 private Angle[] angles3 =
388 { 388 {
389 new Angle(0.0f, 1.0f, 0.0f), 389 new Angle(0.0f, 1.0f, 0.0f),
390 new Angle(0.33333333333333333f, -0.5f, 0.86602540378443871f), 390 new Angle(0.33333333333333333f, -0.5f, 0.86602540378443871f),
391 new Angle(0.66666666666666667f, -0.5f, -0.86602540378443837f), 391 new Angle(0.66666666666666667f, -0.5f, -0.86602540378443837f),
392 new Angle(1.0f, 1.0f, 0.0f) 392 new Angle(1.0f, 1.0f, 0.0f)
393 }; 393 };
394 394
395 private Coord[] normals3 = 395 private Coord[] normals3 =
396 { 396 {
397 new Coord(0.25f, 0.4330127019f, 0.0f).Normalize(), 397 new Coord(0.25f, 0.4330127019f, 0.0f).Normalize(),
398 new Coord(-0.5f, 0.0f, 0.0f).Normalize(), 398 new Coord(-0.5f, 0.0f, 0.0f).Normalize(),
399 new Coord(0.25f, -0.4330127019f, 0.0f).Normalize(), 399 new Coord(0.25f, -0.4330127019f, 0.0f).Normalize(),
400 new Coord(0.25f, 0.4330127019f, 0.0f).Normalize() 400 new Coord(0.25f, 0.4330127019f, 0.0f).Normalize()
401 }; 401 };
402 402
403 private Angle[] angles4 = 403 private Angle[] angles4 =
404 { 404 {
405 new Angle(0.0f, 1.0f, 0.0f), 405 new Angle(0.0f, 1.0f, 0.0f),
406 new Angle(0.25f, 0.0f, 1.0f), 406 new Angle(0.25f, 0.0f, 1.0f),
407 new Angle(0.5f, -1.0f, 0.0f), 407 new Angle(0.5f, -1.0f, 0.0f),
408 new Angle(0.75f, 0.0f, -1.0f), 408 new Angle(0.75f, 0.0f, -1.0f),
409 new Angle(1.0f, 1.0f, 0.0f) 409 new Angle(1.0f, 1.0f, 0.0f)
410 }; 410 };
411 411
412 private Coord[] normals4 = 412 private Coord[] normals4 =
413 { 413 {
414 new Coord(0.5f, 0.5f, 0.0f).Normalize(), 414 new Coord(0.5f, 0.5f, 0.0f).Normalize(),
415 new Coord(-0.5f, 0.5f, 0.0f).Normalize(), 415 new Coord(-0.5f, 0.5f, 0.0f).Normalize(),
416 new Coord(-0.5f, -0.5f, 0.0f).Normalize(), 416 new Coord(-0.5f, -0.5f, 0.0f).Normalize(),
417 new Coord(0.5f, -0.5f, 0.0f).Normalize(), 417 new Coord(0.5f, -0.5f, 0.0f).Normalize(),
418 new Coord(0.5f, 0.5f, 0.0f).Normalize() 418 new Coord(0.5f, 0.5f, 0.0f).Normalize()
419 }; 419 };
420 420
421 private Angle[] angles24 = 421 private Angle[] angles24 =
422 { 422 {
423 new Angle(0.0f, 1.0f, 0.0f), 423 new Angle(0.0f, 1.0f, 0.0f),
424 new Angle(0.041666666666666664f, 0.96592582628906831f, 0.25881904510252074f), 424 new Angle(0.041666666666666664f, 0.96592582628906831f, 0.25881904510252074f),
425 new Angle(0.083333333333333329f, 0.86602540378443871f, 0.5f), 425 new Angle(0.083333333333333329f, 0.86602540378443871f, 0.5f),
426 new Angle(0.125f, 0.70710678118654757f, 0.70710678118654746f), 426 new Angle(0.125f, 0.70710678118654757f, 0.70710678118654746f),
427 new Angle(0.16666666666666667f, 0.5f, 0.8660254037844386f), 427 new Angle(0.16666666666666667f, 0.5f, 0.8660254037844386f),
428 new Angle(0.20833333333333331f, 0.25881904510252096f, 0.9659258262890682f), 428 new Angle(0.20833333333333331f, 0.25881904510252096f, 0.9659258262890682f),
429 new Angle(0.25f, 0.0f, 1.0f), 429 new Angle(0.25f, 0.0f, 1.0f),
430 new Angle(0.29166666666666663f, -0.25881904510252063f, 0.96592582628906831f), 430 new Angle(0.29166666666666663f, -0.25881904510252063f, 0.96592582628906831f),
431 new Angle(0.33333333333333333f, -0.5f, 0.86602540378443871f), 431 new Angle(0.33333333333333333f, -0.5f, 0.86602540378443871f),
432 new Angle(0.375f, -0.70710678118654746f, 0.70710678118654757f), 432 new Angle(0.375f, -0.70710678118654746f, 0.70710678118654757f),
433 new Angle(0.41666666666666663f, -0.86602540378443849f, 0.5f), 433 new Angle(0.41666666666666663f, -0.86602540378443849f, 0.5f),
434 new Angle(0.45833333333333331f, -0.9659258262890682f, 0.25881904510252102f), 434 new Angle(0.45833333333333331f, -0.9659258262890682f, 0.25881904510252102f),
435 new Angle(0.5f, -1.0f, 0.0f), 435 new Angle(0.5f, -1.0f, 0.0f),
436 new Angle(0.54166666666666663f, -0.96592582628906842f, -0.25881904510252035f), 436 new Angle(0.54166666666666663f, -0.96592582628906842f, -0.25881904510252035f),
437 new Angle(0.58333333333333326f, -0.86602540378443882f, -0.5f), 437 new Angle(0.58333333333333326f, -0.86602540378443882f, -0.5f),
438 new Angle(0.62499999999999989f, -0.70710678118654791f, -0.70710678118654713f), 438 new Angle(0.62499999999999989f, -0.70710678118654791f, -0.70710678118654713f),
439 new Angle(0.66666666666666667f, -0.5f, -0.86602540378443837f), 439 new Angle(0.66666666666666667f, -0.5f, -0.86602540378443837f),
440 new Angle(0.70833333333333326f, -0.25881904510252152f, -0.96592582628906809f), 440 new Angle(0.70833333333333326f, -0.25881904510252152f, -0.96592582628906809f),
441 new Angle(0.75f, 0.0f, -1.0f), 441 new Angle(0.75f, 0.0f, -1.0f),
442 new Angle(0.79166666666666663f, 0.2588190451025203f, -0.96592582628906842f), 442 new Angle(0.79166666666666663f, 0.2588190451025203f, -0.96592582628906842f),
443 new Angle(0.83333333333333326f, 0.5f, -0.86602540378443904f), 443 new Angle(0.83333333333333326f, 0.5f, -0.86602540378443904f),
444 new Angle(0.875f, 0.70710678118654735f, -0.70710678118654768f), 444 new Angle(0.875f, 0.70710678118654735f, -0.70710678118654768f),
445 new Angle(0.91666666666666663f, 0.86602540378443837f, -0.5f), 445 new Angle(0.91666666666666663f, 0.86602540378443837f, -0.5f),
446 new Angle(0.95833333333333326f, 0.96592582628906809f, -0.25881904510252157f), 446 new Angle(0.95833333333333326f, 0.96592582628906809f, -0.25881904510252157f),
447 new Angle(1.0f, 1.0f, 0.0f) 447 new Angle(1.0f, 1.0f, 0.0f)
448 }; 448 };
449 449
450 private Angle interpolatePoints(float newPoint, Angle p1, Angle p2) 450 private Angle interpolatePoints(float newPoint, Angle p1, Angle p2)
451 { 451 {
452 float m = (newPoint - p1.angle) / (p2.angle - p1.angle); 452 float m = (newPoint - p1.angle) / (p2.angle - p1.angle);
453 return new Angle(newPoint, p1.X + m * (p2.X - p1.X), p1.Y + m * (p2.Y - p1.Y)); 453 return new Angle(newPoint, p1.X + m * (p2.X - p1.X), p1.Y + m * (p2.Y - p1.Y));
454 } 454 }
455 455
456 private void intersection(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) 456 private void intersection(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
457 { // ref: http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline2d/ 457 { // ref: http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline2d/
458 double denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1); 458 double denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);
459 double uaNumerator = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3); 459 double uaNumerator = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3);
460 460
461 if (denom != 0.0) 461 if (denom != 0.0)
462 { 462 {
463 double ua = uaNumerator / denom; 463 double ua = uaNumerator / denom;
464 iX = (float)(x1 + ua * (x2 - x1)); 464 iX = (float)(x1 + ua * (x2 - x1));
465 iY = (float)(y1 + ua * (y2 - y1)); 465 iY = (float)(y1 + ua * (y2 - y1));
466 } 466 }
467 } 467 }
468 468
469 internal List<Angle> angles; 469 internal List<Angle> angles;
470 internal List<Coord> normals; 470 internal List<Coord> normals;
471 471
472 internal void makeAngles(int sides, float startAngle, float stopAngle) 472 internal void makeAngles(int sides, float startAngle, float stopAngle)
473 { 473 {
474 angles = new List<Angle>(); 474 angles = new List<Angle>();
475 normals = new List<Coord>(); 475 normals = new List<Coord>();
476 476
477 double twoPi = System.Math.PI * 2.0; 477 double twoPi = System.Math.PI * 2.0;
478 float twoPiInv = 1.0f / (float)twoPi; 478 float twoPiInv = 1.0f / (float)twoPi;
479 479
480 if (sides < 1) 480 if (sides < 1)
481 throw new Exception("number of sides not greater than zero"); 481 throw new Exception("number of sides not greater than zero");
482 if (stopAngle <= startAngle) 482 if (stopAngle <= startAngle)
483 throw new Exception("stopAngle not greater than startAngle"); 483 throw new Exception("stopAngle not greater than startAngle");
484 484
485 if ((sides == 3 || sides == 4 || sides == 24)) 485 if ((sides == 3 || sides == 4 || sides == 24))
486 { 486 {
487 startAngle *= twoPiInv; 487 startAngle *= twoPiInv;
488 stopAngle *= twoPiInv; 488 stopAngle *= twoPiInv;
489 489
490 Angle[] sourceAngles; 490 Angle[] sourceAngles;
491 if (sides == 3) 491 if (sides == 3)
492 sourceAngles = angles3; 492 sourceAngles = angles3;
493 else if (sides == 4) 493 else if (sides == 4)
494 sourceAngles = angles4; 494 sourceAngles = angles4;
495 else sourceAngles = angles24; 495 else sourceAngles = angles24;
496 496
497 int startAngleIndex = (int)(startAngle * sides); 497 int startAngleIndex = (int)(startAngle * sides);
498 int endAngleIndex = sourceAngles.Length - 1; 498 int endAngleIndex = sourceAngles.Length - 1;
499 if (stopAngle < 1.0f) 499 if (stopAngle < 1.0f)
500 endAngleIndex = (int)(stopAngle * sides) + 1; 500 endAngleIndex = (int)(stopAngle * sides) + 1;
501 if (endAngleIndex == startAngleIndex) 501 if (endAngleIndex == startAngleIndex)
502 endAngleIndex++; 502 endAngleIndex++;
503 503
504 for (int angleIndex = startAngleIndex; angleIndex < endAngleIndex + 1; angleIndex++) 504 for (int angleIndex = startAngleIndex; angleIndex < endAngleIndex + 1; angleIndex++)
505 { 505 {
506 angles.Add(sourceAngles[angleIndex]); 506 angles.Add(sourceAngles[angleIndex]);
507 if (sides == 3) 507 if (sides == 3)
508 normals.Add(normals3[angleIndex]); 508 normals.Add(normals3[angleIndex]);
509 else if (sides == 4) 509 else if (sides == 4)
510 normals.Add(normals4[angleIndex]); 510 normals.Add(normals4[angleIndex]);
511 } 511 }
512 512
513 if (startAngle > 0.0f) 513 if (startAngle > 0.0f)
514 angles[0] = interpolatePoints(startAngle, angles[0], angles[1]); 514 angles[0] = interpolatePoints(startAngle, angles[0], angles[1]);
515 515
516 if (stopAngle < 1.0f) 516 if (stopAngle < 1.0f)
517 { 517 {
518 int lastAngleIndex = angles.Count - 1; 518 int lastAngleIndex = angles.Count - 1;
519 angles[lastAngleIndex] = interpolatePoints(stopAngle, angles[lastAngleIndex - 1], angles[lastAngleIndex]); 519 angles[lastAngleIndex] = interpolatePoints(stopAngle, angles[lastAngleIndex - 1], angles[lastAngleIndex]);
520 } 520 }
521 } 521 }
522 else 522 else
523 { 523 {
524 double stepSize = twoPi / sides; 524 double stepSize = twoPi / sides;
525 525
526 int startStep = (int)(startAngle / stepSize); 526 int startStep = (int)(startAngle / stepSize);
527 double angle = stepSize * startStep; 527 double angle = stepSize * startStep;
528 int step = startStep; 528 int step = startStep;
529 double stopAngleTest = stopAngle; 529 double stopAngleTest = stopAngle;
530 if (stopAngle < twoPi) 530 if (stopAngle < twoPi)
531 { 531 {
532 stopAngleTest = stepSize * ((int)(stopAngle / stepSize) + 1); 532 stopAngleTest = stepSize * ((int)(stopAngle / stepSize) + 1);
533 if (stopAngleTest < stopAngle) 533 if (stopAngleTest < stopAngle)
534 stopAngleTest += stepSize; 534 stopAngleTest += stepSize;
535 if (stopAngleTest > twoPi) 535 if (stopAngleTest > twoPi)
536 stopAngleTest = twoPi; 536 stopAngleTest = twoPi;
537 } 537 }
538 538
539 while (angle <= stopAngleTest) 539 while (angle <= stopAngleTest)
540 { 540 {
541 Angle newAngle; 541 Angle newAngle;
542 newAngle.angle = (float)angle; 542 newAngle.angle = (float)angle;
543 newAngle.X = (float)System.Math.Cos(angle); 543 newAngle.X = (float)System.Math.Cos(angle);
544 newAngle.Y = (float)System.Math.Sin(angle); 544 newAngle.Y = (float)System.Math.Sin(angle);
545 angles.Add(newAngle); 545 angles.Add(newAngle);
546 step += 1; 546 step += 1;
547 angle = stepSize * step; 547 angle = stepSize * step;
548 } 548 }
549 549
550 if (startAngle > angles[0].angle) 550 if (startAngle > angles[0].angle)
551 { 551 {
552 Angle newAngle; 552 Angle newAngle;
553 intersection(angles[0].X, angles[0].Y, angles[1].X, angles[1].Y, 0.0f, 0.0f, (float)Math.Cos(startAngle), (float)Math.Sin(startAngle)); 553 intersection(angles[0].X, angles[0].Y, angles[1].X, angles[1].Y, 0.0f, 0.0f, (float)Math.Cos(startAngle), (float)Math.Sin(startAngle));
554 newAngle.angle = startAngle; 554 newAngle.angle = startAngle;
555 newAngle.X = iX; 555 newAngle.X = iX;
556 newAngle.Y = iY; 556 newAngle.Y = iY;
557 angles[0] = newAngle; 557 angles[0] = newAngle;
558 } 558 }
559 559
560 int index = angles.Count - 1; 560 int index = angles.Count - 1;
561 if (stopAngle < angles[index].angle) 561 if (stopAngle < angles[index].angle)
562 { 562 {
563 Angle newAngle; 563 Angle newAngle;
564 intersection(angles[index - 1].X, angles[index - 1].Y, angles[index].X, angles[index].Y, 0.0f, 0.0f, (float)Math.Cos(stopAngle), (float)Math.Sin(stopAngle)); 564 intersection(angles[index - 1].X, angles[index - 1].Y, angles[index].X, angles[index].Y, 0.0f, 0.0f, (float)Math.Cos(stopAngle), (float)Math.Sin(stopAngle));
565 newAngle.angle = stopAngle; 565 newAngle.angle = stopAngle;
566 newAngle.X = iX; 566 newAngle.X = iX;
567 newAngle.Y = iY; 567 newAngle.Y = iY;
568 angles[index] = newAngle; 568 angles[index] = newAngle;
569 } 569 }
570 } 570 }
571 } 571 }
572 } 572 }
573 573
574 /// <summary> 574 /// <summary>
575 /// generates a profile for extrusion 575 /// generates a profile for extrusion
576 /// </summary> 576 /// </summary>
577 internal class Profile 577 internal class Profile
578 { 578 {
579 private const float twoPi = 2.0f * (float)Math.PI; 579 private const float twoPi = 2.0f * (float)Math.PI;
580 580
581 internal List<Coord> coords; 581 internal List<Coord> coords;
582 internal List<Face> faces; 582 internal List<Face> faces;
583 internal List<Coord> vertexNormals; 583 internal List<Coord> vertexNormals;
584 internal List<float> us; 584 internal List<float> us;
585 internal List<UVCoord> faceUVs; 585 internal List<UVCoord> faceUVs;
586 internal List<int> faceNumbers; 586 internal List<int> faceNumbers;
587 587
588 internal Coord faceNormal = new Coord(0.0f, 0.0f, 1.0f); 588 internal Coord faceNormal = new Coord(0.0f, 0.0f, 1.0f);
589 internal Coord cutNormal1 = new Coord(); 589 internal Coord cutNormal1 = new Coord();
590 internal Coord cutNormal2 = new Coord(); 590 internal Coord cutNormal2 = new Coord();
591 591
592 internal int numOuterVerts = 0; 592 internal int numOuterVerts = 0;
593 internal int numHollowVerts = 0; 593 internal int numHollowVerts = 0;
594 594
595 internal bool calcVertexNormals = false; 595 internal bool calcVertexNormals = false;
596 internal int bottomFaceNumber = 0; 596 internal int bottomFaceNumber = 0;
597 internal int numPrimFaces = 0; 597 internal int numPrimFaces = 0;
598 598
599 internal Profile() 599 internal Profile()
600 { 600 {
601 this.coords = new List<Coord>(); 601 this.coords = new List<Coord>();
602 this.faces = new List<Face>(); 602 this.faces = new List<Face>();
603 this.vertexNormals = new List<Coord>(); 603 this.vertexNormals = new List<Coord>();
604 this.us = new List<float>(); 604 this.us = new List<float>();
605 this.faceUVs = new List<UVCoord>(); 605 this.faceUVs = new List<UVCoord>();
606 this.faceNumbers = new List<int>(); 606 this.faceNumbers = new List<int>();
607 } 607 }
608 608
609 internal 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)
610 { 610 {
611 this.calcVertexNormals = calcVertexNormals; 611 this.calcVertexNormals = calcVertexNormals;
612 this.coords = new List<Coord>(); 612 this.coords = new List<Coord>();
613 this.faces = new List<Face>(); 613 this.faces = new List<Face>();
614 this.vertexNormals = new List<Coord>(); 614 this.vertexNormals = new List<Coord>();
615 this.us = new List<float>(); 615 this.us = new List<float>();
616 this.faceUVs = new List<UVCoord>(); 616 this.faceUVs = new List<UVCoord>();
617 this.faceNumbers = new List<int>(); 617 this.faceNumbers = new List<int>();
618 618
619 Coord center = new Coord(0.0f, 0.0f, 0.0f); 619 Coord center = new Coord(0.0f, 0.0f, 0.0f);
620 620
621 List<Coord> hollowCoords = new List<Coord>(); 621 List<Coord> hollowCoords = new List<Coord>();
622 List<Coord> hollowNormals = new List<Coord>(); 622 List<Coord> hollowNormals = new List<Coord>();
623 List<float> hollowUs = new List<float>(); 623 List<float> hollowUs = new List<float>();
624 624
625 bool hasHollow = (hollow > 0.0f); 625 bool hasHollow = (hollow > 0.0f);
626 626
627 bool hasProfileCut = (profileStart > 0.0f || profileEnd < 1.0f); 627 bool hasProfileCut = (profileStart > 0.0f || profileEnd < 1.0f);
628 628
629 AngleList angles = new AngleList(); 629 AngleList angles = new AngleList();
630 AngleList hollowAngles = new AngleList(); 630 AngleList hollowAngles = new AngleList();
631 631
632 float xScale = 0.5f; 632 float xScale = 0.5f;
633 float yScale = 0.5f; 633 float yScale = 0.5f;
634 if (sides == 4) // corners of a square are sqrt(2) from center 634 if (sides == 4) // corners of a square are sqrt(2) from center
635 { 635 {
636 xScale = 0.707f; 636 xScale = 0.707f;
637 yScale = 0.707f; 637 yScale = 0.707f;
638 } 638 }
639 639
640 float startAngle = profileStart * twoPi; 640 float startAngle = profileStart * twoPi;
641 float stopAngle = profileEnd * twoPi; 641 float stopAngle = profileEnd * twoPi;
642 642
643 try { angles.makeAngles(sides, startAngle, stopAngle); } 643 try { angles.makeAngles(sides, startAngle, stopAngle); }
644 catch (Exception ex) 644 catch (Exception ex)
645 { 645 {
646 Console.WriteLine("makeAngles failed: Exception: " + ex.ToString()); 646 Console.WriteLine("makeAngles failed: Exception: " + ex.ToString());
647 Console.WriteLine("sides: " + sides.ToString() + " startAngle: " + startAngle.ToString() + " stopAngle: " + stopAngle.ToString()); 647 Console.WriteLine("sides: " + sides.ToString() + " startAngle: " + startAngle.ToString() + " stopAngle: " + stopAngle.ToString());
648 return; 648 return;
649 } 649 }
650 650
651 this.numOuterVerts = angles.angles.Count; 651 this.numOuterVerts = angles.angles.Count;
652 652
653 // flag to create as few triangles as possible for 3 or 4 side profile 653 // flag to create as few triangles as possible for 3 or 4 side profile
654 bool simpleFace = (sides < 5 && !(hasHollow || hasProfileCut)); 654 bool simpleFace = (sides < 5 && !(hasHollow || hasProfileCut));
655 655
656 if (hasHollow) 656 if (hasHollow)
657 { 657 {
658 if (sides == hollowSides) 658 if (sides == hollowSides)
659 hollowAngles = angles; 659 hollowAngles = angles;
660 else 660 else
661 { 661 {
662 try { hollowAngles.makeAngles(hollowSides, startAngle, stopAngle); } 662 try { hollowAngles.makeAngles(hollowSides, startAngle, stopAngle); }
663 catch (Exception ex) 663 catch (Exception ex)
664 { 664 {
665 Console.WriteLine("makeAngles failed: Exception: " + ex.ToString()); 665 Console.WriteLine("makeAngles failed: Exception: " + ex.ToString());
666 Console.WriteLine("sides: " + sides.ToString() + " startAngle: " + startAngle.ToString() + " stopAngle: " + stopAngle.ToString()); 666 Console.WriteLine("sides: " + sides.ToString() + " startAngle: " + startAngle.ToString() + " stopAngle: " + stopAngle.ToString());
667 return; 667 return;
668 } 668 }
669 } 669 }
670 this.numHollowVerts = hollowAngles.angles.Count; 670 this.numHollowVerts = hollowAngles.angles.Count;
671 } 671 }
672 else if (!simpleFace) 672 else if (!simpleFace)
673 { 673 {
674 this.coords.Add(center); 674 this.coords.Add(center);
675 if (this.calcVertexNormals) 675 if (this.calcVertexNormals)
676 this.vertexNormals.Add(new Coord(0.0f, 0.0f, 1.0f)); 676 this.vertexNormals.Add(new Coord(0.0f, 0.0f, 1.0f));
677 this.us.Add(0.0f); 677 this.us.Add(0.0f);
678 } 678 }
679 679
680 float z = 0.0f; 680 float z = 0.0f;
681 681
682 Angle angle; 682 Angle angle;
683 Coord newVert = new Coord(); 683 Coord newVert = new Coord();
684 if (hasHollow && hollowSides != sides) 684 if (hasHollow && hollowSides != sides)
685 { 685 {
686 int numHollowAngles = hollowAngles.angles.Count; 686 int numHollowAngles = hollowAngles.angles.Count;
687 for (int i = 0; i < numHollowAngles; i++) 687 for (int i = 0; i < numHollowAngles; i++)
688 { 688 {
689 angle = hollowAngles.angles[i]; 689 angle = hollowAngles.angles[i];
690 newVert.X = hollow * xScale * angle.X; 690 newVert.X = hollow * xScale * angle.X;
691 newVert.Y = hollow * yScale * angle.Y; 691 newVert.Y = hollow * yScale * angle.Y;
692 newVert.Z = z; 692 newVert.Z = z;
693 693
694 hollowCoords.Add(newVert); 694 hollowCoords.Add(newVert);
695 if (this.calcVertexNormals) 695 if (this.calcVertexNormals)
696 { 696 {
697 if (hollowSides < 5) 697 if (hollowSides < 5)
698 hollowNormals.Add(hollowAngles.normals[i].Invert()); 698 hollowNormals.Add(hollowAngles.normals[i].Invert());
699 else 699 else
700 hollowNormals.Add(new Coord(-angle.X, -angle.Y, 0.0f)); 700 hollowNormals.Add(new Coord(-angle.X, -angle.Y, 0.0f));
701 701
702 hollowUs.Add(angle.angle * hollow); 702 hollowUs.Add(angle.angle * hollow);
703 } 703 }
704 } 704 }
705 } 705 }
706 706
707 int index = 0; 707 int index = 0;
708 int numAngles = angles.angles.Count; 708 int numAngles = angles.angles.Count;
709 709
710 for (int i = 0; i < numAngles; i++) 710 for (int i = 0; i < numAngles; i++)
711 { 711 {
712 int iNext = i == numAngles ? i + 1 : 0; 712 int iNext = i == numAngles ? i + 1 : 0;
713 angle = angles.angles[i]; 713 angle = angles.angles[i];
714 newVert.X = angle.X * xScale; 714 newVert.X = angle.X * xScale;
715 newVert.Y = angle.Y * yScale; 715 newVert.Y = angle.Y * yScale;
716 newVert.Z = z; 716 newVert.Z = z;
717 this.coords.Add(newVert); 717 this.coords.Add(newVert);
718 if (this.calcVertexNormals) 718 if (this.calcVertexNormals)
719 { 719 {
720 720
721 if (sides < 5) 721 if (sides < 5)
722 { 722 {
723 this.vertexNormals.Add(angles.normals[i]); 723 this.vertexNormals.Add(angles.normals[i]);
724 float u = angle.angle; 724 float u = angle.angle;
725 this.us.Add(u); 725 this.us.Add(u);
726 } 726 }
727 else 727 else
728 { 728 {
729 this.vertexNormals.Add(new Coord(angle.X, angle.Y, 0.0f)); 729 this.vertexNormals.Add(new Coord(angle.X, angle.Y, 0.0f));
730 this.us.Add(angle.angle); 730 this.us.Add(angle.angle);
731 } 731 }
732 } 732 }
733 733
734 if (hollow > 0.0f) 734 if (hollow > 0.0f)
735 { 735 {
736 if (hollowSides == sides) 736 if (hollowSides == sides)
737 { 737 {
738 newVert.X *= hollow; 738 newVert.X *= hollow;
739 newVert.Y *= hollow; 739 newVert.Y *= hollow;
740 newVert.Z = z; 740 newVert.Z = z;
741 hollowCoords.Add(newVert); 741 hollowCoords.Add(newVert);
742 if (this.calcVertexNormals) 742 if (this.calcVertexNormals)
743 { 743 {
744 if (sides < 5) 744 if (sides < 5)
745 { 745 {
746 hollowNormals.Add(angles.normals[i].Invert()); 746 hollowNormals.Add(angles.normals[i].Invert());
747 } 747 }
748 748
749 else 749 else
750 hollowNormals.Add(new Coord(-angle.X, -angle.Y, 0.0f)); 750 hollowNormals.Add(new Coord(-angle.X, -angle.Y, 0.0f));
751 751
752 hollowUs.Add(angle.angle * hollow); 752 hollowUs.Add(angle.angle * hollow);
753 } 753 }
754 } 754 }
755 } 755 }
756 else if (!simpleFace && createFaces && angle.angle > 0.0001f) 756 else if (!simpleFace && createFaces && angle.angle > 0.0001f)
757 { 757 {
758 Face newFace = new Face(); 758 Face newFace = new Face();
759 newFace.v1 = 0; 759 newFace.v1 = 0;
760 newFace.v2 = index; 760 newFace.v2 = index;
761 newFace.v3 = index + 1; 761 newFace.v3 = index + 1;
762 762
763 this.faces.Add(newFace); 763 this.faces.Add(newFace);
764 } 764 }
765 index += 1; 765 index += 1;
766 } 766 }
767 767
768 if (hasHollow) 768 if (hasHollow)
769 { 769 {
770 hollowCoords.Reverse(); 770 hollowCoords.Reverse();
771 if (this.calcVertexNormals) 771 if (this.calcVertexNormals)
772 { 772 {
773 hollowNormals.Reverse(); 773 hollowNormals.Reverse();
774 hollowUs.Reverse(); 774 hollowUs.Reverse();
775 } 775 }
776 776
777 if (createFaces) 777 if (createFaces)
778 { 778 {
779 int numOuterVerts = this.coords.Count; 779 int numOuterVerts = this.coords.Count;
780 int numHollowVerts = hollowCoords.Count; 780 int numHollowVerts = hollowCoords.Count;
781 int numTotalVerts = numOuterVerts + numHollowVerts; 781 int numTotalVerts = numOuterVerts + numHollowVerts;
782 782
783 if (numOuterVerts == numHollowVerts) 783 if (numOuterVerts == numHollowVerts)
784 { 784 {
785 Face newFace = new Face(); 785 Face newFace = new Face();
786 786
787 for (int coordIndex = 0; coordIndex < numOuterVerts - 1; coordIndex++) 787 for (int coordIndex = 0; coordIndex < numOuterVerts - 1; coordIndex++)
788 { 788 {
789 newFace.v1 = coordIndex; 789 newFace.v1 = coordIndex;
790 newFace.v2 = coordIndex + 1; 790 newFace.v2 = coordIndex + 1;
791 newFace.v3 = numTotalVerts - coordIndex - 1; 791 newFace.v3 = numTotalVerts - coordIndex - 1;
792 this.faces.Add(newFace); 792 this.faces.Add(newFace);
793 793
794 newFace.v1 = coordIndex + 1; 794 newFace.v1 = coordIndex + 1;
795 newFace.v2 = numTotalVerts - coordIndex - 2; 795 newFace.v2 = numTotalVerts - coordIndex - 2;
796 newFace.v3 = numTotalVerts - coordIndex - 1; 796 newFace.v3 = numTotalVerts - coordIndex - 1;
797 this.faces.Add(newFace); 797 this.faces.Add(newFace);
798 } 798 }
799 } 799 }
800 else 800 else
801 { 801 {
802 if (numOuterVerts < numHollowVerts) 802 if (numOuterVerts < numHollowVerts)
803 { 803 {
804 Face newFace = new Face(); 804 Face newFace = new Face();
805 int j = 0; // j is the index for outer vertices 805 int j = 0; // j is the index for outer vertices
806 int maxJ = numOuterVerts - 1; 806 int maxJ = numOuterVerts - 1;
807 for (int i = 0; i < numHollowVerts; i++) // i is the index for inner vertices 807 for (int i = 0; i < numHollowVerts; i++) // i is the index for inner vertices
808 { 808 {
809 if (j < maxJ) 809 if (j < maxJ)
810 if (angles.angles[j + 1].angle - hollowAngles.angles[i].angle <= hollowAngles.angles[i].angle - angles.angles[j].angle) 810 if (angles.angles[j + 1].angle - hollowAngles.angles[i].angle <= hollowAngles.angles[i].angle - angles.angles[j].angle)
811 { 811 {
812 newFace.v1 = numTotalVerts - i - 1; 812 newFace.v1 = numTotalVerts - i - 1;
813 newFace.v2 = j; 813 newFace.v2 = j;
814 newFace.v3 = j + 1; 814 newFace.v3 = j + 1;
815 815
816 this.faces.Add(newFace); 816 this.faces.Add(newFace);
817 j += 1; 817 j += 1;
818 } 818 }
819 819
820 newFace.v1 = j; 820 newFace.v1 = j;
821 newFace.v2 = numTotalVerts - i - 2; 821 newFace.v2 = numTotalVerts - i - 2;
822 newFace.v3 = numTotalVerts - i - 1; 822 newFace.v3 = numTotalVerts - i - 1;
823 823
824 this.faces.Add(newFace); 824 this.faces.Add(newFace);
825 } 825 }
826 } 826 }
827 else // numHollowVerts < numOuterVerts 827 else // numHollowVerts < numOuterVerts
828 { 828 {
829 Face newFace = new Face(); 829 Face newFace = new Face();
830 int j = 0; // j is the index for inner vertices 830 int j = 0; // j is the index for inner vertices
831 int maxJ = numHollowVerts - 1; 831 int maxJ = numHollowVerts - 1;
832 for (int i = 0; i < numOuterVerts; i++) 832 for (int i = 0; i < numOuterVerts; i++)
833 { 833 {
834 if (j < maxJ) 834 if (j < maxJ)
835 if (hollowAngles.angles[j + 1].angle - angles.angles[i].angle <= angles.angles[i].angle - hollowAngles.angles[j].angle) 835 if (hollowAngles.angles[j + 1].angle - angles.angles[i].angle <= angles.angles[i].angle - hollowAngles.angles[j].angle)
836 { 836 {
837 newFace.v1 = i; 837 newFace.v1 = i;
838 newFace.v2 = numTotalVerts - j - 2; 838 newFace.v2 = numTotalVerts - j - 2;
839 newFace.v3 = numTotalVerts - j - 1; 839 newFace.v3 = numTotalVerts - j - 1;
840 840
841 this.faces.Add(newFace); 841 this.faces.Add(newFace);
842 j += 1; 842 j += 1;
843 } 843 }
844 844
845 newFace.v1 = numTotalVerts - j - 1; 845 newFace.v1 = numTotalVerts - j - 1;
846 newFace.v2 = i; 846 newFace.v2 = i;
847 newFace.v3 = i + 1; 847 newFace.v3 = i + 1;
848 848
849 this.faces.Add(newFace); 849 this.faces.Add(newFace);
850 } 850 }
851 } 851 }
852 } 852 }
853 } 853 }
854 854
855 this.coords.AddRange(hollowCoords); 855 this.coords.AddRange(hollowCoords);
856 if (this.calcVertexNormals) 856 if (this.calcVertexNormals)
857 { 857 {
858 this.vertexNormals.AddRange(hollowNormals); 858 this.vertexNormals.AddRange(hollowNormals);
859 this.us.AddRange(hollowUs); 859 this.us.AddRange(hollowUs);
860 860
861 } 861 }
862 } 862 }
863 863
864 if (simpleFace && createFaces) 864 if (simpleFace && createFaces)
865 { 865 {
866 if (sides == 3) 866 if (sides == 3)
867 this.faces.Add(new Face(0, 1, 2)); 867 this.faces.Add(new Face(0, 1, 2));
868 else if (sides == 4) 868 else if (sides == 4)
869 { 869 {
870 this.faces.Add(new Face(0, 1, 2)); 870 this.faces.Add(new Face(0, 1, 2));
871 this.faces.Add(new Face(0, 2, 3)); 871 this.faces.Add(new Face(0, 2, 3));
872 } 872 }
873 } 873 }
874 874
875 if (calcVertexNormals && hasProfileCut) 875 if (calcVertexNormals && hasProfileCut)
876 { 876 {
877 if (hasHollow) 877 if (hasHollow)
878 { 878 {
879 int lastOuterVertIndex = this.numOuterVerts - 1; 879 int lastOuterVertIndex = this.numOuterVerts - 1;
880 880
881 this.cutNormal1.X = this.coords[0].Y - this.coords[this.coords.Count - 1].Y; 881 this.cutNormal1.X = this.coords[0].Y - this.coords[this.coords.Count - 1].Y;
882 this.cutNormal1.Y = -(this.coords[0].X - this.coords[this.coords.Count - 1].X); 882 this.cutNormal1.Y = -(this.coords[0].X - this.coords[this.coords.Count - 1].X);
883 883
884 this.cutNormal2.X = this.coords[lastOuterVertIndex + 1].Y - this.coords[lastOuterVertIndex].Y; 884 this.cutNormal2.X = this.coords[lastOuterVertIndex + 1].Y - this.coords[lastOuterVertIndex].Y;
885 this.cutNormal2.Y = -(this.coords[lastOuterVertIndex + 1].X - this.coords[lastOuterVertIndex].X); 885 this.cutNormal2.Y = -(this.coords[lastOuterVertIndex + 1].X - this.coords[lastOuterVertIndex].X);
886 } 886 }
887 887
888 else 888 else
889 { 889 {
890 this.cutNormal1.X = this.vertexNormals[1].Y; 890 this.cutNormal1.X = this.vertexNormals[1].Y;
891 this.cutNormal1.Y = -this.vertexNormals[1].X; 891 this.cutNormal1.Y = -this.vertexNormals[1].X;
892 892
893 this.cutNormal2.X = -this.vertexNormals[this.vertexNormals.Count - 2].Y; 893 this.cutNormal2.X = -this.vertexNormals[this.vertexNormals.Count - 2].Y;
894 this.cutNormal2.Y = this.vertexNormals[this.vertexNormals.Count - 2].X; 894 this.cutNormal2.Y = this.vertexNormals[this.vertexNormals.Count - 2].X;
895 895
896 } 896 }
897 this.cutNormal1.Normalize(); 897 this.cutNormal1.Normalize();
898 this.cutNormal2.Normalize(); 898 this.cutNormal2.Normalize();
899 } 899 }
900 900
901 this.MakeFaceUVs(); 901 this.MakeFaceUVs();
902 902
903 hollowCoords = null; 903 hollowCoords = null;
904 hollowNormals = null; 904 hollowNormals = null;
905 hollowUs = null; 905 hollowUs = null;
906 906
907 if (calcVertexNormals) 907 if (calcVertexNormals)
908 { // calculate prim face numbers 908 { // calculate prim face numbers
909 // I know it's ugly but so is the whole concept of prim face numbers 909 // I know it's ugly but so is the whole concept of prim face numbers
910 int faceNum = 1; 910 int faceNum = 1;
911 int startVert = hasProfileCut && !hasHollow ? 1 : 0; 911 int startVert = hasProfileCut && !hasHollow ? 1 : 0;
912 if (startVert > 0) 912 if (startVert > 0)
913 this.faceNumbers.Add(0); 913 this.faceNumbers.Add(0);
914 for (int i = 0; i < numOuterVerts; i++) 914 for (int i = 0; i < numOuterVerts; i++)
915 this.faceNumbers.Add(sides < 5 ? faceNum++ : faceNum); 915 this.faceNumbers.Add(sides < 5 ? faceNum++ : faceNum);
916 if (sides > 4) 916 if (sides > 4)
917 faceNum++; 917 faceNum++;
918 if (hasProfileCut) 918 if (hasProfileCut)
919 this.faceNumbers.Add(0); 919 this.faceNumbers.Add(0);
920 for (int i = 0; i < numHollowVerts; i++) 920 for (int i = 0; i < numHollowVerts; i++)
921 this.faceNumbers.Add(faceNum++); 921 this.faceNumbers.Add(faceNum++);
922 this.bottomFaceNumber = faceNum++; 922 this.bottomFaceNumber = faceNum++;
923 if (hasHollow && hasProfileCut) 923 if (hasHollow && hasProfileCut)
924 this.faceNumbers.Add(faceNum++); 924 this.faceNumbers.Add(faceNum++);
925 for (int i = 0; i < this.faceNumbers.Count; i++) 925 for (int i = 0; i < this.faceNumbers.Count; i++)
926 if (this.faceNumbers[i] == 0) 926 if (this.faceNumbers[i] == 0)
927 this.faceNumbers[i] = faceNum++; 927 this.faceNumbers[i] = faceNum++;
928 928
929 this.numPrimFaces = faceNum; 929 this.numPrimFaces = faceNum;
930 } 930 }
931 931
932 } 932 }
933 933
934 internal void MakeFaceUVs() 934 internal void MakeFaceUVs()
935 { 935 {
936 this.faceUVs = new List<UVCoord>(); 936 this.faceUVs = new List<UVCoord>();
937 foreach (Coord c in this.coords) 937 foreach (Coord c in this.coords)
938 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)));
939 } 939 }
940 940
941 internal Profile Clone() 941 internal Profile Clone()
942 { 942 {
943 return this.Clone(true); 943 return this.Clone(true);
944 } 944 }
945 945
946 internal Profile Clone(bool needFaces) 946 internal Profile Clone(bool needFaces)
947 { 947 {
948 Profile clone = new Profile(); 948 Profile clone = new Profile();
949 949
950 clone.coords.AddRange(this.coords); 950 clone.coords.AddRange(this.coords);
951 clone.faceUVs.AddRange(this.faceUVs); 951 clone.faceUVs.AddRange(this.faceUVs);
952 952
953 if (needFaces) 953 if (needFaces)
954 clone.faces.AddRange(this.faces); 954 clone.faces.AddRange(this.faces);
955 if ((clone.calcVertexNormals = this.calcVertexNormals) == true) 955 if ((clone.calcVertexNormals = this.calcVertexNormals) == true)
956 { 956 {
957 clone.vertexNormals.AddRange(this.vertexNormals); 957 clone.vertexNormals.AddRange(this.vertexNormals);
958 clone.faceNormal = this.faceNormal; 958 clone.faceNormal = this.faceNormal;
959 clone.cutNormal1 = this.cutNormal1; 959 clone.cutNormal1 = this.cutNormal1;
960 clone.cutNormal2 = this.cutNormal2; 960 clone.cutNormal2 = this.cutNormal2;
961 clone.us.AddRange(this.us); 961 clone.us.AddRange(this.us);
962 clone.faceNumbers.AddRange(this.faceNumbers); 962 clone.faceNumbers.AddRange(this.faceNumbers);
963 } 963 }
964 clone.numOuterVerts = this.numOuterVerts; 964 clone.numOuterVerts = this.numOuterVerts;
965 clone.numHollowVerts = this.numHollowVerts; 965 clone.numHollowVerts = this.numHollowVerts;
966 966
967 return clone; 967 return clone;
968 } 968 }
969 969
970 internal void AddPos(Coord v) 970 internal void AddPos(Coord v)
971 { 971 {
972 this.AddPos(v.X, v.Y, v.Z); 972 this.AddPos(v.X, v.Y, v.Z);
973 } 973 }
974 974
975 internal void AddPos(float x, float y, float z) 975 internal void AddPos(float x, float y, float z)
976 { 976 {
977 int i; 977 int i;
978 int numVerts = this.coords.Count; 978 int numVerts = this.coords.Count;
979 Coord vert; 979 Coord vert;
980 980
981 for (i = 0; i < numVerts; i++) 981 for (i = 0; i < numVerts; i++)
982 { 982 {
983 vert = this.coords[i]; 983 vert = this.coords[i];
984 vert.X += x; 984 vert.X += x;
985 vert.Y += y; 985 vert.Y += y;
986 vert.Z += z; 986 vert.Z += z;
987 this.coords[i] = vert; 987 this.coords[i] = vert;
988 } 988 }
989 } 989 }
990 990
991 internal void AddRot(Quat q) 991 internal void AddRot(Quat q)
992 { 992 {
993 int i; 993 int i;
994 int numVerts = this.coords.Count; 994 int numVerts = this.coords.Count;
995 995
996 for (i = 0; i < numVerts; i++) 996 for (i = 0; i < numVerts; i++)
997 this.coords[i] *= q; 997 this.coords[i] *= q;
998 998
999 if (this.calcVertexNormals) 999 if (this.calcVertexNormals)
1000 { 1000 {
1001 int numNormals = this.vertexNormals.Count; 1001 int numNormals = this.vertexNormals.Count;
1002 for (i = 0; i < numNormals; i++) 1002 for (i = 0; i < numNormals; i++)
1003 this.vertexNormals[i] *= q; 1003 this.vertexNormals[i] *= q;
1004 1004
1005 this.faceNormal *= q; 1005 this.faceNormal *= q;
1006 this.cutNormal1 *= q; 1006 this.cutNormal1 *= q;
1007 this.cutNormal2 *= q; 1007 this.cutNormal2 *= q;
1008 1008
1009 } 1009 }
1010 } 1010 }
1011 1011
1012 internal void Scale(float x, float y) 1012 internal void Scale(float x, float y)
1013 { 1013 {
1014 int i; 1014 int i;
1015 int numVerts = this.coords.Count; 1015 int numVerts = this.coords.Count;
1016 Coord vert; 1016 Coord vert;
1017 1017
1018 for (i = 0; i < numVerts; i++) 1018 for (i = 0; i < numVerts; i++)
1019 { 1019 {
1020 vert = this.coords[i]; 1020 vert = this.coords[i];
1021 vert.X *= x; 1021 vert.X *= x;
1022 vert.Y *= y; 1022 vert.Y *= y;
1023 this.coords[i] = vert; 1023 this.coords[i] = vert;
1024 } 1024 }
1025 } 1025 }
1026 1026
1027 /// <summary> 1027 /// <summary>
1028 /// 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
1029 /// </summary> 1029 /// </summary>
1030 internal void FlipNormals() 1030 internal void FlipNormals()
1031 { 1031 {
1032 int i; 1032 int i;
1033 int numFaces = this.faces.Count; 1033 int numFaces = this.faces.Count;
1034 Face tmpFace; 1034 Face tmpFace;
1035 int tmp; 1035 int tmp;
1036 1036
1037 for (i = 0; i < numFaces; i++) 1037 for (i = 0; i < numFaces; i++)
1038 { 1038 {
1039 tmpFace = this.faces[i]; 1039 tmpFace = this.faces[i];
1040 tmp = tmpFace.v3; 1040 tmp = tmpFace.v3;
1041 tmpFace.v3 = tmpFace.v1; 1041 tmpFace.v3 = tmpFace.v1;
1042 tmpFace.v1 = tmp; 1042 tmpFace.v1 = tmp;
1043 this.faces[i] = tmpFace; 1043 this.faces[i] = tmpFace;
1044 } 1044 }
1045 1045
1046 if (this.calcVertexNormals) 1046 if (this.calcVertexNormals)
1047 { 1047 {
1048 int normalCount = this.vertexNormals.Count; 1048 int normalCount = this.vertexNormals.Count;
1049 if (normalCount > 0) 1049 if (normalCount > 0)
1050 { 1050 {
1051 Coord n = this.vertexNormals[normalCount - 1]; 1051 Coord n = this.vertexNormals[normalCount - 1];
1052 n.Z = -n.Z; 1052 n.Z = -n.Z;
1053 this.vertexNormals[normalCount - 1] = n; 1053 this.vertexNormals[normalCount - 1] = n;
1054 } 1054 }
1055 } 1055 }
1056 1056
1057 this.faceNormal.X = -this.faceNormal.X; 1057 this.faceNormal.X = -this.faceNormal.X;
1058 this.faceNormal.Y = -this.faceNormal.Y; 1058 this.faceNormal.Y = -this.faceNormal.Y;
1059 this.faceNormal.Z = -this.faceNormal.Z; 1059 this.faceNormal.Z = -this.faceNormal.Z;
1060 1060
1061 int numfaceUVs = this.faceUVs.Count; 1061 int numfaceUVs = this.faceUVs.Count;
1062 for (i = 0; i < numfaceUVs; i++) 1062 for (i = 0; i < numfaceUVs; i++)
1063 { 1063 {
1064 UVCoord uv = this.faceUVs[i]; 1064 UVCoord uv = this.faceUVs[i];
1065 uv.V = 1.0f - uv.V; 1065 uv.V = 1.0f - uv.V;
1066 this.faceUVs[i] = uv; 1066 this.faceUVs[i] = uv;
1067 } 1067 }
1068 } 1068 }
1069 1069
1070 internal void AddValue2FaceVertexIndices(int num) 1070 internal void AddValue2FaceVertexIndices(int num)
1071 { 1071 {
1072 int numFaces = this.faces.Count; 1072 int numFaces = this.faces.Count;
1073 Face tmpFace; 1073 Face tmpFace;
1074 for (int i = 0; i < numFaces; i++) 1074 for (int i = 0; i < numFaces; i++)
1075 { 1075 {
1076 tmpFace = this.faces[i]; 1076 tmpFace = this.faces[i];
1077 tmpFace.v1 += num; 1077 tmpFace.v1 += num;
1078 tmpFace.v2 += num; 1078 tmpFace.v2 += num;
1079 tmpFace.v3 += num; 1079 tmpFace.v3 += num;
1080 1080
1081 this.faces[i] = tmpFace; 1081 this.faces[i] = tmpFace;
1082 } 1082 }
1083 } 1083 }
1084 1084
1085 internal void AddValue2FaceNormalIndices(int num) 1085 internal void AddValue2FaceNormalIndices(int num)
1086 { 1086 {
1087 if (this.calcVertexNormals) 1087 if (this.calcVertexNormals)
1088 { 1088 {
1089 int numFaces = this.faces.Count; 1089 int numFaces = this.faces.Count;
1090 Face tmpFace; 1090 Face tmpFace;
1091 for (int i = 0; i < numFaces; i++) 1091 for (int i = 0; i < numFaces; i++)
1092 { 1092 {
1093 tmpFace = this.faces[i]; 1093 tmpFace = this.faces[i];
1094 tmpFace.n1 += num; 1094 tmpFace.n1 += num;
1095 tmpFace.n2 += num; 1095 tmpFace.n2 += num;
1096 tmpFace.n3 += num; 1096 tmpFace.n3 += num;
1097 1097
1098 this.faces[i] = tmpFace; 1098 this.faces[i] = tmpFace;
1099 } 1099 }
1100 } 1100 }
1101 } 1101 }
1102 1102
1103 internal void DumpRaw(String path, String name, String title) 1103 internal void DumpRaw(String path, String name, String title)
1104 { 1104 {
1105 if (path == null) 1105 if (path == null)
1106 return; 1106 return;
1107 String fileName = name + "_" + title + ".raw"; 1107 String fileName = name + "_" + title + ".raw";
1108 String completePath = Path.Combine(path, fileName); 1108 String completePath = Path.Combine(path, fileName);
1109 StreamWriter sw = new StreamWriter(completePath); 1109 StreamWriter sw = new StreamWriter(completePath);
1110 1110
1111 for (int i = 0; i < this.faces.Count; i++) 1111 for (int i = 0; i < this.faces.Count; i++)
1112 { 1112 {
1113 string s = this.coords[this.faces[i].v1].ToString(); 1113 string s = this.coords[this.faces[i].v1].ToString();
1114 s += " " + this.coords[this.faces[i].v2].ToString(); 1114 s += " " + this.coords[this.faces[i].v2].ToString();
1115 s += " " + this.coords[this.faces[i].v3].ToString(); 1115 s += " " + this.coords[this.faces[i].v3].ToString();
1116 1116
1117 sw.WriteLine(s); 1117 sw.WriteLine(s);
1118 } 1118 }
1119 1119
1120 sw.Close(); 1120 sw.Close();
1121 } 1121 }
1122 } 1122 }
1123 1123
1124 public class PrimMesh 1124 public class PrimMesh
1125 { 1125 {
1126 private const float twoPi = 2.0f * (float)Math.PI; 1126 private const float twoPi = 2.0f * (float)Math.PI;
1127 1127
1128 public List<Coord> coords; 1128 public List<Coord> coords;
1129 public List<Coord> normals; 1129 public List<Coord> normals;
1130 public List<Face> faces; 1130 public List<Face> faces;
1131 1131
1132 public List<ViewerFace> viewerFaces; 1132 public List<ViewerFace> viewerFaces;
1133 1133
1134 private int sides = 4; 1134 private int sides = 4;
1135 private int hollowSides = 4; 1135 private int hollowSides = 4;
1136 private float profileStart = 0.0f; 1136 private float profileStart = 0.0f;
1137 private float profileEnd = 1.0f; 1137 private float profileEnd = 1.0f;
1138 private float hollow = 0.0f; 1138 private float hollow = 0.0f;
1139 public int twistBegin = 0; 1139 public int twistBegin = 0;
1140 public int twistEnd = 0; 1140 public int twistEnd = 0;
1141 public float topShearX = 0.0f; 1141 public float topShearX = 0.0f;
1142 public float topShearY = 0.0f; 1142 public float topShearY = 0.0f;
1143 public float pathCutBegin = 0.0f; 1143 public float pathCutBegin = 0.0f;
1144 public float pathCutEnd = 1.0f; 1144 public float pathCutEnd = 1.0f;
1145 public float dimpleBegin = 0.0f; 1145 public float dimpleBegin = 0.0f;
1146 public float dimpleEnd = 1.0f; 1146 public float dimpleEnd = 1.0f;
1147 public float skew = 0.0f; 1147 public float skew = 0.0f;
1148 public float holeSizeX = 1.0f; // called pathScaleX in pbs 1148 public float holeSizeX = 1.0f; // called pathScaleX in pbs
1149 public float holeSizeY = 0.25f; 1149 public float holeSizeY = 0.25f;
1150 public float taperX = 0.0f; 1150 public float taperX = 0.0f;
1151 public float taperY = 0.0f; 1151 public float taperY = 0.0f;
1152 public float radius = 0.0f; 1152 public float radius = 0.0f;
1153 public float revolutions = 1.0f; 1153 public float revolutions = 1.0f;
1154 public int stepsPerRevolution = 24; 1154 public int stepsPerRevolution = 24;
1155 1155
1156 private bool hasProfileCut = false; 1156 private bool hasProfileCut = false;
1157 private bool hasHollow = false; 1157 private bool hasHollow = false;
1158 public bool calcVertexNormals = false; 1158 public bool calcVertexNormals = false;
1159 private bool normalsProcessed = false; 1159 private bool normalsProcessed = false;
1160 public bool viewerMode = false; 1160 public bool viewerMode = false;
1161 1161
1162 public int numPrimFaces = 0; 1162 public int numPrimFaces = 0;
1163 1163
1164 /// <summary> 1164 /// <summary>
1165 /// Human readable string representation of the parameters used to create a mesh. 1165 /// Human readable string representation of the parameters used to create a mesh.
1166 /// </summary> 1166 /// </summary>
1167 /// <returns></returns> 1167 /// <returns></returns>
1168 public string ParamsToDisplayString() 1168 public string ParamsToDisplayString()
1169 { 1169 {
1170 string s = ""; 1170 string s = "";
1171 s += "sides..................: " + this.sides.ToString(); 1171 s += "sides..................: " + this.sides.ToString();
1172 s += "\nhollowSides..........: " + this.hollowSides.ToString(); 1172 s += "\nhollowSides..........: " + this.hollowSides.ToString();
1173 s += "\nprofileStart.........: " + this.profileStart.ToString(); 1173 s += "\nprofileStart.........: " + this.profileStart.ToString();
1174 s += "\nprofileEnd...........: " + this.profileEnd.ToString(); 1174 s += "\nprofileEnd...........: " + this.profileEnd.ToString();
1175 s += "\nhollow...............: " + this.hollow.ToString(); 1175 s += "\nhollow...............: " + this.hollow.ToString();
1176 s += "\ntwistBegin...........: " + this.twistBegin.ToString(); 1176 s += "\ntwistBegin...........: " + this.twistBegin.ToString();
1177 s += "\ntwistEnd.............: " + this.twistEnd.ToString(); 1177 s += "\ntwistEnd.............: " + this.twistEnd.ToString();
1178 s += "\ntopShearX............: " + this.topShearX.ToString(); 1178 s += "\ntopShearX............: " + this.topShearX.ToString();
1179 s += "\ntopShearY............: " + this.topShearY.ToString(); 1179 s += "\ntopShearY............: " + this.topShearY.ToString();
1180 s += "\npathCutBegin.........: " + this.pathCutBegin.ToString(); 1180 s += "\npathCutBegin.........: " + this.pathCutBegin.ToString();
1181 s += "\npathCutEnd...........: " + this.pathCutEnd.ToString(); 1181 s += "\npathCutEnd...........: " + this.pathCutEnd.ToString();
1182 s += "\ndimpleBegin..........: " + this.dimpleBegin.ToString(); 1182 s += "\ndimpleBegin..........: " + this.dimpleBegin.ToString();
1183 s += "\ndimpleEnd............: " + this.dimpleEnd.ToString(); 1183 s += "\ndimpleEnd............: " + this.dimpleEnd.ToString();
1184 s += "\nskew.................: " + this.skew.ToString(); 1184 s += "\nskew.................: " + this.skew.ToString();
1185 s += "\nholeSizeX............: " + this.holeSizeX.ToString(); 1185 s += "\nholeSizeX............: " + this.holeSizeX.ToString();
1186 s += "\nholeSizeY............: " + this.holeSizeY.ToString(); 1186 s += "\nholeSizeY............: " + this.holeSizeY.ToString();
1187 s += "\ntaperX...............: " + this.taperX.ToString(); 1187 s += "\ntaperX...............: " + this.taperX.ToString();
1188 s += "\ntaperY...............: " + this.taperY.ToString(); 1188 s += "\ntaperY...............: " + this.taperY.ToString();
1189 s += "\nradius...............: " + this.radius.ToString(); 1189 s += "\nradius...............: " + this.radius.ToString();
1190 s += "\nrevolutions..........: " + this.revolutions.ToString(); 1190 s += "\nrevolutions..........: " + this.revolutions.ToString();
1191 s += "\nstepsPerRevolution...: " + this.stepsPerRevolution.ToString(); 1191 s += "\nstepsPerRevolution...: " + this.stepsPerRevolution.ToString();
1192 1192
1193 return s; 1193 return s;
1194 } 1194 }
1195 1195
1196 /// <summary> 1196 /// <summary>
1197 /// Constructs a PrimMesh object and creates the profile for extrusion. 1197 /// Constructs a PrimMesh object and creates the profile for extrusion.
1198 /// </summary> 1198 /// </summary>
1199 /// <param name="sides"></param> 1199 /// <param name="sides"></param>
1200 /// <param name="profileStart"></param> 1200 /// <param name="profileStart"></param>
1201 /// <param name="profileEnd"></param> 1201 /// <param name="profileEnd"></param>
1202 /// <param name="hollow"></param> 1202 /// <param name="hollow"></param>
1203 /// <param name="hollowSides"></param> 1203 /// <param name="hollowSides"></param>
1204 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)
1205 { 1205 {
1206 this.coords = new List<Coord>(); 1206 this.coords = new List<Coord>();
1207 this.faces = new List<Face>(); 1207 this.faces = new List<Face>();
1208 1208
1209 this.sides = sides; 1209 this.sides = sides;
1210 this.profileStart = profileStart; 1210 this.profileStart = profileStart;
1211 this.profileEnd = profileEnd; 1211 this.profileEnd = profileEnd;
1212 this.hollow = hollow; 1212 this.hollow = hollow;
1213 this.hollowSides = hollowSides; 1213 this.hollowSides = hollowSides;
1214 1214
1215 if (sides < 3) 1215 if (sides < 3)
1216 this.sides = 3; 1216 this.sides = 3;
1217 if (hollowSides < 3) 1217 if (hollowSides < 3)
1218 this.hollowSides = 3; 1218 this.hollowSides = 3;
1219 if (profileStart < 0.0f) 1219 if (profileStart < 0.0f)
1220 this.profileStart = 0.0f; 1220 this.profileStart = 0.0f;
1221 if (profileEnd > 1.0f) 1221 if (profileEnd > 1.0f)
1222 this.profileEnd = 1.0f; 1222 this.profileEnd = 1.0f;
1223 if (profileEnd < 0.02f) 1223 if (profileEnd < 0.02f)
1224 this.profileEnd = 0.02f; 1224 this.profileEnd = 0.02f;
1225 if (profileStart >= profileEnd) 1225 if (profileStart >= profileEnd)
1226 this.profileStart = profileEnd - 0.02f; 1226 this.profileStart = profileEnd - 0.02f;
1227 if (hollow > 1.0f) 1227 if (hollow > 1.0f)
1228 this.hollow = 1.0f; 1228 this.hollow = 1.0f;
1229 if (hollow < 0.0f) 1229 if (hollow < 0.0f)
1230 this.hollow = 0.0f; 1230 this.hollow = 0.0f;
1231 1231
1232 this.hasProfileCut = (this.profileStart > 0.0f || this.profileEnd < 1.0f); 1232 this.hasProfileCut = (this.profileStart > 0.0f || this.profileEnd < 1.0f);
1233 this.hasHollow = (this.hollow > 0.001f); 1233 this.hasHollow = (this.hollow > 0.001f);
1234 } 1234 }
1235 1235
1236 /// <summary> 1236 /// <summary>
1237 /// Extrudes a profile along a straight line path. Used for prim types box, cylinder, and prism. 1237 /// Extrudes a profile along a straight line path. Used for prim types box, cylinder, and prism.
1238 /// </summary> 1238 /// </summary>
1239 public void ExtrudeLinear() 1239 public void ExtrudeLinear()
1240 { 1240 {
1241 this.coords = new List<Coord>(); 1241 this.coords = new List<Coord>();
1242 this.faces = new List<Face>(); 1242 this.faces = new List<Face>();
1243 1243
1244 if (this.viewerMode) 1244 if (this.viewerMode)
1245 { 1245 {
1246 this.viewerFaces = new List<ViewerFace>(); 1246 this.viewerFaces = new List<ViewerFace>();
1247 this.calcVertexNormals = true; 1247 this.calcVertexNormals = true;
1248 } 1248 }
1249 1249
1250 if (this.calcVertexNormals) 1250 if (this.calcVertexNormals)
1251 this.normals = new List<Coord>(); 1251 this.normals = new List<Coord>();
1252 1252
1253 int step = 0; 1253 int step = 0;
1254 int steps = 1; 1254 int steps = 1;
1255 1255
1256 float length = this.pathCutEnd - this.pathCutBegin; 1256 float length = this.pathCutEnd - this.pathCutBegin;
1257 normalsProcessed = false; 1257 normalsProcessed = false;
1258 1258
1259 if (this.viewerMode && this.sides == 3) 1259 if (this.viewerMode && this.sides == 3)
1260 { 1260 {
1261 // prisms don't taper well so add some vertical resolution 1261 // prisms don't taper well so add some vertical resolution
1262 // other prims may benefit from this but just do prisms for now 1262 // other prims may benefit from this but just do prisms for now
1263 if (Math.Abs(this.taperX) > 0.01 || Math.Abs(this.taperY) > 0.01) 1263 if (Math.Abs(this.taperX) > 0.01 || Math.Abs(this.taperY) > 0.01)
1264 steps = (int)(steps * 4.5 * length); 1264 steps = (int)(steps * 4.5 * length);
1265 } 1265 }
1266 1266
1267 1267
1268 float twistBegin = this.twistBegin / 360.0f * twoPi; 1268 float twistBegin = this.twistBegin / 360.0f * twoPi;
1269 float twistEnd = this.twistEnd / 360.0f * twoPi; 1269 float twistEnd = this.twistEnd / 360.0f * twoPi;
1270 float twistTotal = twistEnd - twistBegin; 1270 float twistTotal = twistEnd - twistBegin;
1271 float twistTotalAbs = Math.Abs(twistTotal); 1271 float twistTotalAbs = Math.Abs(twistTotal);
1272 if (twistTotalAbs > 0.01f) 1272 if (twistTotalAbs > 0.01f)
1273 steps += (int)(twistTotalAbs * 3.66); // dahlia's magic number 1273 steps += (int)(twistTotalAbs * 3.66); // dahlia's magic number
1274 1274
1275 float start = -0.5f; 1275 float start = -0.5f;
1276 float stepSize = length / (float)steps; 1276 float stepSize = length / (float)steps;
1277 float percentOfPathMultiplier = stepSize; 1277 float percentOfPathMultiplier = stepSize;
1278 float xProfileScale = 1.0f; 1278 float xProfileScale = 1.0f;
1279 float yProfileScale = 1.0f; 1279 float yProfileScale = 1.0f;
1280 float xOffset = 0.0f; 1280 float xOffset = 0.0f;
1281 float yOffset = 0.0f; 1281 float yOffset = 0.0f;
1282 float zOffset = start; 1282 float zOffset = start;
1283 float xOffsetStepIncrement = this.topShearX / steps; 1283 float xOffsetStepIncrement = this.topShearX / steps;
1284 float yOffsetStepIncrement = this.topShearY / steps; 1284 float yOffsetStepIncrement = this.topShearY / steps;
1285 1285
1286 float percentOfPath = this.pathCutBegin; 1286 float percentOfPath = this.pathCutBegin;
1287 zOffset += percentOfPath; 1287 zOffset += percentOfPath;
1288 1288
1289 float hollow = this.hollow; 1289 float hollow = this.hollow;
1290 1290
1291 // sanity checks 1291 // sanity checks
1292 float initialProfileRot = 0.0f; 1292 float initialProfileRot = 0.0f;
1293 if (this.sides == 3) 1293 if (this.sides == 3)
1294 { 1294 {
1295 if (this.hollowSides == 4) 1295 if (this.hollowSides == 4)
1296 { 1296 {
1297 if (hollow > 0.7f) 1297 if (hollow > 0.7f)
1298 hollow = 0.7f; 1298 hollow = 0.7f;
1299 hollow *= 0.707f; 1299 hollow *= 0.707f;
1300 } 1300 }
1301 else hollow *= 0.5f; 1301 else hollow *= 0.5f;
1302 } 1302 }
1303 else if (this.sides == 4) 1303 else if (this.sides == 4)
1304 { 1304 {
1305 initialProfileRot = 1.25f * (float)Math.PI; 1305 initialProfileRot = 1.25f * (float)Math.PI;
1306 if (this.hollowSides != 4) 1306 if (this.hollowSides != 4)
1307 hollow *= 0.707f; 1307 hollow *= 0.707f;
1308 } 1308 }
1309 else if (this.sides == 24 && this.hollowSides == 4) 1309 else if (this.sides == 24 && this.hollowSides == 4)
1310 hollow *= 1.414f; 1310 hollow *= 1.414f;
1311 1311
1312 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; 1313 this.numPrimFaces = profile.numPrimFaces;
1314 1314
1315 int cut1Vert = -1; 1315 int cut1Vert = -1;
1316 int cut2Vert = -1; 1316 int cut2Vert = -1;
1317 if (hasProfileCut) 1317 if (hasProfileCut)
1318 { 1318 {
1319 cut1Vert = hasHollow ? profile.coords.Count - 1 : 0; 1319 cut1Vert = hasHollow ? profile.coords.Count - 1 : 0;
1320 cut2Vert = hasHollow ? profile.numOuterVerts - 1 : profile.numOuterVerts; 1320 cut2Vert = hasHollow ? profile.numOuterVerts - 1 : profile.numOuterVerts;
1321 } 1321 }
1322 1322
1323 if (initialProfileRot != 0.0f) 1323 if (initialProfileRot != 0.0f)
1324 { 1324 {
1325 profile.AddRot(new Quat(new Coord(0.0f, 0.0f, 1.0f), initialProfileRot)); 1325 profile.AddRot(new Quat(new Coord(0.0f, 0.0f, 1.0f), initialProfileRot));
1326 if (viewerMode) 1326 if (viewerMode)
1327 profile.MakeFaceUVs(); 1327 profile.MakeFaceUVs();
1328 } 1328 }
1329 1329
1330 1330
1331 Coord lastCutNormal1 = new Coord(); 1331 Coord lastCutNormal1 = new Coord();
1332 Coord lastCutNormal2 = new Coord(); 1332 Coord lastCutNormal2 = new Coord();
1333 float lastV = 1.0f; 1333 float lastV = 1.0f;
1334 1334
1335 bool done = false; 1335 bool done = false;
1336 while (!done) 1336 while (!done)
1337 { 1337 {
1338 Profile newLayer = profile.Clone(); 1338 Profile newLayer = profile.Clone();
1339 1339
1340 if (this.taperX == 0.0f) 1340 if (this.taperX == 0.0f)
1341 xProfileScale = 1.0f; 1341 xProfileScale = 1.0f;
1342 else if (this.taperX > 0.0f) 1342 else if (this.taperX > 0.0f)
1343 xProfileScale = 1.0f - percentOfPath * this.taperX; 1343 xProfileScale = 1.0f - percentOfPath * this.taperX;
1344 else xProfileScale = 1.0f + (1.0f - percentOfPath) * this.taperX; 1344 else xProfileScale = 1.0f + (1.0f - percentOfPath) * this.taperX;
1345 1345
1346 if (this.taperY == 0.0f) 1346 if (this.taperY == 0.0f)
1347 yProfileScale = 1.0f; 1347 yProfileScale = 1.0f;
1348 else if (this.taperY > 0.0f) 1348 else if (this.taperY > 0.0f)
1349 yProfileScale = 1.0f - percentOfPath * this.taperY; 1349 yProfileScale = 1.0f - percentOfPath * this.taperY;
1350 else yProfileScale = 1.0f + (1.0f - percentOfPath) * this.taperY; 1350 else yProfileScale = 1.0f + (1.0f - percentOfPath) * this.taperY;
1351 1351
1352 if (xProfileScale != 1.0f || yProfileScale != 1.0f) 1352 if (xProfileScale != 1.0f || yProfileScale != 1.0f)
1353 newLayer.Scale(xProfileScale, yProfileScale); 1353 newLayer.Scale(xProfileScale, yProfileScale);
1354 1354
1355 float twist = twistBegin + twistTotal * percentOfPath; 1355 float twist = twistBegin + twistTotal * percentOfPath;
1356 if (twist != 0.0f) 1356 if (twist != 0.0f)
1357 newLayer.AddRot(new Quat(new Coord(0.0f, 0.0f, 1.0f), twist)); 1357 newLayer.AddRot(new Quat(new Coord(0.0f, 0.0f, 1.0f), twist));
1358 1358
1359 newLayer.AddPos(xOffset, yOffset, zOffset); 1359 newLayer.AddPos(xOffset, yOffset, zOffset);
1360 1360
1361 if (step == 0) 1361 if (step == 0)
1362 { 1362 {
1363 newLayer.FlipNormals(); 1363 newLayer.FlipNormals();
1364 1364
1365 // add the top faces to the viewerFaces list here 1365 // add the top faces to the viewerFaces list here
1366 if (this.viewerMode) 1366 if (this.viewerMode)
1367 { 1367 {
1368 Coord faceNormal = newLayer.faceNormal; 1368 Coord faceNormal = newLayer.faceNormal;
1369 ViewerFace newViewerFace = new ViewerFace(0); 1369 ViewerFace newViewerFace = new ViewerFace(0);
1370 foreach (Face face in newLayer.faces) 1370 foreach (Face face in newLayer.faces)
1371 { 1371 {
1372 newViewerFace.v1 = newLayer.coords[face.v1]; 1372 newViewerFace.v1 = newLayer.coords[face.v1];
1373 newViewerFace.v2 = newLayer.coords[face.v2]; 1373 newViewerFace.v2 = newLayer.coords[face.v2];
1374 newViewerFace.v3 = newLayer.coords[face.v3]; 1374 newViewerFace.v3 = newLayer.coords[face.v3];
1375 1375
1376 newViewerFace.n1 = faceNormal; 1376 newViewerFace.n1 = faceNormal;
1377 newViewerFace.n2 = faceNormal; 1377 newViewerFace.n2 = faceNormal;
1378 newViewerFace.n3 = faceNormal; 1378 newViewerFace.n3 = faceNormal;
1379 1379
1380 newViewerFace.uv1 = newLayer.faceUVs[face.v1]; 1380 newViewerFace.uv1 = newLayer.faceUVs[face.v1];
1381 newViewerFace.uv2 = newLayer.faceUVs[face.v2]; 1381 newViewerFace.uv2 = newLayer.faceUVs[face.v2];
1382 newViewerFace.uv3 = newLayer.faceUVs[face.v3]; 1382 newViewerFace.uv3 = newLayer.faceUVs[face.v3];
1383 1383
1384 this.viewerFaces.Add(newViewerFace); 1384 this.viewerFaces.Add(newViewerFace);
1385 } 1385 }
1386 } 1386 }
1387 } 1387 }
1388 1388
1389 // append this layer 1389 // append this layer
1390 1390
1391 int coordsLen = this.coords.Count; 1391 int coordsLen = this.coords.Count;
1392 newLayer.AddValue2FaceVertexIndices(coordsLen); 1392 newLayer.AddValue2FaceVertexIndices(coordsLen);
1393 1393
1394 this.coords.AddRange(newLayer.coords); 1394 this.coords.AddRange(newLayer.coords);
1395 1395
1396 if (this.calcVertexNormals) 1396 if (this.calcVertexNormals)
1397 { 1397 {
1398 newLayer.AddValue2FaceNormalIndices(this.normals.Count); 1398 newLayer.AddValue2FaceNormalIndices(this.normals.Count);
1399 this.normals.AddRange(newLayer.vertexNormals); 1399 this.normals.AddRange(newLayer.vertexNormals);
1400 } 1400 }
1401 1401
1402 if (percentOfPath < this.pathCutBegin + 0.01f || percentOfPath > this.pathCutEnd - 0.01f) 1402 if (percentOfPath < this.pathCutBegin + 0.01f || percentOfPath > this.pathCutEnd - 0.01f)
1403 this.faces.AddRange(newLayer.faces); 1403 this.faces.AddRange(newLayer.faces);
1404 1404
1405 // fill faces between layers 1405 // fill faces between layers
1406 1406
1407 int numVerts = newLayer.coords.Count; 1407 int numVerts = newLayer.coords.Count;
1408 Face newFace = new Face(); 1408 Face newFace = new Face();
1409 1409
1410 if (step > 0) 1410 if (step > 0)
1411 { 1411 {
1412 int startVert = coordsLen + 1; 1412 int startVert = coordsLen + 1;
1413 int endVert = this.coords.Count; 1413 int endVert = this.coords.Count;
1414 1414
1415 if (sides < 5 || this.hasProfileCut || hollow > 0.0f) 1415 if (sides < 5 || this.hasProfileCut || hollow > 0.0f)
1416 startVert--; 1416 startVert--;
1417 1417
1418 for (int i = startVert; i < endVert; i++) 1418 for (int i = startVert; i < endVert; i++)
1419 { 1419 {
1420 int iNext = i + 1; 1420 int iNext = i + 1;
1421 if (i == endVert - 1) 1421 if (i == endVert - 1)
1422 iNext = startVert; 1422 iNext = startVert;
1423 1423
1424 int whichVert = i - startVert; 1424 int whichVert = i - startVert;
1425 1425
1426 newFace.v1 = i; 1426 newFace.v1 = i;
1427 newFace.v2 = i - numVerts; 1427 newFace.v2 = i - numVerts;
1428 newFace.v3 = iNext - numVerts; 1428 newFace.v3 = iNext - numVerts;
1429 this.faces.Add(newFace); 1429 this.faces.Add(newFace);
1430 1430
1431 newFace.v2 = iNext - numVerts; 1431 newFace.v2 = iNext - numVerts;
1432 newFace.v3 = iNext; 1432 newFace.v3 = iNext;
1433 this.faces.Add(newFace); 1433 this.faces.Add(newFace);
1434 1434
1435 if (this.viewerMode) 1435 if (this.viewerMode)
1436 { 1436 {
1437 // add the side faces to the list of viewerFaces here 1437 // add the side faces to the list of viewerFaces here
1438 int primFaceNum = 1; 1438 int primFaceNum = 1;
1439 if (whichVert >= sides) 1439 if (whichVert >= sides)
1440 primFaceNum = 2; 1440 primFaceNum = 2;
1441 ViewerFace newViewerFace1 = new ViewerFace(primFaceNum); 1441 ViewerFace newViewerFace1 = new ViewerFace(primFaceNum);
1442 ViewerFace newViewerFace2 = new ViewerFace(primFaceNum); 1442 ViewerFace newViewerFace2 = new ViewerFace(primFaceNum);
1443 1443
1444 float u1 = newLayer.us[whichVert]; 1444 float u1 = newLayer.us[whichVert];
1445 float u2 = 1.0f; 1445 float u2 = 1.0f;
1446 if (whichVert < newLayer.us.Count - 1) 1446 if (whichVert < newLayer.us.Count - 1)
1447 u2 = newLayer.us[whichVert + 1]; 1447 u2 = newLayer.us[whichVert + 1];
1448 1448
1449 if (whichVert == cut1Vert || whichVert == cut2Vert) 1449 if (whichVert == cut1Vert || whichVert == cut2Vert)
1450 { 1450 {
1451 u1 = 0.0f; 1451 u1 = 0.0f;
1452 u2 = 1.0f; 1452 u2 = 1.0f;
1453 } 1453 }
1454 else if (sides < 5) 1454 else if (sides < 5)
1455 { // boxes and prisms have one texture face per side of the prim, so the U values have to be scaled 1455 { // boxes and prisms have one texture face per side of the prim, so the U values have to be scaled
1456 // to reflect the entire texture width 1456 // to reflect the entire texture width
1457 u1 *= sides; 1457 u1 *= sides;
1458 u2 *= sides; 1458 u2 *= sides;
1459 u2 -= (int)u1; 1459 u2 -= (int)u1;
1460 u1 -= (int)u1; 1460 u1 -= (int)u1;
1461 if (u2 < 0.1f) 1461 if (u2 < 0.1f)
1462 u2 = 1.0f; 1462 u2 = 1.0f;
1463 1463
1464 //newViewerFace2.primFaceNumber = newViewerFace1.primFaceNumber = whichVert + 1; 1464 //newViewerFace2.primFaceNumber = newViewerFace1.primFaceNumber = whichVert + 1;
1465 } 1465 }
1466 1466
1467 newViewerFace1.uv1.U = u1; 1467 newViewerFace1.uv1.U = u1;
1468 newViewerFace1.uv2.U = u1; 1468 newViewerFace1.uv2.U = u1;
1469 newViewerFace1.uv3.U = u2; 1469 newViewerFace1.uv3.U = u2;
1470 1470
1471 newViewerFace1.uv1.V = 1.0f - percentOfPath; 1471 newViewerFace1.uv1.V = 1.0f - percentOfPath;
1472 newViewerFace1.uv2.V = lastV; 1472 newViewerFace1.uv2.V = lastV;
1473 newViewerFace1.uv3.V = lastV; 1473 newViewerFace1.uv3.V = lastV;
1474 1474
1475 newViewerFace2.uv1.U = u1; 1475 newViewerFace2.uv1.U = u1;
1476 newViewerFace2.uv2.U = u2; 1476 newViewerFace2.uv2.U = u2;
1477 newViewerFace2.uv3.U = u2; 1477 newViewerFace2.uv3.U = u2;
1478 1478
1479 newViewerFace2.uv1.V = 1.0f - percentOfPath; 1479 newViewerFace2.uv1.V = 1.0f - percentOfPath;
1480 newViewerFace2.uv2.V = lastV; 1480 newViewerFace2.uv2.V = lastV;
1481 newViewerFace2.uv3.V = 1.0f - percentOfPath; 1481 newViewerFace2.uv3.V = 1.0f - percentOfPath;
1482 1482
1483 newViewerFace1.v1 = this.coords[i]; 1483 newViewerFace1.v1 = this.coords[i];
1484 newViewerFace1.v2 = this.coords[i - numVerts]; 1484 newViewerFace1.v2 = this.coords[i - numVerts];
1485 newViewerFace1.v3 = this.coords[iNext - numVerts]; 1485 newViewerFace1.v3 = this.coords[iNext - numVerts];
1486 1486
1487 newViewerFace2.v1 = this.coords[i]; 1487 newViewerFace2.v1 = this.coords[i];
1488 newViewerFace2.v2 = this.coords[iNext - numVerts]; 1488 newViewerFace2.v2 = this.coords[iNext - numVerts];
1489 newViewerFace2.v3 = this.coords[iNext]; 1489 newViewerFace2.v3 = this.coords[iNext];
1490 1490
1491 // profile cut faces 1491 // profile cut faces
1492 if (whichVert == cut1Vert) 1492 if (whichVert == cut1Vert)
1493 { 1493 {
1494 newViewerFace1.n1 = newLayer.cutNormal1; 1494 newViewerFace1.n1 = newLayer.cutNormal1;
1495 newViewerFace1.n2 = newViewerFace1.n3 = lastCutNormal1; 1495 newViewerFace1.n2 = newViewerFace1.n3 = lastCutNormal1;
1496 1496
1497 newViewerFace2.n1 = newViewerFace2.n3 = newLayer.cutNormal1; 1497 newViewerFace2.n1 = newViewerFace2.n3 = newLayer.cutNormal1;
1498 newViewerFace2.n2 = lastCutNormal1; 1498 newViewerFace2.n2 = lastCutNormal1;
1499 } 1499 }
1500 else if (whichVert == cut2Vert) 1500 else if (whichVert == cut2Vert)
1501 { 1501 {
1502 newViewerFace1.n1 = newLayer.cutNormal2; 1502 newViewerFace1.n1 = newLayer.cutNormal2;
1503 newViewerFace1.n2 = newViewerFace1.n3 = lastCutNormal2; 1503 newViewerFace1.n2 = newViewerFace1.n3 = lastCutNormal2;
1504 1504
1505 newViewerFace2.n1 = newViewerFace2.n3 = newLayer.cutNormal2; 1505 newViewerFace2.n1 = newViewerFace2.n3 = newLayer.cutNormal2;
1506 newViewerFace2.n2 = lastCutNormal2; 1506 newViewerFace2.n2 = lastCutNormal2;
1507 } 1507 }
1508 1508
1509 else // outer and hollow faces 1509 else // outer and hollow faces
1510 { 1510 {
1511 if ((sides < 5 && whichVert < newLayer.numOuterVerts) || (hollowSides < 5 && whichVert >= newLayer.numOuterVerts)) 1511 if ((sides < 5 && whichVert < newLayer.numOuterVerts) || (hollowSides < 5 && whichVert >= newLayer.numOuterVerts))
1512 { 1512 {
1513 newViewerFace1.CalcSurfaceNormal(); 1513 newViewerFace1.CalcSurfaceNormal();
1514 newViewerFace2.CalcSurfaceNormal(); 1514 newViewerFace2.CalcSurfaceNormal();
1515 } 1515 }
1516 else 1516 else
1517 { 1517 {
1518 newViewerFace1.n1 = this.normals[i]; 1518 newViewerFace1.n1 = this.normals[i];
1519 newViewerFace1.n2 = this.normals[i - numVerts]; 1519 newViewerFace1.n2 = this.normals[i - numVerts];
1520 newViewerFace1.n3 = this.normals[iNext - numVerts]; 1520 newViewerFace1.n3 = this.normals[iNext - numVerts];
1521 1521
1522 newViewerFace2.n1 = this.normals[i]; 1522 newViewerFace2.n1 = this.normals[i];
1523 newViewerFace2.n2 = this.normals[iNext - numVerts]; 1523 newViewerFace2.n2 = this.normals[iNext - numVerts];
1524 newViewerFace2.n3 = this.normals[iNext]; 1524 newViewerFace2.n3 = this.normals[iNext];
1525 } 1525 }
1526 } 1526 }
1527 1527
1528 newViewerFace2.primFaceNumber = newViewerFace1.primFaceNumber = newLayer.faceNumbers[whichVert]; 1528 newViewerFace2.primFaceNumber = newViewerFace1.primFaceNumber = newLayer.faceNumbers[whichVert];
1529 1529
1530 this.viewerFaces.Add(newViewerFace1); 1530 this.viewerFaces.Add(newViewerFace1);
1531 this.viewerFaces.Add(newViewerFace2); 1531 this.viewerFaces.Add(newViewerFace2);
1532 1532
1533 } 1533 }
1534 } 1534 }
1535 } 1535 }
1536 1536
1537 lastCutNormal1 = newLayer.cutNormal1; 1537 lastCutNormal1 = newLayer.cutNormal1;
1538 lastCutNormal2 = newLayer.cutNormal2; 1538 lastCutNormal2 = newLayer.cutNormal2;
1539 lastV = 1.0f - percentOfPath; 1539 lastV = 1.0f - percentOfPath;
1540 1540
1541 // calc the step for the next iteration of the loop 1541 // calc the step for the next iteration of the loop
1542 1542
1543 if (step < steps) 1543 if (step < steps)
1544 { 1544 {
1545 step += 1; 1545 step += 1;
1546 percentOfPath += percentOfPathMultiplier; 1546 percentOfPath += percentOfPathMultiplier;
1547 xOffset += xOffsetStepIncrement; 1547 xOffset += xOffsetStepIncrement;
1548 yOffset += yOffsetStepIncrement; 1548 yOffset += yOffsetStepIncrement;
1549 zOffset += stepSize; 1549 zOffset += stepSize;
1550 if (percentOfPath > this.pathCutEnd) 1550 if (percentOfPath > this.pathCutEnd)
1551 done = true; 1551 done = true;
1552 } 1552 }
1553 else done = true; 1553 else done = true;
1554 1554
1555 if (done && viewerMode) 1555 if (done && viewerMode)
1556 { 1556 {
1557 // add the top faces to the viewerFaces list here 1557 // add the top faces to the viewerFaces list here
1558 Coord faceNormal = newLayer.faceNormal; 1558 Coord faceNormal = newLayer.faceNormal;
1559 ViewerFace newViewerFace = new ViewerFace(); 1559 ViewerFace newViewerFace = new ViewerFace();
1560 newViewerFace.primFaceNumber = newLayer.bottomFaceNumber; 1560 newViewerFace.primFaceNumber = newLayer.bottomFaceNumber;
1561 foreach (Face face in newLayer.faces) 1561 foreach (Face face in newLayer.faces)
1562 { 1562 {
1563 newViewerFace.v1 = newLayer.coords[face.v1 - coordsLen]; 1563 newViewerFace.v1 = newLayer.coords[face.v1 - coordsLen];
1564 newViewerFace.v2 = newLayer.coords[face.v2 - coordsLen]; 1564 newViewerFace.v2 = newLayer.coords[face.v2 - coordsLen];
1565 newViewerFace.v3 = newLayer.coords[face.v3 - coordsLen]; 1565 newViewerFace.v3 = newLayer.coords[face.v3 - coordsLen];
1566 1566
1567 newViewerFace.n1 = faceNormal; 1567 newViewerFace.n1 = faceNormal;
1568 newViewerFace.n2 = faceNormal; 1568 newViewerFace.n2 = faceNormal;
1569 newViewerFace.n3 = faceNormal; 1569 newViewerFace.n3 = faceNormal;
1570 1570
1571 newViewerFace.uv1 = newLayer.faceUVs[face.v1 - coordsLen]; 1571 newViewerFace.uv1 = newLayer.faceUVs[face.v1 - coordsLen];
1572 newViewerFace.uv2 = newLayer.faceUVs[face.v2 - coordsLen]; 1572 newViewerFace.uv2 = newLayer.faceUVs[face.v2 - coordsLen];
1573 newViewerFace.uv3 = newLayer.faceUVs[face.v3 - coordsLen]; 1573 newViewerFace.uv3 = newLayer.faceUVs[face.v3 - coordsLen];
1574 1574
1575 this.viewerFaces.Add(newViewerFace); 1575 this.viewerFaces.Add(newViewerFace);
1576 } 1576 }
1577 } 1577 }
1578 } 1578 }
1579 } 1579 }
1580 1580
1581 /// <summary> 1581 /// <summary>
1582 /// Extrude a profile into a circular path prim mesh. Used for prim types torus, tube, and ring. 1582 /// Extrude a profile into a circular path prim mesh. Used for prim types torus, tube, and ring.
1583 /// </summary> 1583 /// </summary>
1584 public void ExtrudeCircular() 1584 public void ExtrudeCircular()
1585 { 1585 {
1586 this.coords = new List<Coord>(); 1586 this.coords = new List<Coord>();
1587 this.faces = new List<Face>(); 1587 this.faces = new List<Face>();
1588 1588
1589 if (this.viewerMode) 1589 if (this.viewerMode)
1590 { 1590 {
1591 this.viewerFaces = new List<ViewerFace>(); 1591 this.viewerFaces = new List<ViewerFace>();
1592 this.calcVertexNormals = true; 1592 this.calcVertexNormals = true;
1593 } 1593 }
1594 1594
1595 if (this.calcVertexNormals) 1595 if (this.calcVertexNormals)
1596 this.normals = new List<Coord>(); 1596 this.normals = new List<Coord>();
1597 1597
1598 int step = 0; 1598 int step = 0;
1599 int steps = 24; 1599 int steps = 24;
1600 1600
1601 normalsProcessed = false; 1601 normalsProcessed = false;
1602 1602
1603 float twistBegin = this.twistBegin / 360.0f * twoPi; 1603 float twistBegin = this.twistBegin / 360.0f * twoPi;
1604 float twistEnd = this.twistEnd / 360.0f * twoPi; 1604 float twistEnd = this.twistEnd / 360.0f * twoPi;
1605 float twistTotal = twistEnd - twistBegin; 1605 float twistTotal = twistEnd - twistBegin;
1606 1606
1607 // if the profile has a lot of twist, add more layers otherwise the layers may overlap 1607 // if the profile has a lot of twist, add more layers otherwise the layers may overlap
1608 // and the resulting mesh may be quite inaccurate. This method is arbitrary and doesn't 1608 // and the resulting mesh may be quite inaccurate. This method is arbitrary and doesn't
1609 // accurately match the viewer 1609 // accurately match the viewer
1610 float twistTotalAbs = Math.Abs(twistTotal); 1610 float twistTotalAbs = Math.Abs(twistTotal);
1611 if (twistTotalAbs > 0.01f) 1611 if (twistTotalAbs > 0.01f)
1612 { 1612 {
1613 if (twistTotalAbs > Math.PI * 1.5f) 1613 if (twistTotalAbs > Math.PI * 1.5f)
1614 steps *= 2; 1614 steps *= 2;
1615 if (twistTotalAbs > Math.PI * 3.0f) 1615 if (twistTotalAbs > Math.PI * 3.0f)
1616 steps *= 2; 1616 steps *= 2;
1617 } 1617 }
1618 1618
1619 float yPathScale = this.holeSizeY * 0.5f; 1619 float yPathScale = this.holeSizeY * 0.5f;
1620 float pathLength = this.pathCutEnd - this.pathCutBegin; 1620 float pathLength = this.pathCutEnd - this.pathCutBegin;
1621 float totalSkew = this.skew * 2.0f * pathLength; 1621 float totalSkew = this.skew * 2.0f * pathLength;
1622 float skewStart = this.pathCutBegin * 2.0f * this.skew - this.skew; 1622 float skewStart = this.pathCutBegin * 2.0f * this.skew - this.skew;
1623 float xOffsetTopShearXFactor = this.topShearX * (0.25f + 0.5f * (0.5f - this.holeSizeY)); 1623 float xOffsetTopShearXFactor = this.topShearX * (0.25f + 0.5f * (0.5f - this.holeSizeY));
1624 float yShearCompensation = 1.0f + Math.Abs(this.topShearY) * 0.25f; 1624 float yShearCompensation = 1.0f + Math.Abs(this.topShearY) * 0.25f;
1625 1625
1626 // It's not quite clear what pushY (Y top shear) does, but subtracting it from the start and end 1626 // It's not quite clear what pushY (Y top shear) does, but subtracting it from the start and end
1627 // angles appears to approximate it's effects on path cut. Likewise, adding it to the angle used 1627 // angles appears to approximate it's effects on path cut. Likewise, adding it to the angle used
1628 // to calculate the sine for generating the path radius appears to approximate it's effects there 1628 // to calculate the sine for generating the path radius appears to approximate it's effects there
1629 // too, but there are some subtle differences in the radius which are noticeable as the prim size 1629 // too, but there are some subtle differences in the radius which are noticeable as the prim size
1630 // increases and it may affect megaprims quite a bit. The effect of the Y top shear parameter on 1630 // increases and it may affect megaprims quite a bit. The effect of the Y top shear parameter on
1631 // the meshes generated with this technique appear nearly identical in shape to the same prims when 1631 // the meshes generated with this technique appear nearly identical in shape to the same prims when
1632 // displayed by the viewer. 1632 // displayed by the viewer.
1633 1633
1634 float startAngle = (twoPi * this.pathCutBegin * this.revolutions) - this.topShearY * 0.9f; 1634 float startAngle = (twoPi * this.pathCutBegin * this.revolutions) - this.topShearY * 0.9f;
1635 float endAngle = (twoPi * this.pathCutEnd * this.revolutions) - this.topShearY * 0.9f; 1635 float endAngle = (twoPi * this.pathCutEnd * this.revolutions) - this.topShearY * 0.9f;
1636 float stepSize = twoPi / this.stepsPerRevolution; 1636 float stepSize = twoPi / this.stepsPerRevolution;
1637 1637
1638 step = (int)(startAngle / stepSize); 1638 step = (int)(startAngle / stepSize);
1639 int firstStep = step; 1639 int firstStep = step;
1640 float angle = startAngle; 1640 float angle = startAngle;
1641 float hollow = this.hollow; 1641 float hollow = this.hollow;
1642 1642
1643 // sanity checks 1643 // sanity checks
1644 float initialProfileRot = 0.0f; 1644 float initialProfileRot = 0.0f;
1645 if (this.sides == 3) 1645 if (this.sides == 3)
1646 { 1646 {
1647 initialProfileRot = (float)Math.PI; 1647 initialProfileRot = (float)Math.PI;
1648 if (this.hollowSides == 4) 1648 if (this.hollowSides == 4)
1649 { 1649 {
1650 if (hollow > 0.7f) 1650 if (hollow > 0.7f)
1651 hollow = 0.7f; 1651 hollow = 0.7f;
1652 hollow *= 0.707f; 1652 hollow *= 0.707f;
1653 } 1653 }
1654 else hollow *= 0.5f; 1654 else hollow *= 0.5f;
1655 } 1655 }
1656 else if (this.sides == 4) 1656 else if (this.sides == 4)
1657 { 1657 {
1658 initialProfileRot = 0.25f * (float)Math.PI; 1658 initialProfileRot = 0.25f * (float)Math.PI;
1659 if (this.hollowSides != 4) 1659 if (this.hollowSides != 4)
1660 hollow *= 0.707f; 1660 hollow *= 0.707f;
1661 } 1661 }
1662 else if (this.sides > 4) 1662 else if (this.sides > 4)
1663 { 1663 {
1664 initialProfileRot = (float)Math.PI; 1664 initialProfileRot = (float)Math.PI;
1665 if (this.hollowSides == 4) 1665 if (this.hollowSides == 4)
1666 { 1666 {
1667 if (hollow > 0.7f) 1667 if (hollow > 0.7f)
1668 hollow = 0.7f; 1668 hollow = 0.7f;
1669 hollow /= 0.7f; 1669 hollow /= 0.7f;
1670 } 1670 }
1671 } 1671 }
1672 1672
1673 bool needEndFaces = false; 1673 bool needEndFaces = false;
1674 if (this.pathCutBegin != 0.0f || this.pathCutEnd != 1.0f) 1674 if (this.pathCutBegin != 0.0f || this.pathCutEnd != 1.0f)
1675 needEndFaces = true; 1675 needEndFaces = true;
1676 else if (this.taperX != 0.0f || this.taperY != 0.0f) 1676 else if (this.taperX != 0.0f || this.taperY != 0.0f)
1677 needEndFaces = true; 1677 needEndFaces = true;
1678 else if (this.skew != 0.0f) 1678 else if (this.skew != 0.0f)
1679 needEndFaces = true; 1679 needEndFaces = true;
1680 else if (twistTotal != 0.0f) 1680 else if (twistTotal != 0.0f)
1681 needEndFaces = true; 1681 needEndFaces = true;
1682 else if (this.radius != 0.0f) 1682 else if (this.radius != 0.0f)
1683 needEndFaces = true; 1683 needEndFaces = true;
1684 1684
1685 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; 1686 this.numPrimFaces = profile.numPrimFaces;
1687 1687
1688 int cut1Vert = -1; 1688 int cut1Vert = -1;
1689 int cut2Vert = -1; 1689 int cut2Vert = -1;
1690 if (hasProfileCut) 1690 if (hasProfileCut)
1691 { 1691 {
1692 cut1Vert = hasHollow ? profile.coords.Count - 1 : 0; 1692 cut1Vert = hasHollow ? profile.coords.Count - 1 : 0;
1693 cut2Vert = hasHollow ? profile.numOuterVerts - 1 : profile.numOuterVerts; 1693 cut2Vert = hasHollow ? profile.numOuterVerts - 1 : profile.numOuterVerts;
1694 } 1694 }
1695 1695
1696 if (initialProfileRot != 0.0f) 1696 if (initialProfileRot != 0.0f)
1697 { 1697 {
1698 profile.AddRot(new Quat(new Coord(0.0f, 0.0f, 1.0f), initialProfileRot)); 1698 profile.AddRot(new Quat(new Coord(0.0f, 0.0f, 1.0f), initialProfileRot));
1699 if (viewerMode) 1699 if (viewerMode)
1700 profile.MakeFaceUVs(); 1700 profile.MakeFaceUVs();
1701 } 1701 }
1702 1702
1703 Coord lastCutNormal1 = new Coord(); 1703 Coord lastCutNormal1 = new Coord();
1704 Coord lastCutNormal2 = new Coord(); 1704 Coord lastCutNormal2 = new Coord();
1705 float lastV = 1.0f; 1705 float lastV = 1.0f;
1706 1706
1707 bool done = false; 1707 bool done = false;
1708 while (!done) // loop through the length of the path and add the layers 1708 while (!done) // loop through the length of the path and add the layers
1709 { 1709 {
1710 bool isEndLayer = false; 1710 bool isEndLayer = false;
1711 if (angle <= startAngle + .01f || angle >= endAngle - .01f) 1711 if (angle <= startAngle + .01f || angle >= endAngle - .01f)
1712 isEndLayer = true; 1712 isEndLayer = true;
1713 1713
1714 //Profile newLayer = profile.Clone(isEndLayer && needEndFaces); 1714 //Profile newLayer = profile.Clone(isEndLayer && needEndFaces);
1715 Profile newLayer = profile.Clone(); 1715 Profile newLayer = profile.Clone();
1716 1716
1717 float xProfileScale = (1.0f - Math.Abs(this.skew)) * this.holeSizeX; 1717 float xProfileScale = (1.0f - Math.Abs(this.skew)) * this.holeSizeX;
1718 float yProfileScale = this.holeSizeY; 1718 float yProfileScale = this.holeSizeY;
1719 1719
1720 float percentOfPath = angle / (twoPi * this.revolutions); 1720 float percentOfPath = angle / (twoPi * this.revolutions);
1721 float percentOfAngles = (angle - startAngle) / (endAngle - startAngle); 1721 float percentOfAngles = (angle - startAngle) / (endAngle - startAngle);
1722 1722
1723 if (this.taperX > 0.01f) 1723 if (this.taperX > 0.01f)
1724 xProfileScale *= 1.0f - percentOfPath * this.taperX; 1724 xProfileScale *= 1.0f - percentOfPath * this.taperX;
1725 else if (this.taperX < -0.01f) 1725 else if (this.taperX < -0.01f)
1726 xProfileScale *= 1.0f + (1.0f - percentOfPath) * this.taperX; 1726 xProfileScale *= 1.0f + (1.0f - percentOfPath) * this.taperX;
1727 1727
1728 if (this.taperY > 0.01f) 1728 if (this.taperY > 0.01f)
1729 yProfileScale *= 1.0f - percentOfPath * this.taperY; 1729 yProfileScale *= 1.0f - percentOfPath * this.taperY;
1730 else if (this.taperY < -0.01f) 1730 else if (this.taperY < -0.01f)
1731 yProfileScale *= 1.0f + (1.0f - percentOfPath) * this.taperY; 1731 yProfileScale *= 1.0f + (1.0f - percentOfPath) * this.taperY;
1732 1732
1733 if (xProfileScale != 1.0f || yProfileScale != 1.0f) 1733 if (xProfileScale != 1.0f || yProfileScale != 1.0f)
1734 newLayer.Scale(xProfileScale, yProfileScale); 1734 newLayer.Scale(xProfileScale, yProfileScale);
1735 1735
1736 float radiusScale = 1.0f; 1736 float radiusScale = 1.0f;
1737 if (this.radius > 0.001f) 1737 if (this.radius > 0.001f)
1738 radiusScale = 1.0f - this.radius * percentOfPath; 1738 radiusScale = 1.0f - this.radius * percentOfPath;
1739 else if (this.radius < 0.001f) 1739 else if (this.radius < 0.001f)
1740 radiusScale = 1.0f + this.radius * (1.0f - percentOfPath); 1740 radiusScale = 1.0f + this.radius * (1.0f - percentOfPath);
1741 1741
1742 float twist = twistBegin + twistTotal * percentOfPath; 1742 float twist = twistBegin + twistTotal * percentOfPath;
1743 1743
1744 float xOffset = 0.5f * (skewStart + totalSkew * percentOfAngles); 1744 float xOffset = 0.5f * (skewStart + totalSkew * percentOfAngles);
1745 xOffset += (float)Math.Sin(angle) * xOffsetTopShearXFactor; 1745 xOffset += (float)Math.Sin(angle) * xOffsetTopShearXFactor;
1746 1746
1747 float yOffset = yShearCompensation * (float)Math.Cos(angle) * (0.5f - yPathScale) * radiusScale; 1747 float yOffset = yShearCompensation * (float)Math.Cos(angle) * (0.5f - yPathScale) * radiusScale;
1748 1748
1749 float zOffset = (float)Math.Sin(angle + this.topShearY) * (0.5f - yPathScale) * radiusScale; 1749 float zOffset = (float)Math.Sin(angle + this.topShearY) * (0.5f - yPathScale) * radiusScale;
1750 1750
1751 // next apply twist rotation to the profile layer 1751 // next apply twist rotation to the profile layer
1752 if (twistTotal != 0.0f || twistBegin != 0.0f) 1752 if (twistTotal != 0.0f || twistBegin != 0.0f)
1753 newLayer.AddRot(new Quat(new Coord(0.0f, 0.0f, 1.0f), twist)); 1753 newLayer.AddRot(new Quat(new Coord(0.0f, 0.0f, 1.0f), twist));
1754 1754
1755 // now orient the rotation of the profile layer relative to it's position on the path 1755 // now orient the rotation of the profile layer relative to it's position on the path
1756 // adding taperY to the angle used to generate the quat appears to approximate the viewer 1756 // adding taperY to the angle used to generate the quat appears to approximate the viewer
1757 newLayer.AddRot(new Quat(new Coord(1.0f, 0.0f, 0.0f), angle + this.topShearY)); 1757 newLayer.AddRot(new Quat(new Coord(1.0f, 0.0f, 0.0f), angle + this.topShearY));
1758 newLayer.AddPos(xOffset, yOffset, zOffset); 1758 newLayer.AddPos(xOffset, yOffset, zOffset);
1759 1759
1760 if (isEndLayer && angle <= startAngle + .01f) 1760 if (isEndLayer && angle <= startAngle + .01f)
1761 { 1761 {
1762 newLayer.FlipNormals(); 1762 newLayer.FlipNormals();
1763 1763
1764 // add the top faces to the viewerFaces list here 1764 // add the top faces to the viewerFaces list here
1765 if (this.viewerMode && needEndFaces) 1765 if (this.viewerMode && needEndFaces)
1766 { 1766 {
1767 Coord faceNormal = newLayer.faceNormal; 1767 Coord faceNormal = newLayer.faceNormal;
1768 ViewerFace newViewerFace = new ViewerFace(); 1768 ViewerFace newViewerFace = new ViewerFace();
1769 newViewerFace.primFaceNumber = 0; 1769 newViewerFace.primFaceNumber = 0;
1770 foreach (Face face in newLayer.faces) 1770 foreach (Face face in newLayer.faces)
1771 { 1771 {
1772 newViewerFace.v1 = newLayer.coords[face.v1]; 1772 newViewerFace.v1 = newLayer.coords[face.v1];
1773 newViewerFace.v2 = newLayer.coords[face.v2]; 1773 newViewerFace.v2 = newLayer.coords[face.v2];
1774 newViewerFace.v3 = newLayer.coords[face.v3]; 1774 newViewerFace.v3 = newLayer.coords[face.v3];
1775 1775
1776 newViewerFace.n1 = faceNormal; 1776 newViewerFace.n1 = faceNormal;
1777 newViewerFace.n2 = faceNormal; 1777 newViewerFace.n2 = faceNormal;
1778 newViewerFace.n3 = faceNormal; 1778 newViewerFace.n3 = faceNormal;
1779 1779
1780 newViewerFace.uv1 = newLayer.faceUVs[face.v1]; 1780 newViewerFace.uv1 = newLayer.faceUVs[face.v1];
1781 newViewerFace.uv2 = newLayer.faceUVs[face.v2]; 1781 newViewerFace.uv2 = newLayer.faceUVs[face.v2];
1782 newViewerFace.uv3 = newLayer.faceUVs[face.v3]; 1782 newViewerFace.uv3 = newLayer.faceUVs[face.v3];
1783 1783
1784 this.viewerFaces.Add(newViewerFace); 1784 this.viewerFaces.Add(newViewerFace);
1785 } 1785 }
1786 } 1786 }
1787 } 1787 }
1788 1788
1789 // append the layer and fill in the sides 1789 // append the layer and fill in the sides
1790 1790
1791 int coordsLen = this.coords.Count; 1791 int coordsLen = this.coords.Count;
1792 newLayer.AddValue2FaceVertexIndices(coordsLen); 1792 newLayer.AddValue2FaceVertexIndices(coordsLen);
1793 1793
1794 this.coords.AddRange(newLayer.coords); 1794 this.coords.AddRange(newLayer.coords);
1795 1795
1796 if (this.calcVertexNormals) 1796 if (this.calcVertexNormals)
1797 { 1797 {
1798 newLayer.AddValue2FaceNormalIndices(this.normals.Count); 1798 newLayer.AddValue2FaceNormalIndices(this.normals.Count);
1799 this.normals.AddRange(newLayer.vertexNormals); 1799 this.normals.AddRange(newLayer.vertexNormals);
1800 } 1800 }
1801 1801
1802 if (isEndLayer) 1802 if (isEndLayer)
1803 this.faces.AddRange(newLayer.faces); 1803 this.faces.AddRange(newLayer.faces);
1804 1804
1805 // fill faces between layers 1805 // fill faces between layers
1806 1806
1807 int numVerts = newLayer.coords.Count; 1807 int numVerts = newLayer.coords.Count;
1808 Face newFace = new Face(); 1808 Face newFace = new Face();
1809 if (step > firstStep) 1809 if (step > firstStep)
1810 { 1810 {
1811 int startVert = coordsLen + 1; 1811 int startVert = coordsLen + 1;
1812 int endVert = this.coords.Count; 1812 int endVert = this.coords.Count;
1813 1813
1814 if (sides < 5 || this.hasProfileCut || hollow > 0.0f) 1814 if (sides < 5 || this.hasProfileCut || hollow > 0.0f)
1815 startVert--; 1815 startVert--;
1816 1816
1817 for (int i = startVert; i < endVert; i++) 1817 for (int i = startVert; i < endVert; i++)
1818 { 1818 {
1819 int iNext = i + 1; 1819 int iNext = i + 1;
1820 if (i == endVert - 1) 1820 if (i == endVert - 1)
1821 iNext = startVert; 1821 iNext = startVert;
1822 1822
1823 int whichVert = i - startVert; 1823 int whichVert = i - startVert;
1824 1824
1825 newFace.v1 = i; 1825 newFace.v1 = i;
1826 newFace.v2 = i - numVerts; 1826 newFace.v2 = i - numVerts;
1827 newFace.v3 = iNext - numVerts; 1827 newFace.v3 = iNext - numVerts;
1828 this.faces.Add(newFace); 1828 this.faces.Add(newFace);
1829 1829
1830 newFace.v2 = iNext - numVerts; 1830 newFace.v2 = iNext - numVerts;
1831 newFace.v3 = iNext; 1831 newFace.v3 = iNext;
1832 this.faces.Add(newFace); 1832 this.faces.Add(newFace);
1833 1833
1834 if (this.viewerMode) 1834 if (this.viewerMode)
1835 { 1835 {
1836 // add the side faces to the list of viewerFaces here 1836 // add the side faces to the list of viewerFaces here
1837 ViewerFace newViewerFace1 = new ViewerFace(); 1837 ViewerFace newViewerFace1 = new ViewerFace();
1838 ViewerFace newViewerFace2 = new ViewerFace(); 1838 ViewerFace newViewerFace2 = new ViewerFace();
1839 float u1 = newLayer.us[whichVert]; 1839 float u1 = newLayer.us[whichVert];
1840 float u2 = 1.0f; 1840 float u2 = 1.0f;
1841 if (whichVert < newLayer.us.Count - 1) 1841 if (whichVert < newLayer.us.Count - 1)
1842 u2 = newLayer.us[whichVert + 1]; 1842 u2 = newLayer.us[whichVert + 1];
1843 1843
1844 if (whichVert == cut1Vert || whichVert == cut2Vert) 1844 if (whichVert == cut1Vert || whichVert == cut2Vert)
1845 { 1845 {
1846 u1 = 0.0f; 1846 u1 = 0.0f;
1847 u2 = 1.0f; 1847 u2 = 1.0f;
1848 } 1848 }
1849 else if (sides < 5) 1849 else if (sides < 5)
1850 { // boxes and prisms have one texture face per side of the prim, so the U values have to be scaled 1850 { // boxes and prisms have one texture face per side of the prim, so the U values have to be scaled
1851 // to reflect the entire texture width 1851 // to reflect the entire texture width
1852 u1 *= sides; 1852 u1 *= sides;
1853 u2 *= sides; 1853 u2 *= sides;
1854 u2 -= (int)u1; 1854 u2 -= (int)u1;
1855 u1 -= (int)u1; 1855 u1 -= (int)u1;
1856 if (u2 < 0.1f) 1856 if (u2 < 0.1f)
1857 u2 = 1.0f; 1857 u2 = 1.0f;
1858 1858
1859 //newViewerFace2.primFaceNumber = newViewerFace1.primFaceNumber = whichVert + 1; 1859 //newViewerFace2.primFaceNumber = newViewerFace1.primFaceNumber = whichVert + 1;
1860 } 1860 }
1861 1861
1862 newViewerFace1.uv1.U = u1; 1862 newViewerFace1.uv1.U = u1;
1863 newViewerFace1.uv2.U = u1; 1863 newViewerFace1.uv2.U = u1;
1864 newViewerFace1.uv3.U = u2; 1864 newViewerFace1.uv3.U = u2;
1865 1865
1866 newViewerFace1.uv1.V = 1.0f - percentOfPath; 1866 newViewerFace1.uv1.V = 1.0f - percentOfPath;
1867 newViewerFace1.uv2.V = lastV; 1867 newViewerFace1.uv2.V = lastV;
1868 newViewerFace1.uv3.V = lastV; 1868 newViewerFace1.uv3.V = lastV;
1869 1869
1870 newViewerFace2.uv1.U = u1; 1870 newViewerFace2.uv1.U = u1;
1871 newViewerFace2.uv2.U = u2; 1871 newViewerFace2.uv2.U = u2;
1872 newViewerFace2.uv3.U = u2; 1872 newViewerFace2.uv3.U = u2;
1873 1873
1874 newViewerFace2.uv1.V = 1.0f - percentOfPath; 1874 newViewerFace2.uv1.V = 1.0f - percentOfPath;
1875 newViewerFace2.uv2.V = lastV; 1875 newViewerFace2.uv2.V = lastV;
1876 newViewerFace2.uv3.V = 1.0f - percentOfPath; 1876 newViewerFace2.uv3.V = 1.0f - percentOfPath;
1877 1877
1878 newViewerFace1.v1 = this.coords[i]; 1878 newViewerFace1.v1 = this.coords[i];
1879 newViewerFace1.v2 = this.coords[i - numVerts]; 1879 newViewerFace1.v2 = this.coords[i - numVerts];
1880 newViewerFace1.v3 = this.coords[iNext - numVerts]; 1880 newViewerFace1.v3 = this.coords[iNext - numVerts];
1881 1881
1882 newViewerFace2.v1 = this.coords[i]; 1882 newViewerFace2.v1 = this.coords[i];
1883 newViewerFace2.v2 = this.coords[iNext - numVerts]; 1883 newViewerFace2.v2 = this.coords[iNext - numVerts];
1884 newViewerFace2.v3 = this.coords[iNext]; 1884 newViewerFace2.v3 = this.coords[iNext];
1885 1885
1886 // profile cut faces 1886 // profile cut faces
1887 if (whichVert == cut1Vert) 1887 if (whichVert == cut1Vert)
1888 { 1888 {
1889 newViewerFace1.n1 = newLayer.cutNormal1; 1889 newViewerFace1.n1 = newLayer.cutNormal1;
1890 newViewerFace1.n2 = newViewerFace1.n3 = lastCutNormal1; 1890 newViewerFace1.n2 = newViewerFace1.n3 = lastCutNormal1;
1891 1891
1892 newViewerFace2.n1 = newViewerFace2.n3 = newLayer.cutNormal1; 1892 newViewerFace2.n1 = newViewerFace2.n3 = newLayer.cutNormal1;
1893 newViewerFace2.n2 = lastCutNormal1; 1893 newViewerFace2.n2 = lastCutNormal1;
1894 } 1894 }
1895 else if (whichVert == cut2Vert) 1895 else if (whichVert == cut2Vert)
1896 { 1896 {
1897 newViewerFace1.n1 = newLayer.cutNormal2; 1897 newViewerFace1.n1 = newLayer.cutNormal2;
1898 newViewerFace1.n2 = newViewerFace1.n3 = lastCutNormal2; 1898 newViewerFace1.n2 = newViewerFace1.n3 = lastCutNormal2;
1899 1899
1900 newViewerFace2.n1 = newViewerFace2.n3 = newLayer.cutNormal2; 1900 newViewerFace2.n1 = newViewerFace2.n3 = newLayer.cutNormal2;
1901 newViewerFace2.n2 = lastCutNormal2; 1901 newViewerFace2.n2 = lastCutNormal2;
1902 } 1902 }
1903 else // periphery faces 1903 else // periphery faces
1904 { 1904 {
1905 if (sides < 5 && whichVert < newLayer.numOuterVerts) 1905 if (sides < 5 && whichVert < newLayer.numOuterVerts)
1906 { 1906 {
1907 newViewerFace1.n1 = this.normals[i]; 1907 newViewerFace1.n1 = this.normals[i];
1908 newViewerFace1.n2 = this.normals[i - numVerts]; 1908 newViewerFace1.n2 = this.normals[i - numVerts];
1909 newViewerFace1.n3 = this.normals[i - numVerts]; 1909 newViewerFace1.n3 = this.normals[i - numVerts];
1910 1910
1911 newViewerFace2.n1 = this.normals[i]; 1911 newViewerFace2.n1 = this.normals[i];
1912 newViewerFace2.n2 = this.normals[i - numVerts]; 1912 newViewerFace2.n2 = this.normals[i - numVerts];
1913 newViewerFace2.n3 = this.normals[i]; 1913 newViewerFace2.n3 = this.normals[i];
1914 } 1914 }
1915 else if (hollowSides < 5 && whichVert >= newLayer.numOuterVerts) 1915 else if (hollowSides < 5 && whichVert >= newLayer.numOuterVerts)
1916 { 1916 {
1917 newViewerFace1.n1 = this.normals[iNext]; 1917 newViewerFace1.n1 = this.normals[iNext];
1918 newViewerFace1.n2 = this.normals[iNext - numVerts]; 1918 newViewerFace1.n2 = this.normals[iNext - numVerts];
1919 newViewerFace1.n3 = this.normals[iNext - numVerts]; 1919 newViewerFace1.n3 = this.normals[iNext - numVerts];
1920 1920
1921 newViewerFace2.n1 = this.normals[iNext]; 1921 newViewerFace2.n1 = this.normals[iNext];
1922 newViewerFace2.n2 = this.normals[iNext - numVerts]; 1922 newViewerFace2.n2 = this.normals[iNext - numVerts];
1923 newViewerFace2.n3 = this.normals[iNext]; 1923 newViewerFace2.n3 = this.normals[iNext];
1924 } 1924 }
1925 else 1925 else
1926 { 1926 {
1927 newViewerFace1.n1 = this.normals[i]; 1927 newViewerFace1.n1 = this.normals[i];
1928 newViewerFace1.n2 = this.normals[i - numVerts]; 1928 newViewerFace1.n2 = this.normals[i - numVerts];
1929 newViewerFace1.n3 = this.normals[iNext - numVerts]; 1929 newViewerFace1.n3 = this.normals[iNext - numVerts];
1930 1930
1931 newViewerFace2.n1 = this.normals[i]; 1931 newViewerFace2.n1 = this.normals[i];
1932 newViewerFace2.n2 = this.normals[iNext - numVerts]; 1932 newViewerFace2.n2 = this.normals[iNext - numVerts];
1933 newViewerFace2.n3 = this.normals[iNext]; 1933 newViewerFace2.n3 = this.normals[iNext];
1934 } 1934 }
1935 } 1935 }
1936 1936
1937 newViewerFace1.primFaceNumber = newViewerFace2.primFaceNumber = newLayer.faceNumbers[whichVert]; 1937 newViewerFace1.primFaceNumber = newViewerFace2.primFaceNumber = newLayer.faceNumbers[whichVert];
1938 this.viewerFaces.Add(newViewerFace1); 1938 this.viewerFaces.Add(newViewerFace1);
1939 this.viewerFaces.Add(newViewerFace2); 1939 this.viewerFaces.Add(newViewerFace2);
1940 1940
1941 } 1941 }
1942 } 1942 }
1943 } 1943 }
1944 1944
1945 lastCutNormal1 = newLayer.cutNormal1; 1945 lastCutNormal1 = newLayer.cutNormal1;
1946 lastCutNormal2 = newLayer.cutNormal2; 1946 lastCutNormal2 = newLayer.cutNormal2;
1947 lastV = 1.0f - percentOfPath; 1947 lastV = 1.0f - percentOfPath;
1948 1948
1949 // calculate terms for next iteration 1949 // calculate terms for next iteration
1950 // calculate the angle for the next iteration of the loop 1950 // calculate the angle for the next iteration of the loop
1951 1951
1952 if (angle >= endAngle) 1952 if (angle >= endAngle)
1953 done = true; 1953 done = true;
1954 else 1954 else
1955 { 1955 {
1956 step += 1; 1956 step += 1;
1957 angle = stepSize * step; 1957 angle = stepSize * step;
1958 if (angle > endAngle) 1958 if (angle > endAngle)
1959 angle = endAngle; 1959 angle = endAngle;
1960 } 1960 }
1961 1961
1962 if (done && viewerMode && needEndFaces) 1962 if (done && viewerMode && needEndFaces)
1963 { 1963 {
1964 // add the bottom faces to the viewerFaces list here 1964 // add the bottom faces to the viewerFaces list here
1965 Coord faceNormal = newLayer.faceNormal; 1965 Coord faceNormal = newLayer.faceNormal;
1966 ViewerFace newViewerFace = new ViewerFace(); 1966 ViewerFace newViewerFace = new ViewerFace();
1967 newViewerFace.primFaceNumber = newLayer.bottomFaceNumber; 1967 newViewerFace.primFaceNumber = newLayer.bottomFaceNumber;
1968 foreach (Face face in newLayer.faces) 1968 foreach (Face face in newLayer.faces)
1969 { 1969 {
1970 newViewerFace.v1 = newLayer.coords[face.v1 - coordsLen]; 1970 newViewerFace.v1 = newLayer.coords[face.v1 - coordsLen];
1971 newViewerFace.v2 = newLayer.coords[face.v2 - coordsLen]; 1971 newViewerFace.v2 = newLayer.coords[face.v2 - coordsLen];
1972 newViewerFace.v3 = newLayer.coords[face.v3 - coordsLen]; 1972 newViewerFace.v3 = newLayer.coords[face.v3 - coordsLen];
1973 1973
1974 newViewerFace.n1 = faceNormal; 1974 newViewerFace.n1 = faceNormal;
1975 newViewerFace.n2 = faceNormal; 1975 newViewerFace.n2 = faceNormal;
1976 newViewerFace.n3 = faceNormal; 1976 newViewerFace.n3 = faceNormal;
1977 1977
1978 newViewerFace.uv1 = newLayer.faceUVs[face.v1 - coordsLen]; 1978 newViewerFace.uv1 = newLayer.faceUVs[face.v1 - coordsLen];
1979 newViewerFace.uv2 = newLayer.faceUVs[face.v2 - coordsLen]; 1979 newViewerFace.uv2 = newLayer.faceUVs[face.v2 - coordsLen];
1980 newViewerFace.uv3 = newLayer.faceUVs[face.v3 - coordsLen]; 1980 newViewerFace.uv3 = newLayer.faceUVs[face.v3 - coordsLen];
1981 1981
1982 this.viewerFaces.Add(newViewerFace); 1982 this.viewerFaces.Add(newViewerFace);
1983 } 1983 }
1984 } 1984 }
1985 } 1985 }
1986 } 1986 }
1987 1987
1988 private Coord SurfaceNormal(Coord c1, Coord c2, Coord c3) 1988 private Coord SurfaceNormal(Coord c1, Coord c2, Coord c3)
1989 { 1989 {
1990 Coord edge1 = new Coord(c2.X - c1.X, c2.Y - c1.Y, c2.Z - c1.Z); 1990 Coord edge1 = new Coord(c2.X - c1.X, c2.Y - c1.Y, c2.Z - c1.Z);
1991 Coord edge2 = new Coord(c3.X - c1.X, c3.Y - c1.Y, c3.Z - c1.Z); 1991 Coord edge2 = new Coord(c3.X - c1.X, c3.Y - c1.Y, c3.Z - c1.Z);
1992 1992
1993 Coord normal = Coord.Cross(edge1, edge2); 1993 Coord normal = Coord.Cross(edge1, edge2);
1994 1994
1995 normal.Normalize(); 1995 normal.Normalize();
1996 1996
1997 return normal; 1997 return normal;
1998 } 1998 }
1999 1999
2000 private Coord SurfaceNormal(Face face) 2000 private Coord SurfaceNormal(Face face)
2001 { 2001 {
2002 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]);
2003 } 2003 }
2004 2004
2005 /// <summary> 2005 /// <summary>
2006 /// Calculate the surface normal for a face in the list of faces 2006 /// Calculate the surface normal for a face in the list of faces
2007 /// </summary> 2007 /// </summary>
2008 /// <param name="faceIndex"></param> 2008 /// <param name="faceIndex"></param>
2009 /// <returns></returns> 2009 /// <returns></returns>
2010 public Coord SurfaceNormal(int faceIndex) 2010 public Coord SurfaceNormal(int faceIndex)
2011 { 2011 {
2012 int numFaces = this.faces.Count; 2012 int numFaces = this.faces.Count;
2013 if (faceIndex < 0 || faceIndex >= numFaces) 2013 if (faceIndex < 0 || faceIndex >= numFaces)
2014 throw new Exception("faceIndex out of range"); 2014 throw new Exception("faceIndex out of range");
2015 2015
2016 return SurfaceNormal(this.faces[faceIndex]); 2016 return SurfaceNormal(this.faces[faceIndex]);
2017 } 2017 }
2018 2018
2019 /// <summary> 2019 /// <summary>
2020 /// Calculate surface normals for all of the faces in the list of faces in this mesh 2020 /// Calculate surface normals for all of the faces in the list of faces in this mesh
2021 /// </summary> 2021 /// </summary>
2022 public void CalcNormals() 2022 public void CalcNormals()
2023 { 2023 {
2024 if (normalsProcessed) 2024 if (normalsProcessed)
2025 return; 2025 return;
2026 2026
2027 normalsProcessed = true; 2027 normalsProcessed = true;
2028 2028
2029 int numFaces = faces.Count; 2029 int numFaces = faces.Count;
2030 2030
2031 if (!this.calcVertexNormals) 2031 if (!this.calcVertexNormals)
2032 this.normals = new List<Coord>(); 2032 this.normals = new List<Coord>();
2033 2033
2034 for (int i = 0; i < numFaces; i++) 2034 for (int i = 0; i < numFaces; i++)
2035 { 2035 {
2036 Face face = faces[i]; 2036 Face face = faces[i];
2037 2037
2038 this.normals.Add(SurfaceNormal(i).Normalize()); 2038 this.normals.Add(SurfaceNormal(i).Normalize());
2039 2039
2040 int normIndex = normals.Count - 1; 2040 int normIndex = normals.Count - 1;
2041 face.n1 = normIndex; 2041 face.n1 = normIndex;
2042 face.n2 = normIndex; 2042 face.n2 = normIndex;
2043 face.n3 = normIndex; 2043 face.n3 = normIndex;
2044 2044
2045 this.faces[i] = face; 2045 this.faces[i] = face;
2046 } 2046 }
2047 } 2047 }
2048 2048
2049 /// <summary> 2049 /// <summary>
2050 /// Adds a value to each XYZ vertex coordinate in the mesh 2050 /// Adds a value to each XYZ vertex coordinate in the mesh
2051 /// </summary> 2051 /// </summary>
2052 /// <param name="x"></param> 2052 /// <param name="x"></param>
2053 /// <param name="y"></param> 2053 /// <param name="y"></param>
2054 /// <param name="z"></param> 2054 /// <param name="z"></param>
2055 public void AddPos(float x, float y, float z) 2055 public void AddPos(float x, float y, float z)
2056 { 2056 {
2057 int i; 2057 int i;
2058 int numVerts = this.coords.Count; 2058 int numVerts = this.coords.Count;
2059 Coord vert; 2059 Coord vert;
2060 2060
2061 for (i = 0; i < numVerts; i++) 2061 for (i = 0; i < numVerts; i++)
2062 { 2062 {
2063 vert = this.coords[i]; 2063 vert = this.coords[i];
2064 vert.X += x; 2064 vert.X += x;
2065 vert.Y += y; 2065 vert.Y += y;
2066 vert.Z += z; 2066 vert.Z += z;
2067 this.coords[i] = vert; 2067 this.coords[i] = vert;
2068 } 2068 }
2069 } 2069 }
2070 2070
2071 /// <summary> 2071 /// <summary>
2072 /// Rotates the mesh 2072 /// Rotates the mesh
2073 /// </summary> 2073 /// </summary>
2074 /// <param name="q"></param> 2074 /// <param name="q"></param>
2075 public void AddRot(Quat q) 2075 public void AddRot(Quat q)
2076 { 2076 {
2077 int i; 2077 int i;
2078 int numVerts = this.coords.Count; 2078 int numVerts = this.coords.Count;
2079 2079
2080 for (i = 0; i < numVerts; i++) 2080 for (i = 0; i < numVerts; i++)
2081 this.coords[i] *= q; 2081 this.coords[i] *= q;
2082 2082
2083 if (this.normals != null) 2083 if (this.normals != null)
2084 { 2084 {
2085 int numNormals = this.normals.Count; 2085 int numNormals = this.normals.Count;
2086 for (i = 0; i < numNormals; i++) 2086 for (i = 0; i < numNormals; i++)
2087 this.normals[i] *= q; 2087 this.normals[i] *= q;
2088 } 2088 }
2089 2089
2090 if (this.viewerFaces != null) 2090 if (this.viewerFaces != null)
2091 { 2091 {
2092 int numViewerFaces = this.viewerFaces.Count; 2092 int numViewerFaces = this.viewerFaces.Count;
2093 2093
2094 for (i = 0; i < numViewerFaces; i++) 2094 for (i = 0; i < numViewerFaces; i++)
2095 { 2095 {
2096 ViewerFace v = this.viewerFaces[i]; 2096 ViewerFace v = this.viewerFaces[i];
2097 v.v1 *= q; 2097 v.v1 *= q;
2098 v.v2 *= q; 2098 v.v2 *= q;
2099 v.v3 *= q; 2099 v.v3 *= q;
2100 2100
2101 v.n1 *= q; 2101 v.n1 *= q;
2102 v.n2 *= q; 2102 v.n2 *= q;
2103 v.n3 *= q; 2103 v.n3 *= q;
2104 this.viewerFaces[i] = v; 2104 this.viewerFaces[i] = v;
2105 } 2105 }
2106 } 2106 }
2107 2107
2108 } 2108 }
2109 2109
2110 /// <summary> 2110 /// <summary>
2111 /// Scales the mesh 2111 /// Scales the mesh
2112 /// </summary> 2112 /// </summary>
2113 /// <param name="x"></param> 2113 /// <param name="x"></param>
2114 /// <param name="y"></param> 2114 /// <param name="y"></param>
2115 /// <param name="z"></param> 2115 /// <param name="z"></param>
2116 public void Scale(float x, float y, float z) 2116 public void Scale(float x, float y, float z)
2117 { 2117 {
2118 int i; 2118 int i;
2119 int numVerts = this.coords.Count; 2119 int numVerts = this.coords.Count;
2120 //Coord vert; 2120 //Coord vert;
2121 2121
2122 Coord m = new Coord(x, y, z); 2122 Coord m = new Coord(x, y, z);
2123 for (i = 0; i < numVerts; i++) 2123 for (i = 0; i < numVerts; i++)
2124 this.coords[i] *= m; 2124 this.coords[i] *= m;
2125 2125
2126 if (this.viewerFaces != null) 2126 if (this.viewerFaces != null)
2127 { 2127 {
2128 int numViewerFaces = this.viewerFaces.Count; 2128 int numViewerFaces = this.viewerFaces.Count;
2129 for (i = 0; i < numViewerFaces; i++) 2129 for (i = 0; i < numViewerFaces; i++)
2130 { 2130 {
2131 ViewerFace v = this.viewerFaces[i]; 2131 ViewerFace v = this.viewerFaces[i];
2132 v.v1 *= m; 2132 v.v1 *= m;
2133 v.v2 *= m; 2133 v.v2 *= m;
2134 v.v3 *= m; 2134 v.v3 *= m;
2135 this.viewerFaces[i] = v; 2135 this.viewerFaces[i] = v;
2136 } 2136 }
2137 2137
2138 } 2138 }
2139 2139
2140 } 2140 }
2141 2141
2142 /// <summary> 2142 /// <summary>
2143 /// Dumps the mesh to a Blender compatible "Raw" format file 2143 /// Dumps the mesh to a Blender compatible "Raw" format file
2144 /// </summary> 2144 /// </summary>
2145 /// <param name="path"></param> 2145 /// <param name="path"></param>
2146 /// <param name="name"></param> 2146 /// <param name="name"></param>
2147 /// <param name="title"></param> 2147 /// <param name="title"></param>
2148 public void DumpRaw(String path, String name, String title) 2148 public void DumpRaw(String path, String name, String title)
2149 { 2149 {
2150 if (path == null) 2150 if (path == null)
2151 return; 2151 return;
2152 String fileName = name + "_" + title + ".raw"; 2152 String fileName = name + "_" + title + ".raw";
2153 String completePath = Path.Combine(path, fileName); 2153 String completePath = Path.Combine(path, fileName);
2154 StreamWriter sw = new StreamWriter(completePath); 2154 StreamWriter sw = new StreamWriter(completePath);
2155 2155
2156 for (int i = 0; i < this.faces.Count; i++) 2156 for (int i = 0; i < this.faces.Count; i++)
2157 { 2157 {
2158 string s = this.coords[this.faces[i].v1].ToString(); 2158 string s = this.coords[this.faces[i].v1].ToString();
2159 s += " " + this.coords[this.faces[i].v2].ToString(); 2159 s += " " + this.coords[this.faces[i].v2].ToString();
2160 s += " " + this.coords[this.faces[i].v3].ToString(); 2160 s += " " + this.coords[this.faces[i].v3].ToString();
2161 2161
2162 sw.WriteLine(s); 2162 sw.WriteLine(s);
2163 } 2163 }
2164 2164
2165 sw.Close(); 2165 sw.Close();
2166 } 2166 }
2167 } 2167 }
2168} 2168}
diff --git a/OpenSim/Region/Physics/Meshing/SculptMesh.cs b/OpenSim/Region/Physics/Meshing/SculptMesh.cs
index 312f89a..826030b 100644
--- a/OpenSim/Region/Physics/Meshing/SculptMesh.cs
+++ b/OpenSim/Region/Physics/Meshing/SculptMesh.cs
@@ -1,343 +1,343 @@
1/* 1/*
2 * Copyright (c) Contributors 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
6 * modification, are permitted provided that the following conditions are met: 6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright 7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer. 8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright 9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the 10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution. 11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the 12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products 13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission. 14 * derived from this software without specific prior written permission.
15 * 15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY 16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY 19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 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 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 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 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. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Text; 30using System.Text;
31using System.IO; 31using System.IO;
32using System.Drawing; 32using System.Drawing;
33using System.Drawing.Imaging; 33using System.Drawing.Imaging;
34 34
35namespace PrimMesher 35namespace PrimMesher
36{ 36{
37 37
38 public class SculptMesh 38 public class SculptMesh
39 { 39 {
40 public List<Coord> coords; 40 public List<Coord> coords;
41 public List<Face> faces; 41 public List<Face> faces;
42 42
43 public List<ViewerFace> viewerFaces; 43 public List<ViewerFace> viewerFaces;
44 public List<Coord> normals; 44 public List<Coord> normals;
45 public List<UVCoord> uvs; 45 public List<UVCoord> uvs;
46 46
47 public enum SculptType { sphere = 1, torus = 2, plane = 3, cylinder = 4 }; 47 public enum SculptType { sphere = 1, torus = 2, plane = 3, cylinder = 4 };
48 private const float pixScale = 0.00390625f; // 1.0 / 256 48 private const float pixScale = 0.00390625f; // 1.0 / 256
49 49
50 private Bitmap ScaleImage(Bitmap srcImage, float scale) 50 private Bitmap ScaleImage(Bitmap srcImage, float scale)
51 { 51 {
52 int sourceWidth = srcImage.Width; 52 int sourceWidth = srcImage.Width;
53 int sourceHeight = srcImage.Height; 53 int sourceHeight = srcImage.Height;
54 int sourceX = 0; 54 int sourceX = 0;
55 int sourceY = 0; 55 int sourceY = 0;
56 56
57 int destX = 0; 57 int destX = 0;
58 int destY = 0; 58 int destY = 0;
59 int destWidth = (int)(sourceWidth * scale); 59 int destWidth = (int)(sourceWidth * scale);
60 int destHeight = (int)(sourceHeight * scale); 60 int destHeight = (int)(sourceHeight * scale);
61 61
62 Bitmap scaledImage = new Bitmap(destWidth, destHeight, 62 Bitmap scaledImage = new Bitmap(destWidth, destHeight,
63 PixelFormat.Format24bppRgb); 63 PixelFormat.Format24bppRgb);
64 scaledImage.SetResolution(srcImage.HorizontalResolution, 64 scaledImage.SetResolution(srcImage.HorizontalResolution,
65 srcImage.VerticalResolution); 65 srcImage.VerticalResolution);
66 66
67 Graphics grPhoto = Graphics.FromImage(scaledImage); 67 Graphics grPhoto = Graphics.FromImage(scaledImage);
68 grPhoto.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Bilinear; 68 grPhoto.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Bilinear;
69 69
70 grPhoto.DrawImage(srcImage, 70 grPhoto.DrawImage(srcImage,
71 new Rectangle(destX, destY, destWidth, destHeight), 71 new Rectangle(destX, destY, destWidth, destHeight),
72 new Rectangle(sourceX, sourceY, sourceWidth, sourceHeight), 72 new Rectangle(sourceX, sourceY, sourceWidth, sourceHeight),
73 GraphicsUnit.Pixel); 73 GraphicsUnit.Pixel);
74 74
75 grPhoto.Dispose(); 75 grPhoto.Dispose();
76 return scaledImage; 76 return scaledImage;
77 } 77 }
78 78
79 public SculptMesh SculptMeshFromFile(string fileName, SculptType sculptType, int lod, bool viewerMode) 79 public SculptMesh SculptMeshFromFile(string fileName, SculptType sculptType, int lod, bool viewerMode)
80 { 80 {
81 Bitmap bitmap = (Bitmap)Bitmap.FromFile(fileName); 81 Bitmap bitmap = (Bitmap)Bitmap.FromFile(fileName);
82 SculptMesh sculptMesh = new SculptMesh(bitmap, sculptType, lod, viewerMode); 82 SculptMesh sculptMesh = new SculptMesh(bitmap, sculptType, lod, viewerMode);
83 bitmap.Dispose(); 83 bitmap.Dispose();
84 return sculptMesh; 84 return sculptMesh;
85 } 85 }
86 86
87 public SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode) 87 public SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode)
88 { 88 {
89 coords = new List<Coord>(); 89 coords = new List<Coord>();
90 faces = new List<Face>(); 90 faces = new List<Face>();
91 normals = new List<Coord>(); 91 normals = new List<Coord>();
92 uvs = new List<UVCoord>(); 92 uvs = new List<UVCoord>();
93 93
94 float sourceScaleFactor = (float)lod / (float)Math.Max(sculptBitmap.Width, sculptBitmap.Height); 94 float sourceScaleFactor = (float)lod / (float)Math.Max(sculptBitmap.Width, sculptBitmap.Height);
95 bool scaleSourceImage = sourceScaleFactor < 1.0f ? true : false; 95 bool scaleSourceImage = sourceScaleFactor < 1.0f ? true : false;
96 96
97 Bitmap bitmap; 97 Bitmap bitmap;
98 if (scaleSourceImage) 98 if (scaleSourceImage)
99 bitmap = ScaleImage(sculptBitmap, sourceScaleFactor); 99 bitmap = ScaleImage(sculptBitmap, sourceScaleFactor);
100 else 100 else
101 bitmap = sculptBitmap; 101 bitmap = sculptBitmap;
102 102
103 viewerFaces = new List<ViewerFace>(); 103 viewerFaces = new List<ViewerFace>();
104 104
105 int width = bitmap.Width; 105 int width = bitmap.Width;
106 int height = bitmap.Height; 106 int height = bitmap.Height;
107 107
108 float widthUnit = 1.0f / width; 108 float widthUnit = 1.0f / width;
109 float heightUnit = 1.0f / (height - 1); 109 float heightUnit = 1.0f / (height - 1);
110 110
111 int p1, p2, p3, p4; 111 int p1, p2, p3, p4;
112 Color color; 112 Color color;
113 float x, y, z; 113 float x, y, z;
114 114
115 int imageX, imageY; 115 int imageX, imageY;
116 116
117 if (sculptType == SculptType.sphere) 117 if (sculptType == SculptType.sphere)
118 { // average the top and bottom row pixel values so the resulting vertices appear to converge 118 { // average the top and bottom row pixel values so the resulting vertices appear to converge
119 int lastRow = height - 1; 119 int lastRow = height - 1;
120 int r1 = 0, g1 = 0, b1 = 0; 120 int r1 = 0, g1 = 0, b1 = 0;
121 int r2 = 0, g2 = 0, b2 = 0; 121 int r2 = 0, g2 = 0, b2 = 0;
122 for (imageX = 0; imageX < width; imageX++) 122 for (imageX = 0; imageX < width; imageX++)
123 { 123 {
124 Color c1 = bitmap.GetPixel(imageX, 0); 124 Color c1 = bitmap.GetPixel(imageX, 0);
125 Color c2 = bitmap.GetPixel(imageX, lastRow); 125 Color c2 = bitmap.GetPixel(imageX, lastRow);
126 126
127 r1 += c1.R; 127 r1 += c1.R;
128 g1 += c1.G; 128 g1 += c1.G;
129 b1 += c1.B; 129 b1 += c1.B;
130 130
131 r2 += c2.R; 131 r2 += c2.R;
132 g2 += c2.G; 132 g2 += c2.G;
133 b2 += c2.B; 133 b2 += c2.B;
134 } 134 }
135 135
136 Color newC1 = Color.FromArgb(r1 / width, g1 / width, b1 / width); 136 Color newC1 = Color.FromArgb(r1 / width, g1 / width, b1 / width);
137 Color newC2 = Color.FromArgb(r2 / width, g2 / width, b2 / width); 137 Color newC2 = Color.FromArgb(r2 / width, g2 / width, b2 / width);
138 138
139 for (imageX = 0; imageX < width; imageX++) 139 for (imageX = 0; imageX < width; imageX++)
140 { 140 {
141 bitmap.SetPixel(imageX, 0, newC1); 141 bitmap.SetPixel(imageX, 0, newC1);
142 bitmap.SetPixel(imageX, lastRow, newC2); 142 bitmap.SetPixel(imageX, lastRow, newC2);
143 } 143 }
144 } 144 }
145 145
146 146
147 int pixelsAcross = sculptType == SculptType.plane ? width : width + 1; 147 int pixelsAcross = sculptType == SculptType.plane ? width : width + 1;
148 int pixelsDown = sculptType == SculptType.sphere || sculptType == SculptType.cylinder ? height + 1 : height; 148 int pixelsDown = sculptType == SculptType.sphere || sculptType == SculptType.cylinder ? height + 1 : height;
149 149
150 for (imageY = 0; imageY < pixelsDown; imageY++) 150 for (imageY = 0; imageY < pixelsDown; imageY++)
151 { 151 {
152 int rowOffset = imageY * width; 152 int rowOffset = imageY * width;
153 153
154 for (imageX = 0; imageX < pixelsAcross; imageX++) 154 for (imageX = 0; imageX < pixelsAcross; imageX++)
155 { 155 {
156 /* 156 /*
157 * p1-----p2 157 * p1-----p2
158 * | \ f2 | 158 * | \ f2 |
159 * | \ | 159 * | \ |
160 * | f1 \| 160 * | f1 \|
161 * p3-----p4 161 * p3-----p4
162 */ 162 */
163 163
164 if (imageX < width) 164 if (imageX < width)
165 { 165 {
166 p4 = rowOffset + imageX; 166 p4 = rowOffset + imageX;
167 p3 = p4 - 1; 167 p3 = p4 - 1;
168 } 168 }
169 else 169 else
170 { 170 {
171 p4 = rowOffset; // wrap around to beginning 171 p4 = rowOffset; // wrap around to beginning
172 p3 = rowOffset + imageX - 1; 172 p3 = rowOffset + imageX - 1;
173 } 173 }
174 174
175 p2 = p4 - width; 175 p2 = p4 - width;
176 p1 = p3 - width; 176 p1 = p3 - width;
177 177
178 color = bitmap.GetPixel(imageX == width ? 0 : imageX, imageY == height ? height - 1 : imageY); 178 color = bitmap.GetPixel(imageX == width ? 0 : imageX, imageY == height ? height - 1 : imageY);
179 179
180 x = (color.R - 128) * pixScale; 180 x = (color.R - 128) * pixScale;
181 y = (color.G - 128) * pixScale; 181 y = (color.G - 128) * pixScale;
182 z = (color.B - 128) * pixScale; 182 z = (color.B - 128) * pixScale;
183 183
184 Coord c = new Coord(x, y, z); 184 Coord c = new Coord(x, y, z);
185 this.coords.Add(c); 185 this.coords.Add(c);
186 if (viewerMode) 186 if (viewerMode)
187 { 187 {
188 this.normals.Add(new Coord()); 188 this.normals.Add(new Coord());
189 this.uvs.Add(new UVCoord(widthUnit * imageX, heightUnit * imageY)); 189 this.uvs.Add(new UVCoord(widthUnit * imageX, heightUnit * imageY));
190 } 190 }
191 191
192 if (imageY > 0 && imageX > 0) 192 if (imageY > 0 && imageX > 0)
193 { 193 {
194 Face f1, f2; 194 Face f1, f2;
195 195
196 if (viewerMode) 196 if (viewerMode)
197 { 197 {
198 f1 = new Face(p1, p3, p4, p1, p3, p4); 198 f1 = new Face(p1, p3, p4, p1, p3, p4);
199 f1.uv1 = p1; 199 f1.uv1 = p1;
200 f1.uv2 = p3; 200 f1.uv2 = p3;
201 f1.uv3 = p4; 201 f1.uv3 = p4;
202 202
203 f2 = new Face(p1, p4, p2, p1, p4, p2); 203 f2 = new Face(p1, p4, p2, p1, p4, p2);
204 f2.uv1 = p1; 204 f2.uv1 = p1;
205 f2.uv2 = p4; 205 f2.uv2 = p4;
206 f2.uv3 = p2; 206 f2.uv3 = p2;
207 } 207 }
208 else 208 else
209 { 209 {
210 f1 = new Face(p1, p3, p4); 210 f1 = new Face(p1, p3, p4);
211 f2 = new Face(p1, p4, p2); 211 f2 = new Face(p1, p4, p2);
212 } 212 }
213 213
214 this.faces.Add(f1); 214 this.faces.Add(f1);
215 this.faces.Add(f2); 215 this.faces.Add(f2);
216 } 216 }
217 } 217 }
218 } 218 }
219 219
220 if (scaleSourceImage) 220 if (scaleSourceImage)
221 bitmap.Dispose(); 221 bitmap.Dispose();
222 222
223 if (viewerMode) 223 if (viewerMode)
224 { // compute vertex normals by summing all the surface normals of all the triangles sharing 224 { // compute vertex normals by summing all the surface normals of all the triangles sharing
225 // each vertex and then normalizing 225 // each vertex and then normalizing
226 int numFaces = this.faces.Count; 226 int numFaces = this.faces.Count;
227 for (int i = 0; i < numFaces; i++) 227 for (int i = 0; i < numFaces; i++)
228 { 228 {
229 Face face = this.faces[i]; 229 Face face = this.faces[i];
230 Coord surfaceNormal = face.SurfaceNormal(this.coords); 230 Coord surfaceNormal = face.SurfaceNormal(this.coords);
231 this.normals[face.v1] += surfaceNormal; 231 this.normals[face.v1] += surfaceNormal;
232 this.normals[face.v2] += surfaceNormal; 232 this.normals[face.v2] += surfaceNormal;
233 this.normals[face.v3] += surfaceNormal; 233 this.normals[face.v3] += surfaceNormal;
234 } 234 }
235 235
236 int numCoords = this.coords.Count; 236 int numCoords = this.coords.Count;
237 for (int i = 0; i < numCoords; i++) 237 for (int i = 0; i < numCoords; i++)
238 this.coords[i].Normalize(); 238 this.coords[i].Normalize();
239 239
240 if (sculptType != SculptType.plane) 240 if (sculptType != SculptType.plane)
241 { // blend the vertex normals at the cylinder seam 241 { // blend the vertex normals at the cylinder seam
242 pixelsAcross = width + 1; 242 pixelsAcross = width + 1;
243 for (imageY = 0; imageY < height; imageY++) 243 for (imageY = 0; imageY < height; imageY++)
244 { 244 {
245 int rowOffset = imageY * pixelsAcross; 245 int rowOffset = imageY * pixelsAcross;
246 246
247 this.normals[rowOffset] = this.normals[rowOffset + width - 1] = (this.normals[rowOffset] + this.normals[rowOffset + width - 1]).Normalize(); 247 this.normals[rowOffset] = this.normals[rowOffset + width - 1] = (this.normals[rowOffset] + this.normals[rowOffset + width - 1]).Normalize();
248 } 248 }
249 } 249 }
250 250
251 foreach (Face face in this.faces) 251 foreach (Face face in this.faces)
252 { 252 {
253 ViewerFace vf = new ViewerFace(0); 253 ViewerFace vf = new ViewerFace(0);
254 vf.v1 = this.coords[face.v1]; 254 vf.v1 = this.coords[face.v1];
255 vf.v2 = this.coords[face.v2]; 255 vf.v2 = this.coords[face.v2];
256 vf.v3 = this.coords[face.v3]; 256 vf.v3 = this.coords[face.v3];
257 257
258 vf.n1 = this.normals[face.n1]; 258 vf.n1 = this.normals[face.n1];
259 vf.n2 = this.normals[face.n2]; 259 vf.n2 = this.normals[face.n2];
260 vf.n3 = this.normals[face.n3]; 260 vf.n3 = this.normals[face.n3];
261 261
262 vf.uv1 = this.uvs[face.uv1]; 262 vf.uv1 = this.uvs[face.uv1];
263 vf.uv2 = this.uvs[face.uv2]; 263 vf.uv2 = this.uvs[face.uv2];
264 vf.uv3 = this.uvs[face.uv3]; 264 vf.uv3 = this.uvs[face.uv3];
265 265
266 this.viewerFaces.Add(vf); 266 this.viewerFaces.Add(vf);
267 } 267 }
268 } 268 }
269 } 269 }
270 270
271 public void AddRot(Quat q) 271 public void AddRot(Quat q)
272 { 272 {
273 int i; 273 int i;
274 int numVerts = this.coords.Count; 274 int numVerts = this.coords.Count;
275 275
276 for (i = 0; i < numVerts; i++) 276 for (i = 0; i < numVerts; i++)
277 this.coords[i] *= q; 277 this.coords[i] *= q;
278 278
279 if (this.viewerFaces != null) 279 if (this.viewerFaces != null)
280 { 280 {
281 int numViewerFaces = this.viewerFaces.Count; 281 int numViewerFaces = this.viewerFaces.Count;
282 282
283 for (i = 0; i < numViewerFaces; i++) 283 for (i = 0; i < numViewerFaces; i++)
284 { 284 {
285 ViewerFace v = this.viewerFaces[i]; 285 ViewerFace v = this.viewerFaces[i];
286 v.v1 *= q; 286 v.v1 *= q;
287 v.v2 *= q; 287 v.v2 *= q;
288 v.v3 *= q; 288 v.v3 *= q;
289 289
290 v.n1 *= q; 290 v.n1 *= q;
291 v.n2 *= q; 291 v.n2 *= q;
292 v.n3 *= q; 292 v.n3 *= q;
293 293
294 this.viewerFaces[i] = v; 294 this.viewerFaces[i] = v;
295 } 295 }
296 } 296 }
297 } 297 }
298 298
299 public void Scale(float x, float y, float z) 299 public void Scale(float x, float y, float z)
300 { 300 {
301 int i; 301 int i;
302 int numVerts = this.coords.Count; 302 int numVerts = this.coords.Count;
303 //Coord vert; 303 //Coord vert;
304 304
305 Coord m = new Coord(x, y, z); 305 Coord m = new Coord(x, y, z);
306 for (i = 0; i < numVerts; i++) 306 for (i = 0; i < numVerts; i++)
307 this.coords[i] *= m; 307 this.coords[i] *= m;
308 308
309 if (this.viewerFaces != null) 309 if (this.viewerFaces != null)
310 { 310 {
311 int numViewerFaces = this.viewerFaces.Count; 311 int numViewerFaces = this.viewerFaces.Count;
312 for (i = 0; i < numViewerFaces; i++) 312 for (i = 0; i < numViewerFaces; i++)
313 { 313 {
314 ViewerFace v = this.viewerFaces[i]; 314 ViewerFace v = this.viewerFaces[i];
315 v.v1 *= m; 315 v.v1 *= m;
316 v.v2 *= m; 316 v.v2 *= m;
317 v.v3 *= m; 317 v.v3 *= m;
318 this.viewerFaces[i] = v; 318 this.viewerFaces[i] = v;
319 } 319 }
320 } 320 }
321 } 321 }
322 322
323 public void DumpRaw(String path, String name, String title) 323 public void DumpRaw(String path, String name, String title)
324 { 324 {
325 if (path == null) 325 if (path == null)
326 return; 326 return;
327 String fileName = name + "_" + title + ".raw"; 327 String fileName = name + "_" + title + ".raw";
328 String completePath = Path.Combine(path, fileName); 328 String completePath = Path.Combine(path, fileName);
329 StreamWriter sw = new StreamWriter(completePath); 329 StreamWriter sw = new StreamWriter(completePath);
330 330
331 for (int i = 0; i < this.faces.Count; i++) 331 for (int i = 0; i < this.faces.Count; i++)
332 { 332 {
333 string s = this.coords[this.faces[i].v1].ToString(); 333 string s = this.coords[this.faces[i].v1].ToString();
334 s += " " + this.coords[this.faces[i].v2].ToString(); 334 s += " " + this.coords[this.faces[i].v2].ToString();
335 s += " " + this.coords[this.faces[i].v3].ToString(); 335 s += " " + this.coords[this.faces[i].v3].ToString();
336 336
337 sw.WriteLine(s); 337 sw.WriteLine(s);
338 } 338 }
339 339
340 sw.Close(); 340 sw.Close();
341 } 341 }
342 } 342 }
343} 343}