OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
SculptMesh.cs
Go to the documentation of this file.
1 /*
2  * Copyright (c) Contributors
3  * See CONTRIBUTORS.TXT for a full list of copyright holders.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  * * Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * * Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * * Neither the name of the OpenSimulator Project nor the
13  * names of its contributors may be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
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
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
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 // to build without references to System.Drawing, comment this out
29 #define SYSTEM_DRAWING
30 
31 using System;
32 using System.Collections.Generic;
33 using System.Text;
34 using System.IO;
35 
36 #if SYSTEM_DRAWING
37 using System.Drawing;
38 using System.Drawing.Imaging;
39 #endif
40 
41 namespace PrimMesher
42 {
43 
44  public class SculptMesh
45  {
46  public List<Coord> coords;
47  public List<Face> faces;
48 
49  public List<ViewerFace> viewerFaces;
50  public List<Coord> normals;
51  public List<UVCoord> uvs;
52 
53  public enum SculptType { sphere = 1, torus = 2, plane = 3, cylinder = 4 };
54 
55 #if SYSTEM_DRAWING
56 
57  public SculptMesh SculptMeshFromFile(string fileName, SculptType sculptType, int lod, bool viewerMode)
58  {
59  Bitmap bitmap = (Bitmap)Bitmap.FromFile(fileName);
60  SculptMesh sculptMesh = new SculptMesh(bitmap, sculptType, lod, viewerMode);
61  bitmap.Dispose();
62  return sculptMesh;
63  }
64 
65 
66  public SculptMesh(string fileName, int sculptType, int lod, int viewerMode, int mirror, int invert)
67  {
68  Bitmap bitmap = (Bitmap)Bitmap.FromFile(fileName);
69  _SculptMesh(bitmap, (SculptType)sculptType, lod, viewerMode != 0, mirror != 0, invert != 0);
70  bitmap.Dispose();
71  }
72 #endif
73 
84  public SculptMesh(float[,] zMap, float xBegin, float xEnd, float yBegin, float yEnd, bool viewerMode)
85  {
86  float xStep, yStep;
87  float uStep, vStep;
88 
89  int numYElements = zMap.GetLength(0);
90  int numXElements = zMap.GetLength(1);
91 
92  try
93  {
94  xStep = (xEnd - xBegin) / (float)(numXElements - 1);
95  yStep = (yEnd - yBegin) / (float)(numYElements - 1);
96 
97  uStep = 1.0f / (numXElements - 1);
98  vStep = 1.0f / (numYElements - 1);
99  }
100  catch (DivideByZeroException)
101  {
102  return;
103  }
104 
105  coords = new List<Coord>();
106  faces = new List<Face>();
107  normals = new List<Coord>();
108  uvs = new List<UVCoord>();
109 
110  viewerFaces = new List<ViewerFace>();
111 
112  int p1, p2, p3, p4;
113 
114  int x, y;
115  int xStart = 0, yStart = 0;
116 
117  for (y = yStart; y < numYElements; y++)
118  {
119  int rowOffset = y * numXElements;
120 
121  for (x = xStart; x < numXElements; x++)
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  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  invert = !invert;
314 
315  viewerFaces = new List<ViewerFace>();
316 
317  int width = rows[0].Count;
318 
319  int p1, p2, p3, p4;
320 
321  int imageX, imageY;
322 
323  if (sculptType != SculptType.plane)
324  {
325  if (rows.Count % 2 == 0)
326  {
327  for (int rowNdx = 0; rowNdx < rows.Count; rowNdx++)
328  rows[rowNdx].Add(rows[rowNdx][0]);
329  }
330  else
331  {
332  int lastIndex = rows[0].Count - 1;
333 
334  for (int i = 0; i < rows.Count; i++)
335  rows[i][0] = rows[i][lastIndex];
336  }
337  }
338 
339  Coord topPole = rows[0][width / 2];
340  Coord bottomPole = rows[rows.Count - 1][width / 2];
341 
342  if (sculptType == SculptType.sphere)
343  {
344  if (rows.Count % 2 == 0)
345  {
346  int count = rows[0].Count;
347  List<Coord> topPoleRow = new List<Coord>(count);
348  List<Coord> bottomPoleRow = new List<Coord>(count);
349 
350  for (int i = 0; i < count; i++)
351  {
352  topPoleRow.Add(topPole);
353  bottomPoleRow.Add(bottomPole);
354  }
355  rows.Insert(0, topPoleRow);
356  rows.Add(bottomPoleRow);
357  }
358  else
359  {
360  int count = rows[0].Count;
361 
362  List<Coord> topPoleRow = rows[0];
363  List<Coord> bottomPoleRow = rows[rows.Count - 1];
364 
365  for (int i = 0; i < count; i++)
366  {
367  topPoleRow[i] = topPole;
368  bottomPoleRow[i] = bottomPole;
369  }
370  }
371  }
372 
373  if (sculptType == SculptType.torus)
374  rows.Add(rows[0]);
375 
376  int coordsDown = rows.Count;
377  int coordsAcross = rows[0].Count;
378 // int lastColumn = coordsAcross - 1;
379 
380  float widthUnit = 1.0f / (coordsAcross - 1);
381  float heightUnit = 1.0f / (coordsDown - 1);
382 
383  for (imageY = 0; imageY < coordsDown; imageY++)
384  {
385  int rowOffset = imageY * coordsAcross;
386 
387  for (imageX = 0; imageX < coordsAcross; imageX++)
388  {
389  /*
390  * p1-----p2
391  * | \ f2 |
392  * | \ |
393  * | f1 \|
394  * p3-----p4
395  */
396 
397  p4 = rowOffset + imageX;
398  p3 = p4 - 1;
399 
400  p2 = p4 - coordsAcross;
401  p1 = p3 - coordsAcross;
402 
403  this.coords.Add(rows[imageY][imageX]);
404  if (viewerMode)
405  {
406  this.normals.Add(new Coord());
407  this.uvs.Add(new UVCoord(widthUnit * imageX, heightUnit * imageY));
408  }
409 
410  if (imageY > 0 && imageX > 0)
411  {
412  Face f1, f2;
413 
414  if (viewerMode)
415  {
416  if (invert)
417  {
418  f1 = new Face(p1, p4, p3, p1, p4, p3);
419  f1.uv1 = p1;
420  f1.uv2 = p4;
421  f1.uv3 = p3;
422 
423  f2 = new Face(p1, p2, p4, p1, p2, p4);
424  f2.uv1 = p1;
425  f2.uv2 = p2;
426  f2.uv3 = p4;
427  }
428  else
429  {
430  f1 = new Face(p1, p3, p4, p1, p3, p4);
431  f1.uv1 = p1;
432  f1.uv2 = p3;
433  f1.uv3 = p4;
434 
435  f2 = new Face(p1, p4, p2, p1, p4, p2);
436  f2.uv1 = p1;
437  f2.uv2 = p4;
438  f2.uv3 = p2;
439  }
440  }
441  else
442  {
443  if (invert)
444  {
445  f1 = new Face(p1, p4, p3);
446  f2 = new Face(p1, p2, p4);
447  }
448  else
449  {
450  f1 = new Face(p1, p3, p4);
451  f2 = new Face(p1, p4, p2);
452  }
453  }
454 
455  this.faces.Add(f1);
456  this.faces.Add(f2);
457  }
458  }
459  }
460 
461  if (viewerMode)
462  calcVertexNormals(sculptType, coordsAcross, coordsDown);
463  }
464 
469  public SculptMesh Copy()
470  {
471  return new SculptMesh(this);
472  }
473 
475  {
476  coords = new List<Coord>(sm.coords);
477  faces = new List<Face>(sm.faces);
478  viewerFaces = new List<ViewerFace>(sm.viewerFaces);
479  normals = new List<Coord>(sm.normals);
480  uvs = new List<UVCoord>(sm.uvs);
481  }
482 
483  private void calcVertexNormals(SculptType sculptType, int xSize, int ySize)
484  { // compute vertex normals by summing all the surface normals of all the triangles sharing
485  // each vertex and then normalizing
486  int numFaces = this.faces.Count;
487  for (int i = 0; i < numFaces; i++)
488  {
489  Face face = this.faces[i];
490  Coord surfaceNormal = face.SurfaceNormal(this.coords);
491  this.normals[face.n1] += surfaceNormal;
492  this.normals[face.n2] += surfaceNormal;
493  this.normals[face.n3] += surfaceNormal;
494  }
495 
496  int numNormals = this.normals.Count;
497  for (int i = 0; i < numNormals; i++)
498  this.normals[i] = this.normals[i].Normalize();
499 
500  if (sculptType != SculptType.plane)
501  { // blend the vertex normals at the cylinder seam
502  for (int y = 0; y < ySize; y++)
503  {
504  int rowOffset = y * xSize;
505 
506  this.normals[rowOffset] = this.normals[rowOffset + xSize - 1] = (this.normals[rowOffset] + this.normals[rowOffset + xSize - 1]).Normalize();
507  }
508  }
509 
510  foreach (Face face in this.faces)
511  {
512  ViewerFace vf = new ViewerFace(0);
513  vf.v1 = this.coords[face.v1];
514  vf.v2 = this.coords[face.v2];
515  vf.v3 = this.coords[face.v3];
516 
517  vf.coordIndex1 = face.v1;
518  vf.coordIndex2 = face.v2;
519  vf.coordIndex3 = face.v3;
520 
521  vf.n1 = this.normals[face.n1];
522  vf.n2 = this.normals[face.n2];
523  vf.n3 = this.normals[face.n3];
524 
525  vf.uv1 = this.uvs[face.uv1];
526  vf.uv2 = this.uvs[face.uv2];
527  vf.uv3 = this.uvs[face.uv3];
528 
529  this.viewerFaces.Add(vf);
530  }
531  }
532 
539  public void AddPos(float x, float y, float z)
540  {
541  int i;
542  int numVerts = this.coords.Count;
543  Coord vert;
544 
545  for (i = 0; i < numVerts; i++)
546  {
547  vert = this.coords[i];
548  vert.X += x;
549  vert.Y += y;
550  vert.Z += z;
551  this.coords[i] = vert;
552  }
553 
554  if (this.viewerFaces != null)
555  {
556  int numViewerFaces = this.viewerFaces.Count;
557 
558  for (i = 0; i < numViewerFaces; i++)
559  {
560  ViewerFace v = this.viewerFaces[i];
561  v.AddPos(x, y, z);
562  this.viewerFaces[i] = v;
563  }
564  }
565  }
566 
571  public void AddRot(Quat q)
572  {
573  int i;
574  int numVerts = this.coords.Count;
575 
576  for (i = 0; i < numVerts; i++)
577  this.coords[i] *= q;
578 
579  int numNormals = this.normals.Count;
580  for (i = 0; i < numNormals; i++)
581  this.normals[i] *= q;
582 
583  if (this.viewerFaces != null)
584  {
585  int numViewerFaces = this.viewerFaces.Count;
586 
587  for (i = 0; i < numViewerFaces; i++)
588  {
589  ViewerFace v = this.viewerFaces[i];
590  v.v1 *= q;
591  v.v2 *= q;
592  v.v3 *= q;
593 
594  v.n1 *= q;
595  v.n2 *= q;
596  v.n3 *= q;
597 
598  this.viewerFaces[i] = v;
599  }
600  }
601  }
602 
603  public void Scale(float x, float y, float z)
604  {
605  int i;
606  int numVerts = this.coords.Count;
607 
608  Coord m = new Coord(x, y, z);
609  for (i = 0; i < numVerts; i++)
610  this.coords[i] *= m;
611 
612  if (this.viewerFaces != null)
613  {
614  int numViewerFaces = this.viewerFaces.Count;
615  for (i = 0; i < numViewerFaces; i++)
616  {
617  ViewerFace v = this.viewerFaces[i];
618  v.v1 *= m;
619  v.v2 *= m;
620  v.v3 *= m;
621  this.viewerFaces[i] = v;
622  }
623  }
624  }
625 
626  public void DumpRaw(String path, String name, String title)
627  {
628  if (path == null)
629  return;
630  String fileName = name + "_" + title + ".raw";
631  String completePath = System.IO.Path.Combine(path, fileName);
632  StreamWriter sw = new StreamWriter(completePath);
633 
634  for (int i = 0; i < this.faces.Count; i++)
635  {
636  string s = this.coords[this.faces[i].v1].ToString();
637  s += " " + this.coords[this.faces[i].v2].ToString();
638  s += " " + this.coords[this.faces[i].v3].ToString();
639 
640  sw.WriteLine(s);
641  }
642 
643  sw.Close();
644  }
645  }
646 }
List< Face > faces
Definition: SculptMesh.cs:47
void DumpRaw(String path, String name, String title)
Definition: SculptMesh.cs:626
List< ViewerFace > viewerFaces
Definition: SculptMesh.cs:49
List< Coord > normals
Definition: SculptMesh.cs:50
SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode)
Definition: SculptMesh.cs:178
SculptMesh(List< List< Coord >> rows, SculptType sculptType, bool viewerMode, bool mirror, bool invert)
Definition: SculptMesh.cs:189
SculptMesh(float[,] zMap, float xBegin, float xEnd, float yBegin, float yEnd, bool viewerMode)
** Experimental ** May disappear from future versions ** not recommeneded for use in applications Con...
Definition: SculptMesh.cs:84
void AddRot(Quat q)
Rotates the mesh
Definition: SculptMesh.cs:571
List< Coord > coords
Definition: SculptMesh.cs:46
OpenSim.Region.OptionalModules.Scripting.Minimodule.Object.SculptType SculptType
Definition: SOPObject.cs:39
SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode, bool mirror, bool invert)
Definition: SculptMesh.cs:183
void AddPos(float x, float y, float z)
Adds a value to each XYZ vertex coordinate in the mesh
Definition: SculptMesh.cs:539
SculptMesh(string fileName, int sculptType, int lod, int viewerMode, int mirror, int invert)
Definition: SculptMesh.cs:66
void Scale(float x, float y, float z)
Definition: SculptMesh.cs:603
SculptMesh(SculptMesh sm)
Definition: SculptMesh.cs:474
List< UVCoord > uvs
Definition: SculptMesh.cs:51
SculptMesh SculptMeshFromFile(string fileName, SculptType sculptType, int lod, bool viewerMode)
Definition: SculptMesh.cs:57
SculptMesh Copy()
Duplicates a SculptMesh object. All object properties are copied by value, including lists...
Definition: SculptMesh.cs:469