public override void CopyContentsToMemory(PixelBox dst, FrameBuffer buffer) { if ((dst.Left < 0) || (dst.Right > Width) || (dst.Top < 0) || (dst.Bottom > Height) || (dst.Front != 0) || (dst.Back != 1)) { throw new Exception("Invalid box."); } if (buffer == RenderTarget.FrameBuffer.Auto) { buffer = IsFullScreen ? RenderTarget.FrameBuffer.Front : RenderTarget.FrameBuffer.Back; } int format = GLPixelUtil.GetGLOriginFormat(dst.Format); int type = GLPixelUtil.GetGLOriginDataType(dst.Format); if ((format == Gl.GL_NONE) || (type == 0)) { throw new Exception("Unsupported format."); } // Switch context if different from current one RenderSystem rsys = Root.Instance.RenderSystem; rsys.Viewport = this.GetViewport(0); // Must change the packing to ensure no overruns! Gl.glPixelStorei(Gl.GL_PACK_ALIGNMENT, 1); Gl.glReadBuffer((buffer == RenderTarget.FrameBuffer.Front) ? Gl.GL_FRONT : Gl.GL_BACK); Gl.glReadPixels(dst.Left, dst.Top, dst.Width, dst.Height, format, type, dst.Data); // restore default alignment Gl.glPixelStorei(Gl.GL_PACK_ALIGNMENT, 4); //vertical flip { int rowSpan = dst.Width * PixelUtil.GetNumElemBytes(dst.Format); int height = dst.Height; byte[] tmpData = new byte[rowSpan * height]; unsafe { var dataPtr = dst.Data.ToBytePointer(); //int *srcRow = (uchar *)dst.data, *tmpRow = tmpData + (height - 1) * rowSpan; for (int row = height - 1, tmpRow = 0; row >= 0; row--, tmpRow++) { for (int col = 0; col < rowSpan; col++) { tmpData[tmpRow * rowSpan + col] = dataPtr[row * rowSpan + col]; } } } var tmpDataHandle = BufferBase.Wrap(tmpData); Memory.Copy(tmpDataHandle, dst.Data, rowSpan * height); } }
protected override void download(PixelBox data) { if (data.Width != Width || data.Height != Height || data.Depth != Depth) { throw new ArgumentException("only download of entire buffer is supported by GL"); } Gl.glBindTexture(this._target, this._textureId); if (PixelUtil.IsCompressed(data.Format)) { if (data.Format != Format || !data.IsConsecutive) { throw new ArgumentException("Compressed images must be consecutive, in the source format"); } // Data must be consecutive and at beginning of buffer as PixelStorei not allowed // for compressed formate Gl.glGetCompressedTexImageARB(this._faceTarget, this._level, data.Data.Pin()); data.Data.UnPin(); } else { if (data.Width != data.RowPitch) { Gl.glPixelStorei(Gl.GL_PACK_ROW_LENGTH, data.RowPitch); } if (data.Height * data.Width != data.SlicePitch) { Gl.glPixelStorei(Gl.GL_PACK_IMAGE_HEIGHT, (data.SlicePitch / data.Width)); } if (((data.Width * PixelUtil.GetNumElemBytes(data.Format)) & 3) != 0) { // Standard alignment of 4 is not right Gl.glPixelStorei(Gl.GL_PACK_ALIGNMENT, 1); } // We can only get the entire texture Gl.glGetTexImage(this._faceTarget, this._level, GLPixelUtil.GetGLOriginFormat(data.Format), GLPixelUtil.GetGLOriginDataType(data.Format), data.Data.Pin()); data.Data.UnPin(); // Restore defaults Gl.glPixelStorei(Gl.GL_PACK_ROW_LENGTH, 0); Gl.glPixelStorei(Gl.GL_PACK_IMAGE_HEIGHT, 0); Gl.glPixelStorei(Gl.GL_PACK_ALIGNMENT, 4); } }
protected override void upload(PixelBox box) { Gl.glBindTexture(this._target, this._textureId); if (PixelUtil.IsCompressed(box.Format)) { if (box.Format != Format || !box.IsConsecutive) { throw new ArgumentException("Compressed images must be consecutive, in the source format"); } int format = GLPixelUtil.GetClosestGLInternalFormat(Format); // Data must be consecutive and at beginning of buffer as PixelStorei not allowed // for compressed formats switch (this._target) { case Gl.GL_TEXTURE_1D: Gl.glCompressedTexSubImage1DARB(Gl.GL_TEXTURE_1D, this._level, box.Left, box.Width, format, box.ConsecutiveSize, box.Data.Pin()); box.Data.UnPin(); break; case Gl.GL_TEXTURE_2D: case Gl.GL_TEXTURE_CUBE_MAP: Gl.glCompressedTexSubImage2DARB(this._faceTarget, this._level, box.Left, box.Top, box.Width, box.Height, format, box.ConsecutiveSize, box.Data.Pin()); box.Data.UnPin(); break; case Gl.GL_TEXTURE_3D: Gl.glCompressedTexSubImage3DARB(Gl.GL_TEXTURE_3D, this._level, box.Left, box.Top, box.Front, box.Width, box.Height, box.Depth, format, box.ConsecutiveSize, box.Data.Pin()); box.Data.UnPin(); break; } } else if (this._softwareMipmap) { int internalFormat; Gl.glGetTexLevelParameteriv(this._target, this._level, Gl.GL_TEXTURE_INTERNAL_FORMAT, out internalFormat); if (box.Width != box.RowPitch) { Gl.glPixelStorei(Gl.GL_UNPACK_ROW_LENGTH, box.RowPitch); } if (box.Height * box.Width != box.SlicePitch) { Gl.glPixelStorei(Gl.GL_UNPACK_IMAGE_HEIGHT, (box.SlicePitch / box.Width)); } Gl.glPixelStorei(Gl.GL_UNPACK_ALIGNMENT, 1); switch (this._target) { case Gl.GL_TEXTURE_1D: Glu.gluBuild1DMipmaps(Gl.GL_TEXTURE_1D, internalFormat, box.Width, GLPixelUtil.GetGLOriginFormat(box.Format), GLPixelUtil.GetGLOriginDataType(box.Format), box.Data.Pin()); box.Data.UnPin(); break; case Gl.GL_TEXTURE_2D: case Gl.GL_TEXTURE_CUBE_MAP: Glu.gluBuild2DMipmaps(this._faceTarget, internalFormat, box.Width, box.Height, GLPixelUtil.GetGLOriginFormat(box.Format), GLPixelUtil.GetGLOriginDataType(box.Format), box.Data.Pin()); box.Data.UnPin(); break; case Gl.GL_TEXTURE_3D: /* Requires GLU 1.3 which is harder to come by than cards doing hardware mipmapping * Most 3D textures don't need mipmaps? * Gl.gluBuild3DMipmaps( * Gl.GL_TEXTURE_3D, internalFormat, * box.getWidth(), box.getHeight(), box.getDepth(), * GLPixelUtil.getGLOriginFormat(box.format), GLPixelUtil.getGLOriginDataType(box.format), * box.box); */ Gl.glTexImage3D(Gl.GL_TEXTURE_3D, 0, internalFormat, box.Width, box.Height, box.Depth, 0, GLPixelUtil.GetGLOriginFormat(box.Format), GLPixelUtil.GetGLOriginDataType(box.Format), box.Data.Pin()); box.Data.UnPin(); break; } } else { if (box.Width != box.RowPitch) { Gl.glPixelStorei(Gl.GL_UNPACK_ROW_LENGTH, box.RowPitch); } if (box.Height * box.Width != box.SlicePitch) { Gl.glPixelStorei(Gl.GL_UNPACK_IMAGE_HEIGHT, (box.SlicePitch / box.Width)); } if (((box.Width * PixelUtil.GetNumElemBytes(box.Format)) & 3) != 0) { // Standard alignment of 4 is not right Gl.glPixelStorei(Gl.GL_UNPACK_ALIGNMENT, 1); } switch (this._target) { case Gl.GL_TEXTURE_1D: Gl.glTexSubImage1D(Gl.GL_TEXTURE_1D, this._level, box.Left, box.Width, GLPixelUtil.GetGLOriginFormat(box.Format), GLPixelUtil.GetGLOriginDataType(box.Format), box.Data.Pin()); box.Data.UnPin(); break; case Gl.GL_TEXTURE_2D: case Gl.GL_TEXTURE_CUBE_MAP: Gl.glTexSubImage2D(this._faceTarget, this._level, box.Left, box.Top, box.Width, box.Height, GLPixelUtil.GetGLOriginFormat(box.Format), GLPixelUtil.GetGLOriginDataType(box.Format), box.Data.Pin()); box.Data.UnPin(); break; case Gl.GL_TEXTURE_3D: Gl.glTexSubImage3D(Gl.GL_TEXTURE_3D, this._level, box.Left, box.Top, box.Front, box.Width, box.Height, box.Depth, GLPixelUtil.GetGLOriginFormat(box.Format), GLPixelUtil.GetGLOriginDataType(box.Format), box.Data.Pin()); box.Data.UnPin(); break; } } // Restore defaults Gl.glPixelStorei(Gl.GL_UNPACK_ROW_LENGTH, 0); Gl.glPixelStorei(Gl.GL_UNPACK_IMAGE_HEIGHT, 0); Gl.glPixelStorei(Gl.GL_UNPACK_ALIGNMENT, 4); }