2 // Radegast Metaverse Client
3 // Copyright (c) 2009-2014, Radegast Development Team
4 // All rights reserved.
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions are met:
9 // * Redistributions of source code must retain the above copyright notice,
10 // this list of conditions and the following disclaimer.
11 // * Redistributions in binary form must reproduce the above copyright
12 // notice, this list of conditions and the following disclaimer in the
13 // documentation and/or other materials provided with the distribution.
14 // * Neither the name of the application "Radegast", nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior CreateReflectionTexture permission.
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 using System.Collections.Generic;
34 using OpenTK.Graphics.OpenGL;
37 using OpenMetaverse.Rendering;
39 namespace Radegast.Rendering
41 public class RenderTerrain : SceneObject
43 RadegastInstance Instance;
44 GridClient Client { get { return Instance.Client; } }
46 public bool Modified = true;
47 float[,] heightTable = new float[256, 256];
49 uint[] terrainIndices;
50 ColorVertex[] terrainVertices;
51 int terrainTexture = -1;
52 bool fetchingTerrainTexture = false;
53 Bitmap terrainImage = null;
55 int terrainIndexVBO = -1;
56 bool terrainVBOFailed = false;
57 bool terrainInProgress = false;
58 bool terrainTextureNeedsUpdate = false;
59 float terrainTimeSinceUpdate = RenderSettings.MinimumTimeBetweenTerrainUpdated + 1f; // Update terrain om first run
60 MeshmerizerR renderer;
61 Simulator sim { get { return Instance.Client.Network.CurrentSim; } }
63 public RenderTerrain(RadegastInstance instance)
65 this.Instance = instance;
66 renderer = new MeshmerizerR();
69 public void ResetTerrain()
74 public void ResetTerrain(bool removeImage)
76 if (terrainImage != null)
78 terrainImage.Dispose();
84 Compat.DeleteBuffer(terrainVBO);
88 if (terrainIndexVBO != -1)
90 Compat.DeleteBuffer(terrainIndexVBO);
96 if (terrainTexture != -1)
98 GL.DeleteTexture(terrainTexture);
103 fetchingTerrainTexture = false;
107 private void UpdateTerrain()
109 if (sim == null || sim.Terrain == null) return;
111 WorkPool.QueueUserWorkItem(sync =>
115 for (int x = 0; x < 256; x += step)
117 for (int y = 0; y < 256; y += step)
120 int patchNr = ((int)x / 16) * 16 + (int)y / 16;
121 if (sim.Terrain[patchNr] != null
122 && sim.Terrain[patchNr].Data != null)
124 float[] data = sim.Terrain[patchNr].Data;
125 z = data[(int)x % 16 * 16 + (int)y % 16];
127 heightTable[x, y] = z;
131 terrainFace = renderer.TerrainMesh(heightTable, 0f, 255f, 0f, 255f);
132 terrainVertices = new ColorVertex[terrainFace.Vertices.Count];
133 for (int i = 0; i < terrainFace.Vertices.Count; i++)
135 byte[] part = Utils.IntToBytes(i);
136 terrainVertices[i] = new ColorVertex()
138 Vertex = terrainFace.Vertices[i],
139 Color = new Color4b()
144 A = 253 // terrain picking
148 terrainIndices = new uint[terrainFace.Indices.Count];
149 for (int i = 0; i < terrainIndices.Length; i++)
151 terrainIndices[i] = terrainFace.Indices[i];
153 terrainInProgress = false;
155 terrainTextureNeedsUpdate = true;
156 terrainTimeSinceUpdate = 0f;
160 void UpdateTerrainTexture()
162 if (!fetchingTerrainTexture)
164 fetchingTerrainTexture = true;
165 WorkPool.QueueUserWorkItem(sync =>
167 Simulator sim = Client.Network.CurrentSim;
168 terrainImage = TerrainSplat.Splat(Instance, heightTable,
169 new UUID[] { sim.TerrainDetail0, sim.TerrainDetail1, sim.TerrainDetail2, sim.TerrainDetail3 },
170 new float[] { sim.TerrainStartHeight00, sim.TerrainStartHeight01, sim.TerrainStartHeight10, sim.TerrainStartHeight11 },
171 new float[] { sim.TerrainHeightRange00, sim.TerrainHeightRange01, sim.TerrainHeightRange10, sim.TerrainHeightRange11 });
173 fetchingTerrainTexture = false;
174 terrainTextureNeedsUpdate = false;
179 public bool TryGetVertex(int indeex, out ColorVertex picked)
181 if (indeex < terrainVertices.Length)
183 picked = terrainVertices[indeex];
186 picked = new ColorVertex();
190 public override void Render(RenderPass pass, int pickingID, SceneWindow scene, float time)
192 terrainTimeSinceUpdate += time;
194 if (Modified && terrainTimeSinceUpdate > RenderSettings.MinimumTimeBetweenTerrainUpdated)
196 if (!terrainInProgress)
198 terrainInProgress = true;
204 if (terrainTextureNeedsUpdate)
206 UpdateTerrainTexture();
209 if (terrainIndices == null || terrainVertices == null) return;
211 GL.Color3(1f, 1f, 1f);
212 GL.EnableClientState(ArrayCap.VertexArray);
213 GL.EnableClientState(ArrayCap.TextureCoordArray);
214 GL.EnableClientState(ArrayCap.NormalArray);
215 if (pass == RenderPass.Picking)
217 GL.EnableClientState(ArrayCap.ColorArray);
218 GL.ShadeModel(ShadingModel.Flat);
221 if (terrainImage != null)
223 if (terrainTexture != -1)
225 GL.DeleteTexture(terrainTexture);
228 terrainTexture = RHelp.GLLoadImage(terrainImage, false);
229 terrainImage.Dispose();
233 if (pass != RenderPass.Picking && terrainTexture != -1)
235 GL.Enable(EnableCap.Texture2D);
236 GL.BindTexture(TextureTarget.Texture2D, terrainTexture);
239 if (!RenderSettings.UseVBO || terrainVBOFailed)
243 fixed (float* normalPtr = &terrainVertices[0].Vertex.Normal.X)
244 fixed (float* texPtr = &terrainVertices[0].Vertex.TexCoord.X)
245 fixed (byte* colorPtr = &terrainVertices[0].Color.R)
247 GL.NormalPointer(NormalPointerType.Float, ColorVertex.Size, (IntPtr)normalPtr);
248 GL.TexCoordPointer(2, TexCoordPointerType.Float, ColorVertex.Size, (IntPtr)texPtr);
249 GL.VertexPointer(3, VertexPointerType.Float, ColorVertex.Size, terrainVertices);
250 if (pass == RenderPass.Picking)
252 GL.ColorPointer(4, ColorPointerType.UnsignedByte, ColorVertex.Size, (IntPtr)colorPtr);
254 GL.DrawElements(BeginMode.Triangles, terrainIndices.Length, DrawElementsType.UnsignedInt, terrainIndices);
260 if (terrainVBO == -1)
262 Compat.GenBuffers(out terrainVBO);
263 Compat.BindBuffer(BufferTarget.ArrayBuffer, terrainVBO);
264 Compat.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(terrainVertices.Length * ColorVertex.Size), terrainVertices, BufferUsageHint.StaticDraw);
265 if (Compat.BufferSize(BufferTarget.ArrayBuffer) != terrainVertices.Length * ColorVertex.Size)
267 terrainVBOFailed = true;
268 Compat.BindBuffer(BufferTarget.ArrayBuffer, 0);
274 Compat.BindBuffer(BufferTarget.ArrayBuffer, terrainVBO);
277 if (terrainIndexVBO == -1)
279 Compat.GenBuffers(out terrainIndexVBO);
280 Compat.BindBuffer(BufferTarget.ElementArrayBuffer, terrainIndexVBO);
281 Compat.BufferData(BufferTarget.ElementArrayBuffer, (IntPtr)(terrainIndices.Length * sizeof(uint)), terrainIndices, BufferUsageHint.StaticDraw);
282 if (Compat.BufferSize(BufferTarget.ElementArrayBuffer) != terrainIndices.Length * sizeof(uint))
284 terrainVBOFailed = true;
285 Compat.BindBuffer(BufferTarget.ElementArrayBuffer, 0);
286 terrainIndexVBO = -1;
291 Compat.BindBuffer(BufferTarget.ElementArrayBuffer, terrainIndexVBO);
294 if (!terrainVBOFailed)
296 GL.NormalPointer(NormalPointerType.Float, ColorVertex.Size, (IntPtr)12);
297 GL.TexCoordPointer(2, TexCoordPointerType.Float, ColorVertex.Size, (IntPtr)(24));
298 if (pass == RenderPass.Picking)
300 GL.ColorPointer(4, ColorPointerType.UnsignedByte, ColorVertex.Size, (IntPtr)32);
302 GL.VertexPointer(3, VertexPointerType.Float, ColorVertex.Size, (IntPtr)(0));
304 GL.DrawElements(BeginMode.Triangles, terrainIndices.Length, DrawElementsType.UnsignedInt, IntPtr.Zero);
307 Compat.BindBuffer(BufferTarget.ArrayBuffer, 0);
308 Compat.BindBuffer(BufferTarget.ElementArrayBuffer, 0);
311 if (pass == RenderPass.Picking)
313 GL.DisableClientState(ArrayCap.ColorArray);
314 GL.ShadeModel(ShadingModel.Smooth);
318 GL.BindTexture(TextureTarget.Texture2D, 0);
320 GL.DisableClientState(ArrayCap.VertexArray);
321 GL.DisableClientState(ArrayCap.TextureCoordArray);
322 GL.DisableClientState(ArrayCap.NormalArray);