/// <summary> /// Checks if VBOs are created, if they are, bind them, if not create new /// </summary> /// <param name="face">Which face's mesh is uploaded in this VBO</param> /// <returns>True, if face data was succesfully uploaded to the graphics card memory</returns> public bool CheckVBO(Face face) { if (VertexVBO == -1) { Vertex[] vArray = face.Vertices.ToArray(); Compat.GenBuffers(out VertexVBO); Compat.BindBuffer(BufferTarget.ArrayBuffer, VertexVBO); Compat.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(vArray.Length * VertexSize), vArray, BufferUsageHint.StaticDraw); if (Compat.BufferSize(BufferTarget.ArrayBuffer) != vArray.Length * VertexSize) { VBOFailed = true; Compat.BindBuffer(BufferTarget.ArrayBuffer, 0); Compat.DeleteBuffer(VertexVBO); VertexVBO = -1; return false; } } if (IndexVBO == -1) { ushort[] iArray = face.Indices.ToArray(); Compat.GenBuffers(out IndexVBO); Compat.BindBuffer(BufferTarget.ElementArrayBuffer, IndexVBO); Compat.BufferData(BufferTarget.ElementArrayBuffer, (IntPtr)(iArray.Length * sizeof(ushort)), iArray, BufferUsageHint.StaticDraw); if (Compat.BufferSize(BufferTarget.ElementArrayBuffer) != iArray.Length * sizeof(ushort)) { VBOFailed = true; Compat.BindBuffer(BufferTarget.ElementArrayBuffer, 0); Compat.DeleteBuffer(IndexVBO); IndexVBO = -1; return false; } } return true; }
/// <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); }
public override void Render(RenderPass pass, int pickingID, SceneWindow scene, float time) { terrainTimeSinceUpdate += time; if (Modified && terrainTimeSinceUpdate > RenderSettings.MinimumTimeBetweenTerrainUpdated) { if (!terrainInProgress) { terrainInProgress = true; ResetTerrain(false); UpdateTerrain(); } } if (terrainTextureNeedsUpdate) { UpdateTerrainTexture(); } if (terrainIndices == null || terrainVertices == null) { return; } GL.Color3(1f, 1f, 1f); GL.EnableClientState(ArrayCap.VertexArray); GL.EnableClientState(ArrayCap.TextureCoordArray); GL.EnableClientState(ArrayCap.NormalArray); if (pass == RenderPass.Picking) { GL.EnableClientState(ArrayCap.ColorArray); GL.ShadeModel(ShadingModel.Flat); } if (terrainImage != null) { if (terrainTexture != -1) { GL.DeleteTexture(terrainTexture); } terrainTexture = RHelp.GLLoadImage(terrainImage, false); terrainImage.Dispose(); terrainImage = null; } if (pass != RenderPass.Picking && terrainTexture != -1) { GL.Enable(EnableCap.Texture2D); GL.BindTexture(TextureTarget.Texture2D, terrainTexture); } if (!RenderSettings.UseVBO || terrainVBOFailed) { unsafe { fixed(float *normalPtr = &terrainVertices[0].Vertex.Normal.X) fixed(float *texPtr = &terrainVertices[0].Vertex.TexCoord.X) fixed(byte *colorPtr = &terrainVertices[0].Color.R) { GL.NormalPointer(NormalPointerType.Float, ColorVertex.Size, (IntPtr)normalPtr); GL.TexCoordPointer(2, TexCoordPointerType.Float, ColorVertex.Size, (IntPtr)texPtr); GL.VertexPointer(3, VertexPointerType.Float, ColorVertex.Size, terrainVertices); if (pass == RenderPass.Picking) { GL.ColorPointer(4, ColorPointerType.UnsignedByte, ColorVertex.Size, (IntPtr)colorPtr); } GL.DrawElements(BeginMode.Triangles, terrainIndices.Length, DrawElementsType.UnsignedInt, terrainIndices); } } } else { if (terrainVBO == -1) { Compat.GenBuffers(out terrainVBO); Compat.BindBuffer(BufferTarget.ArrayBuffer, terrainVBO); Compat.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(terrainVertices.Length * ColorVertex.Size), terrainVertices, BufferUsageHint.StaticDraw); if (Compat.BufferSize(BufferTarget.ArrayBuffer) != terrainVertices.Length * ColorVertex.Size) { terrainVBOFailed = true; Compat.BindBuffer(BufferTarget.ArrayBuffer, 0); terrainVBO = -1; } } else { Compat.BindBuffer(BufferTarget.ArrayBuffer, terrainVBO); } if (terrainIndexVBO == -1) { Compat.GenBuffers(out terrainIndexVBO); Compat.BindBuffer(BufferTarget.ElementArrayBuffer, terrainIndexVBO); Compat.BufferData(BufferTarget.ElementArrayBuffer, (IntPtr)(terrainIndices.Length * sizeof(uint)), terrainIndices, BufferUsageHint.StaticDraw); if (Compat.BufferSize(BufferTarget.ElementArrayBuffer) != terrainIndices.Length * sizeof(uint)) { terrainVBOFailed = true; Compat.BindBuffer(BufferTarget.ElementArrayBuffer, 0); terrainIndexVBO = -1; } } else { Compat.BindBuffer(BufferTarget.ElementArrayBuffer, terrainIndexVBO); } if (!terrainVBOFailed) { GL.NormalPointer(NormalPointerType.Float, ColorVertex.Size, (IntPtr)12); GL.TexCoordPointer(2, TexCoordPointerType.Float, ColorVertex.Size, (IntPtr)(24)); if (pass == RenderPass.Picking) { GL.ColorPointer(4, ColorPointerType.UnsignedByte, ColorVertex.Size, (IntPtr)32); } GL.VertexPointer(3, VertexPointerType.Float, ColorVertex.Size, (IntPtr)(0)); GL.DrawElements(BeginMode.Triangles, terrainIndices.Length, DrawElementsType.UnsignedInt, IntPtr.Zero); } Compat.BindBuffer(BufferTarget.ArrayBuffer, 0); Compat.BindBuffer(BufferTarget.ElementArrayBuffer, 0); } if (pass == RenderPass.Picking) { GL.DisableClientState(ArrayCap.ColorArray); GL.ShadeModel(ShadingModel.Smooth); } else { GL.BindTexture(TextureTarget.Texture2D, 0); } GL.DisableClientState(ArrayCap.VertexArray); GL.DisableClientState(ArrayCap.TextureCoordArray); GL.DisableClientState(ArrayCap.NormalArray); }