private unsafe void ReadPixels(int x, int y, int width, int height, ReadPixelsFormat format, ReadPixelsType type, IntPtr data, IAttachable attachment) { byte[] dataStore = attachment.DataStore; //int srcBitSize = InternalFormatHelper.BitSize(attachment.Format); //int srcElementByteLength = (srcBitSize % 8 == 0) ? srcBitSize / 8 : srcBitSize / 8 + 1; // TODO: any better solution? int srcWidth = attachment.Width, srcHeight = attachment.Height; //int dstBitSize = InternalFormatHelper.BitSize((uint)format); //int dstElementByteLength = (dstBitSize % 8 == 0) ? dstBitSize / 8 : dstBitSize / 8 + 1; // TODO: any better solution? var array = (byte *)data.ToPointer(); if (format == ReadPixelsFormat.BGRA && attachment.Format == GL.GL_RGBA) { var indexes = new int[4] { 2, 1, 0, 3 }; for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { for (int t = 0; t < 4; t++) { int dstT = (j * width + i) * 4 + t; int srcT = ((j + y) * srcWidth + (i + x)) * 4 + indexes[t]; array[dstT] = dataStore[srcT]; } } } } else if (format == ReadPixelsFormat.BGRA && attachment.Format == GL.GL_BGRA) { for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { for (int t = 0; t < 4; t++) { int dstT = (j * width + i) * 4 + t; int srcT = ((j + y) * srcWidth + (i + x)) * 4 + t; array[dstT] = dataStore[srcT]; } } } } else // TODO; deal with all possibilities. { throw new NotImplementedException(); } }
private unsafe void ReadPixels(int x, int y, int width, int height, ReadPixelsFormat format, ReadPixelsType type, IntPtr data) { Framebuffer framebuffer = this.currentFramebuffer; if (framebuffer == null) { throw new Exception("This should not happen!"); } if (!Enum.IsDefined(typeof(ReadPixelsFormat), format)) { SetLastError(ErrorCode.InvalidEnum); return; } if (!Enum.IsDefined(typeof(ReadPixelsType), type)) { SetLastError(ErrorCode.InvalidEnum); return; } if (width < 0 || height < 0) { SetLastError(ErrorCode.InvalidValue); return; } if (format == ReadPixelsFormat.StencilIndex && framebuffer.StencilbufferAttachment == null) { SetLastError(ErrorCode.InvalidOperation); return; } if (format == ReadPixelsFormat.DepthComponent && framebuffer.DepthbufferAttachment == null) { SetLastError(ErrorCode.InvalidOperation); return; } if (format == ReadPixelsFormat.DepthStencil && (framebuffer.DepthbufferAttachment == null || framebuffer.StencilbufferAttachment == null)) { SetLastError(ErrorCode.InvalidOperation); return; } if (format == ReadPixelsFormat.DepthStencil && (type != ReadPixelsType.UnsignedInt248 && type != ReadPixelsType.Float32UnsignedInt248Rev)) { SetLastError(ErrorCode.InvalidEnum); return; } if (format != ReadPixelsFormat.RGB && (type == ReadPixelsType.UnsignedByte332 || type == ReadPixelsType.UnsignedByte233Rev || type == ReadPixelsType.UnsignedShort565 || type == ReadPixelsType.UnsignedShort565Rev)) { SetLastError(ErrorCode.InvalidOperation); return; } if ((format != ReadPixelsFormat.RGBA && format != ReadPixelsFormat.BGRA) && (type == ReadPixelsType.UnsignedShort4444 || type == ReadPixelsType.UnsignedShort4444Rev || type == ReadPixelsType.UnsignedShort5551 || type == ReadPixelsType.UnsignedShort1555Rev || type == ReadPixelsType.UnsignedInt8888 || type == ReadPixelsType.UnsignedInt8888Rev || type == ReadPixelsType.UnsignedInt1010102 || type == ReadPixelsType.UnsignedInt2101010Rev)) { SetLastError(ErrorCode.InvalidOperation); return; } // TODO: GL_INVALID_OPERATION is generated if a non-zero buffer object name is bound to the GL_PIXEL_PACK_BUFFER target and the buffer object's data store is currently mapped. // TODO: GL_INVALID_OPERATION is generated if a non-zero buffer object name is bound to the GL_PIXEL_PACK_BUFFER target and the data would be packed to the buffer object such that the memory writes required would exceed the data store size. // TODO: GL_INVALID_OPERATION is generated if a non-zero buffer object name is bound to the GL_PIXEL_PACK_BUFFER target and data is not evenly divisible into the number of bytes needed to store in memory a datum indicated by type. // TODO: GL_INVALID_OPERATION is generated if GL_READ_FRAMEBUFFER_BINDING is non-zero, the read framebuffer is complete, and the value of GL_SAMPLE_BUFFERS for the read framebuffer is greater than zero. IAttachable attachment = null; if (format == ReadPixelsFormat.DepthComponent) { attachment = framebuffer.DepthbufferAttachment; } else if (format == ReadPixelsFormat.StencilIndex) { attachment = framebuffer.StencilbufferAttachment; } else if (format == ReadPixelsFormat.DepthStencil) { attachment = framebuffer.DepthbufferAttachment; } else { IList <uint> drawBuffers = framebuffer.DrawBuffers; if (drawBuffers.Count > 0) { uint index = drawBuffers[0].ToIndex(); attachment = framebuffer.ColorbufferAttachments[index]; } } // copy data from attachment to "data". if (attachment != null) { ReadPixels(x, y, width, height, format, type, data, attachment); } }
/// <summary> /// Reads pixels from this <see cref="FramebufferObject"/>. /// </summary> /// <typeparam name="T">A struct with the same format as a pixel to read.</typeparam> /// <param name="data">The span to which the data will be written.</param> /// <param name="x">The X coordinate of the first pixel to read.</param> /// <param name="y">The (invertex) Y coordinate of the first pixel to read.</param> /// <param name="width">The width of the rectangle of pixels to read.</param> /// <param name="height">The height of the rectangle of pixels to read.</param> /// <param name="pixelFormat">The format the pixel data will be read as.</param> /// <param name="pixelType">The format the pixel data is stored as.</param> public unsafe void ReadPixels <T>(Span <T> data, int x, int y, uint width, uint height, ReadPixelsFormat pixelFormat = ReadPixelsFormat.Rgba, PixelType pixelType = PixelType.UnsignedByte) where T : unmanaged { if (data.Length < (width - x) * (height - y)) { throw new ArgumentException(nameof(data) + " must be able to hold the requested pixel data", nameof(data)); fixed(void *ptr = data) ReadPixelsPtr(ptr, x, y, width, height, pixelFormat, pixelType); }
/// <summary> /// Reads pixels from this <see cref="FramebufferObject"/>. /// </summary> /// <param name="ptr">The pointer to which the pixel data will be written.</param> /// <param name="x">The X coordinate of the first pixel to read.</param> /// <param name="y">The (invertex) Y coordinate of the first pixel to read.</param> /// <param name="width">The width of the rectangle of pixels to read.</param> /// <param name="height">The height of the rectangle of pixels to read.</param> /// <param name="pixelFormat">The format the pixel data will be read as.</param> /// <param name="pixelType">The format the pixel data is stored as.</param> public unsafe void ReadPixelsPtr(void *ptr, int x, int y, uint width, uint height, ReadPixelsFormat pixelFormat = ReadPixelsFormat.Rgba, PixelType pixelType = PixelType.UnsignedByte) { if (x < 0) { throw new ArgumentException(nameof(x) + " must be greater than or equal to 0", nameof(x)); } if (y < 0) { throw new ArgumentException(nameof(y) + " must be greater than or equal to 0", nameof(y)); } if (width <= 0 || width > Width) { throw new ArgumentOutOfRangeException(nameof(width), width, nameof(width) + " must be in the range (0, " + nameof(Width) + "]"); } if (height <= 0 || height > Height) { throw new ArgumentOutOfRangeException(nameof(height), height, nameof(height) + " must be in the range (0, " + nameof(Height) + "]"); } if (x + width > Width || y + height > Height) { throw new ArgumentException("Tried to read outside the " + nameof(FramebufferObject) + "'s image"); } if (pixelFormat == ReadPixelsFormat.DepthStencil && pixelType != (PixelType)GLEnum.UnsignedInt248) { throw new ArgumentException("When reading depth-stencil, " + nameof(pixelType) + " must be UnsignedInt248", nameof(pixelType)); } GraphicsDevice.ReadFramebuffer = this; GL.ReadPixels(x, y, width, height, (PixelFormat)pixelFormat, pixelType, ptr); }