/// <summary> /// Remove any GL resource we may still have in use /// </summary> public override void Dispose() { if (Faces != null) { foreach (Face f in Faces) { if (f.UserData != null && f.UserData is FaceData) { FaceData data = (FaceData)f.UserData; data.Dispose(); data = null; } } Faces = null; } base.Dispose(); }
/// <summary> /// Render Primitive /// </summary> /// <param name="pass">Which pass are we currently in</param> /// <param name="pickingID">ID used to identify which object was picked</param> /// <param name="scene">Main scene renderer</param> /// <param name="time">Time it took to render the last frame</param> public override void Render(RenderPass pass, int pickingID, SceneWindow scene, float time) { if (!RenderSettings.AvatarRenderingEnabled && Attached) return; // Individual prim matrix GL.PushMatrix(); // Prim roation and position and scale GL.MultMatrix(Math3D.CreateSRTMatrix(Prim.Scale, RenderRotation, RenderPosition)); // Do we have animated texture on this face bool animatedTexture = false; // Initialise flags tracking what type of faces this prim has if (pass == RenderPass.Simple) { HasSimpleFaces = false; } else if (pass == RenderPass.Alpha) { HasAlphaFaces = false; } else if (pass == RenderPass.Invisible) { HasInvisibleFaces = false; } // Draw the prim faces for (int j = 0; j < Faces.Count; j++) { Primitive.TextureEntryFace teFace = Prim.Textures.GetFace((uint)j); Face face = Faces[j]; FaceData data = (FaceData)face.UserData; if (data == null) continue; if (teFace == null) continue; // Don't render transparent faces Color4 RGBA = teFace.RGBA; if (data.TextureInfo.FullAlpha || RGBA.A <= 0.01f) continue; bool switchedLightsOff = false; if (pass == RenderPass.Picking) { data.PickingID = pickingID; var primNrBytes = Utils.UInt16ToBytes((ushort)pickingID); var faceColor = new byte[] { primNrBytes[0], primNrBytes[1], (byte)j, 255 }; GL.Color4(faceColor); } else if (pass == RenderPass.Invisible) { if (!data.TextureInfo.IsInvisible) continue; HasInvisibleFaces = true; } else { if (data.TextureInfo.IsInvisible) continue; bool belongToAlphaPass = (RGBA.A < 0.99f) || (data.TextureInfo.HasAlpha && !data.TextureInfo.IsMask); if (belongToAlphaPass && pass != RenderPass.Alpha) continue; if (!belongToAlphaPass && pass == RenderPass.Alpha) continue; if (pass == RenderPass.Simple) { HasSimpleFaces = true; } else if (pass == RenderPass.Alpha) { HasAlphaFaces = true; } if (teFace.Fullbright) { GL.Disable(EnableCap.Lighting); switchedLightsOff = true; } float shiny = 0f; switch (teFace.Shiny) { case Shininess.High: shiny = 0.96f; break; case Shininess.Medium: shiny = 0.64f; break; case Shininess.Low: shiny = 0.24f; break; } if (shiny > 0f) { scene.StartShiny(); } GL.Material(MaterialFace.Front, MaterialParameter.Shininess, shiny); var faceColor = new float[] { RGBA.R, RGBA.G, RGBA.B, RGBA.A }; GL.Color4(faceColor); GL.Material(MaterialFace.Front, MaterialParameter.Specular, new float[] { 0.5f, 0.5f, 0.5f, 1f }); if (data.TextureInfo.TexturePointer == 0) { TextureInfo teInfo; if (scene.TryGetTextureInfo(teFace.TextureID, out teInfo)) { data.TextureInfo = teInfo; } } if (data.TextureInfo.TexturePointer == 0) { GL.Disable(EnableCap.Texture2D); if (!data.TextureInfo.FetchFailed) { scene.DownloadTexture(new TextureLoadItem() { Prim = this.Prim, TeFace = teFace, Data = data }, false); } } else { // Is this face using texture animation if ((Prim.TextureAnim.Flags & Primitive.TextureAnimMode.ANIM_ON) != 0 && (Prim.TextureAnim.Face == j || Prim.TextureAnim.Face == 255)) { if (data.AnimInfo == null) { data.AnimInfo = new TextureAnimationInfo(); } data.AnimInfo.PrimAnimInfo = Prim.TextureAnim; data.AnimInfo.Step(time); animatedTexture = true; } else if (data.AnimInfo != null) // Face texture not animated. Do we have previous anim setting? { data.AnimInfo = null; } GL.Enable(EnableCap.Texture2D); GL.BindTexture(TextureTarget.Texture2D, data.TextureInfo.TexturePointer); } } if (!RenderSettings.UseVBO || data.VBOFailed) { Vertex[] verts = face.Vertices.ToArray(); ushort[] indices = face.Indices.ToArray(); unsafe { fixed (float* normalPtr = &verts[0].Normal.X) fixed (float* texPtr = &verts[0].TexCoord.X) { GL.NormalPointer(NormalPointerType.Float, FaceData.VertexSize, (IntPtr)normalPtr); GL.TexCoordPointer(2, TexCoordPointerType.Float, FaceData.VertexSize, (IntPtr)texPtr); GL.VertexPointer(3, VertexPointerType.Float, FaceData.VertexSize, verts); GL.DrawElements(BeginMode.Triangles, indices.Length, DrawElementsType.UnsignedShort, indices); } } } else { if (data.CheckVBO(face)) { Compat.BindBuffer(BufferTarget.ArrayBuffer, data.VertexVBO); Compat.BindBuffer(BufferTarget.ElementArrayBuffer, data.IndexVBO); GL.NormalPointer(NormalPointerType.Float, FaceData.VertexSize, (IntPtr)12); GL.TexCoordPointer(2, TexCoordPointerType.Float, FaceData.VertexSize, (IntPtr)(24)); GL.VertexPointer(3, VertexPointerType.Float, FaceData.VertexSize, (IntPtr)(0)); GL.DrawElements(BeginMode.Triangles, face.Indices.Count, DrawElementsType.UnsignedShort, IntPtr.Zero); } Compat.BindBuffer(BufferTarget.ArrayBuffer, 0); Compat.BindBuffer(BufferTarget.ElementArrayBuffer, 0); } if (switchedLightsOff) { GL.Enable(EnableCap.Lighting); switchedLightsOff = false; } } GL.BindTexture(TextureTarget.Texture2D, 0); RHelp.ResetMaterial(); // Reset texture coordinates if we modified them in texture animation if (animatedTexture) { GL.MatrixMode(MatrixMode.Texture); GL.LoadIdentity(); GL.MatrixMode(MatrixMode.Modelview); } // Pop the prim matrix GL.PopMatrix(); base.Render(pass, pickingID, scene, time); }
private void UpdatePrimBlocking(Primitive prim) { FacetedMesh mesh = null; FacetedMesh existingMesh = null; lock (Prims) { if (Prims.ContainsKey(prim.LocalID)) { existingMesh = Prims[prim.LocalID]; } } if (prim.Textures == null) { return; } try { if (prim.Sculpt != null && prim.Sculpt.SculptTexture != UUID.Zero) { if (prim.Sculpt.Type != SculptType.Mesh) { // Regular sculptie Image img = null; if (!LoadTexture(prim.Sculpt.SculptTexture, ref img, true)) { return; } mesh = renderer.GenerateFacetedSculptMesh(prim, (Bitmap)img, DetailLevel.Highest); } else { // Mesh AutoResetEvent gotMesh = new AutoResetEvent(false); bool meshSuccess = false; Client.Assets.RequestMesh(prim.Sculpt.SculptTexture, (success, meshAsset) => { if (!success || !FacetedMesh.TryDecodeFromAsset(prim, meshAsset, DetailLevel.Highest, out mesh)) { Logger.Log("Failed to fetch or decode the mesh asset", Helpers.LogLevel.Warning, Client); } else { meshSuccess = true; } gotMesh.Set(); }); if (!gotMesh.WaitOne(20 * 1000, false)) { return; } if (!meshSuccess) { return; } } } else { mesh = renderer.GenerateFacetedMesh(prim, DetailLevel.Highest); } } catch { return; } // Create a FaceData struct for each face that stores the 3D data // in a 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]; data.Normals = 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; data.Normals[k * 3 + 0] = face.Vertices[k].Normal.X; data.Normals[k * 3 + 1] = face.Vertices[k].Normal.Y; data.Normals[k * 3 + 2] = face.Vertices[k].Normal.Z; } // Indices for this face data.Indices = face.Indices.ToArray(); // Texture transform for this face Primitive.TextureEntryFace teFace = prim.Textures.GetFace((uint)j); renderer.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; } // Set the UserData for this face to our FaceData struct face.UserData = data; mesh.Faces[j] = face; if (existingMesh != null && j < existingMesh.Faces.Count && existingMesh.Faces[j].TextureFace.TextureID == teFace.TextureID && ((FaceData)existingMesh.Faces[j].UserData).TextureInfo.TexturePointer != 0 ) { FaceData existingData = (FaceData)existingMesh.Faces[j].UserData; data.TextureInfo.TexturePointer = existingData.TextureInfo.TexturePointer; } else { var textureItem = new TextureLoadItem() { Data = data, Prim = prim, TeFace = teFace }; PendingTextures.Enqueue(textureItem); } } lock (Prims) { Prims[prim.LocalID] = mesh; } SafeInvalidate(); }
private void RenderObjects(RenderPass pass) { lock (Prims) { int primNr = 0; foreach (FacetedMesh mesh in Prims.Values) { primNr++; Primitive prim = mesh.Prim; // Individual prim matrix GL.PushMatrix(); if (prim.ParentID == RootPrimLocalID) { FacetedMesh parent = null; if (Prims.TryGetValue(prim.ParentID, out parent)) { // Apply prim translation and rotation relative to the root prim GL.MultMatrix(Math3D.CreateRotationMatrix(parent.Prim.Rotation)); //GL.MultMatrixf(Math3D.CreateTranslationMatrix(parent.Prim.Position)); } // Prim roation relative to root GL.MultMatrix(Math3D.CreateTranslationMatrix(prim.Position)); } // Prim roation GL.MultMatrix(Math3D.CreateRotationMatrix(prim.Rotation)); // Prim scaling GL.Scale(prim.Scale.X, prim.Scale.Y, prim.Scale.Z); // Draw the prim faces for (int j = 0; j < mesh.Faces.Count; j++) { Primitive.TextureEntryFace teFace = mesh.Prim.Textures.FaceTextures[j]; Face face = mesh.Faces[j]; FaceData data = (FaceData)face.UserData; if (teFace == null) { teFace = mesh.Prim.Textures.DefaultTexture; } if (pass == RenderPass.Picking) { data.PickingID = primNr; var primNrBytes = Utils.Int16ToBytes((short)primNr); var faceColor = new byte[] { primNrBytes[0], primNrBytes[1], (byte)j, 255 }; GL.Color4(faceColor); } else { bool belongToAlphaPass = (teFace.RGBA.A < 0.99) || data.TextureInfo.HasAlpha; if (belongToAlphaPass && pass != RenderPass.Alpha) { continue; } if (!belongToAlphaPass && pass == RenderPass.Alpha) { continue; } // Don't render transparent faces if (teFace.RGBA.A <= 0.01f) { continue; } switch (teFace.Shiny) { case Shininess.High: GL.Material(MaterialFace.Front, MaterialParameter.Shininess, 94f); break; case Shininess.Medium: GL.Material(MaterialFace.Front, MaterialParameter.Shininess, 64f); break; case Shininess.Low: GL.Material(MaterialFace.Front, MaterialParameter.Shininess, 24f); break; case Shininess.None: default: GL.Material(MaterialFace.Front, MaterialParameter.Shininess, 0f); break; } var faceColor = new float[] { teFace.RGBA.R, teFace.RGBA.G, teFace.RGBA.B, teFace.RGBA.A }; GL.Color4(faceColor); GL.Material(MaterialFace.Front, MaterialParameter.AmbientAndDiffuse, faceColor); GL.Material(MaterialFace.Front, MaterialParameter.Specular, faceColor); if (data.TextureInfo.TexturePointer != 0) { GL.Enable(EnableCap.Texture2D); } else { GL.Disable(EnableCap.Texture2D); } // Bind the texture GL.BindTexture(TextureTarget.Texture2D, data.TextureInfo.TexturePointer); } GL.TexCoordPointer(2, TexCoordPointerType.Float, 0, data.TexCoords); GL.VertexPointer(3, VertexPointerType.Float, 0, data.Vertices); GL.NormalPointer(NormalPointerType.Float, 0, data.Normals); GL.DrawElements(BeginMode.Triangles, data.Indices.Length, DrawElementsType.UnsignedShort, data.Indices); } // Pop the prim matrix GL.PopMatrix(); } } }