protected override void BindSurfaceImpl(int attachment, RenderTexture target) { Contract.Requires(attachment < Config.MaxMultipleRenderTargets); // Get buffer and surface to bind to var buffer = (D3D9HardwarePixelBuffer)(target["BUFFER"]); Proclaim.NotNull(buffer); // Find first non null target int y; for (y = 0; y < Config.MaxMultipleRenderTargets && this._renderTargets[y] == null; ++y) { ; } if (y != Config.MaxMultipleRenderTargets) { // If there is another target bound, compare sizes if (this._renderTargets[y].Width != buffer.Width || this._renderTargets[y].Height != buffer.Height) { throw new AxiomException("MultiRenderTarget surfaces are not the same size."); } if (!Root.Instance.RenderSystem.Capabilities.HasCapability(Capabilities.MRTDifferentBitDepths) && (PixelUtil.GetNumElemBits(this._renderTargets[y].Format) != PixelUtil.GetNumElemBits(buffer.Format))) { throw new AxiomException("MultiRenderTarget surfaces are not of same bit depth and hardware requires it"); } } this._renderTargets[attachment] = buffer; _checkAndUpdate(); }
public void Rebind(XnaHardwarePixelBuffer buffer) { pixelBuffer = buffer; width = pixelBuffer.Width; height = pixelBuffer.Height; colorDepth = PixelUtil.GetNumElemBits(buffer.Format); }
public bool IsEquivalentFormatSupported(TextureType ttype, PixelFormat format, TextureUsage usage) { PixelFormat supportedFormat = GetNativeFormat(ttype, format, usage); // Assume that same or greater number of bits means quality not degraded return(PixelUtil.GetNumElemBits(supportedFormat) >= PixelUtil.GetNumElemBits(format)); }
public RenderTexture(HardwarePixelBuffer buffer, int zOffset) { pixelBuffer = buffer; this.zOffset = zOffset; priority = RenderTargetPriority.High; width = buffer.Width; height = buffer.Height; colorDepth = PixelUtil.GetNumElemBits(buffer.Format); }
private FI.FIBITMAP _encode(Stream input, CodecData codecData) { var ret = new FI.FIBITMAP(); ret.SetNull(); var imgData = codecData as ImageData; if (imgData != null) { var data = new byte[(int)input.Length]; input.Read(data, 0, data.Length); var dataPtr = BufferBase.Wrap(data); var src = new PixelBox(imgData.width, imgData.height, imgData.depth, imgData.format, dataPtr); // The required format, which will adjust to the format // actually supported by FreeImage. var requiredFormat = imgData.format; // determine the settings var imageType = FI.FREE_IMAGE_TYPE.FIT_UNKNOWN; var determiningFormat = imgData.format; switch (determiningFormat) { case PixelFormat.R5G6B5: case PixelFormat.B5G6R5: case PixelFormat.R8G8B8: case PixelFormat.B8G8R8: case PixelFormat.A8R8G8B8: case PixelFormat.X8R8G8B8: case PixelFormat.A8B8G8R8: case PixelFormat.X8B8G8R8: case PixelFormat.B8G8R8A8: case PixelFormat.R8G8B8A8: case PixelFormat.A4L4: case PixelFormat.BYTE_LA: case PixelFormat.R3G3B2: case PixelFormat.A4R4G4B4: case PixelFormat.A1R5G5B5: case PixelFormat.A2R10G10B10: case PixelFormat.A2B10G10R10: // I'd like to be able to use r/g/b masks to get FreeImage to load the data // in it's existing format, but that doesn't work, FreeImage needs to have // data in RGB[A] (big endian) and BGR[A] (little endian), always. if (PixelUtil.HasAlpha(determiningFormat)) { if (FI.FreeImageEngine.IsLittleEndian) { requiredFormat = PixelFormat.BYTE_BGRA; } else { requiredFormat = PixelFormat.BYTE_RGBA; } } else { if (FI.FreeImageEngine.IsLittleEndian) { requiredFormat = PixelFormat.BYTE_BGR; } else { requiredFormat = PixelFormat.BYTE_RGB; } } imageType = FI.FREE_IMAGE_TYPE.FIT_BITMAP; break; case PixelFormat.L8: case PixelFormat.A8: imageType = FI.FREE_IMAGE_TYPE.FIT_BITMAP; break; case PixelFormat.L16: imageType = FI.FREE_IMAGE_TYPE.FIT_UINT16; break; case PixelFormat.SHORT_GR: requiredFormat = PixelFormat.SHORT_RGB; break; case PixelFormat.SHORT_RGB: imageType = FI.FREE_IMAGE_TYPE.FIT_RGB16; break; case PixelFormat.SHORT_RGBA: imageType = FI.FREE_IMAGE_TYPE.FIT_RGBA16; break; case PixelFormat.FLOAT16_R: requiredFormat = PixelFormat.FLOAT32_R; break; case PixelFormat.FLOAT32_R: imageType = FI.FREE_IMAGE_TYPE.FIT_FLOAT; break; case PixelFormat.FLOAT16_GR: case PixelFormat.FLOAT16_RGB: case PixelFormat.FLOAT32_GR: requiredFormat = PixelFormat.FLOAT32_RGB; break; case PixelFormat.FLOAT32_RGB: imageType = FI.FREE_IMAGE_TYPE.FIT_RGBF; break; case PixelFormat.FLOAT16_RGBA: requiredFormat = PixelFormat.FLOAT32_RGBA; break; case PixelFormat.FLOAT32_RGBA: imageType = FI.FREE_IMAGE_TYPE.FIT_RGBAF; break; default: throw new AxiomException("Not Supported image format :{0}", determiningFormat.ToString()); } //end switch // Check support for this image type & bit depth if (!FI.FreeImage.FIFSupportsExportType((FI.FREE_IMAGE_FORMAT) this._freeImageType, imageType) || !FI.FreeImage.FIFSupportsExportBPP((FI.FREE_IMAGE_FORMAT) this._freeImageType, PixelUtil.GetNumElemBits(requiredFormat))) { // Ok, need to allocate a fallback // Only deal with RGBA . RGB for now switch (requiredFormat) { case PixelFormat.BYTE_RGBA: requiredFormat = PixelFormat.BYTE_RGB; break; case PixelFormat.BYTE_BGRA: requiredFormat = PixelFormat.BYTE_BGR; break; default: break; } } var conversionRequired = false; input.Position = 0; var srcData = new byte[(int)input.Length]; input.Read(srcData, 0, srcData.Length); var srcDataPtr = BufferBase.Wrap(srcData); // Check BPP var bpp = PixelUtil.GetNumElemBits(requiredFormat); if (!FI.FreeImage.FIFSupportsExportBPP((FI.FREE_IMAGE_FORMAT) this._freeImageType, bpp)) { if (bpp == 32 && PixelUtil.HasAlpha(imgData.format) && FI.FreeImage.FIFSupportsExportBPP((FI.FREE_IMAGE_FORMAT) this._freeImageType, 24)) { // drop to 24 bit (lose alpha) if (FI.FreeImage.IsLittleEndian()) { requiredFormat = PixelFormat.BYTE_BGR; } else { requiredFormat = PixelFormat.BYTE_RGB; } bpp = 24; } else if (bpp == 128 && PixelUtil.HasAlpha(imgData.format) && FI.FreeImage.FIFSupportsExportBPP((FI.FREE_IMAGE_FORMAT) this._freeImageType, 96)) { // drop to 96-bit floating point requiredFormat = PixelFormat.FLOAT32_RGB; } } var convBox = new PixelBox(imgData.width, imgData.height, 1, requiredFormat); if (requiredFormat != imgData.format) { conversionRequired = true; // Allocate memory var convData = new byte[convBox.ConsecutiveSize]; convBox.Data = BufferBase.Wrap(convData); // perform conversion and reassign source var newSrc = new PixelBox(imgData.width, imgData.height, 1, imgData.format, dataPtr); PixelConverter.BulkPixelConversion(newSrc, convBox); srcDataPtr = convBox.Data; } ret = FI.FreeImage.AllocateT(imageType, imgData.width, imgData.height, bpp); if (ret.IsNull) { if (conversionRequired) { srcDataPtr.SafeDispose(); convBox = null; } throw new AxiomException("FreeImage.AllocateT failed - possibly out of memory. "); } if (requiredFormat == PixelFormat.L8 || requiredFormat == PixelFormat.A8) { // Must explicitly tell FreeImage that this is greyscale by setting // a "grey" palette (otherwise it will save as a normal RGB // palettized image). var tmp = FI.FreeImage.ConvertToGreyscale(ret); FI.FreeImage.Unload(ret); ret = tmp; } var dstPitch = (int)FI.FreeImage.GetPitch(ret); var srcPitch = imgData.width * PixelUtil.GetNumElemBytes(requiredFormat); // Copy data, invert scanlines and respect FreeImage pitch var pSrc = srcDataPtr; using (var pDest = BufferBase.Wrap(FI.FreeImage.GetBits(ret), imgData.height * srcPitch)) { var byteSrcData = pSrc; var byteDstData = pDest; for (var y = 0; y < imgData.height; ++y) { byteSrcData += (imgData.height - y - 1) * srcPitch; Memory.Copy(pSrc, pDest, srcPitch); byteDstData += dstPitch; } } if (conversionRequired) { // delete temporary conversion area srcDataPtr.SafeDispose(); convBox = null; } } return(ret); }
/// <summary> /// Detect allowed FBO formats /// </summary> private void _detectFBOFormats() { // Try all formats, and report which ones work as target int fb, tid; int old_drawbuffer, old_readbuffer; int target = Gl.GL_TEXTURE_2D; Gl.glGetIntegerv(Gl.GL_DRAW_BUFFER, out old_drawbuffer); Gl.glGetIntegerv(Gl.GL_READ_BUFFER, out old_readbuffer); for (int x = 0; x < (int)PixelFormat.Count; ++x) { this._props[x].Valid = false; // Fetch GL format token int fmt = GLPixelUtil.GetGLInternalFormat((PixelFormat)x); if (fmt == Gl.GL_NONE && x != 0) { continue; } // No test for compressed formats if (PixelUtil.IsCompressed((PixelFormat)x)) { continue; } // Buggy ATI cards *crash* on non-RGB(A) formats int[] depths = PixelUtil.GetBitDepths((PixelFormat)x); if (fmt != Gl.GL_NONE && this._atiMode && (depths[0] == 0 || depths[1] == 0 || depths[2] == 0)) { continue; } // Buggy NVidia Drivers fail on 32Bit FP formats on Windows. if (PixelUtil.IsFloatingPoint((PixelFormat)x) && PlatformManager.IsWindowsOS && !this._atiMode) { continue; } // Create and attach framebuffer Gl.glGenFramebuffersEXT(1, out fb); Gl.glBindFramebufferEXT(Gl.GL_FRAMEBUFFER_EXT, fb); if (fmt != Gl.GL_NONE) { // Create and attach texture Gl.glGenTextures(1, out tid); Gl.glBindTexture(target, tid); // Set some default parameters so it won't fail on NVidia cards Gl.glTexParameteri(target, Gl.GL_TEXTURE_MAX_LEVEL, 0); Gl.glTexParameteri(target, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_NEAREST); Gl.glTexParameteri(target, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_NEAREST); Gl.glTexParameteri(target, Gl.GL_TEXTURE_WRAP_S, Gl.GL_CLAMP_TO_EDGE); Gl.glTexParameteri(target, Gl.GL_TEXTURE_WRAP_T, Gl.GL_CLAMP_TO_EDGE); Gl.glTexImage2D(target, 0, fmt, PROBE_SIZE, PROBE_SIZE, 0, Gl.GL_RGBA, Gl.GL_UNSIGNED_BYTE, IntPtr.Zero); Gl.glFramebufferTexture2DEXT(Gl.GL_FRAMEBUFFER_EXT, Gl.GL_COLOR_ATTACHMENT0_EXT, target, tid, 0); } else { // Draw to nowhere -- stencil/depth only tid = 0; Gl.glDrawBuffer(Gl.GL_NONE); Gl.glReadBuffer(Gl.GL_NONE); } // Check status int status = Gl.glCheckFramebufferStatusEXT(Gl.GL_FRAMEBUFFER_EXT); // Ignore status in case of fmt==GL_NONE, because no implementation will accept // a buffer without *any* attachment. Buffers with only stencil and depth attachment // might still be supported, so we must continue probing. if (fmt == Gl.GL_NONE || status == Gl.GL_FRAMEBUFFER_COMPLETE_EXT) { this._props[x].Valid = true; var str = new StringBuilder(); str.AppendFormat("\tFBO {0} depth/stencil support: ", PixelUtil.GetFormatName((PixelFormat)x)); // For each depth/stencil formats for (int depth = 0; depth < this._depthFormats.GetLength(0); ++depth) { if (this._depthFormats[depth] != GL_DEPTH24_STENCIL8_EXT) { // General depth/stencil combination for (int stencil = 0; stencil < this._stencilFormats.GetLength(0); ++stencil) { //LogManager.Instance.Write( "Trying {0} D{1}S{2} ", PixelUtil.GetFormatName( (PixelFormat)x ), _depthBits[ depth ], _stencilBits[ stencil ] ); if (_tryFormat(this._depthFormats[depth], this._stencilFormats[stencil])) { /// Add mode to allowed modes str.AppendFormat("D{0}S{1} ", this._depthBits[depth], this._stencilBits[stencil]); FormatProperties.Mode mode; mode.Depth = depth; mode.Stencil = stencil; this._props[x].Modes.Add(mode); } } } else { // Packed depth/stencil format #if false // Only query packed depth/stencil formats for 32-bit // non-floating point formats (ie not R32!) // Linux nVidia driver segfaults if you query others if (!PlatformManager.IsWindowsOS && (PixelUtil.GetNumElemBits((PixelFormat)x) != 32 || PixelUtil.IsFloatingPoint((PixelFormat)x))) { continue; } #endif if (_tryPackedFormat(this._depthFormats[depth])) { /// Add mode to allowed modes str.AppendFormat("Packed-D{0}S8 ", this._depthBits[depth]); FormatProperties.Mode mode; mode.Depth = depth; mode.Stencil = 0; // unuse this._props[x].Modes.Add(mode); } } } LogManager.Instance.Write(str.ToString()); } // Delete texture and framebuffer Gl.glBindFramebufferEXT(Gl.GL_FRAMEBUFFER_EXT, 0); Gl.glDeleteFramebuffersEXT(1, ref fb); // Workaround for NVIDIA / Linux 169.21 driver problem // see http://www.ogre3d.org/phpBB2/viewtopic.php?t=38037&start=25 Gl.glFinish(); Gl.glDeleteTextures(1, ref tid); } // It seems a bug in nVidia driver: glBindFramebufferEXT should restore // draw and read buffers, but in some unclear circumstances it won't. Gl.glDrawBuffer(old_drawbuffer); Gl.glReadBuffer(old_readbuffer); string fmtstring = ""; for (int x = 0; x < (int)PixelFormat.Count; ++x) { if (this._props[x].Valid) { fmtstring += PixelUtil.GetFormatName((PixelFormat)x) + " "; } } LogManager.Instance.Write("[GL] : Valid FBO targets " + fmtstring); }
public virtual void LoadImages(Image[] images) { if (images.Length < 1) { throw new AxiomException("Cannot load empty vector of images"); } // Set desired texture size and properties from images[0] this.srcWidth = this.width = images[0].Width; this.srcHeight = this.height = images[0].Height; this.srcDepth = this.depth = images[0].Depth; // Get source image format and adjust if required this.srcFormat = images[0].Format; if (this.treatLuminanceAsAlpha && this.srcFormat == PixelFormat.L8) { this.srcFormat = PixelFormat.A8; } if (this.desiredFormat != PixelFormat.Unknown) { // If have desired format, use it this.format = this.desiredFormat; } else { // Get the format according with desired bit depth this.format = PixelUtil.GetFormatForBitDepths(this.srcFormat, this.desiredIntegerBitDepth, this.desiredFloatBitDepth); } // The custom mipmaps in the image have priority over everything var imageMips = images[0].NumMipMaps; if (imageMips > 0) { this.mipmapCount = this.requestedMipmapCount = imageMips; // Disable flag for auto mip generation this.usage &= ~TextureUsage.AutoMipMap; } // Create the texture CreateInternalResources(); // Check if we're loading one image with multiple faces // or a vector of images representing the faces int faces; bool multiImage; // Load from multiple images? if (images.Length > 1) { faces = images.Length; multiImage = true; } else { faces = images[0].NumFaces; multiImage = false; } // Check wether number of faces in images exceeds number of faces // in this texture. If so, clamp it. if (faces > FaceCount) { faces = FaceCount; } // Say what we're doing if (TextureManager.Instance.Verbose) { var msg = new StringBuilder(); msg.AppendFormat("Texture: {0}: Loading {1} faces( {2}, {3}x{4}x{5} ) with", _name, faces, PixelUtil.GetFormatName(images[0].Format), images[0].Width, images[0].Height, images[0].Depth); if (!(this.mipmapsHardwareGenerated && this.mipmapCount == 0)) { msg.AppendFormat(" {0}", this.mipmapCount); } if ((this.usage & TextureUsage.AutoMipMap) == TextureUsage.AutoMipMap) { msg.AppendFormat("{0} generated mipmaps", this.mipmapsHardwareGenerated ? " hardware" : string.Empty); } else { msg.Append(" custom mipmaps"); } msg.AppendFormat(" from {0}.\n\t", multiImage ? "multiple Images" : "an Image"); // Print data about first destination surface var buf = GetBuffer(0, 0); msg.AppendFormat(" Internal format is {0} , {1}x{2}x{3}.", PixelUtil.GetFormatName(buf.Format), buf.Width, buf.Height, buf.Depth); LogManager.Instance.Write(msg.ToString()); } // Main loading loop // imageMips == 0 if the image has no custom mipmaps, otherwise contains the number of custom mips for (var mip = 0; mip <= imageMips; ++mip) { for (var i = 0; i < faces; ++i) { PixelBox src; if (multiImage) { // Load from multiple images src = images[i].GetPixelBox(0, mip); } else { // Load from faces of images[0] src = images[0].GetPixelBox(i, mip); } // Sets to treated format in case is difference src.Format = this.srcFormat; if (this.gamma != 1.0f) { // Apply gamma correction // Do not overwrite original image but do gamma correction in temporary buffer var bufSize = PixelUtil.GetMemorySize(src.Width, src.Height, src.Depth, src.Format); var buff = new byte[bufSize]; var buffer = BufferBase.Wrap(buff); var corrected = new PixelBox(src.Width, src.Height, src.Depth, src.Format, buffer); PixelConverter.BulkPixelConversion(src, corrected); Image.ApplyGamma(corrected.Data, this.gamma, corrected.ConsecutiveSize, PixelUtil.GetNumElemBits(src.Format)); // Destination: entire texture. BlitFromMemory does // the scaling to a power of two for us when needed GetBuffer(i, mip).BlitFromMemory(corrected); } else { // Destination: entire texture. BlitFromMemory does // the scaling to a power of two for us when needed GetBuffer(i, mip).BlitFromMemory(src); } } } // Update size (the final size, not including temp space) Size = FaceCount * PixelUtil.GetMemorySize(this.width, this.height, this.depth, this.format); }
/// <summary> /// /// </summary> /// <param name="width"></param> /// <param name="height"></param> /// <param name="depth"></param> /// <param name="format"></param> private void SetSrcAttributes(int width, int height, int depth, PixelFormat format) { srcWidth = width; srcHeight = height; srcBpp = PixelUtil.GetNumElemBits(format); // say to the world what we are doing const string RenderTargetFormat = "[XNA] : Creating {0} RenderTarget, name : '{1}' with {2} mip map levels."; const string TextureFormat = "[XNA] : Loading {0} Texture, image name : '{1}' with {2} mip map levels."; switch (TextureType) { case TextureType.OneD: if ((Usage & TextureUsage.RenderTarget) == TextureUsage.RenderTarget) { LogManager.Instance.Write(String.Format(RenderTargetFormat, TextureType.OneD, Name, MipmapCount)); } else { LogManager.Instance.Write(String.Format(TextureFormat, TextureType.OneD, Name, MipmapCount)); } break; case TextureType.TwoD: if ((Usage & TextureUsage.RenderTarget) == TextureUsage.RenderTarget) { LogManager.Instance.Write(String.Format(RenderTargetFormat, TextureType.TwoD, Name, MipmapCount)); } else { LogManager.Instance.Write(String.Format(TextureFormat, TextureType.TwoD, Name, MipmapCount)); } break; case TextureType.ThreeD: if ((Usage & TextureUsage.RenderTarget) == TextureUsage.RenderTarget) { LogManager.Instance.Write(String.Format(RenderTargetFormat, TextureType.ThreeD, Name, MipmapCount)); } else { LogManager.Instance.Write(String.Format(TextureFormat, TextureType.ThreeD, Name, MipmapCount)); } break; case TextureType.CubeMap: if ((Usage & TextureUsage.RenderTarget) == TextureUsage.RenderTarget) { LogManager.Instance.Write(String.Format(RenderTargetFormat, TextureType.CubeMap, Name, MipmapCount)); } else { LogManager.Instance.Write(String.Format(TextureFormat, TextureType.CubeMap, Name, MipmapCount)); } break; default: FreeInternalResources(); throw new Exception("Unknown texture type"); } }
protected virtual void LoadImages(List <Image> images) { Debug.Assert(images.Count >= 1); if (isLoaded) { log.InfoFormat("Unloading image: {0}", name); Unload(); } srcWidth = width = images[0].Width; srcHeight = height = images[0].Height; srcDepth = depth = images[0].Depth; if (hasAlpha && images[0].Format == PixelFormat.L8) { format = PixelFormat.A8; srcBpp = 8; } else { this.Format = images[0].Format; } if (finalBpp == 16) { switch (format) { case PixelFormat.R8G8B8: case PixelFormat.X8R8G8B8: format = PixelFormat.R5G6B5; break; case PixelFormat.B8G8R8: case PixelFormat.X8B8G8R8: format = PixelFormat.B5G6R5; break; case PixelFormat.A8R8G8B8: case PixelFormat.R8G8B8A8: case PixelFormat.A8B8G8R8: case PixelFormat.B8G8R8A8: format = PixelFormat.A4R4G4B4; break; default: // use the original format break; } } // The custom mipmaps in the image have priority over everything int imageMips = images[0].NumMipMaps; if (imageMips > 0) { numMipmaps = imageMips; usage &= ~TextureUsage.AutoMipMap; } // Create the texture CreateInternalResources(); // Check if we're loading one image with multiple faces // or a vector of images representing the faces int faces; bool multiImage; // Load from multiple images? if (images.Count > 1) { faces = images.Count; multiImage = true; } else { faces = images[0].NumFaces; multiImage = false; } // Check wether number of faces in images exceeds number of faces // in this texture. If so, clamp it. if (faces > this.NumFaces) { faces = this.NumFaces; } // Say what we're doing log.InfoFormat("Texture: {0}: Loading {1} faces({2},{3}x{4}x{5})", name, faces, PixelUtil.GetFormatName(images[0].Format), images[0].Width, images[0].Height, images[0].Depth); #if NOT // crazy ogre logging if (!(mMipmapsHardwareGenerated && mNumMipmaps == 0)) { str << mNumMipmaps; } if (mUsage & TU_AUTOMIPMAP) { if (mMipmapsHardwareGenerated) { str << " hardware"; } str << " generated mipmaps"; } else { str << " custom mipmaps"; } if (multiImage) { str << " from multiple Images."; } else { str << " from Image."; } // Scoped { // Print data about first destination surface HardwarePixelBufferSharedPtr buf = getBuffer(0, 0); str << " Internal format is " << PixelUtil::getFormatName(buf->getFormat()) << "," << buf->getWidth() << "x" << buf->getHeight() << "x" << buf->getDepth() << "."; } LogManager::getSingleton().logMessage( LML_NORMAL, str.str()); #endif // Main loading loop // imageMips == 0 if the image has no custom mipmaps, otherwise contains the number of custom mips for (int mip = 0; mip <= imageMips; ++mip) { for (int i = 0; i < faces; ++i) { PixelBox src; if (multiImage) { // Load from multiple images src = images[i].GetPixelBox(0, mip); } else { // Load from faces of images[0] src = images[0].GetPixelBox(i, mip); if (hasAlpha && src.Format == PixelFormat.L8) { src.Format = PixelFormat.A8; } } if (gamma != 1.0f) { // Apply gamma correction // Do not overwrite original image but do gamma correction in temporary buffer IntPtr buffer = Marshal.AllocHGlobal(PixelUtil.GetMemorySize(src.Width, src.Height, src.Depth, src.Format)); try { PixelBox corrected = new PixelBox(src.Width, src.Height, src.Depth, src.Format, buffer); PixelUtil.BulkPixelConversion(src, corrected); Image.ApplyGamma(corrected.Data, gamma, corrected.ConsecutiveSize, PixelUtil.GetNumElemBits(src.Format)); // Destination: entire texture. BlitFromMemory does the scaling to // a power of two for us when needed GetBuffer(i, mip).BlitFromMemory(corrected); } finally { Marshal.FreeHGlobal(buffer); } } else { // Destination: entire texture. BlitFromMemory does the scaling to // a power of two for us when needed GetBuffer(i, mip).BlitFromMemory(src); } } } // Update size (the final size, not including temp space) size = this.NumFaces * PixelUtil.GetMemorySize(width, height, depth, format); isLoaded = true; }