corrade-vassal – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 1 /* Copyright (c) 2008 Robert Adams
2 * Redistribution and use in source and binary forms, with or without
3 * modification, are permitted provided that the following conditions are met:
4 * * Redistributions of source code must retain the above copyright
5 * notice, this list of conditions and the following disclaimer.
6 * * Redistributions in binary form must reproduce the above copyright
7 * notice, this list of conditions and the following disclaimer in the
8 * documentation and/or other materials provided with the distribution.
9 * * The name of the copyright holder may not be used to endorse or promote products
10 * derived from this software without specific prior written permission.
11 *
12 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
13 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15 * DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
16 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
18 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
19 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
21 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22 */
23 /*
24 * Portions of this code are:
25 * Copyright (c) Contributors, http://idealistviewer.org
26 * The basic logic of the extrusion code is based on the Idealist viewer code.
27 * The Idealist viewer is licensed under the three clause BSD license.
28 */
29 /*
30 * MeshmerizerR class implments OpenMetaverse.Rendering.IRendering interface
31 * using PrimMesher (http://forge.opensimulator.org/projects/primmesher).
32 */
33  
34 using System;
35 using System.Collections.Generic;
36 using System.Drawing;
37 using System.Text;
38 using OMV = OpenMetaverse;
39 using OMVR = OpenMetaverse.Rendering;
40  
41 namespace OpenMetaverse.Rendering
42 {
43 /// <summary>
44 /// Meshing code based on the Idealist Viewer (20081213).
45 /// </summary>
46 [RendererName("MeshmerizerR")]
47 public class MeshmerizerR : OMVR.IRendering
48 {
49 /// <summary>
50 /// Generates a basic mesh structure from a primitive
51 /// </summary>
52 /// <param name="prim">Primitive to generate the mesh from</param>
53 /// <param name="lod">Level of detail to generate the mesh at</param>
54 /// <returns>The generated mesh or null on failure</returns>
55 public OMVR.SimpleMesh GenerateSimpleMesh(OMV.Primitive prim, OMVR.DetailLevel lod)
56 {
57 PrimMesher.PrimMesh newPrim = GeneratePrimMesh(prim, lod, false);
58 if (newPrim == null)
59 return null;
60  
61 SimpleMesh mesh = new SimpleMesh();
62 mesh.Path = new Path();
63 mesh.Prim = prim;
64 mesh.Profile = new Profile();
65 mesh.Vertices = new List<Vertex>(newPrim.coords.Count);
66 for (int i = 0; i < newPrim.coords.Count; i++)
67 {
68 PrimMesher.Coord c = newPrim.coords[i];
69 mesh.Vertices.Add(new Vertex { Position = new Vector3(c.X, c.Y, c.Z) });
70 }
71  
72 mesh.Indices = new List<ushort>(newPrim.faces.Count * 3);
73 for (int i = 0; i < newPrim.faces.Count; i++)
74 {
75 PrimMesher.Face face = newPrim.faces[i];
76 mesh.Indices.Add((ushort)face.v1);
77 mesh.Indices.Add((ushort)face.v2);
78 mesh.Indices.Add((ushort)face.v3);
79 }
80  
81 return mesh;
82 }
83  
84 /// <summary>
85 /// Generates a basic mesh structure from a sculpted primitive
86 /// </summary>
87 /// <param name="prim">Sculpted primitive to generate the mesh from</param>
88 /// <param name="sculptTexture">Sculpt texture</param>
89 /// <param name="lod">Level of detail to generate the mesh at</param>
90 /// <returns>The generated mesh or null on failure</returns>
91 public OMVR.SimpleMesh GenerateSimpleSculptMesh(OMV.Primitive prim, System.Drawing.Bitmap sculptTexture, OMVR.DetailLevel lod)
92 {
93 OMVR.FacetedMesh faceted = GenerateFacetedSculptMesh(prim, sculptTexture, lod);
94  
95 if (faceted != null && faceted.Faces.Count == 1)
96 {
97 Face face = faceted.Faces[0];
98  
99 SimpleMesh mesh = new SimpleMesh();
100 mesh.Indices = face.Indices;
101 mesh.Vertices = face.Vertices;
102 mesh.Path = faceted.Path;
103 mesh.Prim = prim;
104 mesh.Profile = faceted.Profile;
105 mesh.Vertices = face.Vertices;
106  
107 return mesh;
108 }
109  
110 return null;
111 }
112  
113 /// <summary>
114 /// Generates a a series of faces, each face containing a mesh and
115 /// metadata
116 /// </summary>
117 /// <param name="prim">Primitive to generate the mesh from</param>
118 /// <param name="lod">Level of detail to generate the mesh at</param>
119 /// <returns>The generated mesh</returns >
120 public OMVR.FacetedMesh GenerateFacetedMesh(OMV.Primitive prim, OMVR.DetailLevel lod)
121 {
122 bool isSphere = ((OMV.ProfileCurve)(prim.PrimData.profileCurve & 0x07) == OMV.ProfileCurve.HalfCircle);
123 PrimMesher.PrimMesh newPrim = GeneratePrimMesh(prim, lod, true);
124 if (newPrim == null)
125 return null;
126  
127 // copy the vertex information into OMVR.IRendering structures
128 OMVR.FacetedMesh omvrmesh = new OMVR.FacetedMesh();
129 omvrmesh.Faces = new List<OMVR.Face>();
130 omvrmesh.Prim = prim;
131 omvrmesh.Profile = new OMVR.Profile();
132 omvrmesh.Profile.Faces = new List<OMVR.ProfileFace>();
133 omvrmesh.Profile.Positions = new List<OMV.Vector3>();
134 omvrmesh.Path = new OMVR.Path();
135 omvrmesh.Path.Points = new List<OMVR.PathPoint>();
136 var indexer = newPrim.GetVertexIndexer();
137  
138 for (int i = 0; i < indexer.numPrimFaces; i++)
139 {
140 OMVR.Face oface = new OMVR.Face();
141 oface.Vertices = new List<OMVR.Vertex>();
142 oface.Indices = new List<ushort>();
143 oface.TextureFace = prim.Textures.GetFace((uint)i);
144  
145 for (int j = 0; j < indexer.viewerVertices[i].Count; j++)
146 {
147 var vert = new OMVR.Vertex();
148 var m = indexer.viewerVertices[i][j];
149 vert.Position = new Vector3(m.v.X, m.v.Y, m.v.Z);
150 vert.Normal = new Vector3(m.n.X, m.n.Y, m.n.Z);
151 vert.TexCoord = new OMV.Vector2(m.uv.U, 1.0f - m.uv.V);
152 oface.Vertices.Add(vert);
153 }
154  
155 for (int j = 0; j < indexer.viewerPolygons[i].Count; j++)
156 {
157 var p = indexer.viewerPolygons[i][j];
158 // Skip "degenerate faces" where the same vertex appears twice in the same tri
159 if (p.v1 == p.v2 || p.v1 == p.v2 || p.v2 == p.v3) continue;
160 oface.Indices.Add((ushort)p.v1);
161 oface.Indices.Add((ushort)p.v2);
162 oface.Indices.Add((ushort)p.v3);
163 }
164  
165 omvrmesh.Faces.Add(oface);
166 }
167  
168 return omvrmesh;
169 }
170  
171 /// <summary>
172 /// Create a sculpty faceted mesh. The actual scuplt texture is fetched and passed to this
173 /// routine since all the context for finding teh texture is elsewhere.
174 /// </summary>
175 /// <returns>The faceted mesh or null if can't do it</returns>
176 public OMVR.FacetedMesh GenerateFacetedSculptMesh(OMV.Primitive prim, System.Drawing.Bitmap scupltTexture, OMVR.DetailLevel lod)
177 {
178 PrimMesher.SculptMesh.SculptType smSculptType;
179 switch (prim.Sculpt.Type)
180 {
181 case OpenMetaverse.SculptType.Cylinder:
182 smSculptType = PrimMesher.SculptMesh.SculptType.cylinder;
183 break;
184 case OpenMetaverse.SculptType.Plane:
185 smSculptType = PrimMesher.SculptMesh.SculptType.plane;
186 break;
187 case OpenMetaverse.SculptType.Sphere:
188 smSculptType = PrimMesher.SculptMesh.SculptType.sphere;
189 break;
190 case OpenMetaverse.SculptType.Torus:
191 smSculptType = PrimMesher.SculptMesh.SculptType.torus;
192 break;
193 default:
194 smSculptType = PrimMesher.SculptMesh.SculptType.plane;
195 break;
196 }
197 // The lod for sculpties is the resolution of the texture passed.
198 // The first guess is 1:1 then lower resolutions after that
199 // int mesherLod = (int)Math.Sqrt(scupltTexture.Width * scupltTexture.Height);
200 int mesherLod = 32; // number used in Idealist viewer
201 switch (lod)
202 {
203 case OMVR.DetailLevel.Highest:
204 break;
205 case OMVR.DetailLevel.High:
206 break;
207 case OMVR.DetailLevel.Medium:
208 mesherLod /= 2;
209 break;
210 case OMVR.DetailLevel.Low:
211 mesherLod /= 4;
212 break;
213 }
214 PrimMesher.SculptMesh newMesh =
215 new PrimMesher.SculptMesh(scupltTexture, smSculptType, mesherLod, true, prim.Sculpt.Mirror, prim.Sculpt.Invert);
216  
217 int numPrimFaces = 1; // a scuplty has only one face
218  
219 // copy the vertex information into OMVR.IRendering structures
220 OMVR.FacetedMesh omvrmesh = new OMVR.FacetedMesh();
221 omvrmesh.Faces = new List<OMVR.Face>();
222 omvrmesh.Prim = prim;
223 omvrmesh.Profile = new OMVR.Profile();
224 omvrmesh.Profile.Faces = new List<OMVR.ProfileFace>();
225 omvrmesh.Profile.Positions = new List<OMV.Vector3>();
226 omvrmesh.Path = new OMVR.Path();
227 omvrmesh.Path.Points = new List<OMVR.PathPoint>();
228  
229 Dictionary<OMVR.Vertex, int> vertexAccount = new Dictionary<OMVR.Vertex, int>();
230  
231  
232 for (int ii = 0; ii < numPrimFaces; ii++)
233 {
234 vertexAccount.Clear();
235 OMVR.Face oface = new OMVR.Face();
236 oface.Vertices = new List<OMVR.Vertex>();
237 oface.Indices = new List<ushort>();
238 oface.TextureFace = prim.Textures.GetFace((uint)ii);
239 int faceVertices = newMesh.coords.Count;
240 OMVR.Vertex vert;
241  
242 for (int j = 0; j < faceVertices; j++)
243 {
244 vert = new OMVR.Vertex();
245 vert.Position = new Vector3(newMesh.coords[j].X, newMesh.coords[j].Y, newMesh.coords[j].Z);
246 vert.Normal = new Vector3(newMesh.normals[j].X, newMesh.normals[j].Y, newMesh.normals[j].Z);
247 vert.TexCoord = new Vector2(newMesh.uvs[j].U, newMesh.uvs[j].V);
248 oface.Vertices.Add(vert);
249 }
250  
251 for (int j = 0; j < newMesh.faces.Count; j++)
252 {
253 oface.Indices.Add((ushort)newMesh.faces[j].v1);
254 oface.Indices.Add((ushort)newMesh.faces[j].v2);
255 oface.Indices.Add((ushort)newMesh.faces[j].v3);
256 }
257  
258 if (faceVertices > 0)
259 {
260 oface.TextureFace = prim.Textures.FaceTextures[ii];
261 if (oface.TextureFace == null)
262 {
263 oface.TextureFace = prim.Textures.DefaultTexture;
264 }
265 oface.ID = ii;
266 omvrmesh.Faces.Add(oface);
267 }
268 }
269  
270 return omvrmesh;
271 }
272  
273 /// <summary>
274 /// Apply texture coordinate modifications from a
275 /// <seealso cref="TextureEntryFace"/> to a list of vertices
276 /// </summary>
277 /// <param name="vertices">Vertex list to modify texture coordinates for</param>
278 /// <param name="center">Center-point of the face</param>
279 /// <param name="teFace">Face texture parameters</param>
280 public void TransformTexCoords(List<OMVR.Vertex> vertices, OMV.Vector3 center, OMV.Primitive.TextureEntryFace teFace, Vector3 primScale)
281 {
282 // compute trig stuff up front
283 float cosineAngle = (float)Math.Cos(teFace.Rotation);
284 float sinAngle = (float)Math.Sin(teFace.Rotation);
285  
286 for (int ii = 0; ii < vertices.Count; ii++)
287 {
288 // tex coord comes to us as a number between zero and one
289 // transform about the center of the texture
290 OMVR.Vertex vert = vertices[ii];
291  
292 // aply planar tranforms to the UV first if applicable
293 if (teFace.TexMapType == MappingType.Planar)
294 {
295 Vector3 binormal;
296 float d = Vector3.Dot(vert.Normal, Vector3.UnitX);
297 if (d >= 0.5f || d <= -0.5f)
298 {
299 binormal = Vector3.UnitY;
300 if (vert.Normal.X < 0f) binormal *= -1;
301 }
302 else
303 {
304 binormal = Vector3.UnitX;
305 if (vert.Normal.Y > 0f) binormal *= -1;
306 }
307 Vector3 tangent = binormal % vert.Normal;
308 Vector3 scaledPos = vert.Position * primScale;
309 vert.TexCoord.X = 1f + (Vector3.Dot(binormal, scaledPos) * 2f - 0.5f);
310 vert.TexCoord.Y = -(Vector3.Dot(tangent, scaledPos) * 2f - 0.5f);
311 }
312  
313 float repeatU = teFace.RepeatU;
314 float repeatV = teFace.RepeatV;
315 float tX = vert.TexCoord.X - 0.5f;
316 float tY = vert.TexCoord.Y - 0.5f;
317  
318 vert.TexCoord.X = (tX * cosineAngle + tY * sinAngle) * repeatU + teFace.OffsetU + 0.5f;
319 vert.TexCoord.Y = (-tX * sinAngle + tY * cosineAngle) * repeatV + teFace.OffsetV + 0.5f;
320 vertices[ii] = vert;
321 }
322 return;
323 }
324  
325 private PrimMesher.PrimMesh GeneratePrimMesh(Primitive prim, DetailLevel lod, bool viewerMode)
326 {
327 OMV.Primitive.ConstructionData primData = prim.PrimData;
328 int sides = 4;
329 int hollowsides = 4;
330  
331 float profileBegin = primData.ProfileBegin;
332 float profileEnd = primData.ProfileEnd;
333  
334 bool isSphere = false;
335  
336 if ((OMV.ProfileCurve)(primData.profileCurve & 0x07) == OMV.ProfileCurve.Circle)
337 {
338 switch (lod)
339 {
340 case OMVR.DetailLevel.Low:
341 sides = 6;
342 break;
343 case OMVR.DetailLevel.Medium:
344 sides = 12;
345 break;
346 default:
347 sides = 24;
348 break;
349 }
350 }
351 else if ((OMV.ProfileCurve)(primData.profileCurve & 0x07) == OMV.ProfileCurve.EqualTriangle)
352 sides = 3;
353 else if ((OMV.ProfileCurve)(primData.profileCurve & 0x07) == OMV.ProfileCurve.HalfCircle)
354 {
355 // half circle, prim is a sphere
356 isSphere = true;
357 switch (lod)
358 {
359 case OMVR.DetailLevel.Low:
360 sides = 6;
361 break;
362 case OMVR.DetailLevel.Medium:
363 sides = 12;
364 break;
365 default:
366 sides = 24;
367 break;
368 }
369 profileBegin = 0.5f * profileBegin + 0.5f;
370 profileEnd = 0.5f * profileEnd + 0.5f;
371 }
372  
373 if ((OMV.HoleType)primData.ProfileHole == OMV.HoleType.Same)
374 hollowsides = sides;
375 else if ((OMV.HoleType)primData.ProfileHole == OMV.HoleType.Circle)
376 {
377 switch (lod)
378 {
379 case OMVR.DetailLevel.Low:
380 hollowsides = 6;
381 break;
382 case OMVR.DetailLevel.Medium:
383 hollowsides = 12;
384 break;
385 default:
386 hollowsides = 24;
387 break;
388 }
389 }
390 else if ((OMV.HoleType)primData.ProfileHole == OMV.HoleType.Triangle)
391 hollowsides = 3;
392  
393 PrimMesher.PrimMesh newPrim = new PrimMesher.PrimMesh(sides, profileBegin, profileEnd, (float)primData.ProfileHollow, hollowsides);
394 newPrim.viewerMode = viewerMode;
395 newPrim.sphereMode = isSphere;
396 newPrim.holeSizeX = primData.PathScaleX;
397 newPrim.holeSizeY = primData.PathScaleY;
398 newPrim.pathCutBegin = primData.PathBegin;
399 newPrim.pathCutEnd = primData.PathEnd;
400 newPrim.topShearX = primData.PathShearX;
401 newPrim.topShearY = primData.PathShearY;
402 newPrim.radius = primData.PathRadiusOffset;
403 newPrim.revolutions = primData.PathRevolutions;
404 newPrim.skew = primData.PathSkew;
405 switch (lod)
406 {
407 case OMVR.DetailLevel.Low:
408 newPrim.stepsPerRevolution = 6;
409 break;
410 case OMVR.DetailLevel.Medium:
411 newPrim.stepsPerRevolution = 12;
412 break;
413 default:
414 newPrim.stepsPerRevolution = 24;
415 break;
416 }
417  
418 if ((primData.PathCurve == OMV.PathCurve.Line) || (primData.PathCurve == OMV.PathCurve.Flexible))
419 {
420 newPrim.taperX = 1.0f - primData.PathScaleX;
421 newPrim.taperY = 1.0f - primData.PathScaleY;
422 newPrim.twistBegin = (int)(180 * primData.PathTwistBegin);
423 newPrim.twistEnd = (int)(180 * primData.PathTwist);
424 newPrim.ExtrudeLinear();
425 }
426 else
427 {
428 newPrim.taperX = primData.PathTaperX;
429 newPrim.taperY = primData.PathTaperY;
430 newPrim.twistBegin = (int)(360 * primData.PathTwistBegin);
431 newPrim.twistEnd = (int)(360 * primData.PathTwist);
432 newPrim.ExtrudeCircular();
433 }
434  
435 return newPrim;
436 }
437  
438 /// <summary>
439 /// Method for generating mesh Face from a heightmap
440 /// </summary>
441 /// <param name="zMap">Two dimension array of floats containing height information</param>
442 /// <param name="xBegin">Starting value for X</param>
443 /// <param name="xEnd">Max value for X</param>
444 /// <param name="yBegin">Starting value for Y</param>
445 /// <param name="yEnd">Max value of Y</param>
446 /// <returns></returns>
447 public OMVR.Face TerrainMesh(float[,] zMap, float xBegin, float xEnd, float yBegin, float yEnd)
448 {
449 PrimMesher.SculptMesh newMesh = new PrimMesher.SculptMesh(zMap, xBegin, xEnd, yBegin, yEnd, true);
450 OMVR.Face terrain = new OMVR.Face();
451 int faceVertices = newMesh.coords.Count;
452 terrain.Vertices = new List<Vertex>(faceVertices);
453 terrain.Indices = new List<ushort>(newMesh.faces.Count * 3);
454  
455 for (int j = 0; j < faceVertices; j++)
456 {
457 var vert = new OMVR.Vertex();
458 vert.Position = new Vector3(newMesh.coords[j].X, newMesh.coords[j].Y, newMesh.coords[j].Z);
459 vert.Normal = new Vector3(newMesh.normals[j].X, newMesh.normals[j].Y, newMesh.normals[j].Z);
460 vert.TexCoord = new Vector2(newMesh.uvs[j].U, newMesh.uvs[j].V);
461 terrain.Vertices.Add(vert);
462 }
463  
464 for (int j = 0; j < newMesh.faces.Count; j++)
465 {
466 terrain.Indices.Add((ushort)newMesh.faces[j].v1);
467 terrain.Indices.Add((ushort)newMesh.faces[j].v2);
468 terrain.Indices.Add((ushort)newMesh.faces[j].v3);
469 }
470  
471 return terrain;
472 }
473 }
474 }