aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/Meshing/SculptMesh.cs
diff options
context:
space:
mode:
authorDahlia Trimble2008-11-29 11:02:14 +0000
committerDahlia Trimble2008-11-29 11:02:14 +0000
commitfdd238833163eb947986bfcdd09da82f6949a5f2 (patch)
tree6b90177758405f6106f4f5d4d75e3b98bf08053c /OpenSim/Region/Physics/Meshing/SculptMesh.cs
parentComment the ScriptSponsor and restore the indefinite lifetime for (diff)
downloadopensim-SC-fdd238833163eb947986bfcdd09da82f6949a5f2.zip
opensim-SC-fdd238833163eb947986bfcdd09da82f6949a5f2.tar.gz
opensim-SC-fdd238833163eb947986bfcdd09da82f6949a5f2.tar.bz2
opensim-SC-fdd238833163eb947986bfcdd09da82f6949a5f2.tar.xz
Update meshing code to sync with current PrimMesher.cs on forge.
Migrate sculpt meshing code to primMesher version. This should result in more accurate physical sculpted prim proxies. Remove much obsolete code from Region/Physics/Meshing
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}