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