void IGraphicsBackend.GetOutputPixelData(IntPtr buffer, ColorDataLayout dataLayout, ColorDataElementType dataElementType, int x, int y, int width, int height) { DefaultOpenTKBackendPlugin.GuardSingleThreadState(); NativeRenderTarget lastRt = NativeRenderTarget.BoundRT; NativeRenderTarget.Bind(null); { // Use a temporary local buffer, since the image will be upside-down because // of OpenGL's coordinate system and we'll need to flip it before returning. byte[] byteData = new byte[width * height * 4]; // Retrieve pixel data GL.ReadPixels(x, y, width, height, dataLayout.ToOpenTK(), dataElementType.ToOpenTK(), byteData); // Flip the retrieved image vertically int bytesPerLine = width * 4; byte[] switchLine = new byte[width * 4]; for (int flipY = 0; flipY < height / 2; flipY++) { int lineIndex = flipY * width * 4; int lineIndex2 = (height - 1 - flipY) * width * 4; // Copy the current line to the switch buffer for (int lineX = 0; lineX < bytesPerLine; lineX++) { switchLine[lineX] = byteData[lineIndex + lineX]; } // Copy the opposite line to the current line for (int lineX = 0; lineX < bytesPerLine; lineX++) { byteData[lineIndex + lineX] = byteData[lineIndex2 + lineX]; } // Copy the switch buffer to the opposite line for (int lineX = 0; lineX < bytesPerLine; lineX++) { byteData[lineIndex2 + lineX] = switchLine[lineX]; } } // Copy the flipped data to the output buffer Marshal.Copy(byteData, 0, buffer, width * height * 4); } NativeRenderTarget.Bind(lastRt); }
private void CheckContextCaps() { if (this.contextCapsRetrieved) { return; } this.contextCapsRetrieved = true; Log.Core.Write("Determining OpenGL context capabilities..."); Log.Core.PushIndent(); // Make sure we're not on a render target, which may override // some settings that we'd like to get from the main contexts // backbuffer. NativeRenderTarget oldTarget = NativeRenderTarget.BoundRT; NativeRenderTarget.Bind(null); int targetSamples = this.defaultGraphicsMode.Samples; int actualSamples; // Retrieve how many MSAA samples are actually available, despite what // was offered and requested vis graphics mode. CheckOpenGLErrors(true); actualSamples = GL.GetInteger(GetPName.Samples); if (CheckOpenGLErrors()) { actualSamples = targetSamples; } // If the sample count differs, mention it in the logs. If it is // actually zero, assume MSAA is driver-disabled. if (targetSamples != actualSamples) { Log.Core.Write("Requested {0} MSAA samples, but got {1} samples instead.", targetSamples, actualSamples); if (actualSamples == 0) { this.msaaIsDriverDisabled = true; Log.Core.Write("Assuming MSAA is unavailable. Duality will not use Alpha-to-Coverage masking techniques."); } } NativeRenderTarget.Bind(oldTarget); Log.Core.PopIndent(); }
void IGraphicsBackend.GetOutputPixelData <T>(T[] buffer, ColorDataLayout dataLayout, ColorDataElementType dataElementType, int x, int y, int width, int height) { DefaultOpenTKBackendPlugin.GuardSingleThreadState(); NativeRenderTarget lastRt = NativeRenderTarget.BoundRT; NativeRenderTarget.Bind(null); { GL.ReadPixels(x, y, width, height, dataLayout.ToOpenTK(), dataElementType.ToOpenTK(), buffer); // The image will be upside-down because of OpenGL's coordinate system. Flip it. int structSize = System.Runtime.InteropServices.Marshal.SizeOf(typeof(T)); T[] switchLine = new T[width * 4 / structSize]; for (int flipY = 0; flipY < height / 2; flipY++) { int lineIndex = flipY * width * 4 / structSize; int lineIndex2 = (height - 1 - flipY) * width * 4 / structSize; // Copy the current line to the switch buffer for (int lineX = 0; lineX < width; lineX++) { switchLine[lineX] = buffer[lineIndex + lineX]; } // Copy the opposite line to the current line for (int lineX = 0; lineX < width; lineX++) { buffer[lineIndex + lineX] = buffer[lineIndex2 + lineX]; } // Copy the switch buffer to the opposite line for (int lineX = 0; lineX < width; lineX++) { buffer[lineIndex2 + lineX] = switchLine[lineX]; } } } NativeRenderTarget.Bind(lastRt); }
void IGraphicsBackend.BeginRendering(IDrawDevice device, RenderOptions options, RenderStats stats) { DebugCheckOpenGLErrors(); this.CheckContextCaps(); this.currentDevice = device; this.renderStats = stats; // Prepare the target surface for rendering NativeRenderTarget.Bind(options.Target as NativeRenderTarget); // Determine whether masked blending should use alpha-to-coverage mode if (this.msaaIsDriverDisabled) { this.useAlphaToCoverageBlend = false; } else if (NativeRenderTarget.BoundRT != null) { this.useAlphaToCoverageBlend = NativeRenderTarget.BoundRT.Samples > 0; } else if (this.activeWindow != null) { this.useAlphaToCoverageBlend = this.activeWindow.IsMultisampled; } else { this.useAlphaToCoverageBlend = this.defaultGraphicsMode.Samples > 0; } if (this.primaryVBO == 0) { GL.GenBuffers(1, out this.primaryVBO); } GL.BindBuffer(BufferTarget.ArrayBuffer, this.primaryVBO); // Setup viewport Rect viewportRect = options.Viewport; GL.Viewport((int)viewportRect.X, (int)viewportRect.Y, (int)viewportRect.W, (int)viewportRect.H); GL.Scissor((int)viewportRect.X, (int)viewportRect.Y, (int)viewportRect.W, (int)viewportRect.H); // Clear buffers ClearBufferMask glClearMask = 0; ColorRgba clearColor = options.ClearColor; if ((options.ClearFlags & ClearFlag.Color) != ClearFlag.None) { glClearMask |= ClearBufferMask.ColorBufferBit; } if ((options.ClearFlags & ClearFlag.Depth) != ClearFlag.None) { glClearMask |= ClearBufferMask.DepthBufferBit; } GL.ClearColor(clearColor.R / 255.0f, clearColor.G / 255.0f, clearColor.B / 255.0f, clearColor.A / 255.0f); GL.ClearDepth((double)options.ClearDepth); // The "float version" is from OpenGL 4.1.. GL.Clear(glClearMask); // Configure Rendering params if (options.RenderMode == RenderMatrix.OrthoScreen) { GL.Enable(EnableCap.ScissorTest); GL.Enable(EnableCap.DepthTest); GL.DepthFunc(DepthFunction.Always); } else { GL.Enable(EnableCap.ScissorTest); GL.Enable(EnableCap.DepthTest); GL.DepthFunc(DepthFunction.Lequal); } OpenTK.Matrix4 openTkModelView; Matrix4 modelView = options.ModelViewMatrix; GetOpenTKMatrix(ref modelView, out openTkModelView); GL.MatrixMode(MatrixMode.Modelview); GL.LoadMatrix(ref openTkModelView); OpenTK.Matrix4 openTkProjection; Matrix4 projection = options.ProjectionMatrix; GetOpenTKMatrix(ref projection, out openTkProjection); GL.MatrixMode(MatrixMode.Projection); GL.LoadMatrix(ref openTkProjection); if (NativeRenderTarget.BoundRT != null) { if (options.RenderMode == RenderMatrix.OrthoScreen) { GL.Translate(0.0f, viewportRect.H * 0.5f, 0.0f); } GL.Scale(1.0f, -1.0f, 1.0f); if (options.RenderMode == RenderMatrix.OrthoScreen) { GL.Translate(0.0f, -viewportRect.H * 0.5f, 0.0f); } } }
void IGraphicsBackend.BeginRendering(IDrawDevice device, RenderOptions options, RenderStats stats) { DebugCheckOpenGLErrors(); this.CheckRenderingCapabilities(); this.currentDevice = device; this.renderOptions = options; this.renderStats = stats; // Prepare a shared index buffer object, in case we don't have one yet if (this.sharedBatchIBO == null) { this.sharedBatchIBO = new NativeGraphicsBuffer(GraphicsBufferType.Index); } // Prepare the target surface for rendering NativeRenderTarget.Bind(options.Target as NativeRenderTarget); // Determine whether masked blending should use alpha-to-coverage mode if (this.msaaIsDriverDisabled) { this.useAlphaToCoverageBlend = false; } else if (NativeRenderTarget.BoundRT != null) { this.useAlphaToCoverageBlend = NativeRenderTarget.BoundRT.Samples > 0; } else if (this.activeWindow != null) { this.useAlphaToCoverageBlend = this.activeWindow.IsMultisampled; } else { this.useAlphaToCoverageBlend = this.defaultGraphicsMode.Samples > 0; } // Determine the available size on the active rendering surface Point2 availableSize; if (NativeRenderTarget.BoundRT != null) { availableSize = new Point2(NativeRenderTarget.BoundRT.Width, NativeRenderTarget.BoundRT.Height); } else if (this.activeWindow != null) { availableSize = new Point2(this.activeWindow.Width, this.activeWindow.Height); } else { availableSize = this.externalBackbufferSize; } // Translate viewport coordinates to OpenGL screen coordinates (borrom-left, rising), unless rendering // to a texture, which is laid out Duality-like (top-left, descending) Rect openGLViewport = options.Viewport; if (NativeRenderTarget.BoundRT == null) { openGLViewport.Y = (availableSize.Y - openGLViewport.H) - openGLViewport.Y; } // Setup viewport and scissor rects GL.Viewport((int)openGLViewport.X, (int)openGLViewport.Y, (int)MathF.Ceiling(openGLViewport.W), (int)MathF.Ceiling(openGLViewport.H)); GL.Scissor((int)openGLViewport.X, (int)openGLViewport.Y, (int)MathF.Ceiling(openGLViewport.W), (int)MathF.Ceiling(openGLViewport.H)); // Clear buffers ClearBufferMask glClearMask = 0; ColorRgba clearColor = options.ClearColor; if ((options.ClearFlags & ClearFlag.Color) != ClearFlag.None) { glClearMask |= ClearBufferMask.ColorBufferBit; } if ((options.ClearFlags & ClearFlag.Depth) != ClearFlag.None) { glClearMask |= ClearBufferMask.DepthBufferBit; } GL.ClearColor(clearColor.R / 255.0f, clearColor.G / 255.0f, clearColor.B / 255.0f, clearColor.A / 255.0f); GL.ClearDepth((double)options.ClearDepth); // The "float version" is from OpenGL 4.1.. GL.Clear(glClearMask); // Configure Rendering params GL.Enable(EnableCap.ScissorTest); GL.Enable(EnableCap.DepthTest); if (options.DepthTest) { GL.DepthFunc(DepthFunction.Lequal); } else { GL.DepthFunc(DepthFunction.Always); } // Prepare shared matrix stack for rendering Matrix4 viewMatrix = options.ViewMatrix; Matrix4 projectionMatrix = options.ProjectionMatrix; if (NativeRenderTarget.BoundRT != null) { Matrix4 flipOutput = Matrix4.CreateScale(1.0f, -1.0f, 1.0f); projectionMatrix = projectionMatrix * flipOutput; } this.renderOptions.ShaderParameters.Set( BuiltinShaderFields.ViewMatrix, viewMatrix); this.renderOptions.ShaderParameters.Set( BuiltinShaderFields.ProjectionMatrix, projectionMatrix); this.renderOptions.ShaderParameters.Set( BuiltinShaderFields.ViewProjectionMatrix, viewMatrix * projectionMatrix); }
void IGraphicsBackend.BeginRendering(IDrawDevice device, RenderOptions options, RenderStats stats) { this.currentDevice = device; this.renderStats = stats; // Prepare the target surface for rendering NativeRenderTarget.Bind(options.Target as NativeRenderTarget); if (this.primaryVBO == 0) { GL.GenBuffers(1, out this.primaryVBO); } GL.BindBuffer(BufferTarget.ArrayBuffer, this.primaryVBO); // Setup viewport Rect viewportRect = options.Viewport; GL.Viewport((int)viewportRect.X, (int)viewportRect.Y, (int)viewportRect.W, (int)viewportRect.H); GL.Scissor((int)viewportRect.X, (int)viewportRect.Y, (int)viewportRect.W, (int)viewportRect.H); // Clear buffers ClearBufferMask glClearMask = 0; ColorRgba clearColor = options.ClearColor; if ((options.ClearFlags & ClearFlag.Color) != ClearFlag.None) { glClearMask |= ClearBufferMask.ColorBufferBit; } if ((options.ClearFlags & ClearFlag.Depth) != ClearFlag.None) { glClearMask |= ClearBufferMask.DepthBufferBit; } GL.ClearColor(clearColor.R / 255.0f, clearColor.G / 255.0f, clearColor.B / 255.0f, clearColor.A / 255.0f); GL.ClearDepth((double)options.ClearDepth); // The "float version" is from OpenGL 4.1.. GL.Clear(glClearMask); // Configure Rendering params if (options.RenderMode == RenderMatrix.OrthoScreen) { GL.Enable(EnableCap.ScissorTest); GL.Enable(EnableCap.DepthTest); GL.DepthFunc(DepthFunction.Always); } else { GL.Enable(EnableCap.ScissorTest); GL.Enable(EnableCap.DepthTest); GL.DepthFunc(DepthFunction.Lequal); } OpenTK.Matrix4 openTkModelView; Matrix4 modelView = options.ModelViewMatrix; GetOpenTKMatrix(ref modelView, out openTkModelView); GL.MatrixMode(MatrixMode.Modelview); GL.LoadMatrix(ref openTkModelView); OpenTK.Matrix4 openTkProjection; Matrix4 projection = options.ProjectionMatrix; GetOpenTKMatrix(ref projection, out openTkProjection); GL.MatrixMode(MatrixMode.Projection); GL.LoadMatrix(ref openTkProjection); if (NativeRenderTarget.BoundRT != null) { if (options.RenderMode == RenderMatrix.OrthoScreen) { GL.Translate(0.0f, NativeRenderTarget.BoundRT.Height * 0.5f, 0.0f); } GL.Scale(1.0f, -1.0f, 1.0f); if (options.RenderMode == RenderMatrix.OrthoScreen) { GL.Translate(0.0f, -NativeRenderTarget.BoundRT.Height * 0.5f, 0.0f); } } }