diff --git a/OpenMetaverse.Rendering.Meshmerizer/MeshmerizerR.cs b/OpenMetaverse.Rendering.Meshmerizer/MeshmerizerR.cs
index 6b76012d..d83a0471 100644
--- a/OpenMetaverse.Rendering.Meshmerizer/MeshmerizerR.cs
+++ b/OpenMetaverse.Rendering.Meshmerizer/MeshmerizerR.cs
@@ -1,518 +1,536 @@
-/* Copyright (c) 2008 Robert Adams
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * The name of the copyright holder may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-/*
- * Portions of this code are:
- * Copyright (c) Contributors, http://idealistviewer.org
- * The basic logic of the extrusion code is based on the Idealist viewer code.
- * The Idealist viewer is licensed under the three clause BSD license.
- */
-/*
- * MeshmerizerR class implments OpenMetaverse.Rendering.IRendering interface
- * using PrimMesher (http://forge.opensimulator.org/projects/primmesher).
- * There are a few additions/changes:
- * TransformTexCoords() does regular transformations but does not do planar
- * mapping of textures.
- */
-
-using System;
-using System.Collections.Generic;
-using System.Drawing;
-using System.Text;
-using OMV = OpenMetaverse;
-using OMVR = OpenMetaverse.Rendering;
-
-namespace OpenMetaverse.Rendering
-{
- ///
- /// Meshing code based on the Idealist Viewer (20081213).
- ///
- [RendererName("MeshmerizerR")]
- public class MeshmerizerR : OMVR.IRendering
- {
- ///
- /// Generates a basic mesh structure from a primitive
- ///
- /// Primitive to generate the mesh from
- /// Level of detail to generate the mesh at
- /// The generated mesh or null on failure
- public OMVR.SimpleMesh GenerateSimpleMesh(OMV.Primitive prim, OMVR.DetailLevel lod)
- {
- PrimMesher.PrimMesh newPrim = GeneratePrimMesh(prim, lod, false);
- if (newPrim == null)
- return null;
-
- SimpleMesh mesh = new SimpleMesh();
- mesh.Path = new Path();
- mesh.Prim = prim;
- mesh.Profile = new Profile();
- mesh.Vertices = new List(newPrim.coords.Count);
- for (int i = 0; i < newPrim.coords.Count; i++)
- {
- PrimMesher.Coord c = newPrim.coords[i];
- mesh.Vertices.Add(new Vertex { Position = new Vector3(c.X, c.Y, c.Z) });
- }
-
- mesh.Indices = new List(newPrim.faces.Count * 3);
- for (int i = 0; i < newPrim.faces.Count; i++)
- {
- PrimMesher.Face face = newPrim.faces[i];
- mesh.Indices.Add((ushort)face.v1);
- mesh.Indices.Add((ushort)face.v2);
- mesh.Indices.Add((ushort)face.v3);
- }
-
- return mesh;
- }
-
- ///
- /// Generates a basic mesh structure from a sculpted primitive
- ///
- /// Sculpted primitive to generate the mesh from
- /// Sculpt texture
- /// Level of detail to generate the mesh at
- /// The generated mesh or null on failure
- public OMVR.SimpleMesh GenerateSimpleSculptMesh(OMV.Primitive prim, System.Drawing.Bitmap sculptTexture, OMVR.DetailLevel lod)
- {
- OMVR.FacetedMesh faceted = GenerateFacetedSculptMesh(prim, sculptTexture, lod);
-
- if (faceted != null && faceted.Faces.Count == 1)
- {
- Face face = faceted.Faces[0];
-
- SimpleMesh mesh = new SimpleMesh();
- mesh.Indices = face.Indices;
- mesh.Vertices = face.Vertices;
- mesh.Path = faceted.Path;
- mesh.Prim = prim;
- mesh.Profile = faceted.Profile;
- mesh.Vertices = face.Vertices;
-
- return mesh;
- }
-
- return null;
- }
-
- ///
- /// Generates a a series of faces, each face containing a mesh and
- /// metadata
- ///
- /// Primitive to generate the mesh from
- /// Level of detail to generate the mesh at
- /// The generated mesh
- public OMVR.FacetedMesh GenerateFacetedMesh(OMV.Primitive prim, OMVR.DetailLevel lod)
- {
- bool isSphere = ((OMV.ProfileCurve)(prim.PrimData.profileCurve & 0x07) == OMV.ProfileCurve.HalfCircle);
- PrimMesher.PrimMesh newPrim = GeneratePrimMesh(prim, lod, true);
- if (newPrim == null)
- return null;
-
- int numViewerFaces = newPrim.viewerFaces.Count;
- int numPrimFaces = newPrim.numPrimFaces;
-
- for (uint i = 0; i < numViewerFaces; i++)
- {
- PrimMesher.ViewerFace vf = newPrim.viewerFaces[(int)i];
-
- if (isSphere)
- {
- vf.uv1.U = (vf.uv1.U - 0.5f) * 2.0f;
- vf.uv2.U = (vf.uv2.U - 0.5f) * 2.0f;
- vf.uv3.U = (vf.uv3.U - 0.5f) * 2.0f;
- }
- }
-
- // copy the vertex information into OMVR.IRendering structures
- OMVR.FacetedMesh omvrmesh = new OMVR.FacetedMesh();
- omvrmesh.Faces = new List();
- omvrmesh.Prim = prim;
- omvrmesh.Profile = new OMVR.Profile();
- omvrmesh.Profile.Faces = new List();
- omvrmesh.Profile.Positions = new List();
- omvrmesh.Path = new OMVR.Path();
- omvrmesh.Path.Points = new List();
-
- Dictionary vertexAccount = new Dictionary();
- for (int ii = 0; ii < numPrimFaces; ii++)
- {
- OMVR.Face oface = new OMVR.Face();
- oface.Vertices = new List();
- oface.Indices = new List();
- oface.TextureFace = prim.Textures.GetFace((uint)ii);
- int faceVertices = 0;
- vertexAccount.Clear();
- OMV.Vector3 pos;
- int indx;
- OMVR.Vertex vert;
- foreach (PrimMesher.ViewerFace vface in newPrim.viewerFaces)
- {
- if (vface.primFaceNumber == ii)
- {
- faceVertices++;
- pos = new OMV.Vector3(vface.v1.X, vface.v1.Y, vface.v1.Z);
- if (vertexAccount.ContainsKey(pos))
- {
- // we aleady have this vertex in the list. Just point the index at it
- oface.Indices.Add((ushort)vertexAccount[pos]);
- }
- else
- {
- // the vertex is not in the list. Add it and the new index.
- vert = new OMVR.Vertex();
- vert.Position = pos;
- vert.TexCoord = new OMV.Vector2(vface.uv1.U, 1.0f - vface.uv1.V);
- vert.Normal = new OMV.Vector3(vface.n1.X, vface.n1.Y, vface.n1.Z);
- oface.Vertices.Add(vert);
- indx = oface.Vertices.Count - 1;
- vertexAccount.Add(pos, indx);
- oface.Indices.Add((ushort)indx);
- }
-
- pos = new OMV.Vector3(vface.v2.X, vface.v2.Y, vface.v2.Z);
- if (vertexAccount.ContainsKey(pos))
- {
- oface.Indices.Add((ushort)vertexAccount[pos]);
- }
- else
- {
- vert = new OMVR.Vertex();
- vert.Position = pos;
- vert.TexCoord = new OMV.Vector2(vface.uv2.U, 1.0f - vface.uv2.V);
- vert.Normal = new OMV.Vector3(vface.n2.X, vface.n2.Y, vface.n2.Z);
- oface.Vertices.Add(vert);
- indx = oface.Vertices.Count - 1;
- vertexAccount.Add(pos, indx);
- oface.Indices.Add((ushort)indx);
- }
-
- pos = new OMV.Vector3(vface.v3.X, vface.v3.Y, vface.v3.Z);
- if (vertexAccount.ContainsKey(pos))
- {
- oface.Indices.Add((ushort)vertexAccount[pos]);
- }
- else
- {
- vert = new OMVR.Vertex();
- vert.Position = pos;
- vert.TexCoord = new OMV.Vector2(vface.uv3.U, 1.0f - vface.uv3.V);
- vert.Normal = new OMV.Vector3(vface.n3.X, vface.n3.Y, vface.n3.Z);
- oface.Vertices.Add(vert);
- indx = oface.Vertices.Count - 1;
- vertexAccount.Add(pos, indx);
- oface.Indices.Add((ushort)indx);
- }
- }
- }
- if (faceVertices > 0)
- {
- oface.TextureFace = prim.Textures.FaceTextures[ii];
- if (oface.TextureFace == null)
- {
- oface.TextureFace = prim.Textures.DefaultTexture;
- }
- oface.ID = ii;
- omvrmesh.Faces.Add(oface);
- }
- }
-
- return omvrmesh;
- }
-
- ///
- /// Create a sculpty faceted mesh. The actual scuplt texture is fetched and passed to this
- /// routine since all the context for finding teh texture is elsewhere.
- ///
- /// The faceted mesh or null if can't do it
- public OMVR.FacetedMesh GenerateFacetedSculptMesh(OMV.Primitive prim, System.Drawing.Bitmap scupltTexture, OMVR.DetailLevel lod)
- {
- PrimMesher.SculptMesh.SculptType smSculptType;
- switch (prim.Sculpt.Type)
- {
- case OpenMetaverse.SculptType.Cylinder:
- smSculptType = PrimMesher.SculptMesh.SculptType.cylinder;
- break;
- case OpenMetaverse.SculptType.Plane:
- smSculptType = PrimMesher.SculptMesh.SculptType.plane;
- break;
- case OpenMetaverse.SculptType.Sphere:
- smSculptType = PrimMesher.SculptMesh.SculptType.sphere;
- break;
- case OpenMetaverse.SculptType.Torus:
- smSculptType = PrimMesher.SculptMesh.SculptType.torus;
- break;
- default:
- smSculptType = PrimMesher.SculptMesh.SculptType.plane;
- break;
- }
- // The lod for sculpties is the resolution of the texture passed.
- // The first guess is 1:1 then lower resolutions after that
- // int mesherLod = (int)Math.Sqrt(scupltTexture.Width * scupltTexture.Height);
- int mesherLod = 32; // number used in Idealist viewer
- switch (lod)
- {
- case OMVR.DetailLevel.Highest:
- break;
- case OMVR.DetailLevel.High:
- break;
- case OMVR.DetailLevel.Medium:
- mesherLod /= 2;
- break;
- case OMVR.DetailLevel.Low:
- mesherLod /= 4;
- break;
- }
- PrimMesher.SculptMesh newMesh =
- new PrimMesher.SculptMesh(scupltTexture, smSculptType, mesherLod, true, prim.Sculpt.Mirror, prim.Sculpt.Invert);
-
- int numPrimFaces = 1; // a scuplty has only one face
-
- // copy the vertex information into OMVR.IRendering structures
- OMVR.FacetedMesh omvrmesh = new OMVR.FacetedMesh();
- omvrmesh.Faces = new List();
- omvrmesh.Prim = prim;
- omvrmesh.Profile = new OMVR.Profile();
- omvrmesh.Profile.Faces = new List();
- omvrmesh.Profile.Positions = new List();
- omvrmesh.Path = new OMVR.Path();
- omvrmesh.Path.Points = new List();
-
- Dictionary vertexAccount = new Dictionary();
-
-
- for (int ii = 0; ii < numPrimFaces; ii++)
- {
- vertexAccount.Clear();
- OMVR.Face oface = new OMVR.Face();
- oface.Vertices = new List();
- oface.Indices = new List();
- oface.TextureFace = prim.Textures.GetFace((uint)ii);
- int faceVertices = newMesh.coords.Count;
- OMVR.Vertex vert;
-
- for (int j = 0; j < faceVertices; j++)
- {
- vert = new OMVR.Vertex();
- vert.Position = new Vector3(newMesh.coords[j].X, newMesh.coords[j].Y, newMesh.coords[j].Z);
- vert.Normal = new Vector3(newMesh.normals[j].X, newMesh.normals[j].Y, newMesh.normals[j].Z);
- vert.TexCoord = new Vector2(newMesh.uvs[j].U, newMesh.uvs[j].V);
- oface.Vertices.Add(vert);
- }
-
- for (int j = 0; j < newMesh.faces.Count; j++)
- {
- oface.Indices.Add((ushort)newMesh.faces[j].v1);
- oface.Indices.Add((ushort)newMesh.faces[j].v2);
- oface.Indices.Add((ushort)newMesh.faces[j].v3);
- }
-
- if (faceVertices > 0)
- {
- oface.TextureFace = prim.Textures.FaceTextures[ii];
- if (oface.TextureFace == null)
- {
- oface.TextureFace = prim.Textures.DefaultTexture;
- }
- oface.ID = ii;
- omvrmesh.Faces.Add(oface);
- }
- }
-
- return omvrmesh;
- }
-
- ///
- /// Apply texture coordinate modifications from a
- /// to a list of vertices
- ///
- /// Vertex list to modify texture coordinates for
- /// Center-point of the face
- /// Face texture parameters
- public void TransformTexCoords(List vertices, OMV.Vector3 center, OMV.Primitive.TextureEntryFace teFace)
- {
- // compute trig stuff up front
- float cosineAngle = (float)Math.Cos(teFace.Rotation);
- float sinAngle = (float)Math.Sin(teFace.Rotation);
-
- // need a check for plainer vs default
- // just do default for now (I don't know what planar is)
- for (int ii = 0; ii < vertices.Count; ii++)
- {
- // tex coord comes to us as a number between zero and one
- // transform about the center of the texture
- OMVR.Vertex vert = vertices[ii];
- float tX = vert.TexCoord.X - 0.5f;
- float tY = vert.TexCoord.Y - 0.5f;
- // rotate, scale, offset
- vert.TexCoord.X = (tX * cosineAngle + tY * sinAngle) * teFace.RepeatU + teFace.OffsetU + 0.5f;
- vert.TexCoord.Y = (-tX * sinAngle + tY * cosineAngle) * teFace.RepeatV + teFace.OffsetV + 0.5f;
- vertices[ii] = vert;
- }
- return;
- }
-
- private PrimMesher.PrimMesh GeneratePrimMesh(Primitive prim, DetailLevel lod, bool viewerMode)
- {
- OMV.Primitive.ConstructionData primData = prim.PrimData;
- int sides = 4;
- int hollowsides = 4;
-
- float profileBegin = primData.ProfileBegin;
- float profileEnd = primData.ProfileEnd;
-
- if ((OMV.ProfileCurve)(primData.profileCurve & 0x07) == OMV.ProfileCurve.Circle)
- {
- switch (lod)
- {
- case OMVR.DetailLevel.Low:
- sides = 6;
- break;
- case OMVR.DetailLevel.Medium:
- sides = 12;
- break;
- default:
- sides = 24;
- break;
- }
- }
- else if ((OMV.ProfileCurve)(primData.profileCurve & 0x07) == OMV.ProfileCurve.EqualTriangle)
- sides = 3;
- else if ((OMV.ProfileCurve)(primData.profileCurve & 0x07) == OMV.ProfileCurve.HalfCircle)
- {
- // half circle, prim is a sphere
- switch (lod)
- {
- case OMVR.DetailLevel.Low:
- sides = 6;
- break;
- case OMVR.DetailLevel.Medium:
- sides = 12;
- break;
- default:
- sides = 24;
- break;
- }
- profileBegin = 0.5f * profileBegin + 0.5f;
- profileEnd = 0.5f * profileEnd + 0.5f;
- }
-
- if ((OMV.HoleType)primData.ProfileHole == OMV.HoleType.Same)
- hollowsides = sides;
- else if ((OMV.HoleType)primData.ProfileHole == OMV.HoleType.Circle)
- {
- switch (lod)
- {
- case OMVR.DetailLevel.Low:
- hollowsides = 6;
- break;
- case OMVR.DetailLevel.Medium:
- hollowsides = 12;
- break;
- default:
- hollowsides = 24;
- break;
- }
- }
- else if ((OMV.HoleType)primData.ProfileHole == OMV.HoleType.Triangle)
- hollowsides = 3;
-
- PrimMesher.PrimMesh newPrim = new PrimMesher.PrimMesh(sides, profileBegin, profileEnd, (float)primData.ProfileHollow, hollowsides);
- newPrim.viewerMode = viewerMode;
- newPrim.holeSizeX = primData.PathScaleX;
- newPrim.holeSizeY = primData.PathScaleY;
- newPrim.pathCutBegin = primData.PathBegin;
- newPrim.pathCutEnd = primData.PathEnd;
- newPrim.topShearX = primData.PathShearX;
- newPrim.topShearY = primData.PathShearY;
- newPrim.radius = primData.PathRadiusOffset;
- newPrim.revolutions = primData.PathRevolutions;
- newPrim.skew = primData.PathSkew;
- switch (lod)
- {
- case OMVR.DetailLevel.Low:
- newPrim.stepsPerRevolution = 6;
- break;
- case OMVR.DetailLevel.Medium:
- newPrim.stepsPerRevolution = 12;
- break;
- default:
- newPrim.stepsPerRevolution = 24;
- break;
- }
-
- if ((primData.PathCurve == OMV.PathCurve.Line) || (primData.PathCurve == OMV.PathCurve.Flexible))
- {
- newPrim.taperX = 1.0f - primData.PathScaleX;
- newPrim.taperY = 1.0f - primData.PathScaleY;
- newPrim.twistBegin = (int)(180 * primData.PathTwistBegin);
- newPrim.twistEnd = (int)(180 * primData.PathTwist);
- newPrim.ExtrudeLinear();
- }
- else
- {
- newPrim.taperX = primData.PathTaperX;
- newPrim.taperY = primData.PathTaperY;
- newPrim.twistBegin = (int)(360 * primData.PathTwistBegin);
- newPrim.twistEnd = (int)(360 * primData.PathTwist);
- newPrim.ExtrudeCircular();
- }
-
- return newPrim;
- }
-
- ///
- /// Method for generating mesh Face from a heightmap
- ///
- /// Two dimension array of floats containing height information
- /// Starting value for X
- /// Max value for X
- /// Starting value for Y
- /// Max value of Y
- ///
- public OMVR.Face TerrainMesh(float[,] zMap, float xBegin, float xEnd, float yBegin, float yEnd)
- {
- PrimMesher.SculptMesh newMesh = new PrimMesher.SculptMesh(zMap, xBegin, xEnd, yBegin, yEnd, true);
- OMVR.Face terrain = new OMVR.Face();
- int faceVertices = newMesh.coords.Count;
- terrain.Vertices = new List(faceVertices);
- terrain.Indices = new List(newMesh.faces.Count * 3);
-
- for (int j = 0; j < faceVertices; j++)
- {
- var vert = new OMVR.Vertex();
- vert.Position = new Vector3(newMesh.coords[j].X, newMesh.coords[j].Y, newMesh.coords[j].Z);
- vert.Normal = new Vector3(newMesh.normals[j].X, newMesh.normals[j].Y, newMesh.normals[j].Z);
- vert.TexCoord = new Vector2(newMesh.uvs[j].U, newMesh.uvs[j].V);
- terrain.Vertices.Add(vert);
- }
-
- for (int j = 0; j < newMesh.faces.Count; j++)
- {
- terrain.Indices.Add((ushort)newMesh.faces[j].v1);
- terrain.Indices.Add((ushort)newMesh.faces[j].v2);
- terrain.Indices.Add((ushort)newMesh.faces[j].v3);
- }
-
- return terrain;
- }
- }
-}
+/* Copyright (c) 2008 Robert Adams
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * The name of the copyright holder may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Portions of this code are:
+ * Copyright (c) Contributors, http://idealistviewer.org
+ * The basic logic of the extrusion code is based on the Idealist viewer code.
+ * The Idealist viewer is licensed under the three clause BSD license.
+ */
+/*
+ * MeshmerizerR class implments OpenMetaverse.Rendering.IRendering interface
+ * using PrimMesher (http://forge.opensimulator.org/projects/primmesher).
+ * There are a few additions/changes:
+ * TransformTexCoords() does regular transformations but does not do planar
+ * mapping of textures.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Text;
+using OMV = OpenMetaverse;
+using OMVR = OpenMetaverse.Rendering;
+
+namespace OpenMetaverse.Rendering
+{
+ ///
+ /// Meshing code based on the Idealist Viewer (20081213).
+ ///
+ [RendererName("MeshmerizerR")]
+ public class MeshmerizerR : OMVR.IRendering
+ {
+ ///
+ /// Generates a basic mesh structure from a primitive
+ ///
+ /// Primitive to generate the mesh from
+ /// Level of detail to generate the mesh at
+ /// The generated mesh or null on failure
+ public OMVR.SimpleMesh GenerateSimpleMesh(OMV.Primitive prim, OMVR.DetailLevel lod)
+ {
+ PrimMesher.PrimMesh newPrim = GeneratePrimMesh(prim, lod, false);
+ if (newPrim == null)
+ return null;
+
+ SimpleMesh mesh = new SimpleMesh();
+ mesh.Path = new Path();
+ mesh.Prim = prim;
+ mesh.Profile = new Profile();
+ mesh.Vertices = new List(newPrim.coords.Count);
+ for (int i = 0; i < newPrim.coords.Count; i++)
+ {
+ PrimMesher.Coord c = newPrim.coords[i];
+ mesh.Vertices.Add(new Vertex { Position = new Vector3(c.X, c.Y, c.Z) });
+ }
+
+ mesh.Indices = new List(newPrim.faces.Count * 3);
+ for (int i = 0; i < newPrim.faces.Count; i++)
+ {
+ PrimMesher.Face face = newPrim.faces[i];
+ mesh.Indices.Add((ushort)face.v1);
+ mesh.Indices.Add((ushort)face.v2);
+ mesh.Indices.Add((ushort)face.v3);
+ }
+
+ return mesh;
+ }
+
+ ///
+ /// Generates a basic mesh structure from a sculpted primitive
+ ///
+ /// Sculpted primitive to generate the mesh from
+ /// Sculpt texture
+ /// Level of detail to generate the mesh at
+ /// The generated mesh or null on failure
+ public OMVR.SimpleMesh GenerateSimpleSculptMesh(OMV.Primitive prim, System.Drawing.Bitmap sculptTexture, OMVR.DetailLevel lod)
+ {
+ OMVR.FacetedMesh faceted = GenerateFacetedSculptMesh(prim, sculptTexture, lod);
+
+ if (faceted != null && faceted.Faces.Count == 1)
+ {
+ Face face = faceted.Faces[0];
+
+ SimpleMesh mesh = new SimpleMesh();
+ mesh.Indices = face.Indices;
+ mesh.Vertices = face.Vertices;
+ mesh.Path = faceted.Path;
+ mesh.Prim = prim;
+ mesh.Profile = faceted.Profile;
+ mesh.Vertices = face.Vertices;
+
+ return mesh;
+ }
+
+ return null;
+ }
+
+ ///
+ /// Generates a a series of faces, each face containing a mesh and
+ /// metadata
+ ///
+ /// Primitive to generate the mesh from
+ /// Level of detail to generate the mesh at
+ /// The generated mesh
+ public OMVR.FacetedMesh GenerateFacetedMesh(OMV.Primitive prim, OMVR.DetailLevel lod)
+ {
+ bool isSphere = ((OMV.ProfileCurve)(prim.PrimData.profileCurve & 0x07) == OMV.ProfileCurve.HalfCircle);
+ PrimMesher.PrimMesh newPrim = GeneratePrimMesh(prim, lod, true);
+ if (newPrim == null)
+ return null;
+
+ int numViewerFaces = newPrim.viewerFaces.Count;
+ int numPrimFaces = newPrim.numPrimFaces;
+
+ for (uint i = 0; i < numViewerFaces; i++)
+ {
+ PrimMesher.ViewerFace vf = newPrim.viewerFaces[(int)i];
+
+ if (isSphere)
+ {
+ vf.uv1.U = (vf.uv1.U - 0.5f) * 2.0f;
+ vf.uv2.U = (vf.uv2.U - 0.5f) * 2.0f;
+ vf.uv3.U = (vf.uv3.U - 0.5f) * 2.0f;
+ }
+ }
+
+ // copy the vertex information into OMVR.IRendering structures
+ OMVR.FacetedMesh omvrmesh = new OMVR.FacetedMesh();
+ omvrmesh.Faces = new List();
+ omvrmesh.Prim = prim;
+ omvrmesh.Profile = new OMVR.Profile();
+ omvrmesh.Profile.Faces = new List();
+ omvrmesh.Profile.Positions = new List();
+ omvrmesh.Path = new OMVR.Path();
+ omvrmesh.Path.Points = new List();
+
+ Dictionary vertexAccount = new Dictionary();
+ for (int ii = 0; ii < numPrimFaces; ii++)
+ {
+ OMVR.Face oface = new OMVR.Face();
+ oface.Vertices = new List();
+ oface.Indices = new List();
+ oface.TextureFace = prim.Textures.GetFace((uint)ii);
+ int faceVertices = 0;
+ vertexAccount.Clear();
+ OMV.Vector3 pos;
+ int indx;
+ OMVR.Vertex vert;
+ foreach (PrimMesher.ViewerFace vface in newPrim.viewerFaces)
+ {
+ if (vface.primFaceNumber == ii)
+ {
+ faceVertices++;
+ pos = new OMV.Vector3(vface.v1.X, vface.v1.Y, vface.v1.Z);
+ if (vertexAccount.ContainsKey(pos))
+ {
+ // we aleady have this vertex in the list. Just point the index at it
+ oface.Indices.Add((ushort)vertexAccount[pos]);
+ }
+ else
+ {
+ // the vertex is not in the list. Add it and the new index.
+ vert = new OMVR.Vertex();
+ vert.Position = pos;
+ vert.TexCoord = new OMV.Vector2(vface.uv1.U, 1.0f - vface.uv1.V);
+ vert.Normal = new OMV.Vector3(vface.n1.X, vface.n1.Y, vface.n1.Z);
+ oface.Vertices.Add(vert);
+ indx = oface.Vertices.Count - 1;
+ vertexAccount.Add(pos, indx);
+ oface.Indices.Add((ushort)indx);
+ }
+
+ pos = new OMV.Vector3(vface.v2.X, vface.v2.Y, vface.v2.Z);
+ if (vertexAccount.ContainsKey(pos))
+ {
+ oface.Indices.Add((ushort)vertexAccount[pos]);
+ }
+ else
+ {
+ vert = new OMVR.Vertex();
+ vert.Position = pos;
+ vert.TexCoord = new OMV.Vector2(vface.uv2.U, 1.0f - vface.uv2.V);
+ vert.Normal = new OMV.Vector3(vface.n2.X, vface.n2.Y, vface.n2.Z);
+ oface.Vertices.Add(vert);
+ indx = oface.Vertices.Count - 1;
+ vertexAccount.Add(pos, indx);
+ oface.Indices.Add((ushort)indx);
+ }
+
+ pos = new OMV.Vector3(vface.v3.X, vface.v3.Y, vface.v3.Z);
+ if (vertexAccount.ContainsKey(pos))
+ {
+ oface.Indices.Add((ushort)vertexAccount[pos]);
+ }
+ else
+ {
+ vert = new OMVR.Vertex();
+ vert.Position = pos;
+ vert.TexCoord = new OMV.Vector2(vface.uv3.U, 1.0f - vface.uv3.V);
+ vert.Normal = new OMV.Vector3(vface.n3.X, vface.n3.Y, vface.n3.Z);
+ oface.Vertices.Add(vert);
+ indx = oface.Vertices.Count - 1;
+ vertexAccount.Add(pos, indx);
+ oface.Indices.Add((ushort)indx);
+ }
+ }
+ }
+ if (faceVertices > 0)
+ {
+ oface.TextureFace = prim.Textures.FaceTextures[ii];
+ if (oface.TextureFace == null)
+ {
+ oface.TextureFace = prim.Textures.DefaultTexture;
+ }
+ oface.ID = ii;
+ omvrmesh.Faces.Add(oface);
+ }
+ }
+
+ return omvrmesh;
+ }
+
+ ///
+ /// Create a sculpty faceted mesh. The actual scuplt texture is fetched and passed to this
+ /// routine since all the context for finding teh texture is elsewhere.
+ ///
+ /// The faceted mesh or null if can't do it
+ public OMVR.FacetedMesh GenerateFacetedSculptMesh(OMV.Primitive prim, System.Drawing.Bitmap scupltTexture, OMVR.DetailLevel lod)
+ {
+ PrimMesher.SculptMesh.SculptType smSculptType;
+ switch (prim.Sculpt.Type)
+ {
+ case OpenMetaverse.SculptType.Cylinder:
+ smSculptType = PrimMesher.SculptMesh.SculptType.cylinder;
+ break;
+ case OpenMetaverse.SculptType.Plane:
+ smSculptType = PrimMesher.SculptMesh.SculptType.plane;
+ break;
+ case OpenMetaverse.SculptType.Sphere:
+ smSculptType = PrimMesher.SculptMesh.SculptType.sphere;
+ break;
+ case OpenMetaverse.SculptType.Torus:
+ smSculptType = PrimMesher.SculptMesh.SculptType.torus;
+ break;
+ default:
+ smSculptType = PrimMesher.SculptMesh.SculptType.plane;
+ break;
+ }
+ // The lod for sculpties is the resolution of the texture passed.
+ // The first guess is 1:1 then lower resolutions after that
+ // int mesherLod = (int)Math.Sqrt(scupltTexture.Width * scupltTexture.Height);
+ int mesherLod = 32; // number used in Idealist viewer
+ switch (lod)
+ {
+ case OMVR.DetailLevel.Highest:
+ break;
+ case OMVR.DetailLevel.High:
+ break;
+ case OMVR.DetailLevel.Medium:
+ mesherLod /= 2;
+ break;
+ case OMVR.DetailLevel.Low:
+ mesherLod /= 4;
+ break;
+ }
+ PrimMesher.SculptMesh newMesh =
+ new PrimMesher.SculptMesh(scupltTexture, smSculptType, mesherLod, true, prim.Sculpt.Mirror, prim.Sculpt.Invert);
+
+ int numPrimFaces = 1; // a scuplty has only one face
+
+ // copy the vertex information into OMVR.IRendering structures
+ OMVR.FacetedMesh omvrmesh = new OMVR.FacetedMesh();
+ omvrmesh.Faces = new List();
+ omvrmesh.Prim = prim;
+ omvrmesh.Profile = new OMVR.Profile();
+ omvrmesh.Profile.Faces = new List();
+ omvrmesh.Profile.Positions = new List();
+ omvrmesh.Path = new OMVR.Path();
+ omvrmesh.Path.Points = new List();
+
+ Dictionary vertexAccount = new Dictionary();
+
+
+ for (int ii = 0; ii < numPrimFaces; ii++)
+ {
+ vertexAccount.Clear();
+ OMVR.Face oface = new OMVR.Face();
+ oface.Vertices = new List();
+ oface.Indices = new List();
+ oface.TextureFace = prim.Textures.GetFace((uint)ii);
+ int faceVertices = newMesh.coords.Count;
+ OMVR.Vertex vert;
+
+ for (int j = 0; j < faceVertices; j++)
+ {
+ vert = new OMVR.Vertex();
+ vert.Position = new Vector3(newMesh.coords[j].X, newMesh.coords[j].Y, newMesh.coords[j].Z);
+ vert.Normal = new Vector3(newMesh.normals[j].X, newMesh.normals[j].Y, newMesh.normals[j].Z);
+ vert.TexCoord = new Vector2(newMesh.uvs[j].U, newMesh.uvs[j].V);
+ oface.Vertices.Add(vert);
+ }
+
+ for (int j = 0; j < newMesh.faces.Count; j++)
+ {
+ oface.Indices.Add((ushort)newMesh.faces[j].v1);
+ oface.Indices.Add((ushort)newMesh.faces[j].v2);
+ oface.Indices.Add((ushort)newMesh.faces[j].v3);
+ }
+
+ if (faceVertices > 0)
+ {
+ oface.TextureFace = prim.Textures.FaceTextures[ii];
+ if (oface.TextureFace == null)
+ {
+ oface.TextureFace = prim.Textures.DefaultTexture;
+ }
+ oface.ID = ii;
+ omvrmesh.Faces.Add(oface);
+ }
+ }
+
+ return omvrmesh;
+ }
+
+ ///
+ /// Apply texture coordinate modifications from a
+ /// to a list of vertices
+ ///
+ /// Vertex list to modify texture coordinates for
+ /// Center-point of the face
+ /// Face texture parameters
+ public void TransformTexCoords(List vertices, OMV.Vector3 center, OMV.Primitive.TextureEntryFace teFace, Vector3 primScale)
+ {
+ // compute trig stuff up front
+ float cosineAngle = (float)Math.Cos(teFace.Rotation);
+ float sinAngle = (float)Math.Sin(teFace.Rotation);
+
+ // need a check for plainer vs default
+ // just do default for now (I don't know what planar is)
+ for (int ii = 0; ii < vertices.Count; ii++)
+ {
+ // tex coord comes to us as a number between zero and one
+ // transform about the center of the texture
+ OMVR.Vertex vert = vertices[ii];
+ float tX = vert.TexCoord.X - 0.5f;
+ float tY = vert.TexCoord.Y - 0.5f;
+ float repeatU = teFace.RepeatU;
+ float repeatV = teFace.RepeatV;
+ if (teFace.TexMapType == MappingType.Planar)
+ {
+ Vector3 scale = primScale;
+ Vector3 normal = vert.Normal;
+ //Dunno...
+ if(normal.X < 0)
+ normal.X *= -1;
+ if (normal.Y < 0)
+ normal.Y *= -1;
+ //Get the diff between the normal and the 'up', then fix the scale
+ Quaternion rot = Vector3.RotationBetween (new Vector3 (0, 0, 1), normal);
+ scale *= rot;
+ //Viewer sends /2 appearently
+ repeatU = (teFace.RepeatU * 2) * (scale.Y);
+ repeatV = (teFace.RepeatV * 2) * (scale.X);
+ }
+ // rotate, scale, offset
+ vert.TexCoord.X = (tX * cosineAngle + tY * sinAngle) * repeatU + teFace.OffsetU + 0.5f;
+ vert.TexCoord.Y = (-tX * sinAngle + tY * cosineAngle) * repeatV + teFace.OffsetV + 0.5f;
+ vertices[ii] = vert;
+ }
+ return;
+ }
+
+ private PrimMesher.PrimMesh GeneratePrimMesh(Primitive prim, DetailLevel lod, bool viewerMode)
+ {
+ OMV.Primitive.ConstructionData primData = prim.PrimData;
+ int sides = 4;
+ int hollowsides = 4;
+
+ float profileBegin = primData.ProfileBegin;
+ float profileEnd = primData.ProfileEnd;
+
+ if ((OMV.ProfileCurve)(primData.profileCurve & 0x07) == OMV.ProfileCurve.Circle)
+ {
+ switch (lod)
+ {
+ case OMVR.DetailLevel.Low:
+ sides = 6;
+ break;
+ case OMVR.DetailLevel.Medium:
+ sides = 12;
+ break;
+ default:
+ sides = 24;
+ break;
+ }
+ }
+ else if ((OMV.ProfileCurve)(primData.profileCurve & 0x07) == OMV.ProfileCurve.EqualTriangle)
+ sides = 3;
+ else if ((OMV.ProfileCurve)(primData.profileCurve & 0x07) == OMV.ProfileCurve.HalfCircle)
+ {
+ // half circle, prim is a sphere
+ switch (lod)
+ {
+ case OMVR.DetailLevel.Low:
+ sides = 6;
+ break;
+ case OMVR.DetailLevel.Medium:
+ sides = 12;
+ break;
+ default:
+ sides = 24;
+ break;
+ }
+ profileBegin = 0.5f * profileBegin + 0.5f;
+ profileEnd = 0.5f * profileEnd + 0.5f;
+ }
+
+ if ((OMV.HoleType)primData.ProfileHole == OMV.HoleType.Same)
+ hollowsides = sides;
+ else if ((OMV.HoleType)primData.ProfileHole == OMV.HoleType.Circle)
+ {
+ switch (lod)
+ {
+ case OMVR.DetailLevel.Low:
+ hollowsides = 6;
+ break;
+ case OMVR.DetailLevel.Medium:
+ hollowsides = 12;
+ break;
+ default:
+ hollowsides = 24;
+ break;
+ }
+ }
+ else if ((OMV.HoleType)primData.ProfileHole == OMV.HoleType.Triangle)
+ hollowsides = 3;
+
+ PrimMesher.PrimMesh newPrim = new PrimMesher.PrimMesh(sides, profileBegin, profileEnd, (float)primData.ProfileHollow, hollowsides);
+ newPrim.viewerMode = viewerMode;
+ newPrim.holeSizeX = primData.PathScaleX;
+ newPrim.holeSizeY = primData.PathScaleY;
+ newPrim.pathCutBegin = primData.PathBegin;
+ newPrim.pathCutEnd = primData.PathEnd;
+ newPrim.topShearX = primData.PathShearX;
+ newPrim.topShearY = primData.PathShearY;
+ newPrim.radius = primData.PathRadiusOffset;
+ newPrim.revolutions = primData.PathRevolutions;
+ newPrim.skew = primData.PathSkew;
+ switch (lod)
+ {
+ case OMVR.DetailLevel.Low:
+ newPrim.stepsPerRevolution = 6;
+ break;
+ case OMVR.DetailLevel.Medium:
+ newPrim.stepsPerRevolution = 12;
+ break;
+ default:
+ newPrim.stepsPerRevolution = 24;
+ break;
+ }
+
+ if ((primData.PathCurve == OMV.PathCurve.Line) || (primData.PathCurve == OMV.PathCurve.Flexible))
+ {
+ newPrim.taperX = 1.0f - primData.PathScaleX;
+ newPrim.taperY = 1.0f - primData.PathScaleY;
+ newPrim.twistBegin = (int)(180 * primData.PathTwistBegin);
+ newPrim.twistEnd = (int)(180 * primData.PathTwist);
+ newPrim.ExtrudeLinear();
+ }
+ else
+ {
+ newPrim.taperX = primData.PathTaperX;
+ newPrim.taperY = primData.PathTaperY;
+ newPrim.twistBegin = (int)(360 * primData.PathTwistBegin);
+ newPrim.twistEnd = (int)(360 * primData.PathTwist);
+ newPrim.ExtrudeCircular();
+ }
+
+ return newPrim;
+ }
+
+ ///
+ /// Method for generating mesh Face from a heightmap
+ ///
+ /// Two dimension array of floats containing height information
+ /// Starting value for X
+ /// Max value for X
+ /// Starting value for Y
+ /// Max value of Y
+ ///
+ public OMVR.Face TerrainMesh(float[,] zMap, float xBegin, float xEnd, float yBegin, float yEnd)
+ {
+ PrimMesher.SculptMesh newMesh = new PrimMesher.SculptMesh(zMap, xBegin, xEnd, yBegin, yEnd, true);
+ OMVR.Face terrain = new OMVR.Face();
+ int faceVertices = newMesh.coords.Count;
+ terrain.Vertices = new List(faceVertices);
+ terrain.Indices = new List(newMesh.faces.Count * 3);
+
+ for (int j = 0; j < faceVertices; j++)
+ {
+ var vert = new OMVR.Vertex();
+ vert.Position = new Vector3(newMesh.coords[j].X, newMesh.coords[j].Y, newMesh.coords[j].Z);
+ vert.Normal = new Vector3(newMesh.normals[j].X, newMesh.normals[j].Y, newMesh.normals[j].Z);
+ vert.TexCoord = new Vector2(newMesh.uvs[j].U, newMesh.uvs[j].V);
+ terrain.Vertices.Add(vert);
+ }
+
+ for (int j = 0; j < newMesh.faces.Count; j++)
+ {
+ terrain.Indices.Add((ushort)newMesh.faces[j].v1);
+ terrain.Indices.Add((ushort)newMesh.faces[j].v2);
+ terrain.Indices.Add((ushort)newMesh.faces[j].v3);
+ }
+
+ return terrain;
+ }
+ }
+}
diff --git a/OpenMetaverse.Rendering.Simple/SimpleRenderer.cs b/OpenMetaverse.Rendering.Simple/SimpleRenderer.cs
index 5746f5ec..a5b1470b 100644
--- a/OpenMetaverse.Rendering.Simple/SimpleRenderer.cs
+++ b/OpenMetaverse.Rendering.Simple/SimpleRenderer.cs
@@ -1,158 +1,158 @@
-/*
- * Copyright (c) 2008, openmetaverse.org
- * All rights reserved.
- *
- * - Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * - Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- * - Neither the name of the openmetaverse.org nor the names
- * of its contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-using System;
-using System.Collections.Generic;
-
-namespace OpenMetaverse.Rendering
-{
- [RendererName("Simple Cube Renderer")]
- public class SimpleRenderer : IRendering
- {
- public SimpleMesh GenerateSimpleMesh(Primitive prim, DetailLevel lod)
- {
- Path path = GeneratePath();
- Profile profile = GenerateProfile();
-
- SimpleMesh mesh = new SimpleMesh();
- mesh.Prim = prim;
- mesh.Path = path;
- mesh.Profile = profile;
- mesh.Vertices = GenerateVertices();
- mesh.Indices = GenerateIndices();
-
- return mesh;
- }
-
- public SimpleMesh GenerateSimpleSculptMesh(Primitive prim, System.Drawing.Bitmap sculptTexture, DetailLevel lod)
- {
- return GenerateSimpleMesh(prim, lod);
- }
-
- public FacetedMesh GenerateFacetedMesh(Primitive prim, DetailLevel lod)
- {
- Path path = GeneratePath();
- Profile profile = GenerateProfile();
-
- FacetedMesh mesh = new FacetedMesh();
- mesh.Prim = prim;
- mesh.Path = path;
- mesh.Profile = profile;
- mesh.Faces = GenerateFaces(prim.Textures);
-
- return mesh;
- }
-
- public FacetedMesh GenerateFacetedSculptMesh(Primitive prim, System.Drawing.Bitmap sculptTexture, DetailLevel lod)
- {
- return GenerateFacetedMesh(prim, lod);
- }
-
- public void TransformTexCoords(List vertices, Vector3 center, Primitive.TextureEntryFace teFace)
- {
- // Lalala...
- }
-
- private Path GeneratePath()
- {
- Path path = new Path();
- path.Points = new List();
- return path;
- }
-
- private Profile GenerateProfile()
- {
- Profile profile = new Profile();
- profile.Faces = new List();
- profile.Positions = new List();
- return profile;
- }
-
- private List GenerateVertices()
- {
- List vertices = new List(8);
-
- Vertex v = new Vertex();
-
- // FIXME: Implement these
- v.Normal = Vector3.Zero;
- v.TexCoord = Vector2.Zero;
-
- v.Position = new Vector3(0.5f, 0.5f, -0.5f);
- vertices.Add(v);
- v.Position = new Vector3(0.5f, -0.5f, -0.5f);
- vertices.Add(v);
- v.Position = new Vector3(-0.5f, -0.5f, -0.5f);
- vertices.Add(v);
- v.Position = new Vector3(-0.5f, 0.5f, -0.5f);
- vertices.Add(v);
- v.Position = new Vector3(0.5f, 0.5f, 0.5f);
- vertices.Add(v);
- v.Position = new Vector3(0.5f, -0.5f, 0.5f);
- vertices.Add(v);
- v.Position = new Vector3(-0.5f, -0.5f, 0.5f);
- vertices.Add(v);
- v.Position = new Vector3(-0.5f, 0.5f, 0.5f);
- vertices.Add(v);
-
- return vertices;
- }
-
- private List GenerateIndices()
- {
- ushort[] indices = new ushort[] {
- 0, 1, 2,
- 0, 2, 3,
- 4, 7, 6,
- 4, 6, 5,
- 0, 4, 5,
- 0, 5, 1,
- 1, 5, 6,
- 1, 6, 2,
- 2, 6, 7,
- 2, 7, 3,
- 4, 0, 3,
- 4, 3, 7,
- };
-
- return new List(indices);
- }
-
- private List GenerateFaces(Primitive.TextureEntry te)
- {
- Face face = new Face();
- face.Edge = new List();
- face.TextureFace = te.DefaultTexture;
- face.Vertices = GenerateVertices();
- face.Indices = GenerateIndices();
-
- List faces = new List(1);
- faces.Add(face);
-
- return faces;
- }
- }
-}
+/*
+ * Copyright (c) 2008, openmetaverse.org
+ * All rights reserved.
+ *
+ * - Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * - Neither the name of the openmetaverse.org nor the names
+ * of its contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Collections.Generic;
+
+namespace OpenMetaverse.Rendering
+{
+ [RendererName("Simple Cube Renderer")]
+ public class SimpleRenderer : IRendering
+ {
+ public SimpleMesh GenerateSimpleMesh(Primitive prim, DetailLevel lod)
+ {
+ Path path = GeneratePath();
+ Profile profile = GenerateProfile();
+
+ SimpleMesh mesh = new SimpleMesh();
+ mesh.Prim = prim;
+ mesh.Path = path;
+ mesh.Profile = profile;
+ mesh.Vertices = GenerateVertices();
+ mesh.Indices = GenerateIndices();
+
+ return mesh;
+ }
+
+ public SimpleMesh GenerateSimpleSculptMesh(Primitive prim, System.Drawing.Bitmap sculptTexture, DetailLevel lod)
+ {
+ return GenerateSimpleMesh(prim, lod);
+ }
+
+ public FacetedMesh GenerateFacetedMesh(Primitive prim, DetailLevel lod)
+ {
+ Path path = GeneratePath();
+ Profile profile = GenerateProfile();
+
+ FacetedMesh mesh = new FacetedMesh();
+ mesh.Prim = prim;
+ mesh.Path = path;
+ mesh.Profile = profile;
+ mesh.Faces = GenerateFaces(prim.Textures);
+
+ return mesh;
+ }
+
+ public FacetedMesh GenerateFacetedSculptMesh(Primitive prim, System.Drawing.Bitmap sculptTexture, DetailLevel lod)
+ {
+ return GenerateFacetedMesh(prim, lod);
+ }
+
+ public void TransformTexCoords(List vertices, Vector3 center, Primitive.TextureEntryFace teFace, Vector3 primScale)
+ {
+ // Lalala...
+ }
+
+ private Path GeneratePath()
+ {
+ Path path = new Path();
+ path.Points = new List();
+ return path;
+ }
+
+ private Profile GenerateProfile()
+ {
+ Profile profile = new Profile();
+ profile.Faces = new List();
+ profile.Positions = new List();
+ return profile;
+ }
+
+ private List GenerateVertices()
+ {
+ List vertices = new List(8);
+
+ Vertex v = new Vertex();
+
+ // FIXME: Implement these
+ v.Normal = Vector3.Zero;
+ v.TexCoord = Vector2.Zero;
+
+ v.Position = new Vector3(0.5f, 0.5f, -0.5f);
+ vertices.Add(v);
+ v.Position = new Vector3(0.5f, -0.5f, -0.5f);
+ vertices.Add(v);
+ v.Position = new Vector3(-0.5f, -0.5f, -0.5f);
+ vertices.Add(v);
+ v.Position = new Vector3(-0.5f, 0.5f, -0.5f);
+ vertices.Add(v);
+ v.Position = new Vector3(0.5f, 0.5f, 0.5f);
+ vertices.Add(v);
+ v.Position = new Vector3(0.5f, -0.5f, 0.5f);
+ vertices.Add(v);
+ v.Position = new Vector3(-0.5f, -0.5f, 0.5f);
+ vertices.Add(v);
+ v.Position = new Vector3(-0.5f, 0.5f, 0.5f);
+ vertices.Add(v);
+
+ return vertices;
+ }
+
+ private List GenerateIndices()
+ {
+ ushort[] indices = new ushort[] {
+ 0, 1, 2,
+ 0, 2, 3,
+ 4, 7, 6,
+ 4, 6, 5,
+ 0, 4, 5,
+ 0, 5, 1,
+ 1, 5, 6,
+ 1, 6, 2,
+ 2, 6, 7,
+ 2, 7, 3,
+ 4, 0, 3,
+ 4, 3, 7,
+ };
+
+ return new List(indices);
+ }
+
+ private List GenerateFaces(Primitive.TextureEntry te)
+ {
+ Face face = new Face();
+ face.Edge = new List();
+ face.TextureFace = te.DefaultTexture;
+ face.Vertices = GenerateVertices();
+ face.Indices = GenerateIndices();
+
+ List faces = new List(1);
+ faces.Add(face);
+
+ return faces;
+ }
+ }
+}
diff --git a/OpenMetaverse/Interfaces/IRendering.cs b/OpenMetaverse/Interfaces/IRendering.cs
index 8bd1eb85..ebcebc81 100644
--- a/OpenMetaverse/Interfaces/IRendering.cs
+++ b/OpenMetaverse/Interfaces/IRendering.cs
@@ -1,101 +1,102 @@
-/*
- * Copyright (c) 2008, openmetaverse.org
- * All rights reserved.
- *
- * - Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * - Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- * - Neither the name of the openmetaverse.org nor the names
- * of its contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-using System;
-using System.Collections.Generic;
-using System.Drawing;
-
-namespace OpenMetaverse.Rendering
-{
- [AttributeUsage(AttributeTargets.Class)]
- public class RendererNameAttribute : System.Attribute
- {
- private string _name;
-
- public RendererNameAttribute(string name)
- : base()
- {
- _name = name;
- }
-
- public override string ToString()
- {
- return _name;
- }
- }
-
- ///
- /// Abstract base for rendering plugins
- ///
- public interface IRendering
- {
- ///
- /// Generates a basic mesh structure from a primitive
- ///
- /// Primitive to generate the mesh from
- /// Level of detail to generate the mesh at
- /// The generated mesh
- SimpleMesh GenerateSimpleMesh(Primitive prim, DetailLevel lod);
-
- ///
- /// Generates a basic mesh structure from a sculpted primitive and
- /// texture
- ///
- /// Sculpted primitive to generate the mesh from
- /// Sculpt texture
- /// Level of detail to generate the mesh at
- /// The generated mesh
- SimpleMesh GenerateSimpleSculptMesh(Primitive prim, Bitmap sculptTexture, DetailLevel lod);
-
- ///
- /// Generates a series of faces, each face containing a mesh and
- /// metadata
- ///
- /// Primitive to generate the mesh from
- /// Level of detail to generate the mesh at
- /// The generated mesh
- FacetedMesh GenerateFacetedMesh(Primitive prim, DetailLevel lod);
-
- ///
- /// Generates a series of faces for a sculpted prim, each face
- /// containing a mesh and metadata
- ///
- /// Sculpted primitive to generate the mesh from
- /// Sculpt texture
- /// Level of detail to generate the mesh at
- /// The generated mesh
- FacetedMesh GenerateFacetedSculptMesh(Primitive prim, Bitmap sculptTexture, DetailLevel lod);
-
- ///
- /// Apply texture coordinate modifications from a
- /// to a list of vertices
- ///
- /// Vertex list to modify texture coordinates for
- /// Center-point of the face
- /// Face texture parameters
- void TransformTexCoords(List vertices, Vector3 center, Primitive.TextureEntryFace teFace);
- }
-}
+/*
+ * Copyright (c) 2008, openmetaverse.org
+ * All rights reserved.
+ *
+ * - Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * - Neither the name of the openmetaverse.org nor the names
+ * of its contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+
+namespace OpenMetaverse.Rendering
+{
+ [AttributeUsage(AttributeTargets.Class)]
+ public class RendererNameAttribute : System.Attribute
+ {
+ private string _name;
+
+ public RendererNameAttribute(string name)
+ : base()
+ {
+ _name = name;
+ }
+
+ public override string ToString()
+ {
+ return _name;
+ }
+ }
+
+ ///
+ /// Abstract base for rendering plugins
+ ///
+ public interface IRendering
+ {
+ ///
+ /// Generates a basic mesh structure from a primitive
+ ///
+ /// Primitive to generate the mesh from
+ /// Level of detail to generate the mesh at
+ /// The generated mesh
+ SimpleMesh GenerateSimpleMesh(Primitive prim, DetailLevel lod);
+
+ ///
+ /// Generates a basic mesh structure from a sculpted primitive and
+ /// texture
+ ///
+ /// Sculpted primitive to generate the mesh from
+ /// Sculpt texture
+ /// Level of detail to generate the mesh at
+ /// The generated mesh
+ SimpleMesh GenerateSimpleSculptMesh(Primitive prim, Bitmap sculptTexture, DetailLevel lod);
+
+ ///
+ /// Generates a series of faces, each face containing a mesh and
+ /// metadata
+ ///
+ /// Primitive to generate the mesh from
+ /// Level of detail to generate the mesh at
+ /// The generated mesh
+ FacetedMesh GenerateFacetedMesh(Primitive prim, DetailLevel lod);
+
+ ///
+ /// Generates a series of faces for a sculpted prim, each face
+ /// containing a mesh and metadata
+ ///
+ /// Sculpted primitive to generate the mesh from
+ /// Sculpt texture
+ /// Level of detail to generate the mesh at
+ /// The generated mesh
+ FacetedMesh GenerateFacetedSculptMesh(Primitive prim, Bitmap sculptTexture, DetailLevel lod);
+
+ ///
+ /// Apply texture coordinate modifications from a
+ /// to a list of vertices
+ ///
+ /// Vertex list to modify texture coordinates for
+ /// Center-point of the face
+ /// Face texture parameters
+ /// Scale of the prim
+ void TransformTexCoords (List vertices, Vector3 center, Primitive.TextureEntryFace teFace, Vector3 primScale);
+ }
+}
diff --git a/Programs/PrimWorkshop/frmBrowser.cs b/Programs/PrimWorkshop/frmBrowser.cs
index dac41358..5126a186 100644
--- a/Programs/PrimWorkshop/frmBrowser.cs
+++ b/Programs/PrimWorkshop/frmBrowser.cs
@@ -1,1961 +1,1961 @@
-using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Drawing;
-using System.Drawing.Imaging;
-using System.Windows.Forms;
-using System.IO;
-using System.Runtime.InteropServices;
-using Tao.OpenGl;
-using Tao.Platform.Windows;
-using ICSharpCode.SharpZipLib.Zip;
-using OpenMetaverse;
-using OpenMetaverse.StructuredData;
-using OpenMetaverse.Imaging;
-using OpenMetaverse.Rendering;
-using OpenMetaverse.Assets;
-
-namespace PrimWorkshop
-{
- public partial class frmBrowser : Form
- {
- const float DEG_TO_RAD = 0.0174532925f;
- const uint TERRAIN_START = (uint)Int32.MaxValue + 1;
-
- ContextMenu ExportPrimMenu;
- ContextMenu ExportTerrainMenu;
-
- GridClient Client;
- Camera Camera;
- Dictionary RenderFoliageList = new Dictionary();
- Dictionary RenderPrimList = new Dictionary();
- Dictionary DownloadList = new Dictionary();
- EventHandler IdleEvent;
-
- System.Timers.Timer ProgressTimer;
- int TotalPrims;
-
- // Textures
- Dictionary Textures = new Dictionary();
-
- // Terrain
- float MaxHeight = 0.1f;
- TerrainPatch[,] Heightmap;
- HeightmapLookupValue[] LookupHeightTable;
-
- // Picking globals
- bool Clicked = false;
- int ClickX = 0;
- int ClickY = 0;
- uint LastHit = 0;
-
- //warning CS0414: The private field `PrimWorkshop.frmBrowser.PivotPosition' is assigned but its value is never used
- Vector3 PivotPosition = Vector3.Zero;
- private bool Pivoting;
- Point LastPivot;
-
- //
- const int SELECT_BUFSIZE = 512;
- uint[] SelectBuffer = new uint[SELECT_BUFSIZE];
-
- //warning CS0414: The private field `PrimWorkshop.frmBrowser.msg' is assigned but its value is never used
- NativeMethods.Message msg;
- private bool AppStillIdle
- {
- get { return !NativeMethods.PeekMessage(out msg, IntPtr.Zero, 0, 0, 0); }
- }
-
- ///
- /// Default constructor
- ///
- public frmBrowser()
- {
- InitializeComponent();
-
- // Setup OpenGL
- glControl.InitializeContexts();
- glControl.SwapBuffers();
- glControl.MouseWheel += new MouseEventHandler(glControl_MouseWheel);
-
- // Login server URLs
- cboServer.Items.Add(Settings.AGNI_LOGIN_SERVER);
- cboServer.Items.Add(Settings.ADITI_LOGIN_SERVER);
- cboServer.Items.Add("http://osgrid.org:8002/");
- cboServer.SelectedIndex = 0;
-
- // Context menus
- ExportPrimMenu = new ContextMenu();
- ExportPrimMenu.MenuItems.Add("Download", new EventHandler(DownloadMenu_Clicked));
- ExportPrimMenu.MenuItems.Add("Download All Objects", new EventHandler(DownloadAllMenu_Clicked));
- ExportTerrainMenu = new ContextMenu();
- ExportTerrainMenu.MenuItems.Add("Teleport", new EventHandler(TeleportMenu_Clicked));
- ExportTerrainMenu.MenuItems.Add("Export Terrain", new EventHandler(ExportTerrainMenu_Clicked));
- ExportTerrainMenu.MenuItems.Add("Import Object", new EventHandler(ImportObjectMenu_Clicked));
- ExportTerrainMenu.MenuItems.Add("Import Sim", new EventHandler(ImportSimMenu_Clicked));
-
- // Setup a timer for updating the progress bar
- ProgressTimer = new System.Timers.Timer(250);
- ProgressTimer.Elapsed +=
- delegate(object sender, System.Timers.ElapsedEventArgs e)
- {
- UpdatePrimProgress();
- };
- ProgressTimer.Start();
-
- IdleEvent = new EventHandler(Application_Idle);
- Application.Idle += IdleEvent;
-
- // Show a flat sim before login so the screen isn't so boring
- InitHeightmap();
- InitOpenGL();
- InitCamera();
-
- glControl_Resize(null, null);
- }
-
- private void InitLists()
- {
- TotalPrims = 0;
-
- lock (Textures)
- {
- foreach (TextureInfo tex in Textures.Values)
- {
- int id = tex.ID;
- Gl.glDeleteTextures(1, ref id);
- }
-
- Textures.Clear();
- }
-
- lock (RenderPrimList) RenderPrimList.Clear();
- lock (RenderFoliageList) RenderFoliageList.Clear();
- }
-
- private void InitializeObjects()
- {
- InitLists();
-
- if (DownloadList != null)
- lock (DownloadList)
- DownloadList.Clear();
-
- // Initialize the SL client
- Client = new GridClient();
- Client.Settings.MULTIPLE_SIMS = false;
- Client.Settings.ALWAYS_DECODE_OBJECTS = true;
- Client.Settings.ALWAYS_REQUEST_OBJECTS = true;
- Client.Settings.SEND_AGENT_UPDATES = true;
- Client.Settings.USE_ASSET_CACHE = true;
- //Client.Settings.ASSET_CACHE_DIR = Application.StartupPath + System.IO.Path.DirectorySeparatorChar + "cache";
- Client.Settings.ALWAYS_REQUEST_PARCEL_ACL = false;
- Client.Settings.ALWAYS_REQUEST_PARCEL_DWELL = false;
- // Crank up the throttle on texture downloads
- Client.Throttle.Texture = 446000.0f;
-
- // FIXME: Write our own avatar tracker so we don't double store prims
- Client.Settings.OBJECT_TRACKING = false; // We use our own object tracking system
- Client.Settings.AVATAR_TRACKING = true; //but we want to use the libsl avatar system
-
- Client.Network.LoginProgress += Network_OnLogin;
- Client.Network.Disconnected += Network_OnDisconnected;
- Client.Network.SimChanged += Network_OnCurrentSimChanged;
- Client.Network.EventQueueRunning += Network_OnEventQueueRunning;
- Client.Objects.ObjectUpdate += Objects_OnNewPrim;
- Client.Terrain.LandPatchReceived += new EventHandler(Terrain_LandPatchReceived);
- Client.Parcels.SimParcelsDownloaded += new EventHandler(Parcels_SimParcelsDownloaded);
- Client.Assets.ImageReceiveProgress += new EventHandler(Assets_ImageReceiveProgress);
- // Initialize the camera object
- InitCamera();
-
- // Setup the libsl camera to match our Camera struct
- UpdateCamera();
- glControl_Resize(null, null);
-
- /*
- // Enable lighting
- Gl.glEnable(Gl.GL_LIGHTING);
- Gl.glEnable(Gl.GL_LIGHT0);
- float[] lightPosition = { 128.0f, 64.0f, 96.0f, 0.0f };
- Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_POSITION, lightPosition);
-
- // Setup ambient property
- float[] ambientLight = { 0.2f, 0.2f, 0.2f, 0.0f };
- Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_AMBIENT, ambientLight);
-
- // Setup specular property
- float[] specularLight = { 0.5f, 0.5f, 0.5f, 0.0f };
- Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_SPECULAR, specularLight);
- */
- }
-
- void Objects_NewPrim(object sender, PrimEventArgs e)
- {
- throw new NotImplementedException();
- }
-
- void Parcels_SimParcelsDownloaded(object sender, SimParcelsDownloadedEventArgs e)
- {
- TotalPrims = 0;
-
- e.Parcels.ForEach(
- delegate(Parcel parcel)
- {
- TotalPrims += parcel.TotalPrims;
- });
-
- UpdatePrimProgress(); TotalPrims = 0;
-
- e.Parcels.ForEach(
- delegate(Parcel parcel)
- {
- TotalPrims += parcel.TotalPrims;
- });
-
- UpdatePrimProgress();
- }
-
-
- private void InitOpenGL()
- {
- Gl.glShadeModel(Gl.GL_SMOOTH);
-
- Gl.glClearDepth(1.0f);
- Gl.glEnable(Gl.GL_DEPTH_TEST);
- Gl.glDepthMask(Gl.GL_TRUE);
- Gl.glDepthFunc(Gl.GL_LEQUAL);
- Gl.glHint(Gl.GL_PERSPECTIVE_CORRECTION_HINT, Gl.GL_NICEST);
- }
-
- private void InitHeightmap()
- {
- // Initialize the heightmap
- Heightmap = new TerrainPatch[16, 16];
- for (int y = 0; y < 16; y++)
- {
- for (int x = 0; x < 16; x++)
- {
- Heightmap[y, x] = new TerrainPatch();
- Heightmap[y, x].Data = new float[16 * 16];
- }
- }
-
- // Speed up terrain exports with a lookup table
- LookupHeightTable = new HeightmapLookupValue[256 * 256];
- for (int i = 0; i < 256; i++)
- {
- for (int j = 0; j < 256; j++)
- {
- LookupHeightTable[i + (j * 256)] = new HeightmapLookupValue((ushort)(i + (j * 256)), ((float)i * ((float)j / 127.0f)));
- }
- }
- Array.Sort(LookupHeightTable);
- }
-
- private void InitCamera()
- {
- Camera = new Camera();
- Camera.Position = new Vector3(128f, -192f, 90f);
- Camera.FocalPoint = new Vector3(128f, 128f, 0f);
- Camera.Zoom = 1.0d;
- Camera.Far = 512.0d;
- }
-
- private void UpdatePrimProgress()
- {
- if (this.InvokeRequired)
- {
- BeginInvoke((MethodInvoker)delegate() { UpdatePrimProgress(); });
- }
- else
- {
- try
- {
- if (RenderPrimList != null && RenderFoliageList != null)
- {
- int count = RenderPrimList.Count + RenderFoliageList.Count;
-
- lblPrims.Text = String.Format("Prims: {0} / {1}", count, TotalPrims);
- progPrims.Maximum = (TotalPrims > count) ? TotalPrims : count;
- progPrims.Value = count;
- }
- else
- {
- lblPrims.Text = String.Format("Prims: 0 / {0}", TotalPrims);
- progPrims.Maximum = TotalPrims;
- progPrims.Value = 0;
- }
- }
- catch (Exception ex)
- {
- Console.WriteLine(ex);
- }
- }
- }
-
- private void UpdateCamera()
- {
- if (Client != null)
- {
- Client.Self.Movement.Camera.LookAt(Camera.Position, Camera.FocalPoint);
- Client.Self.Movement.Camera.Far = (float)Camera.Far;
- }
-
- Gl.glPushMatrix();
- Gl.glMatrixMode(Gl.GL_PROJECTION);
- Gl.glLoadIdentity();
-
- SetPerspective();
-
- Gl.glMatrixMode(Gl.GL_MODELVIEW);
- Gl.glPopMatrix();
- }
-
- private bool ExportObject(RenderablePrim parent, string fileName, out int prims, out int textures, out string error)
- {
- // Build a list of primitives (parent+children) to export
- List primList = new List();
- primList.Add(parent.Prim);
-
- lock (RenderPrimList)
- {
- foreach (RenderablePrim render in RenderPrimList.Values)
- {
- if (render.Prim.ParentID == parent.Prim.LocalID)
- primList.Add(render.Prim);
- }
- }
-
- return ExportObjects(primList, fileName, out prims, out textures, out error);
- }
-
- private bool ExportSim(string fileName, out int prims, out int textures, out string error)
- {
- // Add all of the prims in this sim to the export list
- List primList = new List();
-
- lock (RenderPrimList)
- {
- foreach (RenderablePrim render in RenderPrimList.Values)
- {
- primList.Add(render.Prim);
- }
- }
-
- return ExportObjects(primList, fileName, out prims, out textures, out error);
- }
-
- private bool ExportObjects(List primList, string fileName, out int prims, out int textures, out string error)
- {
- List textureList = new List();
- prims = 0;
- textures = 0;
-
- // Write the LLSD to the hard drive in XML format
- string output = OSDParser.SerializeLLSDXmlString(Helpers.PrimListToOSD(primList));
- try
- {
- // Create a temporary directory
- string tempPath = System.IO.Path.Combine(System.IO.Path.GetTempPath(), System.IO.Path.GetRandomFileName());
- Directory.CreateDirectory(tempPath);
-
- // Write the prim XML file
- File.WriteAllText(System.IO.Path.Combine(tempPath, "prims.xml"), output);
- prims = primList.Count;
-
- // Build a list of all the referenced textures in this prim list
- foreach (Primitive prim in primList)
- {
- for (int i = 0; i < prim.Textures.FaceTextures.Length; i++)
- {
- Primitive.TextureEntryFace face = prim.Textures.FaceTextures[i];
- if (face != null && face.TextureID != UUID.Zero && face.TextureID != Primitive.TextureEntry.WHITE_TEXTURE)
- {
- if (!textureList.Contains(face.TextureID))
- textureList.Add(face.TextureID);
- }
- }
- }
-
- // Copy all of relevant textures from the cache to the temp directory
- foreach (UUID texture in textureList)
- {
- string tempFileName = Client.Assets.Cache.AssetFileName(texture);
-
- if (!String.IsNullOrEmpty(tempFileName))
- {
- File.Copy(tempFileName, System.IO.Path.Combine(tempPath, texture.ToString() + ".jp2"));
- ++textures;
- }
- else
- {
- Console.WriteLine("Missing texture file during download: " + texture.ToString());
- }
- }
-
- // Zip up the directory
- string[] filenames = Directory.GetFiles(tempPath);
- using (ZipOutputStream s = new ZipOutputStream(File.Create(fileName)))
- {
- s.SetLevel(9);
- byte[] buffer = new byte[4096];
-
- foreach (string file in filenames)
- {
- ZipEntry entry = new ZipEntry(System.IO.Path.GetFileName(file));
- entry.DateTime = DateTime.Now;
- s.PutNextEntry(entry);
-
- using (FileStream fs = File.OpenRead(file))
- {
- int sourceBytes;
- do
- {
- sourceBytes = fs.Read(buffer, 0, buffer.Length);
- s.Write(buffer, 0, sourceBytes);
- } while (sourceBytes > 0);
- }
- }
-
- s.Finish();
- s.Close();
- }
-
- error = null;
- return true;
- }
- catch (Exception ex)
- {
- error = ex.Message;
- return false;
- }
- }
-
- private List ImportObjects(string fileName, out string tempPath, out string error)
- {
- tempPath = null;
- error = null;
- string primFile = null;
-
- try
- {
- // Create a temporary directory
- tempPath = System.IO.Path.Combine(System.IO.Path.GetTempPath(), System.IO.Path.GetRandomFileName());
- Directory.CreateDirectory(tempPath);
-
- // Unzip the primpackage
- using (ZipInputStream s = new ZipInputStream(File.OpenRead(fileName)))
- {
- ZipEntry theEntry;
-
- // Loop through and confirm there is a prims.xml file
- while ((theEntry = s.GetNextEntry()) != null)
- {
- if (String.Equals("prims.xml", theEntry.Name.ToLower()))
- {
- primFile = theEntry.Name;
- break;
- }
- }
-
- if (primFile != null)
- {
- // Prepend the path to the primFile (that will be created in the next loop)
- primFile = System.IO.Path.Combine(tempPath, primFile);
- }
- else
- {
- // Didn't find a prims.xml file, bail out
- error = "No prims.xml file found in the archive";
- return null;
- }
-
- // Reset to the beginning of the zip file
- s.Seek(0, SeekOrigin.Begin);
-
- Logger.DebugLog("Unpacking archive to " + tempPath);
-
- // Unzip all of the texture and xml files
- while ((theEntry = s.GetNextEntry()) != null)
- {
- string directory = System.IO.Path.GetDirectoryName(theEntry.Name);
- string file = System.IO.Path.GetFileName(theEntry.Name);
-
- // Skip directories
- if (directory.Length > 0)
- continue;
-
- if (!String.IsNullOrEmpty(file))
- {
- string filelow = file.ToLower();
-
- if (filelow.EndsWith(".jp2") || filelow.EndsWith(".tga") || filelow.EndsWith(".xml"))
- {
- Logger.DebugLog("Unpacking " + file);
-
- // Create the full path from the temp path and new filename
- string filePath = System.IO.Path.Combine(tempPath, file);
-
- using (FileStream streamWriter = File.Create(filePath))
- {
- const int READ_BUFFER_SIZE = 2048;
- int size = READ_BUFFER_SIZE;
- byte[] data = new byte[READ_BUFFER_SIZE];
-
- while (true)
- {
- size = s.Read(data, 0, data.Length);
- if (size > 0)
- streamWriter.Write(data, 0, size);
- else
- break;
- }
- }
- }
- else
- {
- Logger.Log("Skipping file " + file, Helpers.LogLevel.Info);
- }
- }
- }
- }
-
- // Decode the .prims file
- string raw = File.ReadAllText(primFile);
- OSD osd = OSDParser.DeserializeLLSDXml(raw);
- return Helpers.OSDToPrimList(osd);
- }
- catch (Exception e)
- {
- error = e.Message;
- return null;
- }
- }
-
- private void DownloadMenu_Clicked(object sender, EventArgs e)
- {
- // Confirm that there actually is a selected object
- RenderablePrim parent;
- if (RenderPrimList.TryGetValue(LastHit, out parent))
- {
- if (parent.Prim.ParentID == 0)
- {
- // Valid parent prim is selected, throw up the save file dialog
- SaveFileDialog dialog = new SaveFileDialog();
- dialog.Filter = "Prim Package (*.zip)|*.zip";
-
- if (dialog.ShowDialog() == DialogResult.OK)
- {
- string error;
- int prims, textures;
- if (ExportObject(parent, dialog.FileName, out prims, out textures, out error))
- MessageBox.Show(String.Format("Exported {0} prims and {1} textures", prims, textures));
- else
- MessageBox.Show("Export failed: " + error);
- }
- }
- else
- {
- // This should have already been fixed in the picking processing code
- Console.WriteLine("Download menu clicked when a child prim is selected!");
- glControl.ContextMenu = null;
- LastHit = 0;
- }
- }
- else
- {
- Console.WriteLine("Download menu clicked when there is no selected prim!");
- glControl.ContextMenu = null;
- LastHit = 0;
- }
- }
-
- private void DownloadAllMenu_Clicked(object sender, EventArgs e)
- {
- SaveFileDialog dialog = new SaveFileDialog();
- dialog.Filter = "Prim Package (*.zip)|*.zip";
-
- if (dialog.ShowDialog() == DialogResult.OK)
- {
- string error;
- int prims, textures;
- if (ExportSim(dialog.FileName, out prims, out textures, out error))
- MessageBox.Show(String.Format("Exported {0} prims and {1} textures", prims, textures));
- else
- MessageBox.Show("Export failed: " + error);
- }
- }
-
- private void ExportTerrainMenu_Clicked(object sender, EventArgs e)
- {
- // Valid parent prim is selected, throw up the save file dialog
- SaveFileDialog dialog = new SaveFileDialog();
- dialog.Filter = "Terrain RAW (*.raw)|*.raw";
-
- if (dialog.ShowDialog() == DialogResult.OK)
- {
- BackgroundWorker worker = new BackgroundWorker();
- worker.DoWork += delegate(object obj, DoWorkEventArgs args)
- {
- byte red, green, blue, alpha1, alpha2, alpha3, alpha4, alpha5, alpha6, alpha7, alpha8, alpha9, alpha10;
-
- try
- {
- FileInfo file = new FileInfo(dialog.FileName);
- FileStream s = file.Open(FileMode.OpenOrCreate, FileAccess.Write);
- BinaryWriter binStream = new BinaryWriter(s);
-
- for (int y = 0; y < 256; y++)
- {
- for (int x = 0; x < 256; x++)
- {
- int xBlock = x / 16;
- int yBlock = y / 16;
- int xOff = x - (xBlock * 16);
- int yOff = y - (yBlock * 16);
-
- float t = Heightmap[yBlock, xBlock].Data[yOff * 16 + xOff];
- //float min = Single.MaxValue;
- int index = 0;
-
- // The lookup table is pre-sorted, so we either find an exact match or
- // the next closest (smaller) match with a binary search
- index = Array.BinarySearch(LookupHeightTable, new HeightmapLookupValue(0, t));
- if (index < 0)
- index = ~index - 1;
-
- index = LookupHeightTable[index].Index;
-
- /*for (int i = 0; i < 65536; i++)
- {
- if (Math.Abs(t - LookupHeightTable[i].Value) < min)
- {
- min = Math.Abs(t - LookupHeightTable[i].Value);
- index = i;
- }
- }*/
-
- red = (byte)(index & 0xFF);
- green = (byte)((index >> 8) & 0xFF);
- blue = 20;
- alpha1 = 0; // Land Parcels
- alpha2 = 0; // For Sale Land
- alpha3 = 0; // Public Edit Object
- alpha4 = 0; // Public Edit Land
- alpha5 = 255; // Safe Land
- alpha6 = 255; // Flying Allowed
- alpha7 = 255; // Create Landmark
- alpha8 = 255; // Outside Scripts
- alpha9 = red;
- alpha10 = green;
-
- binStream.Write(red);
- binStream.Write(green);
- binStream.Write(blue);
- binStream.Write(alpha1);
- binStream.Write(alpha2);
- binStream.Write(alpha3);
- binStream.Write(alpha4);
- binStream.Write(alpha5);
- binStream.Write(alpha6);
- binStream.Write(alpha7);
- binStream.Write(alpha8);
- binStream.Write(alpha9);
- binStream.Write(alpha10);
- }
- }
-
- binStream.Close();
- s.Close();
-
- BeginInvoke((MethodInvoker)delegate() { System.Windows.Forms.MessageBox.Show("Exported heightmap"); });
- }
- catch (Exception ex)
- {
- BeginInvoke((MethodInvoker)delegate() { System.Windows.Forms.MessageBox.Show("Error exporting heightmap: " + ex.Message); });
- }
- };
-
- worker.RunWorkerAsync();
- }
- }
-
- private void TeleportMenu_Clicked(object sender, EventArgs e)
- {
- if (Client != null && Client.Network.CurrentSim != null)
- {
- if (LastHit >= TERRAIN_START)
- {
- // Determine which piece of terrain was clicked on
- int y = (int)(LastHit - TERRAIN_START) / 16;
- int x = (int)(LastHit - (TERRAIN_START + (y * 16)));
-
- Vector3 targetPos = new Vector3(x * 16 + 8, y * 16 + 8, 0f);
-
- Console.WriteLine("Starting local teleport to " + targetPos.ToString());
- Client.Self.RequestTeleport(Client.Network.CurrentSim.Handle, targetPos);
- }
- else
- {
- // This shouldn't have happened...
- glControl.ContextMenu = null;
- }
- }
- }
-
- private void ImportObjectMenu_Clicked(object sender, EventArgs e)
- {
- OpenFileDialog dialog = new OpenFileDialog();
- dialog.Filter = "Prim Package (*.zip,*.primpackage)|*.zip;*.primpackage";
-
- if (dialog.ShowDialog() == DialogResult.OK)
- {
- // FIXME: Disable any further imports or exports until this is finished
-
- // Import the prims
- string error, texturePath;
- List primList = ImportObjects(dialog.FileName, out texturePath, out error);
- if (primList != null)
- {
- // Determine the total height of the object
- float minHeight = Single.MaxValue;
- float maxHeight = Single.MinValue;
-
- //float totalHeight = 0f;
-
- for (int i = 0; i < primList.Count; i++)
- {
- Primitive prim = primList[i];
-
- // Find the largest scale dimension (quick cheat to avoid figuring in the rotation)
- float scale = prim.Scale.X;
- if (prim.Scale.Y > scale) scale = prim.Scale.Y;
- if (prim.Scale.Z > scale) scale = prim.Scale.Z;
-
- float top = prim.Position.Z + (scale * 0.5f);
- float bottom = top - scale;
-
- if (top > maxHeight) maxHeight = top;
- if (bottom < minHeight) minHeight = bottom;
- }
-
- //totalHeight = maxHeight - minHeight;
-
- // Create a progress bar for the import process
- ProgressBar prog = new ProgressBar();
- prog.Minimum = 0;
- prog.Maximum = primList.Count;
- prog.Value = 0;
-
- // List item
- GlacialComponents.Controls.GLItem item = new GlacialComponents.Controls.GLItem();
- item.SubItems[0].Text = "Import process";
- item.SubItems[1].Control = prog;
-
- lstDownloads.Items.Add(item);
- lstDownloads.Invalidate();
-
- // Start the import process in the background
- BackgroundWorker worker = new BackgroundWorker();
-
- worker.DoWork += delegate(object s, DoWorkEventArgs ea)
- {
- // Set the spot choosing state
-
- // Wait for a spot to be chosen
-
- // mouse2dto3d()
-
- // Add (0, 0, totalHeight * 0.5f) to the clicked position
-
- for (int i = 0; i < primList.Count; i++)
- {
- Primitive prim = primList[i];
-
- for (int j = 0; j < prim.Textures.FaceTextures.Length; j++)
- {
- // Check if this texture exists
-
- // If not, wait while it uploads
- }
-
- // Create this prim (using weird SL math to get the correct position)
-
- // Wait for the callback to fire for this prim being created
-
- // Add this prim's localID to a list
-
- // Set any additional properties. If this is the root prim, do not apply rotation
-
- // Update the progress bar
- BeginInvoke((MethodInvoker)delegate() { prog.Value = i; });
- }
-
- // Link all of the prims together
-
- // Apply root prim rotation
- };
-
- worker.RunWorkerCompleted += delegate(object s, RunWorkerCompletedEventArgs ea)
- {
- BeginInvoke(
- (MethodInvoker)delegate()
- {
- lstDownloads.Items.Remove(item);
- lstDownloads.Invalidate();
- });
- };
-
- worker.RunWorkerAsync();
- }
- else
- {
- // FIXME: Re-enable imports and exports
-
- MessageBox.Show(error);
- return;
- }
- }
- }
-
- private void ImportSimMenu_Clicked(object sender, EventArgs e)
- {
- }
-
- private void SetPerspective()
- {
- Glu.gluPerspective(50.0d * Camera.Zoom, 1.0d, 0.1d, Camera.Far);
- }
-
- private void StartPicking(int cursorX, int cursorY)
- {
- int[] viewport = new int[4];
-
- Gl.glSelectBuffer(SELECT_BUFSIZE, SelectBuffer);
- Gl.glRenderMode(Gl.GL_SELECT);
-
- Gl.glMatrixMode(Gl.GL_PROJECTION);
- Gl.glPushMatrix();
- Gl.glLoadIdentity();
-
- Gl.glGetIntegerv(Gl.GL_VIEWPORT, viewport);
- Glu.gluPickMatrix(cursorX, viewport[3] - cursorY, 5, 5, viewport);
-
- SetPerspective();
-
- Gl.glMatrixMode(Gl.GL_MODELVIEW);
-
- Gl.glInitNames();
- }
-
- private void StopPicking()
- {
- int hits;
-
- // Resotre the original projection matrix
- Gl.glMatrixMode(Gl.GL_PROJECTION);
- Gl.glPopMatrix();
- Gl.glMatrixMode(Gl.GL_MODELVIEW);
- Gl.glFlush();
-
- // Return to normal rendering mode
- hits = Gl.glRenderMode(Gl.GL_RENDER);
-
- // If there are hits process them
- if (hits != 0)
- {
- ProcessHits(hits, SelectBuffer);
- }
- else
- {
- LastHit = 0;
- glControl.ContextMenu = null;
- }
- }
-
- private void ProcessHits(int hits, uint[] selectBuffer)
- {
- uint names = 0;
- uint numNames = 0;
- uint minZ = 0xffffffff;
- uint ptr = 0;
- uint ptrNames = 0;
-
- for (uint i = 0; i < hits; i++)
- {
- names = selectBuffer[ptr];
- ++ptr;
- if (selectBuffer[ptr] < minZ)
- {
- numNames = names;
- minZ = selectBuffer[ptr];
- ptrNames = ptr + 2;
- }
-
- ptr += names + 2;
- }
-
- ptr = ptrNames;
-
- for (uint i = 0; i < numNames; i++, ptr++)
- {
- LastHit = selectBuffer[ptr];
- }
-
- if (LastHit >= TERRAIN_START)
- {
- // Terrain was clicked on, turn off the context menu
- glControl.ContextMenu = ExportTerrainMenu;
- }
- else
- {
- RenderablePrim render;
- if (RenderPrimList.TryGetValue(LastHit, out render))
- {
- if (render.Prim.ParentID == 0)
- {
- Camera.FocalPoint = render.Prim.Position;
- UpdateCamera();
- }
- else
- {
- // See if we have the parent
- RenderablePrim renderParent;
- if (RenderPrimList.TryGetValue(render.Prim.ParentID, out renderParent))
- {
- // Turn on the context menu
- glControl.ContextMenu = ExportPrimMenu;
-
- // Change the clicked on prim to the parent. Camera position stays on the
- // clicked child but the highlighting is applied to all the children
- LastHit = renderParent.Prim.LocalID;
-
- Camera.FocalPoint = renderParent.Prim.Position + render.Prim.Position;
- UpdateCamera();
- }
- else
- {
- Console.WriteLine("Clicked on a child prim with no parent!");
- LastHit = 0;
- }
- }
- }
- }
- }
-
- private void Objects_OnNewPrim(object sender, PrimEventArgs e)
- {
- Primitive prim = e.Prim;
- if (prim.PrimData.PCode == PCode.Grass || prim.PrimData.PCode == PCode.Tree || prim.PrimData.PCode == PCode.NewTree)
- {
- lock (RenderFoliageList)
- RenderFoliageList[prim.LocalID] = prim;
- return;
- }
-
- RenderablePrim render = new RenderablePrim();
- render.Prim = prim;
-
- // FIXME: Handle sculpted prims by calling Render.Plugin.GenerateFacetedSculptMesh() instead
- render.Mesh = Render.Plugin.GenerateFacetedMesh(prim, DetailLevel.High);
-
- // Create a FaceData struct for each face that stores the 3D data
- // in a Tao.OpenGL friendly format
- for (int j = 0; j < render.Mesh.Faces.Count; j++)
- {
- Face face = render.Mesh.Faces[j];
- FaceData data = new FaceData();
-
- // Vertices for this face
- data.Vertices = new float[face.Vertices.Count * 3];
- for (int k = 0; k < face.Vertices.Count; k++)
- {
- data.Vertices[k * 3 + 0] = face.Vertices[k].Position.X;
- data.Vertices[k * 3 + 1] = face.Vertices[k].Position.Y;
- data.Vertices[k * 3 + 2] = face.Vertices[k].Position.Z;
- }
-
- // Indices for this face
- data.Indices = face.Indices.ToArray();
-
- // Texture transform for this face
- Primitive.TextureEntryFace teFace = prim.Textures.GetFace((uint)j);
- Render.Plugin.TransformTexCoords(face.Vertices, face.Center, teFace);
-
- // Texcoords for this face
- data.TexCoords = new float[face.Vertices.Count * 2];
- for (int k = 0; k < face.Vertices.Count; k++)
- {
- data.TexCoords[k * 2 + 0] = face.Vertices[k].TexCoord.X;
- data.TexCoords[k * 2 + 1] = face.Vertices[k].TexCoord.Y;
- }
-
- // Texture for this face
- if (teFace.TextureID != UUID.Zero &&
- teFace.TextureID != Primitive.TextureEntry.WHITE_TEXTURE)
- {
- lock (Textures)
- {
- if (!Textures.ContainsKey(teFace.TextureID))
- {
- // We haven't constructed this image in OpenGL yet, get ahold of it
- Client.Assets.RequestImage(teFace.TextureID, ImageType.Normal, TextureDownloader_OnDownloadFinished);
- }
- }
- }
-
- // Set the UserData for this face to our FaceData struct
- face.UserData = data;
- render.Mesh.Faces[j] = face;
- }
-
- lock (RenderPrimList) RenderPrimList[prim.LocalID] = render;
- }
-
- private void Terrain_LandPatchReceived(object sender, LandPatchReceivedEventArgs e)
- {
- if (Client != null && Client.Network.CurrentSim == e.Simulator)
- {
- Heightmap[e.Y, e.X].Data = e.HeightMap;
- }
-
- // Find the new max height
- for (int i = 0; i < e.HeightMap.Length; i++)
- {
- if (e.HeightMap[i] > MaxHeight)
- MaxHeight = e.HeightMap[i];
- }
- }
-
- private void Network_OnLogin(object sender, LoginProgressEventArgs e)
- {
- if (e.Status == LoginStatus.Success)
- {
- // Success!
- }
- else if (e.Status == LoginStatus.Failed)
- {
- BeginInvoke(
- (MethodInvoker)delegate()
- {
- MessageBox.Show(this, String.Format("Error logging in ({0}): {1}",
- Client.Network.LoginErrorKey, Client.Network.LoginMessage));
- cmdLogin.Text = "Login";
- txtFirst.Enabled = txtLast.Enabled = txtPass.Enabled = true;
- });
- }
- }
-
- private void Network_OnDisconnected(object sender, DisconnectedEventArgs e)
- {
- BeginInvoke(
- (MethodInvoker)delegate()
- {
- cmdTeleport.Enabled = false;
- DoLogout();
- });
- }
-
- private void Network_OnCurrentSimChanged(object sender, SimChangedEventArgs e)
- {
- Console.WriteLine("CurrentSim set to " + Client.Network.CurrentSim + ", downloading parcel information");
-
- BeginInvoke((MethodInvoker)delegate() { txtSim.Text = Client.Network.CurrentSim.Name; });
-
- //InitHeightmap();
- InitLists();
-
- // Disable teleports until the new event queue comes online
- if (!Client.Network.CurrentSim.Caps.IsEventQueueRunning)
- BeginInvoke((MethodInvoker)delegate() { cmdTeleport.Enabled = false; });
- }
-
- private void Network_OnEventQueueRunning(object sender, EventQueueRunningEventArgs e)
- {
- if (e.Simulator == Client.Network.CurrentSim)
- BeginInvoke((MethodInvoker)delegate() { cmdTeleport.Enabled = true; });
-
- // Now seems like a good time to start requesting parcel information
- Client.Parcels.RequestAllSimParcels(Client.Network.CurrentSim, false, 100);
- }
-
- private void RenderScene()
- {
- try
- {
- Gl.glClear(Gl.GL_COLOR_BUFFER_BIT | Gl.GL_DEPTH_BUFFER_BIT);
- Gl.glLoadIdentity();
- Gl.glEnableClientState(Gl.GL_VERTEX_ARRAY);
- Gl.glEnableClientState(Gl.GL_TEXTURE_COORD_ARRAY);
-
- if (Clicked)
- StartPicking(ClickX, ClickY);
-
- // Setup wireframe or solid fill drawing mode
- Gl.glPolygonMode(Gl.GL_FRONT, Gl.GL_LINE);
-
- // Position the camera
- Glu.gluLookAt(
- Camera.Position.X, Camera.Position.Y, Camera.Position.Z,
- Camera.FocalPoint.X, Camera.FocalPoint.Y, Camera.FocalPoint.Z,
- 0f, 0f, 1f);
-
- RenderSkybox();
-
- // Push the world matrix
- Gl.glPushMatrix();
-
- RenderTerrain();
- RenderPrims();
- RenderAvatars();
-
- Gl.glDisableClientState(Gl.GL_TEXTURE_COORD_ARRAY);
- Gl.glDisableClientState(Gl.GL_VERTEX_ARRAY);
-
- if (Clicked)
- {
- Clicked = false;
- StopPicking();
- }
-
- // Pop the world matrix
- Gl.glPopMatrix();
- Gl.glFlush();
-
- glControl.Invalidate();
- }
- catch (Exception)
- {
- }
- }
-
- static readonly Vector3[] SkyboxVerts = new Vector3[]
- {
- // Right side
- new Vector3( 10.0f, 10.0f, -10.0f ), //Top left
- new Vector3( 10.0f, 10.0f, 10.0f ), //Top right
- new Vector3( 10.0f, -10.0f, 10.0f ), //Bottom right
- new Vector3( 10.0f, -10.0f, -10.0f ), //Bottom left
- // Left side
- new Vector3( -10.0f, 10.0f, 10.0f ), //Top left
- new Vector3( -10.0f, 10.0f, -10.0f ), //Top right
- new Vector3( -10.0f, -10.0f, -10.0f ), //Bottom right
- new Vector3( -10.0f, -10.0f, 10.0f ), //Bottom left
- // Top side
- new Vector3( -10.0f, 10.0f, 10.0f ), //Top left
- new Vector3( 10.0f, 10.0f, 10.0f ), //Top right
- new Vector3( 10.0f, 10.0f, -10.0f ), //Bottom right
- new Vector3( -10.0f, 10.0f, -10.0f ), //Bottom left
- // Bottom side
- new Vector3( -10.0f, -10.0f, -10.0f ), //Top left
- new Vector3( 10.0f, -10.0f, -10.0f ), //Top right
- new Vector3( 10.0f, -10.0f, 10.0f ), //Bottom right
- new Vector3( -10.0f, -10.0f, 10.0f ), //Bottom left
- // Front side
- new Vector3( -10.0f, 10.0f, -10.0f ), //Top left
- new Vector3( 10.0f, 10.0f, -10.0f ), //Top right
- new Vector3( 10.0f, -10.0f, -10.0f ), //Bottom right
- new Vector3( -10.0f, -10.0f, -10.0f ), //Bottom left
- // Back side
- new Vector3( 10.0f, 10.0f, 10.0f ), //Top left
- new Vector3( -10.0f, 10.0f, 10.0f ), //Top right
- new Vector3( -10.0f, -10.0f, 10.0f ), //Bottom right
- new Vector3( 10.0f, -10.0f, 10.0f ), //Bottom left
- };
-
- private void RenderSkybox()
- {
- //Gl.glTranslatef(0f, 0f, 0f);
- }
-
- private void RenderTerrain()
- {
- if (Heightmap != null)
- {
- int i = 0;
-
- // No texture
- Gl.glBindTexture(Gl.GL_TEXTURE_2D, 0);
-
- for (int hy = 0; hy < 16; hy++)
- {
- for (int hx = 0; hx < 16; hx++)
- {
- uint patchName = (uint)(TERRAIN_START + i);
- Gl.glPushName(patchName);
- ++i;
-
- // Check if this patch is currently selected
- bool selected = (LastHit == patchName);
-
- for (int y = 0; y < 15; y++)
- {
- Gl.glBegin(Gl.GL_TRIANGLE_STRIP);
-
- for (int x = 0; x < 15; x++)
- {
- // Vertex 0
- float height = Heightmap[hy, hx].Data[y * 16 + x];
- float color = height / MaxHeight;
- float red = (selected) ? 1f : color;
-
- Gl.glColor3f(red, color, color);
- Gl.glTexCoord2f(0f, 0f);
- Gl.glVertex3f(hx * 16 + x, hy * 16 + y, height);
-
- // Vertex 1
- height = Heightmap[hy, hx].Data[y * 16 + (x + 1)];
- color = height / MaxHeight;
- red = (selected) ? 1f : color;
-
- Gl.glColor3f(red, color, color);
- Gl.glTexCoord2f(1f, 0f);
- Gl.glVertex3f(hx * 16 + x + 1, hy * 16 + y, height);
-
- // Vertex 2
- height = Heightmap[hy, hx].Data[(y + 1) * 16 + x];
- color = height / MaxHeight;
- red = (selected) ? 1f : color;
-
- Gl.glColor3f(red, color, color);
- Gl.glTexCoord2f(0f, 1f);
- Gl.glVertex3f(hx * 16 + x, hy * 16 + y + 1, height);
-
- // Vertex 3
- height = Heightmap[hy, hx].Data[(y + 1) * 16 + (x + 1)];
- color = height / MaxHeight;
- red = (selected) ? 1f : color;
-
- Gl.glColor3f(red, color, color);
- Gl.glTexCoord2f(1f, 1f);
- Gl.glVertex3f(hx * 16 + x + 1, hy * 16 + y + 1, height);
- }
-
- Gl.glEnd();
- }
-
- Gl.glPopName();
- }
- }
- }
- }
-
- //int[] CubeMapDefines = new int[]
- //{
- // Gl.GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
- // Gl.GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
- // Gl.GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
- // Gl.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
- // Gl.GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
- // Gl.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
- //};
-
- private void RenderPrims()
- {
- if (RenderPrimList != null && RenderPrimList.Count > 0)
- {
- Gl.glEnable(Gl.GL_TEXTURE_2D);
-
- lock (RenderPrimList)
- {
- bool firstPass = true;
- Gl.glDisable(Gl.GL_BLEND);
- Gl.glEnable(Gl.GL_DEPTH_TEST);
-
- StartRender:
-
- foreach (RenderablePrim render in RenderPrimList.Values)
- {
- RenderablePrim parentRender = RenderablePrim.Empty;
- Primitive prim = render.Prim;
-
- if (prim.ParentID != 0)
- {
- // Get the parent reference
- if (!RenderPrimList.TryGetValue(prim.ParentID, out parentRender))
- {
- // Can't render a child with no parent prim, skip it
- continue;
- }
- }
-
- Gl.glPushName(prim.LocalID);
- Gl.glPushMatrix();
-
- if (prim.ParentID != 0)
- {
- // Child prim
- Primitive parent = parentRender.Prim;
-
- // Apply parent translation and rotation
- Gl.glMultMatrixf(Math3D.CreateTranslationMatrix(parent.Position));
- Gl.glMultMatrixf(Math3D.CreateRotationMatrix(parent.Rotation));
- }
-
- // Apply prim translation and rotation
- Gl.glMultMatrixf(Math3D.CreateTranslationMatrix(prim.Position));
- Gl.glMultMatrixf(Math3D.CreateRotationMatrix(prim.Rotation));
-
- // Scale the prim
- Gl.glScalef(prim.Scale.X, prim.Scale.Y, prim.Scale.Z);
-
- // Draw the prim faces
- for (int j = 0; j < render.Mesh.Faces.Count; j++)
- {
- Face face = render.Mesh.Faces[j];
- FaceData data = (FaceData)face.UserData;
- Color4 color = face.TextureFace.RGBA;
- bool alpha = false;
- int textureID = 0;
-
- if (color.A < 1.0f)
- alpha = true;
-
- #region Texturing
-
- TextureInfo info;
- if (Textures.TryGetValue(face.TextureFace.TextureID, out info))
- {
- if (info.Alpha)
- alpha = true;
-
- textureID = info.ID;
-
- // Enable texturing for this face
- Gl.glPolygonMode(Gl.GL_FRONT_AND_BACK, Gl.GL_FILL);
- }
- else
- {
- if (face.TextureFace.TextureID == Primitive.TextureEntry.WHITE_TEXTURE ||
- face.TextureFace.TextureID == UUID.Zero)
- {
- Gl.glPolygonMode(Gl.GL_FRONT, Gl.GL_FILL);
- }
- else
- {
- Gl.glPolygonMode(Gl.GL_FRONT, Gl.GL_LINE);
- }
- }
-
- if (firstPass && !alpha || !firstPass && alpha)
- {
- // Color this prim differently based on whether it is selected or not
- if (LastHit == prim.LocalID || (LastHit != 0 && LastHit == prim.ParentID))
- {
- Gl.glColor4f(1f, color.G * 0.3f, color.B * 0.3f, color.A);
- }
- else
- {
- Gl.glColor4f(color.R, color.G, color.B, color.A);
- }
-
- // Bind the texture
- Gl.glBindTexture(Gl.GL_TEXTURE_2D, textureID);
-
- Gl.glTexCoordPointer(2, Gl.GL_FLOAT, 0, data.TexCoords);
- Gl.glVertexPointer(3, Gl.GL_FLOAT, 0, data.Vertices);
- Gl.glDrawElements(Gl.GL_TRIANGLES, data.Indices.Length, Gl.GL_UNSIGNED_SHORT, data.Indices);
- }
-
- #endregion Texturing
- }
-
- Gl.glPopMatrix();
- Gl.glPopName();
- }
-
- if (firstPass)
- {
- firstPass = false;
- Gl.glEnable(Gl.GL_BLEND);
- Gl.glBlendFunc(Gl.GL_SRC_ALPHA, Gl.GL_ONE_MINUS_SRC_ALPHA);
- //Gl.glDisable(Gl.GL_DEPTH_TEST);
-
- goto StartRender;
- }
- }
-
- Gl.glEnable(Gl.GL_DEPTH_TEST);
- Gl.glDisable(Gl.GL_TEXTURE_2D);
- }
- }
-
- private void RenderAvatars()
- {
- if (Client != null && Client.Network.CurrentSim != null)
- {
- Gl.glColor3f(0f, 1f, 0f);
-
- Client.Network.CurrentSim.ObjectsAvatars.ForEach(
- delegate(Avatar avatar)
- {
- Gl.glPushMatrix();
- Gl.glTranslatef(avatar.Position.X, avatar.Position.Y, avatar.Position.Z);
-
- Glu.GLUquadric quad = Glu.gluNewQuadric();
- Glu.gluSphere(quad, 1.0d, 10, 10);
- Glu.gluDeleteQuadric(quad);
-
- Gl.glPopMatrix();
- }
- );
-
- Gl.glColor3f(1f, 1f, 1f);
- }
- }
-
- #region Texture Downloading
-
- private void TextureDownloader_OnDownloadFinished(TextureRequestState state, AssetTexture asset)
- {
- bool alpha = false;
- ManagedImage imgData = null;
- byte[] raw = null;
-
- bool success = (state == TextureRequestState.Finished);
-
- UUID id = asset.AssetID;
-
- try
- {
- // Load the image off the disk
- if (success)
- {
- //ImageDownload download = TextureDownloader.GetTextureToRender(id);
- if (OpenJPEG.DecodeToImage(asset.AssetData, out imgData))
- {
- raw = imgData.ExportRaw();
-
- if ((imgData.Channels & ManagedImage.ImageChannels.Alpha) != 0)
- alpha = true;
- }
- else
- {
- success = false;
- Console.WriteLine("Failed to decode texture");
- }
- }
-
- // Make sure the OpenGL commands run on the main thread
- BeginInvoke(
- (MethodInvoker)delegate()
- {
- if (success)
- {
- int textureID = 0;
-
- try
- {
- Gl.glGenTextures(1, out textureID);
- Gl.glBindTexture(Gl.GL_TEXTURE_2D, textureID);
-
- Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_LINEAR_MIPMAP_NEAREST); //Gl.GL_NEAREST);
- Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_LINEAR);
- Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_S, Gl.GL_REPEAT);
- Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_T, Gl.GL_REPEAT);
- Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_GENERATE_MIPMAP, Gl.GL_TRUE); //Gl.GL_FALSE);
-
- //Gl.glTexImage2D(Gl.GL_TEXTURE_2D, 0, Gl.GL_RGBA, bitmap.Width, bitmap.Height, 0, Gl.GL_BGRA, Gl.GL_UNSIGNED_BYTE,
- // bitmapData.Scan0);
- //int error = Gl.glGetError();
-
- int error = Glu.gluBuild2DMipmaps(Gl.GL_TEXTURE_2D, Gl.GL_RGBA, imgData.Width, imgData.Height, Gl.GL_BGRA,
- Gl.GL_UNSIGNED_BYTE, raw);
-
- if (error == 0)
- {
- Textures[id] = new TextureInfo(textureID, alpha);
- Console.WriteLine("Created OpenGL texture for " + id.ToString());
- }
- else
- {
- Textures[id] = new TextureInfo(0, false);
- Console.WriteLine("Error creating OpenGL texture: " + error);
- }
- }
- catch (Exception ex)
- {
- Console.WriteLine(ex);
- }
- }
-
- // Remove this image from the download listbox
- lock (DownloadList)
- {
- GlacialComponents.Controls.GLItem item;
- if (DownloadList.TryGetValue(id, out item))
- {
- DownloadList.Remove(id);
- try { lstDownloads.Items.Remove(item); }
- catch (Exception) { }
- lstDownloads.Invalidate();
- }
- }
- });
- }
- catch (Exception ex)
- {
- Console.WriteLine(ex);
- }
- }
-
- private void Assets_ImageReceiveProgress(object sender, ImageReceiveProgressEventArgs e)
- {
- lock (DownloadList)
- {
- GlacialComponents.Controls.GLItem item;
- if (DownloadList.TryGetValue(e.ImageID, out item))
- {
- // Update an existing item
- BeginInvoke(
- (MethodInvoker)delegate()
- {
- ProgressBar prog = (ProgressBar)item.SubItems[1].Control;
- if (e.Total >= e.Received)
- prog.Value = (int)Math.Round((((double)e.Received / (double)e.Total) * 100.0d));
- });
- }
- else
- {
- // Progress bar
- ProgressBar prog = new ProgressBar();
- prog.Minimum = 0;
- prog.Maximum = 100;
- if (e.Total >= e.Received)
- prog.Value = (int)Math.Round((((double)e.Received / (double)e.Total) * 100.0d));
- else
- prog.Value = 0;
-
- // List item
- item = new GlacialComponents.Controls.GLItem();
- item.SubItems[0].Text = e.ImageID.ToString();
- item.SubItems[1].Control = prog;
-
- DownloadList[e.ImageID] = item;
-
- BeginInvoke(
- (MethodInvoker)delegate()
- {
- lstDownloads.Items.Add(item);
- lstDownloads.Invalidate();
- });
- }
- }
- }
-
- #endregion Texture Downloading
-
- private void frmBrowser_FormClosing(object sender, FormClosingEventArgs e)
- {
- DoLogout();
-
- Application.Idle -= IdleEvent;
- }
-
- private void Application_Idle(object sender, EventArgs e)
- {
- while (AppStillIdle)
- {
- RenderScene();
- }
- }
-
- private void cmdLogin_Click(object sender, EventArgs e)
- {
- if (cmdLogin.Text == "Login")
- {
- // Check that all the input boxes are filled in
- if (txtFirst.Text.Length == 0)
- {
- txtFirst.Select();
- return;
- }
- if (txtLast.Text.Length == 0)
- {
- txtLast.Select();
- return;
- }
- if (txtPass.Text.Length == 0)
- {
- txtPass.Select();
- return;
- }
-
- // Disable input controls
- txtFirst.Enabled = txtLast.Enabled = txtPass.Enabled = false;
- cmdLogin.Text = "Logout";
-
- // Sanity check that we aren't already logged in
- if (Client != null && Client.Network.Connected)
- {
- Client.Network.Logout();
- }
-
- // Re-initialize everything
- InitializeObjects();
-
- // Start the login
- LoginParams loginParams = Client.Network.DefaultLoginParams(txtFirst.Text, txtLast.Text,
- txtPass.Text, "Prim Preview", "0.0.1");
-
- if (!String.IsNullOrEmpty(cboServer.Text))
- loginParams.URI = cboServer.Text;
-
- Client.Network.BeginLogin(loginParams);
- }
- else
- {
- DoLogout();
- }
- }
-
- private void DoLogout()
- {
- if (Client != null && Client.Network.Connected)
- {
- Client.Network.Logout();
- return;
- }
-
- // Clear the download list
- lstDownloads.Items.Clear();
-
- // Set the login button back to login state
- cmdLogin.Text = "Login";
-
- // Enable input controls
- txtFirst.Enabled = txtLast.Enabled = txtPass.Enabled = true;
- }
-
- private void glControl_Resize(object sender, EventArgs e)
- {
- Gl.glClearColor(0.39f, 0.58f, 0.93f, 1.0f);
-
- Gl.glViewport(0, 0, glControl.Width, glControl.Height);
-
- Gl.glPushMatrix();
- Gl.glMatrixMode(Gl.GL_PROJECTION);
- Gl.glLoadIdentity();
-
- SetPerspective();
-
- Gl.glMatrixMode(Gl.GL_MODELVIEW);
- Gl.glPopMatrix();
-
- // Set the center of the glControl as the default pivot point
- LastPivot = glControl.PointToScreen(new Point(glControl.Width / 2, glControl.Height / 2));
- }
-
- private void glControl_MouseClick(object sender, MouseEventArgs e)
- {
- if ((Control.ModifierKeys & Keys.Alt) == 0 && e.Button == MouseButtons.Left)
- {
- // Only allow clicking if alt is not being held down
- ClickX = e.X;
- ClickY = e.Y;
- Clicked = true;
- }
- }
-
- private void glControl_MouseDown(object sender, MouseEventArgs e)
- {
- if ((Control.ModifierKeys & Keys.Alt) != 0 && LastHit > 0)
- {
- // Alt is held down and we have a valid target
- Pivoting = true;
- PivotPosition = Camera.FocalPoint;
-
- Control control = (Control)sender;
- LastPivot = control.PointToScreen(new Point(e.X, e.Y));
- }
- }
-
- private void glControl_MouseMove(object sender, MouseEventArgs e)
- {
- if (Pivoting)
- {
- float a, x, y, z;
-
- Control control = (Control)sender;
- Point mouse = control.PointToScreen(new Point(e.X, e.Y));
-
- // Calculate the deltas from the center of the control to the current position
- int deltaX = (int)((mouse.X - LastPivot.X) * -0.5d);
- int deltaY = (int)((mouse.Y - LastPivot.Y) * -0.5d);
-
- // Translate so the focal point is the origin
- Vector3 altered = Camera.Position - Camera.FocalPoint;
-
- // Rotate the translated point by deltaX
- a = (float)deltaX * DEG_TO_RAD;
- x = (float)((altered.X * Math.Cos(a)) - (altered.Y * Math.Sin(a)));
- y = (float)((altered.X * Math.Sin(a)) + (altered.Y * Math.Cos(a)));
-
- altered.X = x;
- altered.Y = y;
-
- // Rotate the translated point by deltaY
- a = (float)deltaY * DEG_TO_RAD;
- y = (float)((altered.Y * Math.Cos(a)) - (altered.Z * Math.Sin(a)));
- z = (float)((altered.Y * Math.Sin(a)) + (altered.Z * Math.Cos(a)));
-
- altered.Y = y;
- altered.Z = z;
-
- // Translate back to world space
- altered += Camera.FocalPoint;
-
- // Update the camera
- Camera.Position = altered;
- UpdateCamera();
-
- // Update the pivot point
- LastPivot = mouse;
- }
- }
-
- private void glControl_MouseWheel(object sender, MouseEventArgs e)
- {
- /*if (e.Delta != 0)
- {
- Camera.Zoom = Camera.Zoom + (double)(e.Delta / 120) * -0.1d;
- if (Camera.Zoom < 0.05d) Camera.Zoom = 0.05d;
- UpdateCamera();
- }*/
-
- if (e.Delta != 0)
- {
- // Calculate the distance to move to/away
- float dist = (float)(e.Delta / 120) * 10.0f;
-
- if (Vector3.Distance(Camera.Position, Camera.FocalPoint) > dist)
- {
- // Move closer or further away from the focal point
- Vector3 toFocal = Camera.FocalPoint - Camera.Position;
- toFocal.Normalize();
-
- toFocal = toFocal * dist;
-
- Camera.Position += toFocal;
- UpdateCamera();
- }
- }
- }
-
- private void glControl_MouseUp(object sender, MouseEventArgs e)
- {
- // Stop pivoting if we were previously
- Pivoting = false;
- }
-
- private void txtLogin_Enter(object sender, EventArgs e)
- {
- TextBox input = (TextBox)sender;
- input.SelectAll();
- }
-
- private void cmdTeleport_Click(object sender, EventArgs e)
- {
- if (!String.IsNullOrEmpty(txtSim.Text))
- {
- // Parse X/Y/Z
- int x, y, z;
- if (!Int32.TryParse(txtX.Text, out x))
- {
- txtX.SelectAll();
- return;
- }
- if (!Int32.TryParse(txtY.Text, out y))
- {
- txtY.SelectAll();
- return;
- }
- if (!Int32.TryParse(txtZ.Text, out z))
- {
- txtZ.SelectAll();
- return;
- }
-
- string simName = txtSim.Text.Trim().ToLower();
- Vector3 position = new Vector3(x, y, z);
-
- if (Client != null && Client.Network.CurrentSim != null)
- {
- // Check for a local teleport to shortcut the process
- if (simName == Client.Network.CurrentSim.Name.ToLower())
- {
- // Local teleport
- Client.Self.RequestTeleport(Client.Network.CurrentSim.Handle, position);
- }
- else
- {
- // Cross-sim teleport
- bool success = false;
-
- BackgroundWorker worker = new BackgroundWorker();
- worker.DoWork += delegate(object s, DoWorkEventArgs ea) { success = Client.Self.Teleport(simName, position); };
- worker.RunWorkerCompleted += delegate(object s, RunWorkerCompletedEventArgs ea)
- {
- BeginInvoke((MethodInvoker)
- delegate()
- {
- if (!success)
- System.Windows.Forms.MessageBox.Show("Teleport failed");
- });
- };
-
- worker.RunWorkerAsync();
- }
- }
- else
- {
- // Oops! How did the user click this...
- cmdTeleport.Enabled = false;
- }
- }
- }
- }
-
- public struct TextureInfo
- {
- /// OpenGL Texture ID
- public int ID;
- /// True if this texture has an alpha component
- public bool Alpha;
-
- public TextureInfo(int id, bool alpha)
- {
- ID = id;
- Alpha = alpha;
- }
- }
-
- public struct HeightmapLookupValue : IComparable
- {
- public ushort Index;
- public float Value;
-
- public HeightmapLookupValue(ushort index, float value)
- {
- Index = index;
- Value = value;
- }
-
- public int CompareTo(HeightmapLookupValue val)
- {
- return Value.CompareTo(val.Value);
- }
- }
-
- public struct RenderablePrim
- {
- public Primitive Prim;
- public FacetedMesh Mesh;
-
- public readonly static RenderablePrim Empty = new RenderablePrim();
- }
-
- public struct Camera
- {
- public Vector3 Position;
- public Vector3 FocalPoint;
- public double Zoom;
- public double Far;
- }
-
- public struct NativeMethods
- {
- [StructLayout(LayoutKind.Sequential)]
- public struct Message
- {
- public IntPtr HWnd;
- public uint Msg;
- public IntPtr WParam;
- public IntPtr LParam;
- public uint Time;
- public System.Drawing.Point Point;
- }
-
- //[System.Security.SuppressUnmanagedCodeSecurity]
- [DllImport("User32.dll", CharSet = CharSet.Auto)]
- public static extern bool PeekMessage(out Message msg, IntPtr hWnd, uint messageFilterMin, uint messageFilterMax, uint flags);
- }
-
- public static class Math3D
- {
- // Column-major:
- // | 0 4 8 12 |
- // | 1 5 9 13 |
- // | 2 6 10 14 |
- // | 3 7 11 15 |
-
- public static float[] CreateTranslationMatrix(Vector3 v)
- {
- float[] mat = new float[16];
-
- mat[12] = v.X;
- mat[13] = v.Y;
- mat[14] = v.Z;
- mat[0] = mat[5] = mat[10] = mat[15] = 1;
-
- return mat;
- }
-
- public static float[] CreateRotationMatrix(Quaternion q)
- {
- float[] mat = new float[16];
-
- // Transpose the quaternion (don't ask me why)
- q.X = q.X * -1f;
- q.Y = q.Y * -1f;
- q.Z = q.Z * -1f;
-
- float x2 = q.X + q.X;
- float y2 = q.Y + q.Y;
- float z2 = q.Z + q.Z;
- float xx = q.X * x2;
- float xy = q.X * y2;
- float xz = q.X * z2;
- float yy = q.Y * y2;
- float yz = q.Y * z2;
- float zz = q.Z * z2;
- float wx = q.W * x2;
- float wy = q.W * y2;
- float wz = q.W * z2;
-
- mat[0] = 1.0f - (yy + zz);
- mat[1] = xy - wz;
- mat[2] = xz + wy;
- mat[3] = 0.0f;
-
- mat[4] = xy + wz;
- mat[5] = 1.0f - (xx + zz);
- mat[6] = yz - wx;
- mat[7] = 0.0f;
-
- mat[8] = xz - wy;
- mat[9] = yz + wx;
- mat[10] = 1.0f - (xx + yy);
- mat[11] = 0.0f;
-
- mat[12] = 0.0f;
- mat[13] = 0.0f;
- mat[14] = 0.0f;
- mat[15] = 1.0f;
-
- return mat;
- }
-
- public static float[] CreateScaleMatrix(Vector3 v)
- {
- float[] mat = new float[16];
-
- mat[0] = v.X;
- mat[5] = v.Y;
- mat[10] = v.Z;
- mat[15] = 1;
-
- return mat;
- }
- }
-}
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.Windows.Forms;
+using System.IO;
+using System.Runtime.InteropServices;
+using Tao.OpenGl;
+using Tao.Platform.Windows;
+using ICSharpCode.SharpZipLib.Zip;
+using OpenMetaverse;
+using OpenMetaverse.StructuredData;
+using OpenMetaverse.Imaging;
+using OpenMetaverse.Rendering;
+using OpenMetaverse.Assets;
+
+namespace PrimWorkshop
+{
+ public partial class frmBrowser : Form
+ {
+ const float DEG_TO_RAD = 0.0174532925f;
+ const uint TERRAIN_START = (uint)Int32.MaxValue + 1;
+
+ ContextMenu ExportPrimMenu;
+ ContextMenu ExportTerrainMenu;
+
+ GridClient Client;
+ Camera Camera;
+ Dictionary RenderFoliageList = new Dictionary();
+ Dictionary RenderPrimList = new Dictionary();
+ Dictionary DownloadList = new Dictionary();
+ EventHandler IdleEvent;
+
+ System.Timers.Timer ProgressTimer;
+ int TotalPrims;
+
+ // Textures
+ Dictionary Textures = new Dictionary();
+
+ // Terrain
+ float MaxHeight = 0.1f;
+ TerrainPatch[,] Heightmap;
+ HeightmapLookupValue[] LookupHeightTable;
+
+ // Picking globals
+ bool Clicked = false;
+ int ClickX = 0;
+ int ClickY = 0;
+ uint LastHit = 0;
+
+ //warning CS0414: The private field `PrimWorkshop.frmBrowser.PivotPosition' is assigned but its value is never used
+ Vector3 PivotPosition = Vector3.Zero;
+ private bool Pivoting;
+ Point LastPivot;
+
+ //
+ const int SELECT_BUFSIZE = 512;
+ uint[] SelectBuffer = new uint[SELECT_BUFSIZE];
+
+ //warning CS0414: The private field `PrimWorkshop.frmBrowser.msg' is assigned but its value is never used
+ NativeMethods.Message msg;
+ private bool AppStillIdle
+ {
+ get { return !NativeMethods.PeekMessage(out msg, IntPtr.Zero, 0, 0, 0); }
+ }
+
+ ///
+ /// Default constructor
+ ///
+ public frmBrowser()
+ {
+ InitializeComponent();
+
+ // Setup OpenGL
+ glControl.InitializeContexts();
+ glControl.SwapBuffers();
+ glControl.MouseWheel += new MouseEventHandler(glControl_MouseWheel);
+
+ // Login server URLs
+ cboServer.Items.Add(Settings.AGNI_LOGIN_SERVER);
+ cboServer.Items.Add(Settings.ADITI_LOGIN_SERVER);
+ cboServer.Items.Add("http://osgrid.org:8002/");
+ cboServer.SelectedIndex = 0;
+
+ // Context menus
+ ExportPrimMenu = new ContextMenu();
+ ExportPrimMenu.MenuItems.Add("Download", new EventHandler(DownloadMenu_Clicked));
+ ExportPrimMenu.MenuItems.Add("Download All Objects", new EventHandler(DownloadAllMenu_Clicked));
+ ExportTerrainMenu = new ContextMenu();
+ ExportTerrainMenu.MenuItems.Add("Teleport", new EventHandler(TeleportMenu_Clicked));
+ ExportTerrainMenu.MenuItems.Add("Export Terrain", new EventHandler(ExportTerrainMenu_Clicked));
+ ExportTerrainMenu.MenuItems.Add("Import Object", new EventHandler(ImportObjectMenu_Clicked));
+ ExportTerrainMenu.MenuItems.Add("Import Sim", new EventHandler(ImportSimMenu_Clicked));
+
+ // Setup a timer for updating the progress bar
+ ProgressTimer = new System.Timers.Timer(250);
+ ProgressTimer.Elapsed +=
+ delegate(object sender, System.Timers.ElapsedEventArgs e)
+ {
+ UpdatePrimProgress();
+ };
+ ProgressTimer.Start();
+
+ IdleEvent = new EventHandler(Application_Idle);
+ Application.Idle += IdleEvent;
+
+ // Show a flat sim before login so the screen isn't so boring
+ InitHeightmap();
+ InitOpenGL();
+ InitCamera();
+
+ glControl_Resize(null, null);
+ }
+
+ private void InitLists()
+ {
+ TotalPrims = 0;
+
+ lock (Textures)
+ {
+ foreach (TextureInfo tex in Textures.Values)
+ {
+ int id = tex.ID;
+ Gl.glDeleteTextures(1, ref id);
+ }
+
+ Textures.Clear();
+ }
+
+ lock (RenderPrimList) RenderPrimList.Clear();
+ lock (RenderFoliageList) RenderFoliageList.Clear();
+ }
+
+ private void InitializeObjects()
+ {
+ InitLists();
+
+ if (DownloadList != null)
+ lock (DownloadList)
+ DownloadList.Clear();
+
+ // Initialize the SL client
+ Client = new GridClient();
+ Client.Settings.MULTIPLE_SIMS = false;
+ Client.Settings.ALWAYS_DECODE_OBJECTS = true;
+ Client.Settings.ALWAYS_REQUEST_OBJECTS = true;
+ Client.Settings.SEND_AGENT_UPDATES = true;
+ Client.Settings.USE_ASSET_CACHE = true;
+ //Client.Settings.ASSET_CACHE_DIR = Application.StartupPath + System.IO.Path.DirectorySeparatorChar + "cache";
+ Client.Settings.ALWAYS_REQUEST_PARCEL_ACL = false;
+ Client.Settings.ALWAYS_REQUEST_PARCEL_DWELL = false;
+ // Crank up the throttle on texture downloads
+ Client.Throttle.Texture = 446000.0f;
+
+ // FIXME: Write our own avatar tracker so we don't double store prims
+ Client.Settings.OBJECT_TRACKING = false; // We use our own object tracking system
+ Client.Settings.AVATAR_TRACKING = true; //but we want to use the libsl avatar system
+
+ Client.Network.LoginProgress += Network_OnLogin;
+ Client.Network.Disconnected += Network_OnDisconnected;
+ Client.Network.SimChanged += Network_OnCurrentSimChanged;
+ Client.Network.EventQueueRunning += Network_OnEventQueueRunning;
+ Client.Objects.ObjectUpdate += Objects_OnNewPrim;
+ Client.Terrain.LandPatchReceived += new EventHandler(Terrain_LandPatchReceived);
+ Client.Parcels.SimParcelsDownloaded += new EventHandler(Parcels_SimParcelsDownloaded);
+ Client.Assets.ImageReceiveProgress += new EventHandler(Assets_ImageReceiveProgress);
+ // Initialize the camera object
+ InitCamera();
+
+ // Setup the libsl camera to match our Camera struct
+ UpdateCamera();
+ glControl_Resize(null, null);
+
+ /*
+ // Enable lighting
+ Gl.glEnable(Gl.GL_LIGHTING);
+ Gl.glEnable(Gl.GL_LIGHT0);
+ float[] lightPosition = { 128.0f, 64.0f, 96.0f, 0.0f };
+ Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_POSITION, lightPosition);
+
+ // Setup ambient property
+ float[] ambientLight = { 0.2f, 0.2f, 0.2f, 0.0f };
+ Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_AMBIENT, ambientLight);
+
+ // Setup specular property
+ float[] specularLight = { 0.5f, 0.5f, 0.5f, 0.0f };
+ Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_SPECULAR, specularLight);
+ */
+ }
+
+ void Objects_NewPrim(object sender, PrimEventArgs e)
+ {
+ throw new NotImplementedException();
+ }
+
+ void Parcels_SimParcelsDownloaded(object sender, SimParcelsDownloadedEventArgs e)
+ {
+ TotalPrims = 0;
+
+ e.Parcels.ForEach(
+ delegate(Parcel parcel)
+ {
+ TotalPrims += parcel.TotalPrims;
+ });
+
+ UpdatePrimProgress(); TotalPrims = 0;
+
+ e.Parcels.ForEach(
+ delegate(Parcel parcel)
+ {
+ TotalPrims += parcel.TotalPrims;
+ });
+
+ UpdatePrimProgress();
+ }
+
+
+ private void InitOpenGL()
+ {
+ Gl.glShadeModel(Gl.GL_SMOOTH);
+
+ Gl.glClearDepth(1.0f);
+ Gl.glEnable(Gl.GL_DEPTH_TEST);
+ Gl.glDepthMask(Gl.GL_TRUE);
+ Gl.glDepthFunc(Gl.GL_LEQUAL);
+ Gl.glHint(Gl.GL_PERSPECTIVE_CORRECTION_HINT, Gl.GL_NICEST);
+ }
+
+ private void InitHeightmap()
+ {
+ // Initialize the heightmap
+ Heightmap = new TerrainPatch[16, 16];
+ for (int y = 0; y < 16; y++)
+ {
+ for (int x = 0; x < 16; x++)
+ {
+ Heightmap[y, x] = new TerrainPatch();
+ Heightmap[y, x].Data = new float[16 * 16];
+ }
+ }
+
+ // Speed up terrain exports with a lookup table
+ LookupHeightTable = new HeightmapLookupValue[256 * 256];
+ for (int i = 0; i < 256; i++)
+ {
+ for (int j = 0; j < 256; j++)
+ {
+ LookupHeightTable[i + (j * 256)] = new HeightmapLookupValue((ushort)(i + (j * 256)), ((float)i * ((float)j / 127.0f)));
+ }
+ }
+ Array.Sort(LookupHeightTable);
+ }
+
+ private void InitCamera()
+ {
+ Camera = new Camera();
+ Camera.Position = new Vector3(128f, -192f, 90f);
+ Camera.FocalPoint = new Vector3(128f, 128f, 0f);
+ Camera.Zoom = 1.0d;
+ Camera.Far = 512.0d;
+ }
+
+ private void UpdatePrimProgress()
+ {
+ if (this.InvokeRequired)
+ {
+ BeginInvoke((MethodInvoker)delegate() { UpdatePrimProgress(); });
+ }
+ else
+ {
+ try
+ {
+ if (RenderPrimList != null && RenderFoliageList != null)
+ {
+ int count = RenderPrimList.Count + RenderFoliageList.Count;
+
+ lblPrims.Text = String.Format("Prims: {0} / {1}", count, TotalPrims);
+ progPrims.Maximum = (TotalPrims > count) ? TotalPrims : count;
+ progPrims.Value = count;
+ }
+ else
+ {
+ lblPrims.Text = String.Format("Prims: 0 / {0}", TotalPrims);
+ progPrims.Maximum = TotalPrims;
+ progPrims.Value = 0;
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine(ex);
+ }
+ }
+ }
+
+ private void UpdateCamera()
+ {
+ if (Client != null)
+ {
+ Client.Self.Movement.Camera.LookAt(Camera.Position, Camera.FocalPoint);
+ Client.Self.Movement.Camera.Far = (float)Camera.Far;
+ }
+
+ Gl.glPushMatrix();
+ Gl.glMatrixMode(Gl.GL_PROJECTION);
+ Gl.glLoadIdentity();
+
+ SetPerspective();
+
+ Gl.glMatrixMode(Gl.GL_MODELVIEW);
+ Gl.glPopMatrix();
+ }
+
+ private bool ExportObject(RenderablePrim parent, string fileName, out int prims, out int textures, out string error)
+ {
+ // Build a list of primitives (parent+children) to export
+ List primList = new List();
+ primList.Add(parent.Prim);
+
+ lock (RenderPrimList)
+ {
+ foreach (RenderablePrim render in RenderPrimList.Values)
+ {
+ if (render.Prim.ParentID == parent.Prim.LocalID)
+ primList.Add(render.Prim);
+ }
+ }
+
+ return ExportObjects(primList, fileName, out prims, out textures, out error);
+ }
+
+ private bool ExportSim(string fileName, out int prims, out int textures, out string error)
+ {
+ // Add all of the prims in this sim to the export list
+ List primList = new List();
+
+ lock (RenderPrimList)
+ {
+ foreach (RenderablePrim render in RenderPrimList.Values)
+ {
+ primList.Add(render.Prim);
+ }
+ }
+
+ return ExportObjects(primList, fileName, out prims, out textures, out error);
+ }
+
+ private bool ExportObjects(List primList, string fileName, out int prims, out int textures, out string error)
+ {
+ List textureList = new List();
+ prims = 0;
+ textures = 0;
+
+ // Write the LLSD to the hard drive in XML format
+ string output = OSDParser.SerializeLLSDXmlString(Helpers.PrimListToOSD(primList));
+ try
+ {
+ // Create a temporary directory
+ string tempPath = System.IO.Path.Combine(System.IO.Path.GetTempPath(), System.IO.Path.GetRandomFileName());
+ Directory.CreateDirectory(tempPath);
+
+ // Write the prim XML file
+ File.WriteAllText(System.IO.Path.Combine(tempPath, "prims.xml"), output);
+ prims = primList.Count;
+
+ // Build a list of all the referenced textures in this prim list
+ foreach (Primitive prim in primList)
+ {
+ for (int i = 0; i < prim.Textures.FaceTextures.Length; i++)
+ {
+ Primitive.TextureEntryFace face = prim.Textures.FaceTextures[i];
+ if (face != null && face.TextureID != UUID.Zero && face.TextureID != Primitive.TextureEntry.WHITE_TEXTURE)
+ {
+ if (!textureList.Contains(face.TextureID))
+ textureList.Add(face.TextureID);
+ }
+ }
+ }
+
+ // Copy all of relevant textures from the cache to the temp directory
+ foreach (UUID texture in textureList)
+ {
+ string tempFileName = Client.Assets.Cache.AssetFileName(texture);
+
+ if (!String.IsNullOrEmpty(tempFileName))
+ {
+ File.Copy(tempFileName, System.IO.Path.Combine(tempPath, texture.ToString() + ".jp2"));
+ ++textures;
+ }
+ else
+ {
+ Console.WriteLine("Missing texture file during download: " + texture.ToString());
+ }
+ }
+
+ // Zip up the directory
+ string[] filenames = Directory.GetFiles(tempPath);
+ using (ZipOutputStream s = new ZipOutputStream(File.Create(fileName)))
+ {
+ s.SetLevel(9);
+ byte[] buffer = new byte[4096];
+
+ foreach (string file in filenames)
+ {
+ ZipEntry entry = new ZipEntry(System.IO.Path.GetFileName(file));
+ entry.DateTime = DateTime.Now;
+ s.PutNextEntry(entry);
+
+ using (FileStream fs = File.OpenRead(file))
+ {
+ int sourceBytes;
+ do
+ {
+ sourceBytes = fs.Read(buffer, 0, buffer.Length);
+ s.Write(buffer, 0, sourceBytes);
+ } while (sourceBytes > 0);
+ }
+ }
+
+ s.Finish();
+ s.Close();
+ }
+
+ error = null;
+ return true;
+ }
+ catch (Exception ex)
+ {
+ error = ex.Message;
+ return false;
+ }
+ }
+
+ private List ImportObjects(string fileName, out string tempPath, out string error)
+ {
+ tempPath = null;
+ error = null;
+ string primFile = null;
+
+ try
+ {
+ // Create a temporary directory
+ tempPath = System.IO.Path.Combine(System.IO.Path.GetTempPath(), System.IO.Path.GetRandomFileName());
+ Directory.CreateDirectory(tempPath);
+
+ // Unzip the primpackage
+ using (ZipInputStream s = new ZipInputStream(File.OpenRead(fileName)))
+ {
+ ZipEntry theEntry;
+
+ // Loop through and confirm there is a prims.xml file
+ while ((theEntry = s.GetNextEntry()) != null)
+ {
+ if (String.Equals("prims.xml", theEntry.Name.ToLower()))
+ {
+ primFile = theEntry.Name;
+ break;
+ }
+ }
+
+ if (primFile != null)
+ {
+ // Prepend the path to the primFile (that will be created in the next loop)
+ primFile = System.IO.Path.Combine(tempPath, primFile);
+ }
+ else
+ {
+ // Didn't find a prims.xml file, bail out
+ error = "No prims.xml file found in the archive";
+ return null;
+ }
+
+ // Reset to the beginning of the zip file
+ s.Seek(0, SeekOrigin.Begin);
+
+ Logger.DebugLog("Unpacking archive to " + tempPath);
+
+ // Unzip all of the texture and xml files
+ while ((theEntry = s.GetNextEntry()) != null)
+ {
+ string directory = System.IO.Path.GetDirectoryName(theEntry.Name);
+ string file = System.IO.Path.GetFileName(theEntry.Name);
+
+ // Skip directories
+ if (directory.Length > 0)
+ continue;
+
+ if (!String.IsNullOrEmpty(file))
+ {
+ string filelow = file.ToLower();
+
+ if (filelow.EndsWith(".jp2") || filelow.EndsWith(".tga") || filelow.EndsWith(".xml"))
+ {
+ Logger.DebugLog("Unpacking " + file);
+
+ // Create the full path from the temp path and new filename
+ string filePath = System.IO.Path.Combine(tempPath, file);
+
+ using (FileStream streamWriter = File.Create(filePath))
+ {
+ const int READ_BUFFER_SIZE = 2048;
+ int size = READ_BUFFER_SIZE;
+ byte[] data = new byte[READ_BUFFER_SIZE];
+
+ while (true)
+ {
+ size = s.Read(data, 0, data.Length);
+ if (size > 0)
+ streamWriter.Write(data, 0, size);
+ else
+ break;
+ }
+ }
+ }
+ else
+ {
+ Logger.Log("Skipping file " + file, Helpers.LogLevel.Info);
+ }
+ }
+ }
+ }
+
+ // Decode the .prims file
+ string raw = File.ReadAllText(primFile);
+ OSD osd = OSDParser.DeserializeLLSDXml(raw);
+ return Helpers.OSDToPrimList(osd);
+ }
+ catch (Exception e)
+ {
+ error = e.Message;
+ return null;
+ }
+ }
+
+ private void DownloadMenu_Clicked(object sender, EventArgs e)
+ {
+ // Confirm that there actually is a selected object
+ RenderablePrim parent;
+ if (RenderPrimList.TryGetValue(LastHit, out parent))
+ {
+ if (parent.Prim.ParentID == 0)
+ {
+ // Valid parent prim is selected, throw up the save file dialog
+ SaveFileDialog dialog = new SaveFileDialog();
+ dialog.Filter = "Prim Package (*.zip)|*.zip";
+
+ if (dialog.ShowDialog() == DialogResult.OK)
+ {
+ string error;
+ int prims, textures;
+ if (ExportObject(parent, dialog.FileName, out prims, out textures, out error))
+ MessageBox.Show(String.Format("Exported {0} prims and {1} textures", prims, textures));
+ else
+ MessageBox.Show("Export failed: " + error);
+ }
+ }
+ else
+ {
+ // This should have already been fixed in the picking processing code
+ Console.WriteLine("Download menu clicked when a child prim is selected!");
+ glControl.ContextMenu = null;
+ LastHit = 0;
+ }
+ }
+ else
+ {
+ Console.WriteLine("Download menu clicked when there is no selected prim!");
+ glControl.ContextMenu = null;
+ LastHit = 0;
+ }
+ }
+
+ private void DownloadAllMenu_Clicked(object sender, EventArgs e)
+ {
+ SaveFileDialog dialog = new SaveFileDialog();
+ dialog.Filter = "Prim Package (*.zip)|*.zip";
+
+ if (dialog.ShowDialog() == DialogResult.OK)
+ {
+ string error;
+ int prims, textures;
+ if (ExportSim(dialog.FileName, out prims, out textures, out error))
+ MessageBox.Show(String.Format("Exported {0} prims and {1} textures", prims, textures));
+ else
+ MessageBox.Show("Export failed: " + error);
+ }
+ }
+
+ private void ExportTerrainMenu_Clicked(object sender, EventArgs e)
+ {
+ // Valid parent prim is selected, throw up the save file dialog
+ SaveFileDialog dialog = new SaveFileDialog();
+ dialog.Filter = "Terrain RAW (*.raw)|*.raw";
+
+ if (dialog.ShowDialog() == DialogResult.OK)
+ {
+ BackgroundWorker worker = new BackgroundWorker();
+ worker.DoWork += delegate(object obj, DoWorkEventArgs args)
+ {
+ byte red, green, blue, alpha1, alpha2, alpha3, alpha4, alpha5, alpha6, alpha7, alpha8, alpha9, alpha10;
+
+ try
+ {
+ FileInfo file = new FileInfo(dialog.FileName);
+ FileStream s = file.Open(FileMode.OpenOrCreate, FileAccess.Write);
+ BinaryWriter binStream = new BinaryWriter(s);
+
+ for (int y = 0; y < 256; y++)
+ {
+ for (int x = 0; x < 256; x++)
+ {
+ int xBlock = x / 16;
+ int yBlock = y / 16;
+ int xOff = x - (xBlock * 16);
+ int yOff = y - (yBlock * 16);
+
+ float t = Heightmap[yBlock, xBlock].Data[yOff * 16 + xOff];
+ //float min = Single.MaxValue;
+ int index = 0;
+
+ // The lookup table is pre-sorted, so we either find an exact match or
+ // the next closest (smaller) match with a binary search
+ index = Array.BinarySearch(LookupHeightTable, new HeightmapLookupValue(0, t));
+ if (index < 0)
+ index = ~index - 1;
+
+ index = LookupHeightTable[index].Index;
+
+ /*for (int i = 0; i < 65536; i++)
+ {
+ if (Math.Abs(t - LookupHeightTable[i].Value) < min)
+ {
+ min = Math.Abs(t - LookupHeightTable[i].Value);
+ index = i;
+ }
+ }*/
+
+ red = (byte)(index & 0xFF);
+ green = (byte)((index >> 8) & 0xFF);
+ blue = 20;
+ alpha1 = 0; // Land Parcels
+ alpha2 = 0; // For Sale Land
+ alpha3 = 0; // Public Edit Object
+ alpha4 = 0; // Public Edit Land
+ alpha5 = 255; // Safe Land
+ alpha6 = 255; // Flying Allowed
+ alpha7 = 255; // Create Landmark
+ alpha8 = 255; // Outside Scripts
+ alpha9 = red;
+ alpha10 = green;
+
+ binStream.Write(red);
+ binStream.Write(green);
+ binStream.Write(blue);
+ binStream.Write(alpha1);
+ binStream.Write(alpha2);
+ binStream.Write(alpha3);
+ binStream.Write(alpha4);
+ binStream.Write(alpha5);
+ binStream.Write(alpha6);
+ binStream.Write(alpha7);
+ binStream.Write(alpha8);
+ binStream.Write(alpha9);
+ binStream.Write(alpha10);
+ }
+ }
+
+ binStream.Close();
+ s.Close();
+
+ BeginInvoke((MethodInvoker)delegate() { System.Windows.Forms.MessageBox.Show("Exported heightmap"); });
+ }
+ catch (Exception ex)
+ {
+ BeginInvoke((MethodInvoker)delegate() { System.Windows.Forms.MessageBox.Show("Error exporting heightmap: " + ex.Message); });
+ }
+ };
+
+ worker.RunWorkerAsync();
+ }
+ }
+
+ private void TeleportMenu_Clicked(object sender, EventArgs e)
+ {
+ if (Client != null && Client.Network.CurrentSim != null)
+ {
+ if (LastHit >= TERRAIN_START)
+ {
+ // Determine which piece of terrain was clicked on
+ int y = (int)(LastHit - TERRAIN_START) / 16;
+ int x = (int)(LastHit - (TERRAIN_START + (y * 16)));
+
+ Vector3 targetPos = new Vector3(x * 16 + 8, y * 16 + 8, 0f);
+
+ Console.WriteLine("Starting local teleport to " + targetPos.ToString());
+ Client.Self.RequestTeleport(Client.Network.CurrentSim.Handle, targetPos);
+ }
+ else
+ {
+ // This shouldn't have happened...
+ glControl.ContextMenu = null;
+ }
+ }
+ }
+
+ private void ImportObjectMenu_Clicked(object sender, EventArgs e)
+ {
+ OpenFileDialog dialog = new OpenFileDialog();
+ dialog.Filter = "Prim Package (*.zip,*.primpackage)|*.zip;*.primpackage";
+
+ if (dialog.ShowDialog() == DialogResult.OK)
+ {
+ // FIXME: Disable any further imports or exports until this is finished
+
+ // Import the prims
+ string error, texturePath;
+ List primList = ImportObjects(dialog.FileName, out texturePath, out error);
+ if (primList != null)
+ {
+ // Determine the total height of the object
+ float minHeight = Single.MaxValue;
+ float maxHeight = Single.MinValue;
+
+ //float totalHeight = 0f;
+
+ for (int i = 0; i < primList.Count; i++)
+ {
+ Primitive prim = primList[i];
+
+ // Find the largest scale dimension (quick cheat to avoid figuring in the rotation)
+ float scale = prim.Scale.X;
+ if (prim.Scale.Y > scale) scale = prim.Scale.Y;
+ if (prim.Scale.Z > scale) scale = prim.Scale.Z;
+
+ float top = prim.Position.Z + (scale * 0.5f);
+ float bottom = top - scale;
+
+ if (top > maxHeight) maxHeight = top;
+ if (bottom < minHeight) minHeight = bottom;
+ }
+
+ //totalHeight = maxHeight - minHeight;
+
+ // Create a progress bar for the import process
+ ProgressBar prog = new ProgressBar();
+ prog.Minimum = 0;
+ prog.Maximum = primList.Count;
+ prog.Value = 0;
+
+ // List item
+ GlacialComponents.Controls.GLItem item = new GlacialComponents.Controls.GLItem();
+ item.SubItems[0].Text = "Import process";
+ item.SubItems[1].Control = prog;
+
+ lstDownloads.Items.Add(item);
+ lstDownloads.Invalidate();
+
+ // Start the import process in the background
+ BackgroundWorker worker = new BackgroundWorker();
+
+ worker.DoWork += delegate(object s, DoWorkEventArgs ea)
+ {
+ // Set the spot choosing state
+
+ // Wait for a spot to be chosen
+
+ // mouse2dto3d()
+
+ // Add (0, 0, totalHeight * 0.5f) to the clicked position
+
+ for (int i = 0; i < primList.Count; i++)
+ {
+ Primitive prim = primList[i];
+
+ for (int j = 0; j < prim.Textures.FaceTextures.Length; j++)
+ {
+ // Check if this texture exists
+
+ // If not, wait while it uploads
+ }
+
+ // Create this prim (using weird SL math to get the correct position)
+
+ // Wait for the callback to fire for this prim being created
+
+ // Add this prim's localID to a list
+
+ // Set any additional properties. If this is the root prim, do not apply rotation
+
+ // Update the progress bar
+ BeginInvoke((MethodInvoker)delegate() { prog.Value = i; });
+ }
+
+ // Link all of the prims together
+
+ // Apply root prim rotation
+ };
+
+ worker.RunWorkerCompleted += delegate(object s, RunWorkerCompletedEventArgs ea)
+ {
+ BeginInvoke(
+ (MethodInvoker)delegate()
+ {
+ lstDownloads.Items.Remove(item);
+ lstDownloads.Invalidate();
+ });
+ };
+
+ worker.RunWorkerAsync();
+ }
+ else
+ {
+ // FIXME: Re-enable imports and exports
+
+ MessageBox.Show(error);
+ return;
+ }
+ }
+ }
+
+ private void ImportSimMenu_Clicked(object sender, EventArgs e)
+ {
+ }
+
+ private void SetPerspective()
+ {
+ Glu.gluPerspective(50.0d * Camera.Zoom, 1.0d, 0.1d, Camera.Far);
+ }
+
+ private void StartPicking(int cursorX, int cursorY)
+ {
+ int[] viewport = new int[4];
+
+ Gl.glSelectBuffer(SELECT_BUFSIZE, SelectBuffer);
+ Gl.glRenderMode(Gl.GL_SELECT);
+
+ Gl.glMatrixMode(Gl.GL_PROJECTION);
+ Gl.glPushMatrix();
+ Gl.glLoadIdentity();
+
+ Gl.glGetIntegerv(Gl.GL_VIEWPORT, viewport);
+ Glu.gluPickMatrix(cursorX, viewport[3] - cursorY, 5, 5, viewport);
+
+ SetPerspective();
+
+ Gl.glMatrixMode(Gl.GL_MODELVIEW);
+
+ Gl.glInitNames();
+ }
+
+ private void StopPicking()
+ {
+ int hits;
+
+ // Resotre the original projection matrix
+ Gl.glMatrixMode(Gl.GL_PROJECTION);
+ Gl.glPopMatrix();
+ Gl.glMatrixMode(Gl.GL_MODELVIEW);
+ Gl.glFlush();
+
+ // Return to normal rendering mode
+ hits = Gl.glRenderMode(Gl.GL_RENDER);
+
+ // If there are hits process them
+ if (hits != 0)
+ {
+ ProcessHits(hits, SelectBuffer);
+ }
+ else
+ {
+ LastHit = 0;
+ glControl.ContextMenu = null;
+ }
+ }
+
+ private void ProcessHits(int hits, uint[] selectBuffer)
+ {
+ uint names = 0;
+ uint numNames = 0;
+ uint minZ = 0xffffffff;
+ uint ptr = 0;
+ uint ptrNames = 0;
+
+ for (uint i = 0; i < hits; i++)
+ {
+ names = selectBuffer[ptr];
+ ++ptr;
+ if (selectBuffer[ptr] < minZ)
+ {
+ numNames = names;
+ minZ = selectBuffer[ptr];
+ ptrNames = ptr + 2;
+ }
+
+ ptr += names + 2;
+ }
+
+ ptr = ptrNames;
+
+ for (uint i = 0; i < numNames; i++, ptr++)
+ {
+ LastHit = selectBuffer[ptr];
+ }
+
+ if (LastHit >= TERRAIN_START)
+ {
+ // Terrain was clicked on, turn off the context menu
+ glControl.ContextMenu = ExportTerrainMenu;
+ }
+ else
+ {
+ RenderablePrim render;
+ if (RenderPrimList.TryGetValue(LastHit, out render))
+ {
+ if (render.Prim.ParentID == 0)
+ {
+ Camera.FocalPoint = render.Prim.Position;
+ UpdateCamera();
+ }
+ else
+ {
+ // See if we have the parent
+ RenderablePrim renderParent;
+ if (RenderPrimList.TryGetValue(render.Prim.ParentID, out renderParent))
+ {
+ // Turn on the context menu
+ glControl.ContextMenu = ExportPrimMenu;
+
+ // Change the clicked on prim to the parent. Camera position stays on the
+ // clicked child but the highlighting is applied to all the children
+ LastHit = renderParent.Prim.LocalID;
+
+ Camera.FocalPoint = renderParent.Prim.Position + render.Prim.Position;
+ UpdateCamera();
+ }
+ else
+ {
+ Console.WriteLine("Clicked on a child prim with no parent!");
+ LastHit = 0;
+ }
+ }
+ }
+ }
+ }
+
+ private void Objects_OnNewPrim(object sender, PrimEventArgs e)
+ {
+ Primitive prim = e.Prim;
+ if (prim.PrimData.PCode == PCode.Grass || prim.PrimData.PCode == PCode.Tree || prim.PrimData.PCode == PCode.NewTree)
+ {
+ lock (RenderFoliageList)
+ RenderFoliageList[prim.LocalID] = prim;
+ return;
+ }
+
+ RenderablePrim render = new RenderablePrim();
+ render.Prim = prim;
+
+ // FIXME: Handle sculpted prims by calling Render.Plugin.GenerateFacetedSculptMesh() instead
+ render.Mesh = Render.Plugin.GenerateFacetedMesh(prim, DetailLevel.High);
+
+ // Create a FaceData struct for each face that stores the 3D data
+ // in a Tao.OpenGL friendly format
+ for (int j = 0; j < render.Mesh.Faces.Count; j++)
+ {
+ Face face = render.Mesh.Faces[j];
+ FaceData data = new FaceData();
+
+ // Vertices for this face
+ data.Vertices = new float[face.Vertices.Count * 3];
+ for (int k = 0; k < face.Vertices.Count; k++)
+ {
+ data.Vertices[k * 3 + 0] = face.Vertices[k].Position.X;
+ data.Vertices[k * 3 + 1] = face.Vertices[k].Position.Y;
+ data.Vertices[k * 3 + 2] = face.Vertices[k].Position.Z;
+ }
+
+ // Indices for this face
+ data.Indices = face.Indices.ToArray();
+
+ // Texture transform for this face
+ Primitive.TextureEntryFace teFace = prim.Textures.GetFace((uint)j);
+ Render.Plugin.TransformTexCoords(face.Vertices, face.Center, teFace, prim.Scale);
+
+ // Texcoords for this face
+ data.TexCoords = new float[face.Vertices.Count * 2];
+ for (int k = 0; k < face.Vertices.Count; k++)
+ {
+ data.TexCoords[k * 2 + 0] = face.Vertices[k].TexCoord.X;
+ data.TexCoords[k * 2 + 1] = face.Vertices[k].TexCoord.Y;
+ }
+
+ // Texture for this face
+ if (teFace.TextureID != UUID.Zero &&
+ teFace.TextureID != Primitive.TextureEntry.WHITE_TEXTURE)
+ {
+ lock (Textures)
+ {
+ if (!Textures.ContainsKey(teFace.TextureID))
+ {
+ // We haven't constructed this image in OpenGL yet, get ahold of it
+ Client.Assets.RequestImage(teFace.TextureID, ImageType.Normal, TextureDownloader_OnDownloadFinished);
+ }
+ }
+ }
+
+ // Set the UserData for this face to our FaceData struct
+ face.UserData = data;
+ render.Mesh.Faces[j] = face;
+ }
+
+ lock (RenderPrimList) RenderPrimList[prim.LocalID] = render;
+ }
+
+ private void Terrain_LandPatchReceived(object sender, LandPatchReceivedEventArgs e)
+ {
+ if (Client != null && Client.Network.CurrentSim == e.Simulator)
+ {
+ Heightmap[e.Y, e.X].Data = e.HeightMap;
+ }
+
+ // Find the new max height
+ for (int i = 0; i < e.HeightMap.Length; i++)
+ {
+ if (e.HeightMap[i] > MaxHeight)
+ MaxHeight = e.HeightMap[i];
+ }
+ }
+
+ private void Network_OnLogin(object sender, LoginProgressEventArgs e)
+ {
+ if (e.Status == LoginStatus.Success)
+ {
+ // Success!
+ }
+ else if (e.Status == LoginStatus.Failed)
+ {
+ BeginInvoke(
+ (MethodInvoker)delegate()
+ {
+ MessageBox.Show(this, String.Format("Error logging in ({0}): {1}",
+ Client.Network.LoginErrorKey, Client.Network.LoginMessage));
+ cmdLogin.Text = "Login";
+ txtFirst.Enabled = txtLast.Enabled = txtPass.Enabled = true;
+ });
+ }
+ }
+
+ private void Network_OnDisconnected(object sender, DisconnectedEventArgs e)
+ {
+ BeginInvoke(
+ (MethodInvoker)delegate()
+ {
+ cmdTeleport.Enabled = false;
+ DoLogout();
+ });
+ }
+
+ private void Network_OnCurrentSimChanged(object sender, SimChangedEventArgs e)
+ {
+ Console.WriteLine("CurrentSim set to " + Client.Network.CurrentSim + ", downloading parcel information");
+
+ BeginInvoke((MethodInvoker)delegate() { txtSim.Text = Client.Network.CurrentSim.Name; });
+
+ //InitHeightmap();
+ InitLists();
+
+ // Disable teleports until the new event queue comes online
+ if (!Client.Network.CurrentSim.Caps.IsEventQueueRunning)
+ BeginInvoke((MethodInvoker)delegate() { cmdTeleport.Enabled = false; });
+ }
+
+ private void Network_OnEventQueueRunning(object sender, EventQueueRunningEventArgs e)
+ {
+ if (e.Simulator == Client.Network.CurrentSim)
+ BeginInvoke((MethodInvoker)delegate() { cmdTeleport.Enabled = true; });
+
+ // Now seems like a good time to start requesting parcel information
+ Client.Parcels.RequestAllSimParcels(Client.Network.CurrentSim, false, 100);
+ }
+
+ private void RenderScene()
+ {
+ try
+ {
+ Gl.glClear(Gl.GL_COLOR_BUFFER_BIT | Gl.GL_DEPTH_BUFFER_BIT);
+ Gl.glLoadIdentity();
+ Gl.glEnableClientState(Gl.GL_VERTEX_ARRAY);
+ Gl.glEnableClientState(Gl.GL_TEXTURE_COORD_ARRAY);
+
+ if (Clicked)
+ StartPicking(ClickX, ClickY);
+
+ // Setup wireframe or solid fill drawing mode
+ Gl.glPolygonMode(Gl.GL_FRONT, Gl.GL_LINE);
+
+ // Position the camera
+ Glu.gluLookAt(
+ Camera.Position.X, Camera.Position.Y, Camera.Position.Z,
+ Camera.FocalPoint.X, Camera.FocalPoint.Y, Camera.FocalPoint.Z,
+ 0f, 0f, 1f);
+
+ RenderSkybox();
+
+ // Push the world matrix
+ Gl.glPushMatrix();
+
+ RenderTerrain();
+ RenderPrims();
+ RenderAvatars();
+
+ Gl.glDisableClientState(Gl.GL_TEXTURE_COORD_ARRAY);
+ Gl.glDisableClientState(Gl.GL_VERTEX_ARRAY);
+
+ if (Clicked)
+ {
+ Clicked = false;
+ StopPicking();
+ }
+
+ // Pop the world matrix
+ Gl.glPopMatrix();
+ Gl.glFlush();
+
+ glControl.Invalidate();
+ }
+ catch (Exception)
+ {
+ }
+ }
+
+ static readonly Vector3[] SkyboxVerts = new Vector3[]
+ {
+ // Right side
+ new Vector3( 10.0f, 10.0f, -10.0f ), //Top left
+ new Vector3( 10.0f, 10.0f, 10.0f ), //Top right
+ new Vector3( 10.0f, -10.0f, 10.0f ), //Bottom right
+ new Vector3( 10.0f, -10.0f, -10.0f ), //Bottom left
+ // Left side
+ new Vector3( -10.0f, 10.0f, 10.0f ), //Top left
+ new Vector3( -10.0f, 10.0f, -10.0f ), //Top right
+ new Vector3( -10.0f, -10.0f, -10.0f ), //Bottom right
+ new Vector3( -10.0f, -10.0f, 10.0f ), //Bottom left
+ // Top side
+ new Vector3( -10.0f, 10.0f, 10.0f ), //Top left
+ new Vector3( 10.0f, 10.0f, 10.0f ), //Top right
+ new Vector3( 10.0f, 10.0f, -10.0f ), //Bottom right
+ new Vector3( -10.0f, 10.0f, -10.0f ), //Bottom left
+ // Bottom side
+ new Vector3( -10.0f, -10.0f, -10.0f ), //Top left
+ new Vector3( 10.0f, -10.0f, -10.0f ), //Top right
+ new Vector3( 10.0f, -10.0f, 10.0f ), //Bottom right
+ new Vector3( -10.0f, -10.0f, 10.0f ), //Bottom left
+ // Front side
+ new Vector3( -10.0f, 10.0f, -10.0f ), //Top left
+ new Vector3( 10.0f, 10.0f, -10.0f ), //Top right
+ new Vector3( 10.0f, -10.0f, -10.0f ), //Bottom right
+ new Vector3( -10.0f, -10.0f, -10.0f ), //Bottom left
+ // Back side
+ new Vector3( 10.0f, 10.0f, 10.0f ), //Top left
+ new Vector3( -10.0f, 10.0f, 10.0f ), //Top right
+ new Vector3( -10.0f, -10.0f, 10.0f ), //Bottom right
+ new Vector3( 10.0f, -10.0f, 10.0f ), //Bottom left
+ };
+
+ private void RenderSkybox()
+ {
+ //Gl.glTranslatef(0f, 0f, 0f);
+ }
+
+ private void RenderTerrain()
+ {
+ if (Heightmap != null)
+ {
+ int i = 0;
+
+ // No texture
+ Gl.glBindTexture(Gl.GL_TEXTURE_2D, 0);
+
+ for (int hy = 0; hy < 16; hy++)
+ {
+ for (int hx = 0; hx < 16; hx++)
+ {
+ uint patchName = (uint)(TERRAIN_START + i);
+ Gl.glPushName(patchName);
+ ++i;
+
+ // Check if this patch is currently selected
+ bool selected = (LastHit == patchName);
+
+ for (int y = 0; y < 15; y++)
+ {
+ Gl.glBegin(Gl.GL_TRIANGLE_STRIP);
+
+ for (int x = 0; x < 15; x++)
+ {
+ // Vertex 0
+ float height = Heightmap[hy, hx].Data[y * 16 + x];
+ float color = height / MaxHeight;
+ float red = (selected) ? 1f : color;
+
+ Gl.glColor3f(red, color, color);
+ Gl.glTexCoord2f(0f, 0f);
+ Gl.glVertex3f(hx * 16 + x, hy * 16 + y, height);
+
+ // Vertex 1
+ height = Heightmap[hy, hx].Data[y * 16 + (x + 1)];
+ color = height / MaxHeight;
+ red = (selected) ? 1f : color;
+
+ Gl.glColor3f(red, color, color);
+ Gl.glTexCoord2f(1f, 0f);
+ Gl.glVertex3f(hx * 16 + x + 1, hy * 16 + y, height);
+
+ // Vertex 2
+ height = Heightmap[hy, hx].Data[(y + 1) * 16 + x];
+ color = height / MaxHeight;
+ red = (selected) ? 1f : color;
+
+ Gl.glColor3f(red, color, color);
+ Gl.glTexCoord2f(0f, 1f);
+ Gl.glVertex3f(hx * 16 + x, hy * 16 + y + 1, height);
+
+ // Vertex 3
+ height = Heightmap[hy, hx].Data[(y + 1) * 16 + (x + 1)];
+ color = height / MaxHeight;
+ red = (selected) ? 1f : color;
+
+ Gl.glColor3f(red, color, color);
+ Gl.glTexCoord2f(1f, 1f);
+ Gl.glVertex3f(hx * 16 + x + 1, hy * 16 + y + 1, height);
+ }
+
+ Gl.glEnd();
+ }
+
+ Gl.glPopName();
+ }
+ }
+ }
+ }
+
+ //int[] CubeMapDefines = new int[]
+ //{
+ // Gl.GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
+ // Gl.GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
+ // Gl.GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
+ // Gl.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
+ // Gl.GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
+ // Gl.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
+ //};
+
+ private void RenderPrims()
+ {
+ if (RenderPrimList != null && RenderPrimList.Count > 0)
+ {
+ Gl.glEnable(Gl.GL_TEXTURE_2D);
+
+ lock (RenderPrimList)
+ {
+ bool firstPass = true;
+ Gl.glDisable(Gl.GL_BLEND);
+ Gl.glEnable(Gl.GL_DEPTH_TEST);
+
+ StartRender:
+
+ foreach (RenderablePrim render in RenderPrimList.Values)
+ {
+ RenderablePrim parentRender = RenderablePrim.Empty;
+ Primitive prim = render.Prim;
+
+ if (prim.ParentID != 0)
+ {
+ // Get the parent reference
+ if (!RenderPrimList.TryGetValue(prim.ParentID, out parentRender))
+ {
+ // Can't render a child with no parent prim, skip it
+ continue;
+ }
+ }
+
+ Gl.glPushName(prim.LocalID);
+ Gl.glPushMatrix();
+
+ if (prim.ParentID != 0)
+ {
+ // Child prim
+ Primitive parent = parentRender.Prim;
+
+ // Apply parent translation and rotation
+ Gl.glMultMatrixf(Math3D.CreateTranslationMatrix(parent.Position));
+ Gl.glMultMatrixf(Math3D.CreateRotationMatrix(parent.Rotation));
+ }
+
+ // Apply prim translation and rotation
+ Gl.glMultMatrixf(Math3D.CreateTranslationMatrix(prim.Position));
+ Gl.glMultMatrixf(Math3D.CreateRotationMatrix(prim.Rotation));
+
+ // Scale the prim
+ Gl.glScalef(prim.Scale.X, prim.Scale.Y, prim.Scale.Z);
+
+ // Draw the prim faces
+ for (int j = 0; j < render.Mesh.Faces.Count; j++)
+ {
+ Face face = render.Mesh.Faces[j];
+ FaceData data = (FaceData)face.UserData;
+ Color4 color = face.TextureFace.RGBA;
+ bool alpha = false;
+ int textureID = 0;
+
+ if (color.A < 1.0f)
+ alpha = true;
+
+ #region Texturing
+
+ TextureInfo info;
+ if (Textures.TryGetValue(face.TextureFace.TextureID, out info))
+ {
+ if (info.Alpha)
+ alpha = true;
+
+ textureID = info.ID;
+
+ // Enable texturing for this face
+ Gl.glPolygonMode(Gl.GL_FRONT_AND_BACK, Gl.GL_FILL);
+ }
+ else
+ {
+ if (face.TextureFace.TextureID == Primitive.TextureEntry.WHITE_TEXTURE ||
+ face.TextureFace.TextureID == UUID.Zero)
+ {
+ Gl.glPolygonMode(Gl.GL_FRONT, Gl.GL_FILL);
+ }
+ else
+ {
+ Gl.glPolygonMode(Gl.GL_FRONT, Gl.GL_LINE);
+ }
+ }
+
+ if (firstPass && !alpha || !firstPass && alpha)
+ {
+ // Color this prim differently based on whether it is selected or not
+ if (LastHit == prim.LocalID || (LastHit != 0 && LastHit == prim.ParentID))
+ {
+ Gl.glColor4f(1f, color.G * 0.3f, color.B * 0.3f, color.A);
+ }
+ else
+ {
+ Gl.glColor4f(color.R, color.G, color.B, color.A);
+ }
+
+ // Bind the texture
+ Gl.glBindTexture(Gl.GL_TEXTURE_2D, textureID);
+
+ Gl.glTexCoordPointer(2, Gl.GL_FLOAT, 0, data.TexCoords);
+ Gl.glVertexPointer(3, Gl.GL_FLOAT, 0, data.Vertices);
+ Gl.glDrawElements(Gl.GL_TRIANGLES, data.Indices.Length, Gl.GL_UNSIGNED_SHORT, data.Indices);
+ }
+
+ #endregion Texturing
+ }
+
+ Gl.glPopMatrix();
+ Gl.glPopName();
+ }
+
+ if (firstPass)
+ {
+ firstPass = false;
+ Gl.glEnable(Gl.GL_BLEND);
+ Gl.glBlendFunc(Gl.GL_SRC_ALPHA, Gl.GL_ONE_MINUS_SRC_ALPHA);
+ //Gl.glDisable(Gl.GL_DEPTH_TEST);
+
+ goto StartRender;
+ }
+ }
+
+ Gl.glEnable(Gl.GL_DEPTH_TEST);
+ Gl.glDisable(Gl.GL_TEXTURE_2D);
+ }
+ }
+
+ private void RenderAvatars()
+ {
+ if (Client != null && Client.Network.CurrentSim != null)
+ {
+ Gl.glColor3f(0f, 1f, 0f);
+
+ Client.Network.CurrentSim.ObjectsAvatars.ForEach(
+ delegate(Avatar avatar)
+ {
+ Gl.glPushMatrix();
+ Gl.glTranslatef(avatar.Position.X, avatar.Position.Y, avatar.Position.Z);
+
+ Glu.GLUquadric quad = Glu.gluNewQuadric();
+ Glu.gluSphere(quad, 1.0d, 10, 10);
+ Glu.gluDeleteQuadric(quad);
+
+ Gl.glPopMatrix();
+ }
+ );
+
+ Gl.glColor3f(1f, 1f, 1f);
+ }
+ }
+
+ #region Texture Downloading
+
+ private void TextureDownloader_OnDownloadFinished(TextureRequestState state, AssetTexture asset)
+ {
+ bool alpha = false;
+ ManagedImage imgData = null;
+ byte[] raw = null;
+
+ bool success = (state == TextureRequestState.Finished);
+
+ UUID id = asset.AssetID;
+
+ try
+ {
+ // Load the image off the disk
+ if (success)
+ {
+ //ImageDownload download = TextureDownloader.GetTextureToRender(id);
+ if (OpenJPEG.DecodeToImage(asset.AssetData, out imgData))
+ {
+ raw = imgData.ExportRaw();
+
+ if ((imgData.Channels & ManagedImage.ImageChannels.Alpha) != 0)
+ alpha = true;
+ }
+ else
+ {
+ success = false;
+ Console.WriteLine("Failed to decode texture");
+ }
+ }
+
+ // Make sure the OpenGL commands run on the main thread
+ BeginInvoke(
+ (MethodInvoker)delegate()
+ {
+ if (success)
+ {
+ int textureID = 0;
+
+ try
+ {
+ Gl.glGenTextures(1, out textureID);
+ Gl.glBindTexture(Gl.GL_TEXTURE_2D, textureID);
+
+ Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_LINEAR_MIPMAP_NEAREST); //Gl.GL_NEAREST);
+ Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_LINEAR);
+ Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_S, Gl.GL_REPEAT);
+ Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_T, Gl.GL_REPEAT);
+ Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_GENERATE_MIPMAP, Gl.GL_TRUE); //Gl.GL_FALSE);
+
+ //Gl.glTexImage2D(Gl.GL_TEXTURE_2D, 0, Gl.GL_RGBA, bitmap.Width, bitmap.Height, 0, Gl.GL_BGRA, Gl.GL_UNSIGNED_BYTE,
+ // bitmapData.Scan0);
+ //int error = Gl.glGetError();
+
+ int error = Glu.gluBuild2DMipmaps(Gl.GL_TEXTURE_2D, Gl.GL_RGBA, imgData.Width, imgData.Height, Gl.GL_BGRA,
+ Gl.GL_UNSIGNED_BYTE, raw);
+
+ if (error == 0)
+ {
+ Textures[id] = new TextureInfo(textureID, alpha);
+ Console.WriteLine("Created OpenGL texture for " + id.ToString());
+ }
+ else
+ {
+ Textures[id] = new TextureInfo(0, false);
+ Console.WriteLine("Error creating OpenGL texture: " + error);
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine(ex);
+ }
+ }
+
+ // Remove this image from the download listbox
+ lock (DownloadList)
+ {
+ GlacialComponents.Controls.GLItem item;
+ if (DownloadList.TryGetValue(id, out item))
+ {
+ DownloadList.Remove(id);
+ try { lstDownloads.Items.Remove(item); }
+ catch (Exception) { }
+ lstDownloads.Invalidate();
+ }
+ }
+ });
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine(ex);
+ }
+ }
+
+ private void Assets_ImageReceiveProgress(object sender, ImageReceiveProgressEventArgs e)
+ {
+ lock (DownloadList)
+ {
+ GlacialComponents.Controls.GLItem item;
+ if (DownloadList.TryGetValue(e.ImageID, out item))
+ {
+ // Update an existing item
+ BeginInvoke(
+ (MethodInvoker)delegate()
+ {
+ ProgressBar prog = (ProgressBar)item.SubItems[1].Control;
+ if (e.Total >= e.Received)
+ prog.Value = (int)Math.Round((((double)e.Received / (double)e.Total) * 100.0d));
+ });
+ }
+ else
+ {
+ // Progress bar
+ ProgressBar prog = new ProgressBar();
+ prog.Minimum = 0;
+ prog.Maximum = 100;
+ if (e.Total >= e.Received)
+ prog.Value = (int)Math.Round((((double)e.Received / (double)e.Total) * 100.0d));
+ else
+ prog.Value = 0;
+
+ // List item
+ item = new GlacialComponents.Controls.GLItem();
+ item.SubItems[0].Text = e.ImageID.ToString();
+ item.SubItems[1].Control = prog;
+
+ DownloadList[e.ImageID] = item;
+
+ BeginInvoke(
+ (MethodInvoker)delegate()
+ {
+ lstDownloads.Items.Add(item);
+ lstDownloads.Invalidate();
+ });
+ }
+ }
+ }
+
+ #endregion Texture Downloading
+
+ private void frmBrowser_FormClosing(object sender, FormClosingEventArgs e)
+ {
+ DoLogout();
+
+ Application.Idle -= IdleEvent;
+ }
+
+ private void Application_Idle(object sender, EventArgs e)
+ {
+ while (AppStillIdle)
+ {
+ RenderScene();
+ }
+ }
+
+ private void cmdLogin_Click(object sender, EventArgs e)
+ {
+ if (cmdLogin.Text == "Login")
+ {
+ // Check that all the input boxes are filled in
+ if (txtFirst.Text.Length == 0)
+ {
+ txtFirst.Select();
+ return;
+ }
+ if (txtLast.Text.Length == 0)
+ {
+ txtLast.Select();
+ return;
+ }
+ if (txtPass.Text.Length == 0)
+ {
+ txtPass.Select();
+ return;
+ }
+
+ // Disable input controls
+ txtFirst.Enabled = txtLast.Enabled = txtPass.Enabled = false;
+ cmdLogin.Text = "Logout";
+
+ // Sanity check that we aren't already logged in
+ if (Client != null && Client.Network.Connected)
+ {
+ Client.Network.Logout();
+ }
+
+ // Re-initialize everything
+ InitializeObjects();
+
+ // Start the login
+ LoginParams loginParams = Client.Network.DefaultLoginParams(txtFirst.Text, txtLast.Text,
+ txtPass.Text, "Prim Preview", "0.0.1");
+
+ if (!String.IsNullOrEmpty(cboServer.Text))
+ loginParams.URI = cboServer.Text;
+
+ Client.Network.BeginLogin(loginParams);
+ }
+ else
+ {
+ DoLogout();
+ }
+ }
+
+ private void DoLogout()
+ {
+ if (Client != null && Client.Network.Connected)
+ {
+ Client.Network.Logout();
+ return;
+ }
+
+ // Clear the download list
+ lstDownloads.Items.Clear();
+
+ // Set the login button back to login state
+ cmdLogin.Text = "Login";
+
+ // Enable input controls
+ txtFirst.Enabled = txtLast.Enabled = txtPass.Enabled = true;
+ }
+
+ private void glControl_Resize(object sender, EventArgs e)
+ {
+ Gl.glClearColor(0.39f, 0.58f, 0.93f, 1.0f);
+
+ Gl.glViewport(0, 0, glControl.Width, glControl.Height);
+
+ Gl.glPushMatrix();
+ Gl.glMatrixMode(Gl.GL_PROJECTION);
+ Gl.glLoadIdentity();
+
+ SetPerspective();
+
+ Gl.glMatrixMode(Gl.GL_MODELVIEW);
+ Gl.glPopMatrix();
+
+ // Set the center of the glControl as the default pivot point
+ LastPivot = glControl.PointToScreen(new Point(glControl.Width / 2, glControl.Height / 2));
+ }
+
+ private void glControl_MouseClick(object sender, MouseEventArgs e)
+ {
+ if ((Control.ModifierKeys & Keys.Alt) == 0 && e.Button == MouseButtons.Left)
+ {
+ // Only allow clicking if alt is not being held down
+ ClickX = e.X;
+ ClickY = e.Y;
+ Clicked = true;
+ }
+ }
+
+ private void glControl_MouseDown(object sender, MouseEventArgs e)
+ {
+ if ((Control.ModifierKeys & Keys.Alt) != 0 && LastHit > 0)
+ {
+ // Alt is held down and we have a valid target
+ Pivoting = true;
+ PivotPosition = Camera.FocalPoint;
+
+ Control control = (Control)sender;
+ LastPivot = control.PointToScreen(new Point(e.X, e.Y));
+ }
+ }
+
+ private void glControl_MouseMove(object sender, MouseEventArgs e)
+ {
+ if (Pivoting)
+ {
+ float a, x, y, z;
+
+ Control control = (Control)sender;
+ Point mouse = control.PointToScreen(new Point(e.X, e.Y));
+
+ // Calculate the deltas from the center of the control to the current position
+ int deltaX = (int)((mouse.X - LastPivot.X) * -0.5d);
+ int deltaY = (int)((mouse.Y - LastPivot.Y) * -0.5d);
+
+ // Translate so the focal point is the origin
+ Vector3 altered = Camera.Position - Camera.FocalPoint;
+
+ // Rotate the translated point by deltaX
+ a = (float)deltaX * DEG_TO_RAD;
+ x = (float)((altered.X * Math.Cos(a)) - (altered.Y * Math.Sin(a)));
+ y = (float)((altered.X * Math.Sin(a)) + (altered.Y * Math.Cos(a)));
+
+ altered.X = x;
+ altered.Y = y;
+
+ // Rotate the translated point by deltaY
+ a = (float)deltaY * DEG_TO_RAD;
+ y = (float)((altered.Y * Math.Cos(a)) - (altered.Z * Math.Sin(a)));
+ z = (float)((altered.Y * Math.Sin(a)) + (altered.Z * Math.Cos(a)));
+
+ altered.Y = y;
+ altered.Z = z;
+
+ // Translate back to world space
+ altered += Camera.FocalPoint;
+
+ // Update the camera
+ Camera.Position = altered;
+ UpdateCamera();
+
+ // Update the pivot point
+ LastPivot = mouse;
+ }
+ }
+
+ private void glControl_MouseWheel(object sender, MouseEventArgs e)
+ {
+ /*if (e.Delta != 0)
+ {
+ Camera.Zoom = Camera.Zoom + (double)(e.Delta / 120) * -0.1d;
+ if (Camera.Zoom < 0.05d) Camera.Zoom = 0.05d;
+ UpdateCamera();
+ }*/
+
+ if (e.Delta != 0)
+ {
+ // Calculate the distance to move to/away
+ float dist = (float)(e.Delta / 120) * 10.0f;
+
+ if (Vector3.Distance(Camera.Position, Camera.FocalPoint) > dist)
+ {
+ // Move closer or further away from the focal point
+ Vector3 toFocal = Camera.FocalPoint - Camera.Position;
+ toFocal.Normalize();
+
+ toFocal = toFocal * dist;
+
+ Camera.Position += toFocal;
+ UpdateCamera();
+ }
+ }
+ }
+
+ private void glControl_MouseUp(object sender, MouseEventArgs e)
+ {
+ // Stop pivoting if we were previously
+ Pivoting = false;
+ }
+
+ private void txtLogin_Enter(object sender, EventArgs e)
+ {
+ TextBox input = (TextBox)sender;
+ input.SelectAll();
+ }
+
+ private void cmdTeleport_Click(object sender, EventArgs e)
+ {
+ if (!String.IsNullOrEmpty(txtSim.Text))
+ {
+ // Parse X/Y/Z
+ int x, y, z;
+ if (!Int32.TryParse(txtX.Text, out x))
+ {
+ txtX.SelectAll();
+ return;
+ }
+ if (!Int32.TryParse(txtY.Text, out y))
+ {
+ txtY.SelectAll();
+ return;
+ }
+ if (!Int32.TryParse(txtZ.Text, out z))
+ {
+ txtZ.SelectAll();
+ return;
+ }
+
+ string simName = txtSim.Text.Trim().ToLower();
+ Vector3 position = new Vector3(x, y, z);
+
+ if (Client != null && Client.Network.CurrentSim != null)
+ {
+ // Check for a local teleport to shortcut the process
+ if (simName == Client.Network.CurrentSim.Name.ToLower())
+ {
+ // Local teleport
+ Client.Self.RequestTeleport(Client.Network.CurrentSim.Handle, position);
+ }
+ else
+ {
+ // Cross-sim teleport
+ bool success = false;
+
+ BackgroundWorker worker = new BackgroundWorker();
+ worker.DoWork += delegate(object s, DoWorkEventArgs ea) { success = Client.Self.Teleport(simName, position); };
+ worker.RunWorkerCompleted += delegate(object s, RunWorkerCompletedEventArgs ea)
+ {
+ BeginInvoke((MethodInvoker)
+ delegate()
+ {
+ if (!success)
+ System.Windows.Forms.MessageBox.Show("Teleport failed");
+ });
+ };
+
+ worker.RunWorkerAsync();
+ }
+ }
+ else
+ {
+ // Oops! How did the user click this...
+ cmdTeleport.Enabled = false;
+ }
+ }
+ }
+ }
+
+ public struct TextureInfo
+ {
+ /// OpenGL Texture ID
+ public int ID;
+ /// True if this texture has an alpha component
+ public bool Alpha;
+
+ public TextureInfo(int id, bool alpha)
+ {
+ ID = id;
+ Alpha = alpha;
+ }
+ }
+
+ public struct HeightmapLookupValue : IComparable
+ {
+ public ushort Index;
+ public float Value;
+
+ public HeightmapLookupValue(ushort index, float value)
+ {
+ Index = index;
+ Value = value;
+ }
+
+ public int CompareTo(HeightmapLookupValue val)
+ {
+ return Value.CompareTo(val.Value);
+ }
+ }
+
+ public struct RenderablePrim
+ {
+ public Primitive Prim;
+ public FacetedMesh Mesh;
+
+ public readonly static RenderablePrim Empty = new RenderablePrim();
+ }
+
+ public struct Camera
+ {
+ public Vector3 Position;
+ public Vector3 FocalPoint;
+ public double Zoom;
+ public double Far;
+ }
+
+ public struct NativeMethods
+ {
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Message
+ {
+ public IntPtr HWnd;
+ public uint Msg;
+ public IntPtr WParam;
+ public IntPtr LParam;
+ public uint Time;
+ public System.Drawing.Point Point;
+ }
+
+ //[System.Security.SuppressUnmanagedCodeSecurity]
+ [DllImport("User32.dll", CharSet = CharSet.Auto)]
+ public static extern bool PeekMessage(out Message msg, IntPtr hWnd, uint messageFilterMin, uint messageFilterMax, uint flags);
+ }
+
+ public static class Math3D
+ {
+ // Column-major:
+ // | 0 4 8 12 |
+ // | 1 5 9 13 |
+ // | 2 6 10 14 |
+ // | 3 7 11 15 |
+
+ public static float[] CreateTranslationMatrix(Vector3 v)
+ {
+ float[] mat = new float[16];
+
+ mat[12] = v.X;
+ mat[13] = v.Y;
+ mat[14] = v.Z;
+ mat[0] = mat[5] = mat[10] = mat[15] = 1;
+
+ return mat;
+ }
+
+ public static float[] CreateRotationMatrix(Quaternion q)
+ {
+ float[] mat = new float[16];
+
+ // Transpose the quaternion (don't ask me why)
+ q.X = q.X * -1f;
+ q.Y = q.Y * -1f;
+ q.Z = q.Z * -1f;
+
+ float x2 = q.X + q.X;
+ float y2 = q.Y + q.Y;
+ float z2 = q.Z + q.Z;
+ float xx = q.X * x2;
+ float xy = q.X * y2;
+ float xz = q.X * z2;
+ float yy = q.Y * y2;
+ float yz = q.Y * z2;
+ float zz = q.Z * z2;
+ float wx = q.W * x2;
+ float wy = q.W * y2;
+ float wz = q.W * z2;
+
+ mat[0] = 1.0f - (yy + zz);
+ mat[1] = xy - wz;
+ mat[2] = xz + wy;
+ mat[3] = 0.0f;
+
+ mat[4] = xy + wz;
+ mat[5] = 1.0f - (xx + zz);
+ mat[6] = yz - wx;
+ mat[7] = 0.0f;
+
+ mat[8] = xz - wy;
+ mat[9] = yz + wx;
+ mat[10] = 1.0f - (xx + yy);
+ mat[11] = 0.0f;
+
+ mat[12] = 0.0f;
+ mat[13] = 0.0f;
+ mat[14] = 0.0f;
+ mat[15] = 1.0f;
+
+ return mat;
+ }
+
+ public static float[] CreateScaleMatrix(Vector3 v)
+ {
+ float[] mat = new float[16];
+
+ mat[0] = v.X;
+ mat[5] = v.Y;
+ mat[10] = v.Z;
+ mat[15] = 1;
+
+ return mat;
+ }
+ }
+}
diff --git a/Programs/PrimWorkshop/frmPrimWorkshop.cs b/Programs/PrimWorkshop/frmPrimWorkshop.cs
index 81c0089a..33107d82 100644
--- a/Programs/PrimWorkshop/frmPrimWorkshop.cs
+++ b/Programs/PrimWorkshop/frmPrimWorkshop.cs
@@ -1,702 +1,702 @@
-using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Drawing;
-using System.Drawing.Imaging;
-using System.IO;
-using System.Windows.Forms;
-using Tao.OpenGl;
-using Tao.Platform.Windows;
-using ICSharpCode.SharpZipLib.Zip;
-using OpenMetaverse;
-using OpenMetaverse.StructuredData;
-using OpenMetaverse.Imaging;
-using OpenMetaverse.Rendering;
-
-// NOTE: Batches are divided by texture, fullbright, shiny, transparent, and glow
-
-namespace PrimWorkshop
-{
- public partial class frmPrimWorkshop : Form
- {
- #region Form Globals
-
- List Prims = null;
- FacetedMesh CurrentPrim = null;
- ProfileFace? CurrentFace = null;
-
- bool DraggingTexture = false;
- bool Wireframe = true;
- int[] TexturePointers = new int[1];
- Dictionary Textures = new Dictionary();
-
- #endregion Form Globals
-
- public frmPrimWorkshop()
- {
- InitializeComponent();
- glControl.InitializeContexts();
-
- Gl.glShadeModel(Gl.GL_SMOOTH);
- Gl.glClearColor(0f, 0f, 0f, 0f);
-
- Gl.glClearDepth(1.0f);
- Gl.glEnable(Gl.GL_DEPTH_TEST);
- Gl.glDepthMask(Gl.GL_TRUE);
- Gl.glDepthFunc(Gl.GL_LEQUAL);
- Gl.glHint(Gl.GL_PERSPECTIVE_CORRECTION_HINT, Gl.GL_NICEST);
-
- TexturePointers[0] = 0;
-
- // Call the resizing function which sets up the GL drawing window
- // and will also invalidate the GL control
- glControl_Resize(null, null);
- }
-
- private void frmPrimWorkshop_Shown(object sender, EventArgs e)
- {
- // Get a list of rendering plugins
- List renderers = RenderingLoader.ListRenderers(".");
-
- foreach (string r in renderers)
- {
- DialogResult result = MessageBox.Show(
- String.Format("Use renderer {0}?", r), "Select Rendering Plugin", MessageBoxButtons.YesNo);
-
- if (result == DialogResult.Yes)
- {
- Render.Plugin = RenderingLoader.LoadRenderer(r);
- break;
- }
- }
-
- if (Render.Plugin == null)
- {
- MessageBox.Show("No valid rendering plugin loaded, exiting...");
- Application.Exit();
- }
- }
-
- #region GLControl Callbacks
-
- private void glControl_Paint(object sender, PaintEventArgs e)
- {
- Gl.glClear(Gl.GL_COLOR_BUFFER_BIT | Gl.GL_DEPTH_BUFFER_BIT);
- Gl.glLoadIdentity();
-
- // Setup wireframe or solid fill drawing mode
- if (Wireframe)
- Gl.glPolygonMode(Gl.GL_FRONT_AND_BACK, Gl.GL_LINE);
- else
- Gl.glPolygonMode(Gl.GL_FRONT, Gl.GL_FILL);
-
- Vector3 center = Vector3.Zero;
-
- Glu.gluLookAt(
- center.X, (double)scrollZoom.Value * 0.1d + center.Y, center.Z,
- center.X, center.Y, center.Z,
- 0d, 0d, 1d);
-
- // Push the world matrix
- Gl.glPushMatrix();
-
- Gl.glEnableClientState(Gl.GL_VERTEX_ARRAY);
- Gl.glEnableClientState(Gl.GL_TEXTURE_COORD_ARRAY);
-
- // World rotations
- Gl.glRotatef((float)scrollRoll.Value, 1f, 0f, 0f);
- Gl.glRotatef((float)scrollPitch.Value, 0f, 1f, 0f);
- Gl.glRotatef((float)scrollYaw.Value, 0f, 0f, 1f);
-
- if (Prims != null)
- {
- for (int i = 0; i < Prims.Count; i++)
- {
- Primitive prim = Prims[i].Prim;
-
- if (i == cboPrim.SelectedIndex)
- Gl.glColor3f(1f, 0f, 0f);
- else
- Gl.glColor3f(1f, 1f, 1f);
-
- // Individual prim matrix
- Gl.glPushMatrix();
-
- // The root prim position is sim-relative, while child prim positions are
- // parent-relative. We want to apply parent-relative translations but not
- // sim-relative ones
- if (Prims[i].Prim.ParentID != 0)
- {
- // Apply prim translation and rotation
- Gl.glMultMatrixf(Math3D.CreateTranslationMatrix(prim.Position));
- Gl.glMultMatrixf(Math3D.CreateRotationMatrix(prim.Rotation));
- }
-
- // Prim scaling
- Gl.glScalef(prim.Scale.X, prim.Scale.Y, prim.Scale.Z);
-
- // Draw the prim faces
- for (int j = 0; j < Prims[i].Faces.Count; j++)
- {
- if (i == cboPrim.SelectedIndex)
- {
- // This prim is currently selected in the dropdown
- //Gl.glColor3f(0f, 1f, 0f);
- Gl.glColor3f(1f, 1f, 1f);
-
- if (j == cboFace.SelectedIndex)
- {
- // This face is currently selected in the dropdown
- }
- else
- {
- // This face is not currently selected in the dropdown
- }
- }
- else
- {
- // This prim is not currently selected in the dropdown
- Gl.glColor3f(1f, 1f, 1f);
- }
-
- #region Texturing
-
- Face face = Prims[i].Faces[j];
- FaceData data = (FaceData)face.UserData;
-
- if (data.TexturePointer != 0)
- {
- // Set the color to solid white so the texture is not altered
- //Gl.glColor3f(1f, 1f, 1f);
- // Enable texturing for this face
- Gl.glEnable(Gl.GL_TEXTURE_2D);
- }
- else
- {
- Gl.glDisable(Gl.GL_TEXTURE_2D);
- }
-
- // Bind the texture
- Gl.glBindTexture(Gl.GL_TEXTURE_2D, data.TexturePointer);
-
- #endregion Texturing
-
- Gl.glTexCoordPointer(2, Gl.GL_FLOAT, 0, data.TexCoords);
- Gl.glVertexPointer(3, Gl.GL_FLOAT, 0, data.Vertices);
- Gl.glDrawElements(Gl.GL_TRIANGLES, data.Indices.Length, Gl.GL_UNSIGNED_SHORT, data.Indices);
- }
-
- // Pop the prim matrix
- Gl.glPopMatrix();
- }
- }
-
- // Pop the world matrix
- Gl.glPopMatrix();
-
- Gl.glDisableClientState(Gl.GL_TEXTURE_COORD_ARRAY);
- Gl.glDisableClientState(Gl.GL_VERTEX_ARRAY);
-
- Gl.glFlush();
- }
-
- private void glControl_Resize(object sender, EventArgs e)
- {
- Gl.glClearColor(0.39f, 0.58f, 0.93f, 1.0f);
-
- Gl.glViewport(0, 0, glControl.Width, glControl.Height);
-
- Gl.glPushMatrix();
- Gl.glMatrixMode(Gl.GL_PROJECTION);
- Gl.glLoadIdentity();
-
- Glu.gluPerspective(50.0d, 1.0d, 0.1d, 256d);
-
- Gl.glMatrixMode(Gl.GL_MODELVIEW);
- Gl.glPopMatrix();
- }
-
- #endregion GLControl Callbacks
-
- #region Menu Callbacks
-
- private void openPrimXMLToolStripMenuItem1_Click(object sender, EventArgs e)
- {
- Prims = null;
- OpenFileDialog dialog = new OpenFileDialog();
- dialog.Filter = "Prim Package (*.zip)|*.zip|Sculpt Map (*.png)|*.png|OAR XML (*.xml)|*.xml";
-
- if (dialog.ShowDialog() == DialogResult.OK)
- {
- if (dialog.FileName.ToLowerInvariant().EndsWith(".zip"))
- {
- LoadPrimPackage(dialog.FileName);
- }
- else if (dialog.FileName.ToLowerInvariant().EndsWith(".xml"))
- {
- LoadXmlPrim(dialog.FileName);
- }
- else
- {
- LoadSculpt(dialog.FileName);
- }
- }
- }
-
- private void LoadDebugPrim()
- {
- Prims = new List();
- Primitive prim = new Primitive();
- prim.Textures = new Primitive.TextureEntry(UUID.Zero);
- prim.Scale = Vector3.One;
- prim.PrimData = ObjectManager.BuildBasicShape(PrimType.Cylinder);
- prim.PrimData.ProfileHollow = 0.95f;
- SimpleMesh simpleMesh = Render.Plugin.GenerateSimpleMesh(prim, DetailLevel.High);
- FacetedMesh facetedMesh = new FacetedMesh();
- facetedMesh.Faces = new List { new Face { Vertices = simpleMesh.Vertices, Indices = simpleMesh.Indices } };
- facetedMesh.Path = simpleMesh.Path;
- facetedMesh.Profile = simpleMesh.Profile;
- facetedMesh.Prim = prim;
- LoadMesh(facetedMesh, ".");
- PopulatePrimCombobox();
- glControl.Invalidate();
- }
-
- private void LoadXmlPrim(string filename)
- {
- byte[] data = File.ReadAllBytes(filename);
-
- OpenMetaverse.Assets.OarFile.LoadObjects(data, XmlObjectLoadedHandler, 0, data.Length);
- }
-
- private void XmlObjectLoadedHandler(OpenMetaverse.Assets.AssetPrim linkset, long bytesRead, long totalBytes)
- {
- Prims = new List(linkset.Children.Count + 1);
-
- Primitive parent = linkset.Parent.ToPrimitive();
- {
- FacetedMesh mesh = null;
-
- if (parent.Sculpt == null || parent.Sculpt.SculptTexture == UUID.Zero)
- mesh = Render.Plugin.GenerateFacetedMesh(parent, DetailLevel.Highest);
- if (mesh != null)
- LoadMesh(mesh, null);
- }
-
- for (int i = 0; i < linkset.Children.Count; i++)
- {
- Primitive child = linkset.Children[i].ToPrimitive();
- FacetedMesh mesh = null;
-
- if (parent.Sculpt == null || child.Sculpt.SculptTexture == UUID.Zero)
- mesh = Render.Plugin.GenerateFacetedMesh(child, DetailLevel.Highest);
- if (mesh != null)
- LoadMesh(mesh, null);
- }
-
- PopulatePrimCombobox();
-
- glControl.Invalidate();
- }
-
- private void LoadSculpt(string filename)
- {
- // Try to parse this as an image file
- Image sculptTexture = Image.FromFile(filename);
-
- Primitive prim = new Primitive();
- prim.PrimData = ObjectManager.BuildBasicShape(PrimType.Sculpt);
- prim.Sculpt = new Primitive.SculptData { SculptTexture = UUID.Random(), Type = SculptType.Sphere };
- prim.Textures = new Primitive.TextureEntry(UUID.Zero);
- prim.Scale = Vector3.One * 3f;
-
- FacetedMesh mesh = Render.Plugin.GenerateFacetedSculptMesh(prim, (Bitmap)sculptTexture, DetailLevel.Highest);
- if (mesh != null)
- {
- Prims = new List(1);
- LoadMesh(mesh, null);
- }
-
- glControl.Invalidate();
- }
-
- private void LoadPrimPackage(string filename)
- {
- string tempPath = System.IO.Path.Combine(System.IO.Path.GetTempPath(), System.IO.Path.GetRandomFileName());
-
- try
- {
- // Create a temporary directory
- Directory.CreateDirectory(tempPath);
-
- FastZip fastzip = new FastZip();
- fastzip.ExtractZip(filename, tempPath, String.Empty);
- }
- catch (Exception ex)
- {
- MessageBox.Show(ex.Message);
- return;
- }
-
- // Check for the prims.xml file
- string primsFile = System.IO.Path.Combine(tempPath, "prims.xml");
- if (!File.Exists(primsFile))
- {
- MessageBox.Show("prims.xml not found in the archive");
- return;
- }
-
- OSD osd = null;
-
- try { osd = OSDParser.DeserializeLLSDXml(File.ReadAllText(primsFile)); }
- catch (Exception ex) { MessageBox.Show(ex.Message); }
-
- if (osd != null && osd.Type == OSDType.Map)
- {
- List primList = Helpers.OSDToPrimList(osd);
- Prims = new List(primList.Count);
-
- for (int i = 0; i < primList.Count; i++)
- {
- Primitive prim = primList[i];
- FacetedMesh mesh = null;
-
- if (prim.Sculpt.SculptTexture != UUID.Zero)
- {
- Image sculptTexture = null;
- if (LoadTexture(tempPath, prim.Sculpt.SculptTexture, ref sculptTexture))
- mesh = Render.Plugin.GenerateFacetedSculptMesh(prim, (Bitmap)sculptTexture, DetailLevel.Highest);
- }
- else
- {
- mesh = Render.Plugin.GenerateFacetedMesh(prim, DetailLevel.Highest);
- }
-
- if (mesh != null)
- LoadMesh(mesh, tempPath);
- }
-
- // Setup the dropdown list of prims
- PopulatePrimCombobox();
-
- glControl.Invalidate();
- }
- else
- {
- MessageBox.Show("Failed to load LLSD formatted primitive data from " + filename);
- }
-
- Directory.Delete(tempPath);
- }
-
- private void LoadMesh(FacetedMesh mesh, string basePath)
- {
- // Create a FaceData struct for each face that stores the 3D data
- // in a Tao.OpenGL friendly format
- for (int j = 0; j < mesh.Faces.Count; j++)
- {
- Face face = mesh.Faces[j];
- FaceData data = new FaceData();
-
- // Vertices for this face
- data.Vertices = new float[face.Vertices.Count * 3];
- for (int k = 0; k < face.Vertices.Count; k++)
- {
- data.Vertices[k * 3 + 0] = face.Vertices[k].Position.X;
- data.Vertices[k * 3 + 1] = face.Vertices[k].Position.Y;
- data.Vertices[k * 3 + 2] = face.Vertices[k].Position.Z;
- }
-
- // Indices for this face
- data.Indices = face.Indices.ToArray();
-
- // Texture transform for this face
- Primitive.TextureEntryFace teFace = mesh.Prim.Textures.GetFace((uint)j);
- Render.Plugin.TransformTexCoords(face.Vertices, face.Center, teFace);
-
- // Texcoords for this face
- data.TexCoords = new float[face.Vertices.Count * 2];
- for (int k = 0; k < face.Vertices.Count; k++)
- {
- data.TexCoords[k * 2 + 0] = face.Vertices[k].TexCoord.X;
- data.TexCoords[k * 2 + 1] = face.Vertices[k].TexCoord.Y;
- }
-
- // Texture for this face
- if (!String.IsNullOrEmpty(basePath) && LoadTexture(basePath, teFace.TextureID, ref data.Texture))
- {
- Bitmap bitmap = new Bitmap(data.Texture);
- bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY);
- Rectangle rectangle = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
- BitmapData bitmapData = bitmap.LockBits(rectangle, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
-
- Gl.glGenTextures(1, out data.TexturePointer);
- Gl.glBindTexture(Gl.GL_TEXTURE_2D, data.TexturePointer);
-
- Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_LINEAR_MIPMAP_LINEAR);
- Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_LINEAR);
- Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_S, Gl.GL_REPEAT);
- Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_T, Gl.GL_REPEAT);
- Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_GENERATE_MIPMAP, Gl.GL_TRUE);
-
- Glu.gluBuild2DMipmaps(Gl.GL_TEXTURE_2D, Gl.GL_RGB8, bitmap.Width, bitmap.Height, Gl.GL_BGR, Gl.GL_UNSIGNED_BYTE, bitmapData.Scan0);
-
- bitmap.UnlockBits(bitmapData);
- bitmap.Dispose();
- }
-
- // Set the UserData for this face to our FaceData struct
- face.UserData = data;
- mesh.Faces[j] = face;
- }
-
- Prims.Add(mesh);
- }
-
- private bool LoadTexture(string basePath, UUID textureID, ref System.Drawing.Image texture)
- {
- if (Textures.ContainsKey(textureID))
- {
- texture = Textures[textureID];
- return true;
- }
-
- string texturePath = System.IO.Path.Combine(basePath, textureID.ToString());
-
- if (File.Exists(texturePath + ".tga"))
- {
- try
- {
- texture = (Image)LoadTGAClass.LoadTGA(texturePath + ".tga");
- Textures[textureID] = texture;
- return true;
- }
- catch (Exception)
- {
- }
- }
- else if (File.Exists(texturePath + ".jp2"))
- {
- try
- {
- ManagedImage managedImage;
- if (OpenJPEG.DecodeToImage(File.ReadAllBytes(texturePath + ".jp2"), out managedImage, out texture))
- {
- Textures[textureID] = texture;
- return true;
- }
- }
- catch (Exception)
- {
- }
- }
-
- return false;
- }
-
- private void textureToolStripMenuItem_Click(object sender, EventArgs e)
- {
- picTexture.Image = null;
- TexturePointers[0] = 0;
-
- OpenFileDialog dialog = new OpenFileDialog();
-
- if (dialog.ShowDialog() == DialogResult.OK)
- {
- try
- {
- picTexture.Image = System.Drawing.Image.FromFile(dialog.FileName);
- Bitmap bitmap = new Bitmap(picTexture.Image);
- bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY);
-
- // Create the GL texture space
- Gl.glGenTextures(1, TexturePointers);
- Rectangle rectangle = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
- BitmapData bitmapData = bitmap.LockBits(rectangle, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
-
- Gl.glBindTexture(Gl.GL_TEXTURE_2D, TexturePointers[0]);
-
- Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_LINEAR_MIPMAP_LINEAR);
- Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_LINEAR);
- Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_S, Gl.GL_CLAMP_TO_EDGE);
- Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_T, Gl.GL_CLAMP_TO_EDGE);
- Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_GENERATE_MIPMAP, Gl.GL_TRUE);
-
- Glu.gluBuild2DMipmaps(Gl.GL_TEXTURE_2D, Gl.GL_RGB8, bitmap.Width, bitmap.Height, Gl.GL_BGR, Gl.GL_UNSIGNED_BYTE, bitmapData.Scan0);
-
- bitmap.UnlockBits(bitmapData);
- bitmap.Dispose();
- }
- catch (Exception ex)
- {
- MessageBox.Show("Failed to load image from file " + dialog.FileName + ": " + ex.Message);
- }
- }
- }
-
- private void savePrimXMLToolStripMenuItem_Click(object sender, EventArgs e)
- {
-
- }
-
- private void saveTextureToolStripMenuItem_Click(object sender, EventArgs e)
- {
-
- }
-
- private void oBJToolStripMenuItem_Click(object sender, EventArgs e)
- {
- SaveFileDialog dialog = new SaveFileDialog();
- dialog.Filter = "OBJ files (*.obj)|*.obj";
-
- if (dialog.ShowDialog() == DialogResult.OK)
- {
- if (!MeshToOBJ.MeshesToOBJ(Prims, dialog.FileName))
- {
- MessageBox.Show("Failed to save file " + dialog.FileName +
- ". Ensure that you have permission to write to that file and it is currently not in use");
- }
- }
- }
-
- private void exitToolStripMenuItem_Click(object sender, EventArgs e)
- {
- Close();
- }
-
- private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
- {
- MessageBox.Show(
- "Written by John Hurliman (http://www.jhurliman.org/)");
- }
-
- #endregion Menu Callbacks
-
- #region Scrollbar Callbacks
-
- private void scroll_ValueChanged(object sender, EventArgs e)
- {
- glControl.Invalidate();
- }
-
- private void scrollZoom_ValueChanged(object sender, EventArgs e)
- {
- glControl_Resize(null, null);
- glControl.Invalidate();
- }
-
- #endregion Scrollbar Callbacks
-
- #region PictureBox Callbacks
-
- private void picTexture_MouseDown(object sender, MouseEventArgs e)
- {
- DraggingTexture = true;
- }
-
- private void picTexture_MouseUp(object sender, MouseEventArgs e)
- {
- DraggingTexture = false;
- }
-
- private void picTexture_MouseLeave(object sender, EventArgs e)
- {
- DraggingTexture = false;
- }
-
- private void picTexture_MouseMove(object sender, MouseEventArgs e)
- {
- if (DraggingTexture)
- {
- // What is the current action?
- // None, DraggingEdge, DraggingCorner, DraggingWhole
- }
- else
- {
- // Check if the mouse is close to the edge or corner of a selection
- // rectangle
-
- // If so, change the cursor accordingly
- }
- }
-
- private void picTexture_Paint(object sender, PaintEventArgs e)
- {
- // Draw the current selection rectangles
- }
-
- #endregion PictureBox Callbacks
-
- private void cboPrim_SelectedIndexChanged(object sender, EventArgs e)
- {
- CurrentPrim = (FacetedMesh)cboPrim.Items[cboPrim.SelectedIndex];
- PopulateFaceCombobox();
-
- glControl.Invalidate();
- }
-
- private void cboFace_SelectedIndexChanged(object sender, EventArgs e)
- {
- CurrentFace = (ProfileFace)cboFace.Items[cboFace.SelectedIndex];
-
- glControl.Invalidate();
- }
-
- private void PopulatePrimCombobox()
- {
- cboPrim.Items.Clear();
-
- if (Prims != null)
- {
- for (int i = 0; i < Prims.Count; i++)
- cboPrim.Items.Add(Prims[i]);
- }
-
- if (cboPrim.Items.Count > 0)
- cboPrim.SelectedIndex = 0;
- }
-
- private void PopulateFaceCombobox()
- {
- cboFace.Items.Clear();
-
- if (CurrentPrim != null && CurrentPrim.Profile.Faces != null)
- {
- for (int i = 0; i < CurrentPrim.Profile.Faces.Count; i++)
- cboFace.Items.Add(CurrentPrim.Profile.Faces[i]);
- }
-
- if (cboFace.Items.Count > 0)
- cboFace.SelectedIndex = 0;
- }
-
- private void wireframeToolStripMenuItem_Click(object sender, EventArgs e)
- {
- wireframeToolStripMenuItem.Checked = !wireframeToolStripMenuItem.Checked;
- Wireframe = wireframeToolStripMenuItem.Checked;
-
- glControl.Invalidate();
- }
-
- private void worldBrowserToolStripMenuItem_Click(object sender, EventArgs e)
- {
- frmBrowser browser = new frmBrowser();
- browser.ShowDialog();
- }
- }
-
- public struct FaceData
- {
- public float[] Vertices;
- public ushort[] Indices;
- public float[] TexCoords;
- public int TexturePointer;
- public System.Drawing.Image Texture;
- // TODO: Normals
- }
-
- public static class Render
- {
- public static IRendering Plugin;
- }
-}
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.IO;
+using System.Windows.Forms;
+using Tao.OpenGl;
+using Tao.Platform.Windows;
+using ICSharpCode.SharpZipLib.Zip;
+using OpenMetaverse;
+using OpenMetaverse.StructuredData;
+using OpenMetaverse.Imaging;
+using OpenMetaverse.Rendering;
+
+// NOTE: Batches are divided by texture, fullbright, shiny, transparent, and glow
+
+namespace PrimWorkshop
+{
+ public partial class frmPrimWorkshop : Form
+ {
+ #region Form Globals
+
+ List Prims = null;
+ FacetedMesh CurrentPrim = null;
+ ProfileFace? CurrentFace = null;
+
+ bool DraggingTexture = false;
+ bool Wireframe = true;
+ int[] TexturePointers = new int[1];
+ Dictionary Textures = new Dictionary();
+
+ #endregion Form Globals
+
+ public frmPrimWorkshop()
+ {
+ InitializeComponent();
+ glControl.InitializeContexts();
+
+ Gl.glShadeModel(Gl.GL_SMOOTH);
+ Gl.glClearColor(0f, 0f, 0f, 0f);
+
+ Gl.glClearDepth(1.0f);
+ Gl.glEnable(Gl.GL_DEPTH_TEST);
+ Gl.glDepthMask(Gl.GL_TRUE);
+ Gl.glDepthFunc(Gl.GL_LEQUAL);
+ Gl.glHint(Gl.GL_PERSPECTIVE_CORRECTION_HINT, Gl.GL_NICEST);
+
+ TexturePointers[0] = 0;
+
+ // Call the resizing function which sets up the GL drawing window
+ // and will also invalidate the GL control
+ glControl_Resize(null, null);
+ }
+
+ private void frmPrimWorkshop_Shown(object sender, EventArgs e)
+ {
+ // Get a list of rendering plugins
+ List renderers = RenderingLoader.ListRenderers(".");
+
+ foreach (string r in renderers)
+ {
+ DialogResult result = MessageBox.Show(
+ String.Format("Use renderer {0}?", r), "Select Rendering Plugin", MessageBoxButtons.YesNo);
+
+ if (result == DialogResult.Yes)
+ {
+ Render.Plugin = RenderingLoader.LoadRenderer(r);
+ break;
+ }
+ }
+
+ if (Render.Plugin == null)
+ {
+ MessageBox.Show("No valid rendering plugin loaded, exiting...");
+ Application.Exit();
+ }
+ }
+
+ #region GLControl Callbacks
+
+ private void glControl_Paint(object sender, PaintEventArgs e)
+ {
+ Gl.glClear(Gl.GL_COLOR_BUFFER_BIT | Gl.GL_DEPTH_BUFFER_BIT);
+ Gl.glLoadIdentity();
+
+ // Setup wireframe or solid fill drawing mode
+ if (Wireframe)
+ Gl.glPolygonMode(Gl.GL_FRONT_AND_BACK, Gl.GL_LINE);
+ else
+ Gl.glPolygonMode(Gl.GL_FRONT, Gl.GL_FILL);
+
+ Vector3 center = Vector3.Zero;
+
+ Glu.gluLookAt(
+ center.X, (double)scrollZoom.Value * 0.1d + center.Y, center.Z,
+ center.X, center.Y, center.Z,
+ 0d, 0d, 1d);
+
+ // Push the world matrix
+ Gl.glPushMatrix();
+
+ Gl.glEnableClientState(Gl.GL_VERTEX_ARRAY);
+ Gl.glEnableClientState(Gl.GL_TEXTURE_COORD_ARRAY);
+
+ // World rotations
+ Gl.glRotatef((float)scrollRoll.Value, 1f, 0f, 0f);
+ Gl.glRotatef((float)scrollPitch.Value, 0f, 1f, 0f);
+ Gl.glRotatef((float)scrollYaw.Value, 0f, 0f, 1f);
+
+ if (Prims != null)
+ {
+ for (int i = 0; i < Prims.Count; i++)
+ {
+ Primitive prim = Prims[i].Prim;
+
+ if (i == cboPrim.SelectedIndex)
+ Gl.glColor3f(1f, 0f, 0f);
+ else
+ Gl.glColor3f(1f, 1f, 1f);
+
+ // Individual prim matrix
+ Gl.glPushMatrix();
+
+ // The root prim position is sim-relative, while child prim positions are
+ // parent-relative. We want to apply parent-relative translations but not
+ // sim-relative ones
+ if (Prims[i].Prim.ParentID != 0)
+ {
+ // Apply prim translation and rotation
+ Gl.glMultMatrixf(Math3D.CreateTranslationMatrix(prim.Position));
+ Gl.glMultMatrixf(Math3D.CreateRotationMatrix(prim.Rotation));
+ }
+
+ // Prim scaling
+ Gl.glScalef(prim.Scale.X, prim.Scale.Y, prim.Scale.Z);
+
+ // Draw the prim faces
+ for (int j = 0; j < Prims[i].Faces.Count; j++)
+ {
+ if (i == cboPrim.SelectedIndex)
+ {
+ // This prim is currently selected in the dropdown
+ //Gl.glColor3f(0f, 1f, 0f);
+ Gl.glColor3f(1f, 1f, 1f);
+
+ if (j == cboFace.SelectedIndex)
+ {
+ // This face is currently selected in the dropdown
+ }
+ else
+ {
+ // This face is not currently selected in the dropdown
+ }
+ }
+ else
+ {
+ // This prim is not currently selected in the dropdown
+ Gl.glColor3f(1f, 1f, 1f);
+ }
+
+ #region Texturing
+
+ Face face = Prims[i].Faces[j];
+ FaceData data = (FaceData)face.UserData;
+
+ if (data.TexturePointer != 0)
+ {
+ // Set the color to solid white so the texture is not altered
+ //Gl.glColor3f(1f, 1f, 1f);
+ // Enable texturing for this face
+ Gl.glEnable(Gl.GL_TEXTURE_2D);
+ }
+ else
+ {
+ Gl.glDisable(Gl.GL_TEXTURE_2D);
+ }
+
+ // Bind the texture
+ Gl.glBindTexture(Gl.GL_TEXTURE_2D, data.TexturePointer);
+
+ #endregion Texturing
+
+ Gl.glTexCoordPointer(2, Gl.GL_FLOAT, 0, data.TexCoords);
+ Gl.glVertexPointer(3, Gl.GL_FLOAT, 0, data.Vertices);
+ Gl.glDrawElements(Gl.GL_TRIANGLES, data.Indices.Length, Gl.GL_UNSIGNED_SHORT, data.Indices);
+ }
+
+ // Pop the prim matrix
+ Gl.glPopMatrix();
+ }
+ }
+
+ // Pop the world matrix
+ Gl.glPopMatrix();
+
+ Gl.glDisableClientState(Gl.GL_TEXTURE_COORD_ARRAY);
+ Gl.glDisableClientState(Gl.GL_VERTEX_ARRAY);
+
+ Gl.glFlush();
+ }
+
+ private void glControl_Resize(object sender, EventArgs e)
+ {
+ Gl.glClearColor(0.39f, 0.58f, 0.93f, 1.0f);
+
+ Gl.glViewport(0, 0, glControl.Width, glControl.Height);
+
+ Gl.glPushMatrix();
+ Gl.glMatrixMode(Gl.GL_PROJECTION);
+ Gl.glLoadIdentity();
+
+ Glu.gluPerspective(50.0d, 1.0d, 0.1d, 256d);
+
+ Gl.glMatrixMode(Gl.GL_MODELVIEW);
+ Gl.glPopMatrix();
+ }
+
+ #endregion GLControl Callbacks
+
+ #region Menu Callbacks
+
+ private void openPrimXMLToolStripMenuItem1_Click(object sender, EventArgs e)
+ {
+ Prims = null;
+ OpenFileDialog dialog = new OpenFileDialog();
+ dialog.Filter = "Prim Package (*.zip)|*.zip|Sculpt Map (*.png)|*.png|OAR XML (*.xml)|*.xml";
+
+ if (dialog.ShowDialog() == DialogResult.OK)
+ {
+ if (dialog.FileName.ToLowerInvariant().EndsWith(".zip"))
+ {
+ LoadPrimPackage(dialog.FileName);
+ }
+ else if (dialog.FileName.ToLowerInvariant().EndsWith(".xml"))
+ {
+ LoadXmlPrim(dialog.FileName);
+ }
+ else
+ {
+ LoadSculpt(dialog.FileName);
+ }
+ }
+ }
+
+ private void LoadDebugPrim()
+ {
+ Prims = new List();
+ Primitive prim = new Primitive();
+ prim.Textures = new Primitive.TextureEntry(UUID.Zero);
+ prim.Scale = Vector3.One;
+ prim.PrimData = ObjectManager.BuildBasicShape(PrimType.Cylinder);
+ prim.PrimData.ProfileHollow = 0.95f;
+ SimpleMesh simpleMesh = Render.Plugin.GenerateSimpleMesh(prim, DetailLevel.High);
+ FacetedMesh facetedMesh = new FacetedMesh();
+ facetedMesh.Faces = new List { new Face { Vertices = simpleMesh.Vertices, Indices = simpleMesh.Indices } };
+ facetedMesh.Path = simpleMesh.Path;
+ facetedMesh.Profile = simpleMesh.Profile;
+ facetedMesh.Prim = prim;
+ LoadMesh(facetedMesh, ".");
+ PopulatePrimCombobox();
+ glControl.Invalidate();
+ }
+
+ private void LoadXmlPrim(string filename)
+ {
+ byte[] data = File.ReadAllBytes(filename);
+
+ OpenMetaverse.Assets.OarFile.LoadObjects(data, XmlObjectLoadedHandler, 0, data.Length);
+ }
+
+ private void XmlObjectLoadedHandler(OpenMetaverse.Assets.AssetPrim linkset, long bytesRead, long totalBytes)
+ {
+ Prims = new List(linkset.Children.Count + 1);
+
+ Primitive parent = linkset.Parent.ToPrimitive();
+ {
+ FacetedMesh mesh = null;
+
+ if (parent.Sculpt == null || parent.Sculpt.SculptTexture == UUID.Zero)
+ mesh = Render.Plugin.GenerateFacetedMesh(parent, DetailLevel.Highest);
+ if (mesh != null)
+ LoadMesh(mesh, null);
+ }
+
+ for (int i = 0; i < linkset.Children.Count; i++)
+ {
+ Primitive child = linkset.Children[i].ToPrimitive();
+ FacetedMesh mesh = null;
+
+ if (parent.Sculpt == null || child.Sculpt.SculptTexture == UUID.Zero)
+ mesh = Render.Plugin.GenerateFacetedMesh(child, DetailLevel.Highest);
+ if (mesh != null)
+ LoadMesh(mesh, null);
+ }
+
+ PopulatePrimCombobox();
+
+ glControl.Invalidate();
+ }
+
+ private void LoadSculpt(string filename)
+ {
+ // Try to parse this as an image file
+ Image sculptTexture = Image.FromFile(filename);
+
+ Primitive prim = new Primitive();
+ prim.PrimData = ObjectManager.BuildBasicShape(PrimType.Sculpt);
+ prim.Sculpt = new Primitive.SculptData { SculptTexture = UUID.Random(), Type = SculptType.Sphere };
+ prim.Textures = new Primitive.TextureEntry(UUID.Zero);
+ prim.Scale = Vector3.One * 3f;
+
+ FacetedMesh mesh = Render.Plugin.GenerateFacetedSculptMesh(prim, (Bitmap)sculptTexture, DetailLevel.Highest);
+ if (mesh != null)
+ {
+ Prims = new List(1);
+ LoadMesh(mesh, null);
+ }
+
+ glControl.Invalidate();
+ }
+
+ private void LoadPrimPackage(string filename)
+ {
+ string tempPath = System.IO.Path.Combine(System.IO.Path.GetTempPath(), System.IO.Path.GetRandomFileName());
+
+ try
+ {
+ // Create a temporary directory
+ Directory.CreateDirectory(tempPath);
+
+ FastZip fastzip = new FastZip();
+ fastzip.ExtractZip(filename, tempPath, String.Empty);
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show(ex.Message);
+ return;
+ }
+
+ // Check for the prims.xml file
+ string primsFile = System.IO.Path.Combine(tempPath, "prims.xml");
+ if (!File.Exists(primsFile))
+ {
+ MessageBox.Show("prims.xml not found in the archive");
+ return;
+ }
+
+ OSD osd = null;
+
+ try { osd = OSDParser.DeserializeLLSDXml(File.ReadAllText(primsFile)); }
+ catch (Exception ex) { MessageBox.Show(ex.Message); }
+
+ if (osd != null && osd.Type == OSDType.Map)
+ {
+ List primList = Helpers.OSDToPrimList(osd);
+ Prims = new List(primList.Count);
+
+ for (int i = 0; i < primList.Count; i++)
+ {
+ Primitive prim = primList[i];
+ FacetedMesh mesh = null;
+
+ if (prim.Sculpt.SculptTexture != UUID.Zero)
+ {
+ Image sculptTexture = null;
+ if (LoadTexture(tempPath, prim.Sculpt.SculptTexture, ref sculptTexture))
+ mesh = Render.Plugin.GenerateFacetedSculptMesh(prim, (Bitmap)sculptTexture, DetailLevel.Highest);
+ }
+ else
+ {
+ mesh = Render.Plugin.GenerateFacetedMesh(prim, DetailLevel.Highest);
+ }
+
+ if (mesh != null)
+ LoadMesh(mesh, tempPath);
+ }
+
+ // Setup the dropdown list of prims
+ PopulatePrimCombobox();
+
+ glControl.Invalidate();
+ }
+ else
+ {
+ MessageBox.Show("Failed to load LLSD formatted primitive data from " + filename);
+ }
+
+ Directory.Delete(tempPath);
+ }
+
+ private void LoadMesh(FacetedMesh mesh, string basePath)
+ {
+ // Create a FaceData struct for each face that stores the 3D data
+ // in a Tao.OpenGL friendly format
+ for (int j = 0; j < mesh.Faces.Count; j++)
+ {
+ Face face = mesh.Faces[j];
+ FaceData data = new FaceData();
+
+ // Vertices for this face
+ data.Vertices = new float[face.Vertices.Count * 3];
+ for (int k = 0; k < face.Vertices.Count; k++)
+ {
+ data.Vertices[k * 3 + 0] = face.Vertices[k].Position.X;
+ data.Vertices[k * 3 + 1] = face.Vertices[k].Position.Y;
+ data.Vertices[k * 3 + 2] = face.Vertices[k].Position.Z;
+ }
+
+ // Indices for this face
+ data.Indices = face.Indices.ToArray();
+
+ // Texture transform for this face
+ Primitive.TextureEntryFace teFace = mesh.Prim.Textures.GetFace((uint)j);
+ Render.Plugin.TransformTexCoords(face.Vertices, face.Center, teFace, mesh.Prim.Scale);
+
+ // Texcoords for this face
+ data.TexCoords = new float[face.Vertices.Count * 2];
+ for (int k = 0; k < face.Vertices.Count; k++)
+ {
+ data.TexCoords[k * 2 + 0] = face.Vertices[k].TexCoord.X;
+ data.TexCoords[k * 2 + 1] = face.Vertices[k].TexCoord.Y;
+ }
+
+ // Texture for this face
+ if (!String.IsNullOrEmpty(basePath) && LoadTexture(basePath, teFace.TextureID, ref data.Texture))
+ {
+ Bitmap bitmap = new Bitmap(data.Texture);
+ bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY);
+ Rectangle rectangle = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
+ BitmapData bitmapData = bitmap.LockBits(rectangle, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
+
+ Gl.glGenTextures(1, out data.TexturePointer);
+ Gl.glBindTexture(Gl.GL_TEXTURE_2D, data.TexturePointer);
+
+ Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_LINEAR_MIPMAP_LINEAR);
+ Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_LINEAR);
+ Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_S, Gl.GL_REPEAT);
+ Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_T, Gl.GL_REPEAT);
+ Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_GENERATE_MIPMAP, Gl.GL_TRUE);
+
+ Glu.gluBuild2DMipmaps(Gl.GL_TEXTURE_2D, Gl.GL_RGB8, bitmap.Width, bitmap.Height, Gl.GL_BGR, Gl.GL_UNSIGNED_BYTE, bitmapData.Scan0);
+
+ bitmap.UnlockBits(bitmapData);
+ bitmap.Dispose();
+ }
+
+ // Set the UserData for this face to our FaceData struct
+ face.UserData = data;
+ mesh.Faces[j] = face;
+ }
+
+ Prims.Add(mesh);
+ }
+
+ private bool LoadTexture(string basePath, UUID textureID, ref System.Drawing.Image texture)
+ {
+ if (Textures.ContainsKey(textureID))
+ {
+ texture = Textures[textureID];
+ return true;
+ }
+
+ string texturePath = System.IO.Path.Combine(basePath, textureID.ToString());
+
+ if (File.Exists(texturePath + ".tga"))
+ {
+ try
+ {
+ texture = (Image)LoadTGAClass.LoadTGA(texturePath + ".tga");
+ Textures[textureID] = texture;
+ return true;
+ }
+ catch (Exception)
+ {
+ }
+ }
+ else if (File.Exists(texturePath + ".jp2"))
+ {
+ try
+ {
+ ManagedImage managedImage;
+ if (OpenJPEG.DecodeToImage(File.ReadAllBytes(texturePath + ".jp2"), out managedImage, out texture))
+ {
+ Textures[textureID] = texture;
+ return true;
+ }
+ }
+ catch (Exception)
+ {
+ }
+ }
+
+ return false;
+ }
+
+ private void textureToolStripMenuItem_Click(object sender, EventArgs e)
+ {
+ picTexture.Image = null;
+ TexturePointers[0] = 0;
+
+ OpenFileDialog dialog = new OpenFileDialog();
+
+ if (dialog.ShowDialog() == DialogResult.OK)
+ {
+ try
+ {
+ picTexture.Image = System.Drawing.Image.FromFile(dialog.FileName);
+ Bitmap bitmap = new Bitmap(picTexture.Image);
+ bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY);
+
+ // Create the GL texture space
+ Gl.glGenTextures(1, TexturePointers);
+ Rectangle rectangle = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
+ BitmapData bitmapData = bitmap.LockBits(rectangle, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
+
+ Gl.glBindTexture(Gl.GL_TEXTURE_2D, TexturePointers[0]);
+
+ Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_LINEAR_MIPMAP_LINEAR);
+ Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_LINEAR);
+ Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_S, Gl.GL_CLAMP_TO_EDGE);
+ Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_T, Gl.GL_CLAMP_TO_EDGE);
+ Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_GENERATE_MIPMAP, Gl.GL_TRUE);
+
+ Glu.gluBuild2DMipmaps(Gl.GL_TEXTURE_2D, Gl.GL_RGB8, bitmap.Width, bitmap.Height, Gl.GL_BGR, Gl.GL_UNSIGNED_BYTE, bitmapData.Scan0);
+
+ bitmap.UnlockBits(bitmapData);
+ bitmap.Dispose();
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show("Failed to load image from file " + dialog.FileName + ": " + ex.Message);
+ }
+ }
+ }
+
+ private void savePrimXMLToolStripMenuItem_Click(object sender, EventArgs e)
+ {
+
+ }
+
+ private void saveTextureToolStripMenuItem_Click(object sender, EventArgs e)
+ {
+
+ }
+
+ private void oBJToolStripMenuItem_Click(object sender, EventArgs e)
+ {
+ SaveFileDialog dialog = new SaveFileDialog();
+ dialog.Filter = "OBJ files (*.obj)|*.obj";
+
+ if (dialog.ShowDialog() == DialogResult.OK)
+ {
+ if (!MeshToOBJ.MeshesToOBJ(Prims, dialog.FileName))
+ {
+ MessageBox.Show("Failed to save file " + dialog.FileName +
+ ". Ensure that you have permission to write to that file and it is currently not in use");
+ }
+ }
+ }
+
+ private void exitToolStripMenuItem_Click(object sender, EventArgs e)
+ {
+ Close();
+ }
+
+ private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
+ {
+ MessageBox.Show(
+ "Written by John Hurliman (http://www.jhurliman.org/)");
+ }
+
+ #endregion Menu Callbacks
+
+ #region Scrollbar Callbacks
+
+ private void scroll_ValueChanged(object sender, EventArgs e)
+ {
+ glControl.Invalidate();
+ }
+
+ private void scrollZoom_ValueChanged(object sender, EventArgs e)
+ {
+ glControl_Resize(null, null);
+ glControl.Invalidate();
+ }
+
+ #endregion Scrollbar Callbacks
+
+ #region PictureBox Callbacks
+
+ private void picTexture_MouseDown(object sender, MouseEventArgs e)
+ {
+ DraggingTexture = true;
+ }
+
+ private void picTexture_MouseUp(object sender, MouseEventArgs e)
+ {
+ DraggingTexture = false;
+ }
+
+ private void picTexture_MouseLeave(object sender, EventArgs e)
+ {
+ DraggingTexture = false;
+ }
+
+ private void picTexture_MouseMove(object sender, MouseEventArgs e)
+ {
+ if (DraggingTexture)
+ {
+ // What is the current action?
+ // None, DraggingEdge, DraggingCorner, DraggingWhole
+ }
+ else
+ {
+ // Check if the mouse is close to the edge or corner of a selection
+ // rectangle
+
+ // If so, change the cursor accordingly
+ }
+ }
+
+ private void picTexture_Paint(object sender, PaintEventArgs e)
+ {
+ // Draw the current selection rectangles
+ }
+
+ #endregion PictureBox Callbacks
+
+ private void cboPrim_SelectedIndexChanged(object sender, EventArgs e)
+ {
+ CurrentPrim = (FacetedMesh)cboPrim.Items[cboPrim.SelectedIndex];
+ PopulateFaceCombobox();
+
+ glControl.Invalidate();
+ }
+
+ private void cboFace_SelectedIndexChanged(object sender, EventArgs e)
+ {
+ CurrentFace = (ProfileFace)cboFace.Items[cboFace.SelectedIndex];
+
+ glControl.Invalidate();
+ }
+
+ private void PopulatePrimCombobox()
+ {
+ cboPrim.Items.Clear();
+
+ if (Prims != null)
+ {
+ for (int i = 0; i < Prims.Count; i++)
+ cboPrim.Items.Add(Prims[i]);
+ }
+
+ if (cboPrim.Items.Count > 0)
+ cboPrim.SelectedIndex = 0;
+ }
+
+ private void PopulateFaceCombobox()
+ {
+ cboFace.Items.Clear();
+
+ if (CurrentPrim != null && CurrentPrim.Profile.Faces != null)
+ {
+ for (int i = 0; i < CurrentPrim.Profile.Faces.Count; i++)
+ cboFace.Items.Add(CurrentPrim.Profile.Faces[i]);
+ }
+
+ if (cboFace.Items.Count > 0)
+ cboFace.SelectedIndex = 0;
+ }
+
+ private void wireframeToolStripMenuItem_Click(object sender, EventArgs e)
+ {
+ wireframeToolStripMenuItem.Checked = !wireframeToolStripMenuItem.Checked;
+ Wireframe = wireframeToolStripMenuItem.Checked;
+
+ glControl.Invalidate();
+ }
+
+ private void worldBrowserToolStripMenuItem_Click(object sender, EventArgs e)
+ {
+ frmBrowser browser = new frmBrowser();
+ browser.ShowDialog();
+ }
+ }
+
+ public struct FaceData
+ {
+ public float[] Vertices;
+ public ushort[] Indices;
+ public float[] TexCoords;
+ public int TexturePointer;
+ public System.Drawing.Image Texture;
+ // TODO: Normals
+ }
+
+ public static class Render
+ {
+ public static IRendering Plugin;
+ }
+}