aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/Meshing/SculptMesh.cs
diff options
context:
space:
mode:
authordahlia2010-03-12 21:21:28 -0800
committerdahlia2010-03-12 21:21:28 -0800
commit1d14cf8c3f2ac706d7e4e9cc3a32a0dcc76d0061 (patch)
treeb1cbf6422a34feab4c203a382b739c37929d1a15 /OpenSim/Region/Physics/Meshing/SculptMesh.cs
parentminor: remove some mono compiler warnings (diff)
downloadopensim-SC_OLD-1d14cf8c3f2ac706d7e4e9cc3a32a0dcc76d0061.zip
opensim-SC_OLD-1d14cf8c3f2ac706d7e4e9cc3a32a0dcc76d0061.tar.gz
opensim-SC_OLD-1d14cf8c3f2ac706d7e4e9cc3a32a0dcc76d0061.tar.bz2
opensim-SC_OLD-1d14cf8c3f2ac706d7e4e9cc3a32a0dcc76d0061.tar.xz
some improvements to sculptmap alpha handling and LOD
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/Physics/Meshing/SculptMesh.cs1272
1 files changed, 645 insertions, 627 deletions
diff --git a/OpenSim/Region/Physics/Meshing/SculptMesh.cs b/OpenSim/Region/Physics/Meshing/SculptMesh.cs
index 4dc6e2e..11b6cd4 100644
--- a/OpenSim/Region/Physics/Meshing/SculptMesh.cs
+++ b/OpenSim/Region/Physics/Meshing/SculptMesh.cs
@@ -1,627 +1,645 @@
1/* 1/*
2 * Copyright (c) Contributors 2 * Copyright (c) Contributors
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met: 6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright 7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer. 8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright 9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the 10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution. 11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the 12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products 13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission. 14 * derived from this software without specific prior written permission.
15 * 15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY 16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY 19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28// to build without references to System.Drawing, comment this out 28// to build without references to System.Drawing, comment this out
29#define SYSTEM_DRAWING 29#define SYSTEM_DRAWING
30 30
31using System; 31using System;
32using System.Collections.Generic; 32using System.Collections.Generic;
33using System.Text; 33using System.Text;
34using System.IO; 34using System.IO;
35 35
36#if SYSTEM_DRAWING 36#if SYSTEM_DRAWING
37using System.Drawing; 37using System.Drawing;
38using System.Drawing.Imaging; 38using System.Drawing.Imaging;
39#endif 39#endif
40 40
41namespace PrimMesher 41namespace PrimMesher
42{ 42{
43 43
44 public class SculptMesh 44 public class SculptMesh
45 { 45 {
46 public List<Coord> coords; 46 public List<Coord> coords;
47 public List<Face> faces; 47 public List<Face> faces;
48 48
49 public List<ViewerFace> viewerFaces; 49 public List<ViewerFace> viewerFaces;
50 public List<Coord> normals; 50 public List<Coord> normals;
51 public List<UVCoord> uvs; 51 public List<UVCoord> uvs;
52 52
53 public enum SculptType { sphere = 1, torus = 2, plane = 3, cylinder = 4 }; 53 public enum SculptType { sphere = 1, torus = 2, plane = 3, cylinder = 4 };
54 54
55#if SYSTEM_DRAWING 55#if SYSTEM_DRAWING
56 // private Bitmap ScaleImage(Bitmap srcImage, float scale) 56 private Bitmap ScaleImage(Bitmap srcImage, float scale, bool removeAlpha)
57 // { 57 {
58 // int sourceWidth = srcImage.Width; 58 int sourceWidth = srcImage.Width;
59 // int sourceHeight = srcImage.Height; 59 int sourceHeight = srcImage.Height;
60 // int sourceX = 0; 60 int sourceX = 0;
61 // int sourceY = 0; 61 int sourceY = 0;
62 62
63 // int destX = 0; 63 int destX = 0;
64 // int destY = 0; 64 int destY = 0;
65 // int destWidth = (int)(srcImage.Width * scale); 65 int destWidth = (int)(srcImage.Width * scale);
66 // int destHeight = (int)(srcImage.Height * scale); 66 int destHeight = (int)(srcImage.Height * scale);
67 67
68 // if (srcImage.PixelFormat == PixelFormat.Format32bppArgb) 68 Bitmap scaledImage;
69 // for (int y = 0; y < srcImage.Height; y++) 69
70 // for (int x = 0; x < srcImage.Width; x++) 70 if (removeAlpha)
71 // { 71 {
72 // Color c = srcImage.GetPixel(x, y); 72 if (srcImage.PixelFormat == PixelFormat.Format32bppArgb)
73 // srcImage.SetPixel(x, y, Color.FromArgb(255, c.R, c.G, c.B)); 73 for (int y = 0; y < srcImage.Height; y++)
74 // } 74 for (int x = 0; x < srcImage.Width; x++)
75 75 {
76 // Bitmap scaledImage = new Bitmap(destWidth, destHeight, 76 Color c = srcImage.GetPixel(x, y);
77 // PixelFormat.Format24bppRgb); 77 srcImage.SetPixel(x, y, Color.FromArgb(255, c.R, c.G, c.B));
78 78 }
79 // scaledImage.SetResolution(96.0f, 96.0f); 79
80 80 scaledImage = new Bitmap(destWidth, destHeight,
81 // Graphics grPhoto = Graphics.FromImage(scaledImage); 81 PixelFormat.Format24bppRgb);
82 // grPhoto.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Low; 82 }
83 83 else
84 // grPhoto.DrawImage(srcImage, 84 scaledImage = new Bitmap(srcImage, destWidth, destHeight);
85 // new Rectangle(destX, destY, destWidth, destHeight), 85
86 // new Rectangle(sourceX, sourceY, sourceWidth, sourceHeight), 86 scaledImage.SetResolution(96.0f, 96.0f);
87 // GraphicsUnit.Pixel); 87
88 88 Graphics grPhoto = Graphics.FromImage(scaledImage);
89 // grPhoto.Dispose(); 89 grPhoto.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Low;
90 // return scaledImage; 90
91 // } 91 grPhoto.DrawImage(srcImage,
92 92 new Rectangle(destX, destY, destWidth, destHeight),
93 93 new Rectangle(sourceX, sourceY, sourceWidth, sourceHeight),
94 public SculptMesh SculptMeshFromFile(string fileName, SculptType sculptType, int lod, bool viewerMode) 94 GraphicsUnit.Pixel);
95 { 95
96 Bitmap bitmap = (Bitmap)Bitmap.FromFile(fileName); 96 grPhoto.Dispose();
97 SculptMesh sculptMesh = new SculptMesh(bitmap, sculptType, lod, viewerMode); 97 return scaledImage;
98 bitmap.Dispose(); 98 }
99 return sculptMesh; 99
100 } 100
101 101 public SculptMesh SculptMeshFromFile(string fileName, SculptType sculptType, int lod, bool viewerMode)
102 public SculptMesh(string fileName, int sculptType, int lod, int viewerMode, int mirror, int invert) 102 {
103 { 103 Bitmap bitmap = (Bitmap)Bitmap.FromFile(fileName);
104 Bitmap bitmap = (Bitmap)Bitmap.FromFile(fileName); 104 SculptMesh sculptMesh = new SculptMesh(bitmap, sculptType, lod, viewerMode);
105 _SculptMesh(bitmap, (SculptType)sculptType, lod, viewerMode != 0, mirror != 0, invert != 0); 105 bitmap.Dispose();
106 bitmap.Dispose(); 106 return sculptMesh;
107 } 107 }
108#endif 108
109 109 public SculptMesh(string fileName, int sculptType, int lod, int viewerMode, int mirror, int invert)
110 /// <summary> 110 {
111 /// ** Experimental ** May disappear from future versions ** not recommeneded for use in applications 111 Bitmap bitmap = (Bitmap)Bitmap.FromFile(fileName);
112 /// Construct a sculpt mesh from a 2D array of floats 112 _SculptMesh(bitmap, (SculptType)sculptType, lod, viewerMode != 0, mirror != 0, invert != 0);
113 /// </summary> 113 bitmap.Dispose();
114 /// <param name="zMap"></param> 114 }
115 /// <param name="xBegin"></param> 115#endif
116 /// <param name="xEnd"></param> 116
117 /// <param name="yBegin"></param> 117 /// <summary>
118 /// <param name="yEnd"></param> 118 /// ** Experimental ** May disappear from future versions ** not recommeneded for use in applications
119 /// <param name="viewerMode"></param> 119 /// Construct a sculpt mesh from a 2D array of floats
120 public SculptMesh(float[,] zMap, float xBegin, float xEnd, float yBegin, float yEnd, bool viewerMode) 120 /// </summary>
121 { 121 /// <param name="zMap"></param>
122 float xStep, yStep; 122 /// <param name="xBegin"></param>
123 float uStep, vStep; 123 /// <param name="xEnd"></param>
124 124 /// <param name="yBegin"></param>
125 int numYElements = zMap.GetLength(0); 125 /// <param name="yEnd"></param>
126 int numXElements = zMap.GetLength(1); 126 /// <param name="viewerMode"></param>
127 127 public SculptMesh(float[,] zMap, float xBegin, float xEnd, float yBegin, float yEnd, bool viewerMode)
128 try 128 {
129 { 129 float xStep, yStep;
130 xStep = (xEnd - xBegin) / (float)(numXElements - 1); 130 float uStep, vStep;
131 yStep = (yEnd - yBegin) / (float)(numYElements - 1); 131
132 132 int numYElements = zMap.GetLength(0);
133 uStep = 1.0f / (numXElements - 1); 133 int numXElements = zMap.GetLength(1);
134 vStep = 1.0f / (numYElements - 1); 134
135 } 135 try
136 catch (DivideByZeroException) 136 {
137 { 137 xStep = (xEnd - xBegin) / (float)(numXElements - 1);
138 return; 138 yStep = (yEnd - yBegin) / (float)(numYElements - 1);
139 } 139
140 140 uStep = 1.0f / (numXElements - 1);
141 coords = new List<Coord>(); 141 vStep = 1.0f / (numYElements - 1);
142 faces = new List<Face>(); 142 }
143 normals = new List<Coord>(); 143 catch (DivideByZeroException)
144 uvs = new List<UVCoord>(); 144 {
145 145 return;
146 viewerFaces = new List<ViewerFace>(); 146 }
147 147
148 int p1, p2, p3, p4; 148 coords = new List<Coord>();
149 149 faces = new List<Face>();
150 int x, y; 150 normals = new List<Coord>();
151 int xStart = 0, yStart = 0; 151 uvs = new List<UVCoord>();
152 152
153 for (y = yStart; y < numYElements; y++) 153 viewerFaces = new List<ViewerFace>();
154 { 154
155 int rowOffset = y * numXElements; 155 int p1, p2, p3, p4;
156 156
157 for (x = xStart; x < numXElements; x++) 157 int x, y;
158 { 158 int xStart = 0, yStart = 0;
159 /* 159
160 * p1-----p2 160 for (y = yStart; y < numYElements; y++)
161 * | \ f2 | 161 {
162 * | \ | 162 int rowOffset = y * numXElements;
163 * | f1 \| 163
164 * p3-----p4 164 for (x = xStart; x < numXElements; x++)
165 */ 165 {
166 166 /*
167 p4 = rowOffset + x; 167 * p1-----p2
168 p3 = p4 - 1; 168 * | \ f2 |
169 169 * | \ |
170 p2 = p4 - numXElements; 170 * | f1 \|
171 p1 = p3 - numXElements; 171 * p3-----p4
172 172 */
173 Coord c = new Coord(xBegin + x * xStep, yBegin + y * yStep, zMap[y, x]); 173
174 this.coords.Add(c); 174 p4 = rowOffset + x;
175 if (viewerMode) 175 p3 = p4 - 1;
176 { 176
177 this.normals.Add(new Coord()); 177 p2 = p4 - numXElements;
178 this.uvs.Add(new UVCoord(uStep * x, 1.0f - vStep * y)); 178 p1 = p3 - numXElements;
179 } 179
180 180 Coord c = new Coord(xBegin + x * xStep, yBegin + y * yStep, zMap[y, x]);
181 if (y > 0 && x > 0) 181 this.coords.Add(c);
182 { 182 if (viewerMode)
183 Face f1, f2; 183 {
184 184 this.normals.Add(new Coord());
185 if (viewerMode) 185 this.uvs.Add(new UVCoord(uStep * x, 1.0f - vStep * y));
186 { 186 }
187 f1 = new Face(p1, p4, p3, p1, p4, p3); 187
188 f1.uv1 = p1; 188 if (y > 0 && x > 0)
189 f1.uv2 = p4; 189 {
190 f1.uv3 = p3; 190 Face f1, f2;
191 191
192 f2 = new Face(p1, p2, p4, p1, p2, p4); 192 if (viewerMode)
193 f2.uv1 = p1; 193 {
194 f2.uv2 = p2; 194 f1 = new Face(p1, p4, p3, p1, p4, p3);
195 f2.uv3 = p4; 195 f1.uv1 = p1;
196 } 196 f1.uv2 = p4;
197 else 197 f1.uv3 = p3;
198 { 198
199 f1 = new Face(p1, p4, p3); 199 f2 = new Face(p1, p2, p4, p1, p2, p4);
200 f2 = new Face(p1, p2, p4); 200 f2.uv1 = p1;
201 } 201 f2.uv2 = p2;
202 202 f2.uv3 = p4;
203 this.faces.Add(f1); 203 }
204 this.faces.Add(f2); 204 else
205 } 205 {
206 } 206 f1 = new Face(p1, p4, p3);
207 } 207 f2 = new Face(p1, p2, p4);
208 208 }
209 if (viewerMode) 209
210 calcVertexNormals(SculptType.plane, numXElements, numYElements); 210 this.faces.Add(f1);
211 } 211 this.faces.Add(f2);
212 212 }
213#if SYSTEM_DRAWING 213 }
214 public SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode) 214 }
215 { 215
216 _SculptMesh(sculptBitmap, sculptType, lod, viewerMode, false, false); 216 if (viewerMode)
217 } 217 calcVertexNormals(SculptType.plane, numXElements, numYElements);
218 218 }
219 public SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode, bool mirror, bool invert) 219
220 { 220#if SYSTEM_DRAWING
221 _SculptMesh(sculptBitmap, sculptType, lod, viewerMode, mirror, invert); 221 public SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode)
222 } 222 {
223#endif 223 _SculptMesh(sculptBitmap, sculptType, lod, viewerMode, false, false);
224 224 }
225 public SculptMesh(List<List<Coord>> rows, SculptType sculptType, bool viewerMode, bool mirror, bool invert) 225
226 { 226 public SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode, bool mirror, bool invert)
227 _SculptMesh(rows, sculptType, viewerMode, mirror, invert); 227 {
228 } 228 _SculptMesh(sculptBitmap, sculptType, lod, viewerMode, mirror, invert);
229 229 }
230#if SYSTEM_DRAWING 230#endif
231 /// <summary> 231
232 /// converts a bitmap to a list of lists of coords, while scaling the image. 232 public SculptMesh(List<List<Coord>> rows, SculptType sculptType, bool viewerMode, bool mirror, bool invert)
233 /// the scaling is done in floating point so as to allow for reduced vertex position 233 {
234 /// quantization as the position will be averaged between pixel values. this routine will 234 _SculptMesh(rows, sculptType, viewerMode, mirror, invert);
235 /// likely fail if the bitmap width and height are not powers of 2. 235 }
236 /// </summary> 236
237 /// <param name="bitmap"></param> 237#if SYSTEM_DRAWING
238 /// <param name="scale"></param> 238 /// <summary>
239 /// <param name="mirror"></param> 239 /// converts a bitmap to a list of lists of coords, while scaling the image.
240 /// <returns></returns> 240 /// the scaling is done in floating point so as to allow for reduced vertex position
241 private List<List<Coord>> bitmap2Coords(Bitmap bitmap, int scale, bool mirror) 241 /// quantization as the position will be averaged between pixel values. this routine will
242 { 242 /// likely fail if the bitmap width and height are not powers of 2.
243 int numRows = bitmap.Height / scale; 243 /// </summary>
244 int numCols = bitmap.Width / scale; 244 /// <param name="bitmap"></param>
245 List<List<Coord>> rows = new List<List<Coord>>(numRows); 245 /// <param name="scale"></param>
246 246 /// <param name="mirror"></param>
247 float pixScale = 1.0f / (scale * scale); 247 /// <returns></returns>
248 pixScale /= 255; 248 private List<List<Coord>> bitmap2Coords(Bitmap bitmap, int scale, bool mirror)
249 249 {
250 int imageX, imageY = 0; 250 int numRows = bitmap.Height / scale;
251 251 int numCols = bitmap.Width / scale;
252 int rowNdx, colNdx; 252 List<List<Coord>> rows = new List<List<Coord>>(numRows);
253 253
254 for (rowNdx = 0; rowNdx < numRows; rowNdx++) 254 float pixScale = 1.0f / (scale * scale);
255 { 255 pixScale /= 255;
256 List<Coord> row = new List<Coord>(numCols); 256
257 for (colNdx = 0; colNdx < numCols; colNdx++) 257 int imageX, imageY = 0;
258 { 258
259 imageX = colNdx * scale; 259 int rowNdx, colNdx;
260 int imageYStart = rowNdx * scale; 260
261 int imageYEnd = imageYStart + scale; 261 for (rowNdx = 0; rowNdx < numRows; rowNdx++)
262 int imageXEnd = imageX + scale; 262 {
263 float rSum = 0.0f; 263 List<Coord> row = new List<Coord>(numCols);
264 float gSum = 0.0f; 264 for (colNdx = 0; colNdx < numCols; colNdx++)
265 float bSum = 0.0f; 265 {
266 for (; imageX < imageXEnd; imageX++) 266 imageX = colNdx * scale;
267 { 267 int imageYStart = rowNdx * scale;
268 for (imageY = imageYStart; imageY < imageYEnd; imageY++) 268 int imageYEnd = imageYStart + scale;
269 { 269 int imageXEnd = imageX + scale;
270 Color c = bitmap.GetPixel(imageX, imageY); 270 float rSum = 0.0f;
271 rSum += c.R; 271 float gSum = 0.0f;
272 gSum += c.G; 272 float bSum = 0.0f;
273 bSum += c.B; 273 for (; imageX < imageXEnd; imageX++)
274 } 274 {
275 } 275 for (imageY = imageYStart; imageY < imageYEnd; imageY++)
276 if (mirror) 276 {
277 row.Add(new Coord(-(rSum * pixScale - 0.5f), gSum * pixScale - 0.5f, bSum * pixScale - 0.5f)); 277 Color c = bitmap.GetPixel(imageX, imageY);
278 else 278 if (c.A != 255)
279 row.Add(new Coord(rSum * pixScale - 0.5f, gSum * pixScale - 0.5f, bSum * pixScale - 0.5f)); 279 {
280 280 bitmap.SetPixel(imageX, imageY, Color.FromArgb(255, c.R, c.G, c.B));
281 } 281 c = bitmap.GetPixel(imageX, imageY);
282 rows.Add(row); 282 }
283 } 283 rSum += c.R;
284 return rows; 284 gSum += c.G;
285 } 285 bSum += c.B;
286 286 }
287 287 }
288 void _SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode, bool mirror, bool invert) 288 if (mirror)
289 { 289 row.Add(new Coord(-(rSum * pixScale - 0.5f), gSum * pixScale - 0.5f, bSum * pixScale - 0.5f));
290 coords = new List<Coord>(); 290 else
291 faces = new List<Face>(); 291 row.Add(new Coord(rSum * pixScale - 0.5f, gSum * pixScale - 0.5f, bSum * pixScale - 0.5f));
292 normals = new List<Coord>(); 292
293 uvs = new List<UVCoord>(); 293 }
294 294 rows.Add(row);
295 sculptType = (SculptType)(((int)sculptType) & 0x07); 295 }
296 296 return rows;
297 if (mirror) 297 }
298 if (sculptType == SculptType.plane) 298
299 invert = !invert; 299
300 300 void _SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode, bool mirror, bool invert)
301 float sourceScaleFactor = (float)(lod) / (float)Math.Sqrt(sculptBitmap.Width * sculptBitmap.Height); 301 {
302 302 coords = new List<Coord>();
303 int scale = (int)(1.0f / sourceScaleFactor); 303 faces = new List<Face>();
304 if (scale < 1) scale = 1; 304 normals = new List<Coord>();
305 305 uvs = new List<UVCoord>();
306 _SculptMesh(bitmap2Coords(sculptBitmap, scale, mirror), sculptType, viewerMode, mirror, invert); 306
307 } 307 sculptType = (SculptType)(((int)sculptType) & 0x07);
308#endif 308
309 309 if (mirror)
310 310 if (sculptType == SculptType.plane)
311 void _SculptMesh(List<List<Coord>> rows, SculptType sculptType, bool viewerMode, bool mirror, bool invert) 311 invert = !invert;
312 { 312
313 coords = new List<Coord>(); 313 float sculptBitmapLod = (float)Math.Sqrt(sculptBitmap.Width * sculptBitmap.Height);
314 faces = new List<Face>(); 314
315 normals = new List<Coord>(); 315 float sourceScaleFactor = (float)(lod) / sculptBitmapLod;
316 uvs = new List<UVCoord>(); 316
317 317 float fScale = 1.0f / sourceScaleFactor;
318 sculptType = (SculptType)(((int)sculptType) & 0x07); 318
319 319 int iScale = (int)fScale;
320 if (mirror) 320 if (iScale < 1) iScale = 1;
321 if (sculptType == SculptType.plane) 321 if (iScale > 2 && iScale % 2 == 0)
322 invert = !invert; 322 _SculptMesh(bitmap2Coords(ScaleImage(sculptBitmap, 64.0f / sculptBitmapLod, true), 64 / lod, mirror), sculptType, viewerMode, mirror, invert);
323 323 else
324 viewerFaces = new List<ViewerFace>(); 324 _SculptMesh(bitmap2Coords(sculptBitmap, iScale, mirror), sculptType, viewerMode, mirror, invert);
325 325 }
326 int width = rows[0].Count; 326#endif
327 327
328 int p1, p2, p3, p4; 328
329 329 void _SculptMesh(List<List<Coord>> rows, SculptType sculptType, bool viewerMode, bool mirror, bool invert)
330 int imageX, imageY; 330 {
331 331 coords = new List<Coord>();
332 if (sculptType != SculptType.plane) 332 faces = new List<Face>();
333 { 333 normals = new List<Coord>();
334 for (int rowNdx = 0; rowNdx < rows.Count; rowNdx++) 334 uvs = new List<UVCoord>();
335 rows[rowNdx].Add(rows[rowNdx][0]); 335
336 } 336 sculptType = (SculptType)(((int)sculptType) & 0x07);
337 337
338 Coord topPole = rows[0][width / 2]; 338 if (mirror)
339 Coord bottomPole = rows[rows.Count - 1][width / 2]; 339 if (sculptType == SculptType.plane)
340 340 invert = !invert;
341 if (sculptType == SculptType.sphere) 341
342 { 342 viewerFaces = new List<ViewerFace>();
343 int count = rows[0].Count; 343
344 List<Coord> topPoleRow = new List<Coord>(count); 344 int width = rows[0].Count;
345 List<Coord> bottomPoleRow = new List<Coord>(count); 345
346 346 int p1, p2, p3, p4;
347 for (int i = 0; i < count; i++) 347
348 { 348 int imageX, imageY;
349 topPoleRow.Add(topPole); 349
350 bottomPoleRow.Add(bottomPole); 350 if (sculptType != SculptType.plane)
351 } 351 {
352 rows.Insert(0, topPoleRow); 352 for (int rowNdx = 0; rowNdx < rows.Count; rowNdx++)
353 rows.Add(bottomPoleRow); 353 rows[rowNdx].Add(rows[rowNdx][0]);
354 } 354 }
355 else if (sculptType == SculptType.torus) 355
356 rows.Add(rows[0]); 356 Coord topPole = rows[0][width / 2];
357 357 Coord bottomPole = rows[rows.Count - 1][width / 2];
358 int coordsDown = rows.Count; 358
359 int coordsAcross = rows[0].Count; 359 if (sculptType == SculptType.sphere)
360 360 {
361 float widthUnit = 1.0f / (coordsAcross - 1); 361 int count = rows[0].Count;
362 float heightUnit = 1.0f / (coordsDown - 1); 362 List<Coord> topPoleRow = new List<Coord>(count);
363 363 List<Coord> bottomPoleRow = new List<Coord>(count);
364 for (imageY = 0; imageY < coordsDown; imageY++) 364
365 { 365 for (int i = 0; i < count; i++)
366 int rowOffset = imageY * coordsAcross; 366 {
367 367 topPoleRow.Add(topPole);
368 for (imageX = 0; imageX < coordsAcross; imageX++) 368 bottomPoleRow.Add(bottomPole);
369 { 369 }
370 /* 370 rows.Insert(0, topPoleRow);
371 * p1-----p2 371 rows.Add(bottomPoleRow);
372 * | \ f2 | 372 }
373 * | \ | 373 else if (sculptType == SculptType.torus)
374 * | f1 \| 374 rows.Add(rows[0]);
375 * p3-----p4 375
376 */ 376 int coordsDown = rows.Count;
377 377 int coordsAcross = rows[0].Count;
378 p4 = rowOffset + imageX; 378
379 p3 = p4 - 1; 379 float widthUnit = 1.0f / (coordsAcross - 1);
380 380 float heightUnit = 1.0f / (coordsDown - 1);
381 p2 = p4 - coordsAcross; 381
382 p1 = p3 - coordsAcross; 382 for (imageY = 0; imageY < coordsDown; imageY++)
383 383 {
384 this.coords.Add(rows[imageY][imageX]); 384 int rowOffset = imageY * coordsAcross;
385 if (viewerMode) 385
386 { 386 for (imageX = 0; imageX < coordsAcross; imageX++)
387 this.normals.Add(new Coord()); 387 {
388 this.uvs.Add(new UVCoord(widthUnit * imageX, heightUnit * imageY)); 388 /*
389 } 389 * p1-----p2
390 390 * | \ f2 |
391 if (imageY > 0 && imageX > 0) 391 * | \ |
392 { 392 * | f1 \|
393 Face f1, f2; 393 * p3-----p4
394 394 */
395 if (viewerMode) 395
396 { 396 p4 = rowOffset + imageX;
397 if (invert) 397 p3 = p4 - 1;
398 { 398
399 f1 = new Face(p1, p4, p3, p1, p4, p3); 399 p2 = p4 - coordsAcross;
400 f1.uv1 = p1; 400 p1 = p3 - coordsAcross;
401 f1.uv2 = p4; 401
402 f1.uv3 = p3; 402 this.coords.Add(rows[imageY][imageX]);
403 403 if (viewerMode)
404 f2 = new Face(p1, p2, p4, p1, p2, p4); 404 {
405 f2.uv1 = p1; 405 this.normals.Add(new Coord());
406 f2.uv2 = p2; 406 this.uvs.Add(new UVCoord(widthUnit * imageX, heightUnit * imageY));
407 f2.uv3 = p4; 407 }
408 } 408
409 else 409 if (imageY > 0 && imageX > 0)
410 { 410 {
411 f1 = new Face(p1, p3, p4, p1, p3, p4); 411 Face f1, f2;
412 f1.uv1 = p1; 412
413 f1.uv2 = p3; 413 if (viewerMode)
414 f1.uv3 = p4; 414 {
415 415 if (invert)
416 f2 = new Face(p1, p4, p2, p1, p4, p2); 416 {
417 f2.uv1 = p1; 417 f1 = new Face(p1, p4, p3, p1, p4, p3);
418 f2.uv2 = p4; 418 f1.uv1 = p1;
419 f2.uv3 = p2; 419 f1.uv2 = p4;
420 } 420 f1.uv3 = p3;
421 } 421
422 else 422 f2 = new Face(p1, p2, p4, p1, p2, p4);
423 { 423 f2.uv1 = p1;
424 if (invert) 424 f2.uv2 = p2;
425 { 425 f2.uv3 = p4;
426 f1 = new Face(p1, p4, p3); 426 }
427 f2 = new Face(p1, p2, p4); 427 else
428 } 428 {
429 else 429 f1 = new Face(p1, p3, p4, p1, p3, p4);
430 { 430 f1.uv1 = p1;
431 f1 = new Face(p1, p3, p4); 431 f1.uv2 = p3;
432 f2 = new Face(p1, p4, p2); 432 f1.uv3 = p4;
433 } 433
434 } 434 f2 = new Face(p1, p4, p2, p1, p4, p2);
435 435 f2.uv1 = p1;
436 this.faces.Add(f1); 436 f2.uv2 = p4;
437 this.faces.Add(f2); 437 f2.uv3 = p2;
438 } 438 }
439 } 439 }
440 } 440 else
441 441 {
442 if (viewerMode) 442 if (invert)
443 calcVertexNormals(sculptType, coordsAcross, coordsDown); 443 {
444 } 444 f1 = new Face(p1, p4, p3);
445 445 f2 = new Face(p1, p2, p4);
446 /// <summary> 446 }
447 /// Duplicates a SculptMesh object. All object properties are copied by value, including lists. 447 else
448 /// </summary> 448 {
449 /// <returns></returns> 449 f1 = new Face(p1, p3, p4);
450 public SculptMesh Copy() 450 f2 = new Face(p1, p4, p2);
451 { 451 }
452 return new SculptMesh(this); 452 }
453 } 453
454 454 this.faces.Add(f1);
455 public SculptMesh(SculptMesh sm) 455 this.faces.Add(f2);
456 { 456 }
457 coords = new List<Coord>(sm.coords); 457 }
458 faces = new List<Face>(sm.faces); 458 }
459 viewerFaces = new List<ViewerFace>(sm.viewerFaces); 459
460 normals = new List<Coord>(sm.normals); 460 if (viewerMode)
461 uvs = new List<UVCoord>(sm.uvs); 461 calcVertexNormals(sculptType, coordsAcross, coordsDown);
462 } 462 }
463 463
464 private void calcVertexNormals(SculptType sculptType, int xSize, int ySize) 464 /// <summary>
465 { // compute vertex normals by summing all the surface normals of all the triangles sharing 465 /// Duplicates a SculptMesh object. All object properties are copied by value, including lists.
466 // each vertex and then normalizing 466 /// </summary>
467 int numFaces = this.faces.Count; 467 /// <returns></returns>
468 for (int i = 0; i < numFaces; i++) 468 public SculptMesh Copy()
469 { 469 {
470 Face face = this.faces[i]; 470 return new SculptMesh(this);
471 Coord surfaceNormal = face.SurfaceNormal(this.coords); 471 }
472 this.normals[face.n1] += surfaceNormal; 472
473 this.normals[face.n2] += surfaceNormal; 473 public SculptMesh(SculptMesh sm)
474 this.normals[face.n3] += surfaceNormal; 474 {
475 } 475 coords = new List<Coord>(sm.coords);
476 476 faces = new List<Face>(sm.faces);
477 int numNormals = this.normals.Count; 477 viewerFaces = new List<ViewerFace>(sm.viewerFaces);
478 for (int i = 0; i < numNormals; i++) 478 normals = new List<Coord>(sm.normals);
479 this.normals[i] = this.normals[i].Normalize(); 479 uvs = new List<UVCoord>(sm.uvs);
480 480 }
481 if (sculptType != SculptType.plane) 481
482 { // blend the vertex normals at the cylinder seam 482 private void calcVertexNormals(SculptType sculptType, int xSize, int ySize)
483 for (int y = 0; y < ySize; y++) 483 { // compute vertex normals by summing all the surface normals of all the triangles sharing
484 { 484 // each vertex and then normalizing
485 int rowOffset = y * xSize; 485 int numFaces = this.faces.Count;
486 486 for (int i = 0; i < numFaces; i++)
487 this.normals[rowOffset] = this.normals[rowOffset + xSize - 1] = (this.normals[rowOffset] + this.normals[rowOffset + xSize - 1]).Normalize(); 487 {
488 } 488 Face face = this.faces[i];
489 } 489 Coord surfaceNormal = face.SurfaceNormal(this.coords);
490 490 this.normals[face.n1] += surfaceNormal;
491 foreach (Face face in this.faces) 491 this.normals[face.n2] += surfaceNormal;
492 { 492 this.normals[face.n3] += surfaceNormal;
493 ViewerFace vf = new ViewerFace(0); 493 }
494 vf.v1 = this.coords[face.v1]; 494
495 vf.v2 = this.coords[face.v2]; 495 int numNormals = this.normals.Count;
496 vf.v3 = this.coords[face.v3]; 496 for (int i = 0; i < numNormals; i++)
497 497 this.normals[i] = this.normals[i].Normalize();
498 vf.coordIndex1 = face.v1; 498
499 vf.coordIndex2 = face.v2; 499 if (sculptType != SculptType.plane)
500 vf.coordIndex3 = face.v3; 500 { // blend the vertex normals at the cylinder seam
501 501 for (int y = 0; y < ySize; y++)
502 vf.n1 = this.normals[face.n1]; 502 {
503 vf.n2 = this.normals[face.n2]; 503 int rowOffset = y * xSize;
504 vf.n3 = this.normals[face.n3]; 504
505 505 this.normals[rowOffset] = this.normals[rowOffset + xSize - 1] = (this.normals[rowOffset] + this.normals[rowOffset + xSize - 1]).Normalize();
506 vf.uv1 = this.uvs[face.uv1]; 506 }
507 vf.uv2 = this.uvs[face.uv2]; 507 }
508 vf.uv3 = this.uvs[face.uv3]; 508
509 509 foreach (Face face in this.faces)
510 this.viewerFaces.Add(vf); 510 {
511 } 511 ViewerFace vf = new ViewerFace(0);
512 } 512 vf.v1 = this.coords[face.v1];
513 513 vf.v2 = this.coords[face.v2];
514 /// <summary> 514 vf.v3 = this.coords[face.v3];
515 /// Adds a value to each XYZ vertex coordinate in the mesh 515
516 /// </summary> 516 vf.coordIndex1 = face.v1;
517 /// <param name="x"></param> 517 vf.coordIndex2 = face.v2;
518 /// <param name="y"></param> 518 vf.coordIndex3 = face.v3;
519 /// <param name="z"></param> 519
520 public void AddPos(float x, float y, float z) 520 vf.n1 = this.normals[face.n1];
521 { 521 vf.n2 = this.normals[face.n2];
522 int i; 522 vf.n3 = this.normals[face.n3];
523 int numVerts = this.coords.Count; 523
524 Coord vert; 524 vf.uv1 = this.uvs[face.uv1];
525 525 vf.uv2 = this.uvs[face.uv2];
526 for (i = 0; i < numVerts; i++) 526 vf.uv3 = this.uvs[face.uv3];
527 { 527
528 vert = this.coords[i]; 528 this.viewerFaces.Add(vf);
529 vert.X += x; 529 }
530 vert.Y += y; 530 }
531 vert.Z += z; 531
532 this.coords[i] = vert; 532 /// <summary>
533 } 533 /// Adds a value to each XYZ vertex coordinate in the mesh
534 534 /// </summary>
535 if (this.viewerFaces != null) 535 /// <param name="x"></param>
536 { 536 /// <param name="y"></param>
537 int numViewerFaces = this.viewerFaces.Count; 537 /// <param name="z"></param>
538 538 public void AddPos(float x, float y, float z)
539 for (i = 0; i < numViewerFaces; i++) 539 {
540 { 540 int i;
541 ViewerFace v = this.viewerFaces[i]; 541 int numVerts = this.coords.Count;
542 v.AddPos(x, y, z); 542 Coord vert;
543 this.viewerFaces[i] = v; 543
544 } 544 for (i = 0; i < numVerts; i++)
545 } 545 {
546 } 546 vert = this.coords[i];
547 547 vert.X += x;
548 /// <summary> 548 vert.Y += y;
549 /// Rotates the mesh 549 vert.Z += z;
550 /// </summary> 550 this.coords[i] = vert;
551 /// <param name="q"></param> 551 }
552 public void AddRot(Quat q) 552
553 { 553 if (this.viewerFaces != null)
554 int i; 554 {
555 int numVerts = this.coords.Count; 555 int numViewerFaces = this.viewerFaces.Count;
556 556
557 for (i = 0; i < numVerts; i++) 557 for (i = 0; i < numViewerFaces; i++)
558 this.coords[i] *= q; 558 {
559 559 ViewerFace v = this.viewerFaces[i];
560 int numNormals = this.normals.Count; 560 v.AddPos(x, y, z);
561 for (i = 0; i < numNormals; i++) 561 this.viewerFaces[i] = v;
562 this.normals[i] *= q; 562 }
563 563 }
564 if (this.viewerFaces != null) 564 }
565 { 565
566 int numViewerFaces = this.viewerFaces.Count; 566 /// <summary>
567 567 /// Rotates the mesh
568 for (i = 0; i < numViewerFaces; i++) 568 /// </summary>
569 { 569 /// <param name="q"></param>
570 ViewerFace v = this.viewerFaces[i]; 570 public void AddRot(Quat q)
571 v.v1 *= q; 571 {
572 v.v2 *= q; 572 int i;
573 v.v3 *= q; 573 int numVerts = this.coords.Count;
574 574
575 v.n1 *= q; 575 for (i = 0; i < numVerts; i++)
576 v.n2 *= q; 576 this.coords[i] *= q;
577 v.n3 *= q; 577
578 578 int numNormals = this.normals.Count;
579 this.viewerFaces[i] = v; 579 for (i = 0; i < numNormals; i++)
580 } 580 this.normals[i] *= q;
581 } 581
582 } 582 if (this.viewerFaces != null)
583 583 {
584 public void Scale(float x, float y, float z) 584 int numViewerFaces = this.viewerFaces.Count;
585 { 585
586 int i; 586 for (i = 0; i < numViewerFaces; i++)
587 int numVerts = this.coords.Count; 587 {
588 588 ViewerFace v = this.viewerFaces[i];
589 Coord m = new Coord(x, y, z); 589 v.v1 *= q;
590 for (i = 0; i < numVerts; i++) 590 v.v2 *= q;
591 this.coords[i] *= m; 591 v.v3 *= q;
592 592
593 if (this.viewerFaces != null) 593 v.n1 *= q;
594 { 594 v.n2 *= q;
595 int numViewerFaces = this.viewerFaces.Count; 595 v.n3 *= q;
596 for (i = 0; i < numViewerFaces; i++) 596
597 { 597 this.viewerFaces[i] = v;
598 ViewerFace v = this.viewerFaces[i]; 598 }
599 v.v1 *= m; 599 }
600 v.v2 *= m; 600 }
601 v.v3 *= m; 601
602 this.viewerFaces[i] = v; 602 public void Scale(float x, float y, float z)
603 } 603 {
604 } 604 int i;
605 } 605 int numVerts = this.coords.Count;
606 606
607 public void DumpRaw(String path, String name, String title) 607 Coord m = new Coord(x, y, z);
608 { 608 for (i = 0; i < numVerts; i++)
609 if (path == null) 609 this.coords[i] *= m;
610 return; 610
611 String fileName = name + "_" + title + ".raw"; 611 if (this.viewerFaces != null)
612 String completePath = System.IO.Path.Combine(path, fileName); 612 {
613 StreamWriter sw = new StreamWriter(completePath); 613 int numViewerFaces = this.viewerFaces.Count;
614 614 for (i = 0; i < numViewerFaces; i++)
615 for (int i = 0; i < this.faces.Count; i++) 615 {
616 { 616 ViewerFace v = this.viewerFaces[i];
617 string s = this.coords[this.faces[i].v1].ToString(); 617 v.v1 *= m;
618 s += " " + this.coords[this.faces[i].v2].ToString(); 618 v.v2 *= m;
619 s += " " + this.coords[this.faces[i].v3].ToString(); 619 v.v3 *= m;
620 620 this.viewerFaces[i] = v;
621 sw.WriteLine(s); 621 }
622 } 622 }
623 623 }
624 sw.Close(); 624
625 } 625 public void DumpRaw(String path, String name, String title)
626 } 626 {
627} 627 if (path == null)
628 return;
629 String fileName = name + "_" + title + ".raw";
630 String completePath = System.IO.Path.Combine(path, fileName);
631 StreamWriter sw = new StreamWriter(completePath);
632
633 for (int i = 0; i < this.faces.Count; i++)
634 {
635 string s = this.coords[this.faces[i].v1].ToString();
636 s += " " + this.coords[this.faces[i].v2].ToString();
637 s += " " + this.coords[this.faces[i].v3].ToString();
638
639 sw.WriteLine(s);
640 }
641
642 sw.Close();
643 }
644 }
645}