public OpenGLSceneProcessor(IServiceProvider serviceProvider, IRenderWindow renderWindow, SceneGraph sceneGraph) { _serviceProvider = serviceProvider; _cancellationTokenManager = _serviceProvider.GetRequiredService <CancellationTokenSource>(); _logger = _serviceProvider.GetRequiredService <ILogger <RenderWindow> >(); _shaderCompiler = _serviceProvider.GetRequiredService <IShaderCompiler>(); _textureLoader = _serviceProvider.GetRequiredService <ITextureLoader>(); _renderWindow = renderWindow; // This cannot be passed via the service provider otherwise there will be a cycle in the DI graph _sceneGraph = sceneGraph; _renderList = new LinkedList <IRenderCommand>(); _renderInfo = new RenderInfo(); _requestPicking = null; GL.LoadBindings(new GLFWBindingsContext()); // Get human readable log messages during debugging if (Debugger.IsAttached) { GL.Enable(EnableCap.DebugOutput); _debugProc = DebugMessageCallback; _gcHandle = GCHandle.Alloc(_debugProc); GL.DebugMessageCallback(_debugProc, IntPtr.Zero); } GL.Enable(EnableCap.DepthTest); // Save default frame buffer id for later blitting GL.GetInteger(GetPName.FramebufferBinding, out _defaultFrameBufferId); GL.BindFramebuffer(FramebufferTarget.Framebuffer, _defaultFrameBufferId); InitFrameBuffer(640, 360); }
public void UpdateState(IRenderCommand renderCommand) { if (renderCommand is RequestPickingInfo requestPicking) { _requestPicking = requestPicking; } renderCommand.SetState(_renderInfo); InsertCommandInRenderOrder(renderCommand); }
public void Render(double timeSinceLastFrameSeconds) { _renderInfo.TotalRenderTime += timeSinceLastFrameSeconds; _renderInfo.FrameRate = 1.0 / timeSinceLastFrameSeconds; _renderInfo.CurrentViewMatrix = _sceneGraph.ViewMatrix; _renderInfo.CurrentProjectionMatrix = _sceneGraph.ProjectionMatrix; // Resize frame buffer object (FBO) to account for resized window if (_windowSizeChanged) { GL.BindFramebuffer(FramebufferTarget.Framebuffer, _defaultFrameBufferId); GL.Viewport(0, 0, _renderInfo.Width, _renderInfo.Height); // Clean up existing frame buffer GL.DeleteFramebuffer(_mrtFrameBufferId); GL.DeleteTextures(2, new[] { _mrtFrameBufferPickingTextureId, _mrtFrameBufferMainTextureId }); GL.DeleteRenderbuffer(_mrtFrameBufferDepthId); // Create new MRT frameobuffer with resized dimensions InitFrameBuffer(_renderInfo.Width, _renderInfo.Height); _windowSizeChanged = false; _logger.LogInformation($"Window resized to {_renderInfo.Width}x{_renderInfo.Height}={_renderInfo.Width * _renderInfo.Height} pixels"); } GL.BindFramebuffer(FramebufferTarget.Framebuffer, _mrtFrameBufferId); GL.DrawBuffers(2, new[] { DrawBuffersEnum.ColorAttachment0, DrawBuffersEnum.ColorAttachment1 }); if (!_renderList.Any()) { return; } // Render content GL.Clear(ClearBufferMask.DepthBufferBit); GL.ClearBuffer(ClearBuffer.Color, 1, new float[] { 0, 0, 0, 0 }); var currentNode = _renderList.First; while (currentNode != null) { var command = currentNode.Value; command.Render(_renderInfo); var next = currentNode.Next; if (command.SelfDestruct) { _renderList.Remove(currentNode); if (command is IDisposable disposable) { disposable.Dispose(); } } currentNode = next; } // Process picking request if (_requestPicking != null) { var pickingInfo = GetPickingInfo(_renderInfo, _requestPicking.ScreenX, _requestPicking.ScreenY); var writeTask = Task.Run(async() => { await _renderWindow.EventChannel.Writer.WriteAsync(new PickingFeedback(pickingInfo), _cancellationTokenManager.Token); }); writeTask.Wait(); _requestPicking = null; } // Blit MRT source to default frame buffer to display it GL.ReadBuffer(ReadBufferMode.ColorAttachment0); // copy main texture GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, _mrtFrameBufferId); GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, _defaultFrameBufferId); GL.BlitFramebuffer(0, 0, _renderInfo.Width - 1, _renderInfo.Height - 1, // source 0, 0, _renderInfo.Width - 1, _renderInfo.Height - 1, // destination ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit, BlitFramebufferFilter.Nearest); }