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