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.cs523
1 files changed, 263 insertions, 260 deletions
diff --git a/OpenSim/Region/Physics/Meshing/SculptMesh.cs b/OpenSim/Region/Physics/Meshing/SculptMesh.cs
index 0dc7ef2..826030b 100644
--- a/OpenSim/Region/Physics/Meshing/SculptMesh.cs
+++ b/OpenSim/Region/Physics/Meshing/SculptMesh.cs
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (c) Contributors, http://opensimulator.org/ 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
@@ -27,314 +27,317 @@
27 27
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Text;
31using System.IO;
30using System.Drawing; 32using System.Drawing;
31using System.Drawing.Imaging; 33using System.Drawing.Imaging;
32using System.Text;
33using OpenMetaverse.Imaging;
34 34
35namespace OpenSim.Region.Physics.Meshing 35namespace PrimMesher
36{ 36{
37 // This functionality based on the XNA SculptPreview by John Hurliman.
38 public class SculptMesh : Mesh
39 {
40 Image idata = null;
41 Bitmap bLOD = null;
42 Bitmap bBitmap = null;
43 37
44 Vertex northpole = new Vertex(0, 0, 0); 38 public class SculptMesh
45 Vertex southpole = new Vertex(0, 0, 0); 39 {
40 public List<Coord> coords;
41 public List<Face> faces;
46 42
47 private int lod = 32; 43 public List<ViewerFace> viewerFaces;
48 private const float RANGE = 128.0f; 44 public List<Coord> normals;
45 public List<UVCoord> uvs;
49 46
50 public SculptMesh(byte[] jpegData, float _lod) 47 public enum SculptType { sphere = 1, torus = 2, plane = 3, cylinder = 4 };
48 private const float pixScale = 0.00390625f; // 1.0 / 256
49
50 private Bitmap ScaleImage(Bitmap srcImage, float scale)
51 { 51 {
52 if (_lod == 2f || _lod == 4f || _lod == 8f || _lod == 16f || _lod == 32f || _lod == 64f) 52 int sourceWidth = srcImage.Width;
53 lod = (int)_lod; 53 int sourceHeight = srcImage.Height;
54 int sourceX = 0;
55 int sourceY = 0;
56
57 int destX = 0;
58 int destY = 0;
59 int destWidth = (int)(sourceWidth * scale);
60 int destHeight = (int)(sourceHeight * scale);
61
62 Bitmap scaledImage = new Bitmap(destWidth, destHeight,
63 PixelFormat.Format24bppRgb);
64 scaledImage.SetResolution(srcImage.HorizontalResolution,
65 srcImage.VerticalResolution);
66
67 Graphics grPhoto = Graphics.FromImage(scaledImage);
68 grPhoto.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Bilinear;
69
70 grPhoto.DrawImage(srcImage,
71 new Rectangle(destX, destY, destWidth, destHeight),
72 new Rectangle(sourceX, sourceY, sourceWidth, sourceHeight),
73 GraphicsUnit.Pixel);
74
75 grPhoto.Dispose();
76 return scaledImage;
77 }
54 78
55 try 79 public SculptMesh SculptMeshFromFile(string fileName, SculptType sculptType, int lod, bool viewerMode)
56 { 80 {
57 ManagedImage managedImage; // we never use this 81 Bitmap bitmap = (Bitmap)Bitmap.FromFile(fileName);
58 OpenJPEG.DecodeToImage(jpegData, out managedImage, out idata); 82 SculptMesh sculptMesh = new SculptMesh(bitmap, sculptType, lod, viewerMode);
59 //int i = 0; 83 bitmap.Dispose();
60 //i = i / i; 84 return sculptMesh;
61 } 85 }
62 catch (Exception)
63 {
64 System.Console.WriteLine("[PHYSICS]: Unable to generate a Sculpty physics proxy. Sculpty texture decode failed!");
65 return;
66 }
67 86
68 if (idata != null) 87 public SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode)
69 { 88 {
70 bBitmap = new Bitmap(idata); 89 coords = new List<Coord>();
71 if (bBitmap.Width == bBitmap.Height) 90 faces = new List<Face>();
72 { 91 normals = new List<Coord>();
73 DoLOD(); 92 uvs = new List<UVCoord>();
74 93
75 LoadPoles(); 94 float sourceScaleFactor = (float)lod / (float)Math.Max(sculptBitmap.Width, sculptBitmap.Height);
95 bool scaleSourceImage = sourceScaleFactor < 1.0f ? true : false;
76 96
77 processSculptTexture(); 97 Bitmap bitmap;
98 if (scaleSourceImage)
99 bitmap = ScaleImage(sculptBitmap, sourceScaleFactor);
100 else
101 bitmap = sculptBitmap;
78 102
79 bLOD.Dispose(); 103 viewerFaces = new List<ViewerFace>();
80 bBitmap.Dispose();
81 idata.Dispose();
82 }
83 }
84 }
85
86 private Vertex ColorToVertex(Color input)
87 {
88 return new Vertex(
89 ((float)input.R - 128) / RANGE,
90 ((float)input.G - 128) / RANGE,
91 ((float)input.B - 128) / RANGE);
92 }
93
94 private void LoadPoles()
95 {
96 northpole = new Vertex(0, 0, 0);
97 for (int x = 0; x < bLOD.Width; x++)
98 {
99 northpole += ColorToVertex(GetPixel(0, 0));
100 }
101 northpole /= bLOD.Width;
102 104
103 southpole = new Vertex(0, 0, 0); 105 int width = bitmap.Width;
104 for (int x = 0; x < bLOD.Width; x++) 106 int height = bitmap.Height;
105 {
106 //System.Console.WriteLine("Height: " + bLOD.Height.ToString());
107 southpole += ColorToVertex(GetPixel(bLOD.Height - 1, (bLOD.Height - 1)));
108 }
109 southpole /= bBitmap.Width;
110 }
111 107
112 private Color GetPixel(int x, int y) 108 float widthUnit = 1.0f / width;
113 { 109 float heightUnit = 1.0f / (height - 1);
114 return bLOD.GetPixel(x, y);
115 }
116 110
117 public int LOD 111 int p1, p2, p3, p4;
118 { 112 Color color;
119 get 113 float x, y, z;
120 {
121 return (int)Math.Log(Scale, 2);
122 }
123 set
124 {
125 int power = value;
126 if (power == 0)
127 power = 6;
128 if (power < 2)
129 power = 2;
130 if (power > 9)
131 power = 9;
132 int t = (int)Math.Pow(2, power);
133 if (t != Scale)
134 {
135 lod = t;
136 }
137 }
138 }
139 114
140 public int Scale 115 int imageX, imageY;
141 {
142 get
143 {
144 return lod;
145 }
146 }
147
148 private void DoLOD()
149 {
150 int x_max = Math.Min(Scale, bBitmap.Width);
151 int y_max = Math.Min(Scale, bBitmap.Height);
152 if (bBitmap.Width == x_max && bBitmap.Height == y_max)
153 bLOD = bBitmap;
154 116
155 else if (bLOD == null || x_max != bLOD.Width || y_max != bLOD.Height)//don't resize if you don't need to. 117 if (sculptType == SculptType.sphere)
156 { 118 { // average the top and bottom row pixel values so the resulting vertices appear to converge
157 System.Drawing.Bitmap tile = new System.Drawing.Bitmap(bBitmap.Width * 2, bBitmap.Height, PixelFormat.Format24bppRgb); 119 int lastRow = height - 1;
158 System.Drawing.Bitmap tile_LOD = new System.Drawing.Bitmap(x_max * 2, y_max, PixelFormat.Format24bppRgb); 120 int r1 = 0, g1 = 0, b1 = 0;
159 121 int r2 = 0, g2 = 0, b2 = 0;
160 bLOD = new System.Drawing.Bitmap(x_max, y_max, PixelFormat.Format24bppRgb); 122 for (imageX = 0; imageX < width; imageX++)
161 bLOD.SetResolution(bBitmap.HorizontalResolution, bBitmap.VerticalResolution); 123 {
162 124 Color c1 = bitmap.GetPixel(imageX, 0);
163 System.Drawing.Graphics grPhoto = System.Drawing.Graphics.FromImage(tile); 125 Color c2 = bitmap.GetPixel(imageX, lastRow);
164 grPhoto.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
165
166 grPhoto.DrawImage(bBitmap,
167 new System.Drawing.Rectangle(0, 0, bBitmap.Width / 2, bBitmap.Height),
168 new System.Drawing.Rectangle(bBitmap.Width / 2, 0, bBitmap.Width / 2, bBitmap.Height),
169 System.Drawing.GraphicsUnit.Pixel);
170
171 grPhoto.DrawImage(bBitmap,
172 new System.Drawing.Rectangle((3 * bBitmap.Width) / 2, 0, bBitmap.Width / 2, bBitmap.Height),
173 new System.Drawing.Rectangle(0, 0, bBitmap.Width / 2, bBitmap.Height),
174 System.Drawing.GraphicsUnit.Pixel);
175
176 grPhoto.DrawImage(bBitmap,
177 new System.Drawing.Rectangle(bBitmap.Width / 2, 0, bBitmap.Width, bBitmap.Height),
178 new System.Drawing.Rectangle(0, 0, bBitmap.Width, bBitmap.Height),
179 System.Drawing.GraphicsUnit.Pixel);
180
181 grPhoto = System.Drawing.Graphics.FromImage(tile_LOD);
182 //grPhoto.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear;
183 grPhoto.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Bilinear;
184
185 grPhoto.DrawImage(tile,
186 new System.Drawing.Rectangle(0, 0, tile_LOD.Width, tile_LOD.Height),
187 new System.Drawing.Rectangle(0, 0, tile.Width, tile.Height),
188 System.Drawing.GraphicsUnit.Pixel);
189
190 grPhoto = System.Drawing.Graphics.FromImage(bLOD);
191 grPhoto.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
192
193 grPhoto.DrawImage(tile_LOD,
194 new System.Drawing.Rectangle(0, 0, bLOD.Width, bLOD.Height),
195 new System.Drawing.Rectangle(tile_LOD.Width / 4, 0, tile_LOD.Width / 2, tile_LOD.Height),
196 System.Drawing.GraphicsUnit.Pixel);
197
198 grPhoto.Dispose();
199 tile_LOD.Dispose();
200 tile.Dispose();
201 }
202 126
203 } 127 r1 += c1.R;
204 128 g1 += c1.G;
205 public void clearStuff() 129 b1 += c1.B;
206 {
207 this.triangles.Clear();
208 this.vertices.Clear();
209 //normals = new float[0];
210 }
211
212 public void processSculptTexture()
213 {
214 int x_max = Math.Min(Scale, bBitmap.Width);
215 int y_max = Math.Min(Scale, bBitmap.Height);
216 130
217 int COLUMNS = x_max + 1; 131 r2 += c2.R;
132 g2 += c2.G;
133 b2 += c2.B;
134 }
218 135
219 Vertex[] sVertices = new Vertex[COLUMNS * y_max]; 136 Color newC1 = Color.FromArgb(r1 / width, g1 / width, b1 / width);
220 //float[] indices = new float[COLUMNS * (y_max - 1) * 6]; 137 Color newC2 = Color.FromArgb(r2 / width, g2 / width, b2 / width);
221 138
222 for (int y = 0; y < y_max; y++) 139 for (imageX = 0; imageX < width; imageX++)
223 {
224 for (int x = 0; x < x_max; x++)
225 { 140 {
226 // Create the vertex 141 bitmap.SetPixel(imageX, 0, newC1);
227 Vertex v1 = new Vertex(0,0,0); 142 bitmap.SetPixel(imageX, lastRow, newC2);
143 }
144 }
228 145
229 // Create a vertex position from the RGB channels in the current pixel
230 // int ypos = y * bLOD.Width;
231 146
147 int pixelsAcross = sculptType == SculptType.plane ? width : width + 1;
148 int pixelsDown = sculptType == SculptType.sphere || sculptType == SculptType.cylinder ? height + 1 : height;
232 149
233 if (y == 0) 150 for (imageY = 0; imageY < pixelsDown; imageY++)
234 { 151 {
235 v1 = northpole; 152 int rowOffset = imageY * width;
236 } 153
237 else if (y == y_max - 1) 154 for (imageX = 0; imageX < pixelsAcross; imageX++)
155 {
156 /*
157 * p1-----p2
158 * | \ f2 |
159 * | \ |
160 * | f1 \|
161 * p3-----p4
162 */
163
164 if (imageX < width)
238 { 165 {
239 v1 = southpole; 166 p4 = rowOffset + imageX;
167 p3 = p4 - 1;
240 } 168 }
241 else 169 else
242 { 170 {
243 v1 = ColorToVertex(GetPixel(x, y)); 171 p4 = rowOffset; // wrap around to beginning
172 p3 = rowOffset + imageX - 1;
244 } 173 }
245 174
246 // Add the vertex for use later 175 p2 = p4 - width;
247 if (!vertices.Contains(v1)) 176 p1 = p3 - width;
248 Add(v1);
249 177
250 sVertices[y * COLUMNS + x] = v1; 178 color = bitmap.GetPixel(imageX == width ? 0 : imageX, imageY == height ? height - 1 : imageY);
251 //System.Console.WriteLine("adding: " + v1.ToString());
252 }
253 //Vertex tempVertex = vertices[y * COLUMNS];
254 // sVertices[y * COLUMNS + x_max] = tempVertex;
255 }
256 179
257 // Create the Triangles 180 x = (color.R - 128) * pixScale;
258 //int i = 0; 181 y = (color.G - 128) * pixScale;
182 z = (color.B - 128) * pixScale;
259 183
260 for (int y = 0; y < y_max - 1; y++) 184 Coord c = new Coord(x, y, z);
261 { 185 this.coords.Add(c);
262 int x; 186 if (viewerMode)
263
264 for (x = 0; x < x_max; x++)
265 {
266 Vertex vt11 = sVertices[(y * COLUMNS + x)];
267 Vertex vt12 = sVertices[(y * COLUMNS + (x + 1))];
268 Vertex vt13 = sVertices[((y + 1) * COLUMNS + (x + 1))];
269 if (vt11 != null && vt12 != null && vt13 != null)
270 { 187 {
271 if (vt11 != vt12 && vt11 != vt13 && vt12 != vt13) 188 this.normals.Add(new Coord());
272 { 189 this.uvs.Add(new UVCoord(widthUnit * imageX, heightUnit * imageY));
273 Triangle tri1 = new Triangle(vt11, vt12, vt13);
274 //indices[i++] = (ushort)(y * COLUMNS + x);
275 //indices[i++] = (ushort)(y * COLUMNS + (x + 1));
276 //indices[i++] = (ushort)((y + 1) * COLUMNS + (x + 1));
277 Add(tri1);
278 }
279 } 190 }
280 191
281 Vertex vt21 = sVertices[(y * COLUMNS + x)]; 192 if (imageY > 0 && imageX > 0)
282 Vertex vt22 = sVertices[((y + 1) * COLUMNS + (x + 1))];
283 Vertex vt23 = sVertices[((y + 1) * COLUMNS + x)];
284 if (vt21 != null && vt22 != null && vt23 != null)
285 { 193 {
286 if (vt21.Equals(vt22, 0.022f) || vt21.Equals(vt23, 0.022f) || vt22.Equals(vt23, 0.022f)) 194 Face f1, f2;
195
196 if (viewerMode)
287 { 197 {
198 f1 = new Face(p1, p3, p4, p1, p3, p4);
199 f1.uv1 = p1;
200 f1.uv2 = p3;
201 f1.uv3 = p4;
202
203 f2 = new Face(p1, p4, p2, p1, p4, p2);
204 f2.uv1 = p1;
205 f2.uv2 = p4;
206 f2.uv3 = p2;
288 } 207 }
289 else 208 else
290 { 209 {
291 Triangle tri2 = new Triangle(vt21, vt22, vt23); 210 f1 = new Face(p1, p3, p4);
292 //indices[i++] = (ushort)(y * COLUMNS + x); 211 f2 = new Face(p1, p4, p2);
293 //indices[i++] = (ushort)((y + 1) * COLUMNS + (x + 1));
294 //indices[i++] = (ushort)((y + 1) * COLUMNS + x);
295 Add(tri2);
296 } 212 }
213
214 this.faces.Add(f1);
215 this.faces.Add(f2);
297 } 216 }
217 }
218 }
219
220 if (scaleSourceImage)
221 bitmap.Dispose();
222
223 if (viewerMode)
224 { // compute vertex normals by summing all the surface normals of all the triangles sharing
225 // each vertex and then normalizing
226 int numFaces = this.faces.Count;
227 for (int i = 0; i < numFaces; i++)
228 {
229 Face face = this.faces[i];
230 Coord surfaceNormal = face.SurfaceNormal(this.coords);
231 this.normals[face.v1] += surfaceNormal;
232 this.normals[face.v2] += surfaceNormal;
233 this.normals[face.v3] += surfaceNormal;
234 }
298 235
236 int numCoords = this.coords.Count;
237 for (int i = 0; i < numCoords; i++)
238 this.coords[i].Normalize();
239
240 if (sculptType != SculptType.plane)
241 { // blend the vertex normals at the cylinder seam
242 pixelsAcross = width + 1;
243 for (imageY = 0; imageY < height; imageY++)
244 {
245 int rowOffset = imageY * pixelsAcross;
246
247 this.normals[rowOffset] = this.normals[rowOffset + width - 1] = (this.normals[rowOffset] + this.normals[rowOffset + width - 1]).Normalize();
248 }
299 } 249 }
300 //Vertex vt31 = sVertices[(y * x_max + x)];
301 //Vertex vt32 = sVertices[(y * x_max + 0)];
302 //Vertex vt33 = sVertices[((y + 1) * x_max + 0)];
303 //if (vt31 != null && vt32 != null && vt33 != null)
304 //{
305 //if (vt31.Equals(vt32, 0.022f) || vt31.Equals(vt33, 0.022f) || vt32.Equals(vt33, 0.022f))
306 //{
307 //}
308 //else
309 //{
310 //Triangle tri3 = new Triangle(vt31, vt32, vt33);
311 // Wrap the last cell in the row around
312 //indices[i++] = (ushort)(y * x_max + x); //a
313 //indices[i++] = (ushort)(y * x_max + 0); //b
314 //indices[i++] = (ushort)((y + 1) * x_max + 0); //c
315 //Add(tri3);
316 // }
317 //}
318
319 //Vertex vt41 = sVertices[(y * x_max + x)];
320 //Vertex vt42 = sVertices[((y + 1) * x_max + 0)];
321 //Vertex vt43 = sVertices[((y + 1) * x_max + x)];
322 //if (vt41 != null && vt42 != null && vt43 != null)
323 //{
324 //if (vt41.Equals(vt42, 0.022f) || vt31.Equals(vt43, 0.022f) || vt32.Equals(vt43, 0.022f))
325 //{
326 //}
327 // else
328 // {
329 //Triangle tri4 = new Triangle(vt41, vt42, vt43);
330 //indices[i++] = (ushort)(y * x_max + x); //a
331 //indices[i++] = (ushort)((y + 1) * x_max + 0); //b
332 //indices[i++] = (ushort)((y + 1) * x_max + x); //c
333 //Add(tri4);
334 //}
335 //}
336 250
251 foreach (Face face in this.faces)
252 {
253 ViewerFace vf = new ViewerFace(0);
254 vf.v1 = this.coords[face.v1];
255 vf.v2 = this.coords[face.v2];
256 vf.v3 = this.coords[face.v3];
257
258 vf.n1 = this.normals[face.n1];
259 vf.n2 = this.normals[face.n2];
260 vf.n3 = this.normals[face.n3];
261
262 vf.uv1 = this.uvs[face.uv1];
263 vf.uv2 = this.uvs[face.uv2];
264 vf.uv3 = this.uvs[face.uv3];
265
266 this.viewerFaces.Add(vf);
267 }
337 } 268 }
338 } 269 }
270
271 public void AddRot(Quat q)
272 {
273 int i;
274 int numVerts = this.coords.Count;
275
276 for (i = 0; i < numVerts; i++)
277 this.coords[i] *= q;
278
279 if (this.viewerFaces != null)
280 {
281 int numViewerFaces = this.viewerFaces.Count;
282
283 for (i = 0; i < numViewerFaces; i++)
284 {
285 ViewerFace v = this.viewerFaces[i];
286 v.v1 *= q;
287 v.v2 *= q;
288 v.v3 *= q;
289
290 v.n1 *= q;
291 v.n2 *= q;
292 v.n3 *= q;
293
294 this.viewerFaces[i] = v;
295 }
296 }
297 }
298
299 public void Scale(float x, float y, float z)
300 {
301 int i;
302 int numVerts = this.coords.Count;
303 //Coord vert;
304
305 Coord m = new Coord(x, y, z);
306 for (i = 0; i < numVerts; i++)
307 this.coords[i] *= m;
308
309 if (this.viewerFaces != null)
310 {
311 int numViewerFaces = this.viewerFaces.Count;
312 for (i = 0; i < numViewerFaces; i++)
313 {
314 ViewerFace v = this.viewerFaces[i];
315 v.v1 *= m;
316 v.v2 *= m;
317 v.v3 *= m;
318 this.viewerFaces[i] = v;
319 }
320 }
321 }
322
323 public void DumpRaw(String path, String name, String title)
324 {
325 if (path == null)
326 return;
327 String fileName = name + "_" + title + ".raw";
328 String completePath = Path.Combine(path, fileName);
329 StreamWriter sw = new StreamWriter(completePath);
330
331 for (int i = 0; i < this.faces.Count; i++)
332 {
333 string s = this.coords[this.faces[i].v1].ToString();
334 s += " " + this.coords[this.faces[i].v2].ToString();
335 s += " " + this.coords[this.faces[i].v3].ToString();
336
337 sw.WriteLine(s);
338 }
339
340 sw.Close();
341 }
339 } 342 }
340} 343}