aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/Meshing/SculptMesh.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Physics/Meshing/SculptMesh.cs')
-rw-r--r--OpenSim/Region/Physics/Meshing/SculptMesh.cs1282
1 files changed, 641 insertions, 641 deletions
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}