/// <summary> /// The render thread. This is the owner of the GLControl and does the actual loop for reblitting. /// </summary> private void rendererMain() { //Make the GLControl current on this thread GLControl.MakeCurrent(); //Enable all necessary GL captions GL.Enable(EnableCap.DepthTest); GL.DepthFunc(DepthFunction.Lequal); GL.Enable(EnableCap.ColorMaterial); GL.Light(LightName.Light0, LightParameter.Diffuse, OpenTK.Graphics.Color4.White); GL.Light(LightName.Light0, LightParameter.Position, new Vector4(8.0f, 8.0f, -1.0f, 1.0f)); GL.Enable(EnableCap.Light0); setupViewport(); //Create the VAOs for several graphic objects cubeHandle = new DataStructures.VBOHandle(DataStructures.ObjectName.Cube); pyramidHandle = new DataStructures.VBOHandle(DataStructures.ObjectName.Pyramid); gridHandle = new DataStructures.VBOHandle(DataStructures.ObjectName.Grid, map.xSizeCache, map.ySizeCache, map.zSizeCache); sizeOfGrid = new Tuple <int, int, int>(map.xSizeCache, map.ySizeCache, map.zSizeCache); selectorGrid = new DataStructures.VBOHandle(DataStructures.ObjectName.Grid, 1, 1, 1, 1.3f, 1.3f, 1.3f); RMessage current; //The main loop for rendering. Check and wait for messages and process them do { lock (messageQueue) { while (!messageQueue.Any()) { System.Threading.Monitor.Wait(messageQueue); } current = messageQueue.Dequeue(); } switch (current) { case RMessage.Reblit: reblit(); break; } }while (!(current == RMessage.Abort)); //Release VAOs cubeHandle.Dispose(); pyramidHandle.Dispose(); gridHandle.Dispose(); selectorGrid.Dispose(); }
/// <summary> /// Renders the entire scene and updates it on the screen. /// </summary> private void reblit() { GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); GL.Color3(0.4, 0.4, 0.4); //Resize the grid and adjust the camera if necessary if (map.xSizeCache != sizeOfGrid.Item1 || map.ySizeCache != sizeOfGrid.Item2 || map.zSizeCache != sizeOfGrid.Item3) { gridHandle.Dispose(); gridHandle = new DataStructures.VBOHandle(DataStructures.ObjectName.Grid, map.xSizeCache, map.ySizeCache, map.zSizeCache); sizeOfGrid = new Tuple <int, int, int>(map.xSizeCache, map.ySizeCache, map.zSizeCache); lock (map) { camera.moveCamera(new Vector3d((double)map.xSizeCache / 2, (double)map.ySizeCache / 2, (double)map.zSizeCache / 2 + map.xSizeCache + CAMERA_HEIGHT_PADDING)); camera.changeTarget(new Vector3d((double)map.xSizeCache / 2, (double)map.ySizeCache / 2, (double)map.zSizeCache / 2)); } Matrix4d cameraCache = camera.cameraMatrix; GL.LoadMatrix(ref cameraCache); } GL.BindVertexArray(gridHandle.VAOName); GL.Translate((float)map.xSizeCache / 2, (float)map.ySizeCache / 2, (float)map.zSizeCache / 2); GL.DrawElements(BeginMode.Lines, gridHandle.NumberOfElements, DrawElementsType.UnsignedShort, IntPtr.Zero); GL.Translate((float)-map.xSizeCache / 2, (float)-map.ySizeCache / 2, (float)-map.zSizeCache / 2); GL.Enable(EnableCap.Lighting); GL.BindVertexArray(cubeHandle.VAOName); lock (map) { GL.Color3(0.0, 0.0, 1.0); foreach (WorldMap.BlockInfo info in map) { if (info.status.HasFlag(MapNode.Status.isWall)) { GL.Translate(info.x + 0.5, info.y + 0.5, info.z + 0.5); GL.DrawElements(BeginMode.Triangles, cubeHandle.NumberOfElements, DrawElementsType.UnsignedShort, IntPtr.Zero); GL.Translate(-info.x - 0.5, -info.y - 0.5, -info.z - 0.5); } } if (map.start != null) { GL.BindVertexArray(pyramidHandle.VAOName); GL.Translate(map.start.Item1 + 0.5, map.start.Item2 + 0.5, map.start.Item3 + 0.5); GL.Color3(1.0, 0.0, 0.0); GL.DrawElements(BeginMode.Triangles, pyramidHandle.NumberOfElements, DrawElementsType.UnsignedShort, IntPtr.Zero); GL.Translate(-map.start.Item1 - 0.5, -map.start.Item2 - 0.5, -map.start.Item3 - 0.5); } if (map.goal != null) { //This should be much cheaper than just binding the VAO again. if (map.start == null) { GL.BindVertexArray(pyramidHandle.VAOName); } GL.Translate(map.goal.Item1 + 0.5, map.goal.Item2 + 0.5, map.goal.Item3 + 0.5); GL.Color3(0.0, 1.0, 0.0); GL.DrawElements(BeginMode.Triangles, pyramidHandle.NumberOfElements, DrawElementsType.UnsignedShort, IntPtr.Zero); GL.Translate(-map.goal.Item1 - 0.5, -map.goal.Item2 - 0.5, -map.goal.Item3 - 0.5); } GL.Color3(1.0, 0.0, 0.0); GL.Disable(EnableCap.Lighting); if (map.path.Any()) { LinkedListNode <WorldMap.BlockInfo> cache = map.path.First; while (cache.Next != null) { GL.Begin(BeginMode.Lines); GL.Vertex3(cache.Value.x + 0.5, cache.Value.y + 0.5, cache.Value.z + 0.5); GL.Vertex3(cache.Next.Value.x + 0.5, cache.Next.Value.y + 0.5, cache.Next.Value.z + 0.5); GL.End(); cache = cache.Next; } } } //Cache the selector so it cannot change between the pair of GL.Translates Vector3d selectorCache = AstarInterface.selector; GL.Translate(selectorCache.X + 0.5, selectorCache.Y + 0.5, selectorCache.Z + 0.5); GL.Color3(1.0, 0.4, 0.4); GL.BindVertexArray(selectorGrid.VAOName); GL.DrawElements(BeginMode.Lines, selectorGrid.NumberOfElements, DrawElementsType.UnsignedShort, IntPtr.Zero); GL.Translate(-selectorCache.X - 0.5, -selectorCache.Y - 0.5, -selectorCache.Z - 0.5); GLControl.SwapBuffers(); GL.BindVertexArray(0); }