///<summary> /// Internal implementation of <see cref="HardwareBuffer.Lock"/>. ///</summary> protected override PixelBox LockImpl(BasicBox lockBox, BufferLocking options) { _lockedBox = lockBox; // Set extents and format var rval = new PixelBox(lockBox, Format); var sizeInBytes = PixelUtil.GetMemorySize(lockBox.Width, lockBox.Height, lockBox.Depth, XnaHelper.Convert(surface.Format)); if (_bufferBytes == null || _bufferBytes.Length != sizeInBytes) { _bufferBytes = new byte[sizeInBytes]; #if !SILVERLIGHT if (surface != null) { surface.GetData(mipLevel, XnaHelper.ToRectangle(lockBox), _bufferBytes, 0, _bufferBytes.Length); } else if (cube != null) { cube.GetData(face, mipLevel, XnaHelper.ToRectangle(lockBox), _bufferBytes, 0, _bufferBytes.Length); } else { volume.GetData(mipLevel, lockBox.Left, lockBox.Top, lockBox.Right, lockBox.Bottom, lockBox.Front, lockBox.Back, _bufferBytes, 0, _bufferBytes.Length); } #endif } rval.Data = BufferBase.Wrap(_bufferBytes); return(rval); }
public virtual void ConvertToImage(out Image destImage, bool includeMipMaps) #endif { var numMips = includeMipMaps ? MipmapCount + 1 : 1; var dataSize = Image.CalculateSize(numMips, FaceCount, Width, Height, Depth, Format); var pixData = new byte[dataSize]; // if there are multiple faces and mipmaps we must pack them into the data // faces, then mips var currentPixData = BufferBase.Wrap(pixData); for (var face = 0; face < FaceCount; ++face) { for (var mip = 0; mip < numMips; ++mip) { var mipDataSize = PixelUtil.GetMemorySize(Width, Height, Depth, Format); var pixBox = new PixelBox(Width, Height, Depth, Format, currentPixData); GetBuffer(face, mip).BlitToMemory(pixBox); currentPixData += mipDataSize; } } currentPixData.Dispose(); // load, and tell Image to delete the memory when it's done. destImage = (new Image()).FromDynamicImage(pixData, Width, Height, Depth, Format, true, FaceCount, numMips - 1); }
protected static void BuildMipmaps(PixelBox data) { int width = 0; int height = 0; int logW = 0; int logH = 0; int level = 0; PixelBox scaled = data; scaled.Data = data.Data; scaled.Left = data.Left; scaled.Right = data.Right; scaled.Top = data.Top; scaled.Bottom = data.Bottom; scaled.Front = data.Front; scaled.Back = data.Back; All format = GLESPixelUtil.GetGLOriginFormat(data.Format); All dataType = GLESPixelUtil.GetGLOriginDataType(data.Format); width = data.Width; height = data.Height; logW = ComputeLog(width); logH = ComputeLog(height); level = (logW > logH ? logW : logH); for (int mip = 0; mip <= level; mip++) { format = GLESPixelUtil.GetGLOriginFormat(scaled.Format); dataType = GLESPixelUtil.GetGLOriginDataType(scaled.Format); OpenGL.TexImage2D(All.Texture2D, mip, (int)format, width, height, 0, format, dataType, scaled.Data); GLESConfig.GlCheckError(null); if (mip != 0) { scaled.Data = IntPtr.Zero; } if (width > 1) { width = width / 2; } if (height > 1) { height = height / 2; } int sizeInBytes = PixelUtil.GetMemorySize(width, height, 1, data.Format); scaled = new PixelBox(width, height, 1, data.Format); var dataarr = new byte[sizeInBytes]; scaled.Data = Memory.PinObject(dataarr); Image.Scale(data, scaled, ImageFilter.Linear); } }
public void Bind(D3D9.Device dev, D3D9.Volume volume, D3D9.BaseTexture mipTex) { //Entering critical section LockDeviceAccess(); var bufferResources = GetBufferResources(dev); var isNewBuffer = false; if (bufferResources == null) { bufferResources = new BufferResources(); this.mapDeviceToBufferResources.Add(dev, bufferResources); isNewBuffer = true; } bufferResources.MipTex = mipTex; bufferResources.Volume = volume; var desc = volume.Description; width = desc.Width; height = desc.Height; depth = desc.Depth; format = D3D9Helper.ConvertEnum(desc.Format); // Default rowPitch = Width; slicePitch = Height * Width; sizeInBytes = PixelUtil.GetMemorySize(Width, Height, Depth, Format); if (isNewBuffer && this.ownerTexture.IsManuallyLoaded) { foreach (var it in this.mapDeviceToBufferResources) { if (it.Value != bufferResources && it.Value.Volume != null && it.Key.TestCooperativeLevel().Success&& dev.TestCooperativeLevel().Success) { var fullBufferBox = new BasicBox(0, 0, 0, Width, Height, Depth); var dstBox = new PixelBox(fullBufferBox, Format); var data = new byte[sizeInBytes]; using (var d = BufferBase.Wrap(data)) { dstBox.Data = d; BlitToMemory(fullBufferBox, dstBox, it.Value, it.Key); BlitFromMemory(dstBox, fullBufferBox, bufferResources); Array.Clear(data, 0, sizeInBytes); } break; } } } //Leaving critical section UnlockDeviceAccess(); }
private void BuildMipmaps(PixelBox data) { int width, height, logW, logH, level; PixelBox scaled = data; scaled.Data = data.Data; scaled.Left = data.Left; scaled.Right = data.Right; scaled.Top = data.Top; scaled.Bottom = data.Bottom; scaled.Front = data.Front; scaled.Back = data.Back; width = data.Width; height = data.Height; logW = (int)System.Math.Log(width); logH = (int)System.Math.Log(height); level = (logW > logH ? logW : logH); for (int mip = 0; mip < level; mip++) { All glFormat = GLES2PixelUtil.GetGLOriginFormat(scaled.Format); All dataType = GLES2PixelUtil.GetGLOriginDataType(scaled.Format); GL.TexImage2D(this.faceTarget, mip, (int)glFormat, width, height, 0, glFormat, dataType, scaled.Data.Pin()); GLES2Config.GlCheckError(this); if (mip != 0) { scaled.Data = null; } if (width > 1) { width /= 2; } if (height > 1) { height /= 2; } int sizeInBytes = PixelUtil.GetMemorySize(width, height, 1, data.Format); scaled = new PixelBox(width, height, 1, data.Format); scaled.Data = BufferBase.Wrap(new byte[sizeInBytes]); Image.Scale(data, scaled, ImageFilter.Linear); } //Delete the scaled data for the last level if (level > 0) { scaled.Data = null; } }
/// <summary> /// </summary> /// <param name="name"> </param> /// <param name="target"> </param> /// <param name="id"> </param> /// <param name="width"> </param> /// <param name="height"> </param> /// <param name="format"> </param> /// <param name="face"> </param> /// <param name="level"> </param> /// <param name="usage"> </param> /// <param name="crappyCard"> </param> /// <param name="writeGamma"> </param> /// <param name="fsaa"> </param> public GLESTextureBuffer(string basename, All targetfmt, int id, int width, int height, int format, int face, int level, BufferUsage usage, bool crappyCard, bool writeGamma, int fsaa) : base(0, 0, 0, Media.PixelFormat.Unknown, usage) { this._target = targetfmt; this._textureId = id; this._face = face; this._level = level; this._softwareMipmap = crappyCard; GLESConfig.GlCheckError(this); OpenGL.BindTexture(All.Texture2D, this._textureId); GLESConfig.GlCheckError(this); // Get face identifier this._faceTarget = this._target; // TODO verify who get this Width = width; Height = height; Depth = 1; _glInternalFormat = (All)format; Format = GLESPixelUtil.GetClosestAxiomFormat(_glInternalFormat); RowPitch = Width; SlicePitch = Height * Width; sizeInBytes = PixelUtil.GetMemorySize(Width, Height, Depth, Format); // Set up a pixel box _buffer = new PixelBox(Width, Height, Depth, Format); if (Width == 0 || Height == 0 || Depth == 0) { /// We are invalid, do not allocate a buffer return; } // Is this a render target? if (((int)Usage & (int)TextureUsage.RenderTarget) != 0) { // Create render target for each slice for (int zoffset = 0; zoffset < Depth; zoffset++) { string name = string.Empty; name = "rtt/" + GetHashCode() + "/" + basename; var target = new GLESSurfaceDescription(); target.Buffer = this; target.ZOffset = zoffset; RenderTexture trt = GLESRTTManager.Instance.CreateRenderTexture(name, target, writeGamma, fsaa); this._sliceTRT.Add(trt); Root.Instance.RenderSystem.AttachRenderTarget(this._sliceTRT[zoffset]); } } }
///<summary> /// Copies a region from normal memory to a region of this pixelbuffer. The source /// image can be in any pixel format supported by Axiom, and in any size. ///</summary> ///<param name="src">PixelBox containing the source pixels and format in memory</param> ///<param name="dstBox">Image.BasicBox describing the destination region in this buffer</param> ///<remarks> /// The source and destination regions dimensions don't have to match, in which /// case scaling is done. This scaling is generally done using a bilinear filter in hardware, /// but it is faster to pass the source image in the right dimensions. /// Only call this function when both buffers are unlocked. ///</remarks> public override void BlitFromMemory(PixelBox src, BasicBox dstBox) { var converted = src; var bufGCHandle = new GCHandle(); var bufSize = 0; // Get src.Data as byte[] bufSize = PixelUtil.GetMemorySize(src.Width, src.Height, src.Depth, Format); var newBuffer = new byte[bufSize]; //bufGCHandle = GCHandle.Alloc( newBuffer, GCHandleType.Pinned ); //XnaHelper.Convert(XFG.SurfaceFormat) would never have returned SurfaceFormat.Unknown anyway... //if (XnaHelper.Convert(src.Format) != XFG.SurfaceFormat.Unknown) { converted = new PixelBox(src.Width, src.Height, src.Depth, Format, BufferBase.Wrap(newBuffer)); PixelConverter.BulkPixelConversion(src, converted); } //else //{ // Memory.Copy(converted.Data, BufferBase.Wrap(newBuffer), bufSize); //} if (surface != null) { surface.SetData(mipLevel, XnaHelper.ToRectangle(dstBox), newBuffer, 0, bufSize); } else if (cube != null) { cube.SetData(face, mipLevel, XnaHelper.ToRectangle(dstBox), newBuffer, 0, bufSize); } else { throw new NotSupportedException("BlitFromMemory on Volume Textures not supported."); } // If we allocated a buffer for the temporary conversion, free it here if (bufGCHandle.IsAllocated) { bufGCHandle.Free(); } if (doMipmapGen) { GenMipmaps(); } }
public void Bind(GraphicsDevice device, RenderTarget2D surface, bool update) { this.device = device; renderTarget = surface; width = surface.Width / (int)Utility.Pow(2, mipLevel); height = surface.Height / (int)Utility.Pow(2, mipLevel); depth = 1; format = XnaHelper.Convert(surface.Format); // Default rowPitch = Width; slicePitch = Height * Width; sizeInBytes = PixelUtil.GetMemorySize(Width, Height, Depth, Format); if (((int)usage & (int)TextureUsage.RenderTarget) != 0) { CreateRenderTextures(update); } }
///<summary> /// Call this to associate a Xna Texture3D with this pixel buffer ///</summary> public void Bind(GraphicsDevice device, Texture3D volume, bool update) { this.device = device; this.volume = volume; width = volume.Width; height = volume.Height; depth = volume.Depth; format = XnaHelper.Convert(volume.Format); // Default rowPitch = Width; slicePitch = Height * Width; sizeInBytes = PixelUtil.GetMemorySize(Width, Height, Depth, Format); if (((int)usage & (int)TextureUsage.RenderTarget) != 0) { CreateRenderTextures(update); } }
///<summary> /// Call this to associate a D3D volume with this pixel buffer ///</summary> public void Bind(D3D.Device device, D3D.Volume volume, bool update) { this.device = device; this.volume = volume; D3D.VolumeDescription desc = volume.Description; width = desc.Width; height = desc.Height; depth = desc.Depth; format = D3DHelper.ConvertEnum(desc.Format); // Default rowPitch = width; slicePitch = height * width; sizeInBytes = PixelUtil.GetMemorySize(width, height, depth, format); if (((int)usage & (int)TextureUsage.RenderTarget) != 0) { CreateRenderTextures(update); } }
public void Bind(GraphicsDevice device, TextureCube cube, ushort face, ushort miplevel, bool update) { this.device = device; this.cube = cube; this.face = (CubeMapFace)face; mipLevel = miplevel; width = cube.Size / (int)Utility.Pow(2, mipLevel); height = cube.Size / (int)Utility.Pow(2, mipLevel); depth = 1; format = XnaHelper.Convert(cube.Format); // Default rowPitch = Width; slicePitch = Height * Width; sizeInBytes = PixelUtil.GetMemorySize(Width, Height, Depth, Format); if (((int)usage & (int)TextureUsage.RenderTarget) != 0) { CreateRenderTextures(update); } }
/// <summary> /// Save our texture to a stream /// </summary> /// <param name="stream"></param> /// <param name="requestedFormat"></param> public override void Save(System.IO.Stream stream, PixelFormat requestedFormat) { // First try to see if we can use the fast method to save this image. // TODO: I should be able to make the common path closer to this in performance ([email protected]) if (pixelBuffer.Format == PixelFormat.A8R8G8B8) { if (requestedFormat == PixelFormat.A8B8G8R8 || requestedFormat == PixelFormat.B8G8R8) { SimpleSave(stream, requestedFormat); return; } } int bufSize = PixelUtil.GetMemorySize(pixelBuffer.Width, pixelBuffer.Height, pixelBuffer.Depth, requestedFormat); byte[] buffer = new byte[bufSize]; // Pin down the byte array GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned); IntPtr address = handle.AddrOfPinnedObject(); PixelBox box = new PixelBox(pixelBuffer.Width, pixelBuffer.Height, pixelBuffer.Depth, requestedFormat, address); pixelBuffer.BlitToMemory(box); handle.Free(); // I need to flip this image, since it was upside down in the // internal buffers. I could do this in the save pass, which // would make this more efficient, but I don't currently think // that efficiency is that important. Image image = Image.FromDynamicImage(buffer, pixelBuffer.Width, pixelBuffer.Height, pixelBuffer.Depth, requestedFormat); image.FlipAroundX(); // Ok, now the data in buffer has been flipped. // Go ahead and discard the image image.Dispose(); // write the data to the stream provided stream.Write(buffer, 0, bufSize); }
protected void BlitFromMemoryImpl(PixelBox src, BasicBox dstBox) { // TODO: This currently does way too many copies. We copy // from src to a converted buffer (if needed), then from // converted to a byte array, then into the temporary surface, // and finally from the temporary surface to the real surface. PixelBox converted = src; IntPtr bufPtr = IntPtr.Zero; GCHandle bufGCHandle = new GCHandle(); // convert to pixelbuffer's native format if necessary if (D3DHelper.ConvertEnum(src.Format) == D3D.Format.Unknown) { int bufSize = PixelUtil.GetMemorySize(src.Width, src.Height, src.Depth, format); byte[] newBuffer = new byte[bufSize]; bufGCHandle = GCHandle.Alloc(newBuffer, GCHandleType.Pinned); bufPtr = bufGCHandle.AddrOfPinnedObject(); converted = new PixelBox(src.Width, src.Height, src.Depth, format, bufPtr); PixelUtil.BulkPixelConversion(src, converted); } // int formatBytes = PixelUtil.GetNumElemBytes(converted.Format); Surface tmpSurface = device.CreateOffscreenPlainSurface(converted.Width, converted.Height, D3DHelper.ConvertEnum(converted.Format), Pool.Scratch); int pitch; // Ideally I would be using the Array mechanism here, but that doesn't seem to work GraphicsStream buf = tmpSurface.LockRectangle(LockFlags.NoSystemLock, out pitch); buf.Position = 0; unsafe { int bufSize = PixelUtil.GetMemorySize(converted.Width, converted.Height, converted.Depth, converted.Format); byte * srcPtr = (byte *)converted.Data.ToPointer(); byte[] ugh = new byte[bufSize]; for (int i = 0; i < bufSize; ++i) { ugh[i] = srcPtr[i]; } buf.Write(ugh); } tmpSurface.UnlockRectangle(); buf.Dispose(); //ImageInformation imageInfo = new ImageInformation(); //imageInfo.Format = D3DHelper.ConvertEnum(converted.Format); //imageInfo.Width = converted.Width; //imageInfo.Height = converted.Height; //imageInfo.Depth = converted.Depth; if (surface != null) { // I'm trying to write to surface using the data in converted Rectangle srcRect = ToD3DRectangleExtent(converted); Rectangle destRect = ToD3DRectangle(dstBox); SurfaceLoader.FromSurface(surface, destRect, tmpSurface, srcRect, Filter.None, 0); } else { D3D.Box srcBox = ToD3DBoxExtent(converted); D3D.Box destBox = ToD3DBox(dstBox); Debug.Assert(false, "Volume textures not yet supported"); // VolumeLoader.FromStream(volume, destBox, converted.Data, converted.RowPitch * converted.SlicePitch * formatBytes, srcBox, Filter.None, 0); VolumeLoader.FromStream(volume, destBox, buf, srcBox, Filter.None, 0); } tmpSurface.Dispose(); // If we allocated a buffer for the temporary conversion, free it here // If I used bufPtr to store my temporary data while I converted // it, I need to free it here. This invalidates converted. // My data has already been copied to tmpSurface and then to the // real surface. if (bufGCHandle.IsAllocated) { bufGCHandle.Free(); } if (doMipmapGen) { GenMipmaps(); } }
/// <summary> /// </summary> protected override void createInternalResources() { // Convert to nearest power-of-two size if required Width = GLESPixelUtil.OptionalPO2(Width); Height = GLESPixelUtil.OptionalPO2(Height); Depth = GLESPixelUtil.OptionalPO2(Depth); //adjust format if required Format = TextureManager.Instance.GetNativeFormat(Graphics.TextureType.TwoD, Format, Usage); // Check requested number of mipmaps int maxMips = GLESPixelUtil.GetMaxMipmaps(Width, Height, Depth, Format); if (PixelUtil.IsCompressed(Format) && _mipmapCount == 0) { RequestedMipmapCount = 0; } _mipmapCount = RequestedMipmapCount; if (_mipmapCount > maxMips) { _mipmapCount = maxMips; } // Generate texture name OpenGL.GenTextures(1, ref this._textureID); GLESConfig.GlCheckError(this); // Set texture type OpenGL.BindTexture(All.Texture2D, this._textureID); GLESConfig.GlCheckError(this); // Set some misc default parameters, these can of course be changed later OpenGL.TexParameter(All.Texture2D, All.TextureMinFilter, (int)All.LinearMipmapNearest); GLESConfig.GlCheckError(this); OpenGL.TexParameter(All.Texture2D, All.TextureMagFilter, (int)All.Nearest); GLESConfig.GlCheckError(this); OpenGL.TexParameter(All.Texture2D, All.TextureWrapS, (int)All.ClampToEdge); GLESConfig.GlCheckError(this); OpenGL.TexParameter(All.Texture2D, All.TextureWrapT, (int)All.ClampToEdge); GLESConfig.GlCheckError(this); // If we can do automip generation and the user desires this, do so MipmapsHardwareGenerated = Root.Instance.RenderSystem.HardwareCapabilities.HasCapability(Capabilities.HardwareMipMaps) && !PixelUtil.IsCompressed(Format); if ((Usage & TextureUsage.AutoMipMap) == TextureUsage.AutoMipMap && RequestedMipmapCount > 0 && MipmapsHardwareGenerated) { OpenGL.TexParameter(All.Texture2D, All.GenerateMipmap, (int)All.True); GLESConfig.GlCheckError(this); } // Allocate internal buffer so that TexSubImageXD can be used // Internal format All format = GLESPixelUtil.GetClosestGLInternalFormat(Format, HardwareGammaEnabled); int width = Width; int height = Height; int depth = Depth; if (PixelUtil.IsCompressed(Format)) { // Compressed formats int size = PixelUtil.GetMemorySize(Width, Height, Depth, Format); // Provide temporary buffer filled with zeroes as glCompressedTexImageXD does not // accept a 0 pointer like normal glTexImageXD // Run through this process for every mipmap to pregenerate mipmap pyramid var tmpData = new byte[size]; IntPtr tmpDataptr = Memory.PinObject(tmpData); for (int mip = 0; mip <= MipmapCount; mip++) { size = PixelUtil.GetMemorySize(Width, Height, Depth, Format); OpenGL.CompressedTexImage2D(All.Texture2D, mip, format, width, height, 0, size, tmpDataptr); GLESConfig.GlCheckError(this); if (width > 1) { width = width / 2; } if (height > 1) { height = height / 2; } if (depth > 1) { depth = depth / 2; } } Memory.UnpinObject(tmpData); } else { // Run through this process to pregenerate mipmap pyramid for (int mip = 0; mip <= MipmapCount; mip++) { OpenGL.TexImage2D(All.Texture2D, mip, (int)format, width, height, 0, format, All.UnsignedByte, IntPtr.Zero); GLESConfig.GlCheckError(this); if (width > 1) { width = width / 2; } if (height > 1) { height = height / 2; } } } CreateSurfaceList(); // Get final internal format Format = GetBuffer(0, 0).Format; }
public override void BlitFromMemory(PixelBox src, BasicBox dstBox) { // Fall back to normal GLHardwarePixelBuffer::blitFromMemory in case // - FBO is not supported // - Either source or target is luminance due doesn't looks like supported by hardware // - the source dimensions match the destination ones, in which case no scaling is needed //Ogre TODO: Check that extension is NOT available if (PixelUtil.IsLuminance(src.Format) || PixelUtil.IsLuminance(this.format) || (src.Width == dstBox.Width && src.Height == dstBox.Height && src.Depth == dstBox.Depth)) { base.BlitFromMemory(src, dstBox); return; } if (!Buffer.Contains(dstBox)) { throw new ArgumentOutOfRangeException("dstBox", "Destination box out of range"); } //For scoped deletion of conversion buffer PixelBox srcPB; BufferBase buf; //first, convert the srcbox to a OpenGL compatible pixel format if (GLES2PixelUtil.GetGLOriginFormat(src.Format) == 0) { //Conver to buffer intenral format buf = BufferBase.Wrap(new byte[PixelUtil.GetMemorySize(src.Width, src.Height, src.Depth, this.format)]); srcPB = new PixelBox(src.Width, src.Height, src.Depth, this.format, buf); PixelConverter.BulkPixelConversion(src, srcPB); } else { //No conversion needed srcPB = src; } //Create temporary texture to store source data int id = 0; All target = All.Texture2D; int width = GLES2PixelUtil.OptionalPO2(src.Width); int height = GLES2PixelUtil.OptionalPO2(src.Height); All format = GLES2PixelUtil.GetClosestGLInternalFormat(src.Format); All datatype = GLES2PixelUtil.GetGLOriginDataType(src.Format); //Generate texture name GL.GenTextures(1, ref id); GLES2Config.GlCheckError(this); //Set texture type GL.BindTexture(target, id); GLES2Config.GlCheckError(this); //Allocate texture memory GL.TexImage2D(target, 0, (int)format, width, height, 0, format, datatype, IntPtr.Zero); GLES2Config.GlCheckError(this); var tex = new GLES2TextureBuffer(string.Empty, target, id, width, height, format, (All)src.Format, 0, 0, BufferUsage.StaticWriteOnly, false, false, 0); //Upload data to 0,0,0 in temprary texture var tempTarget = new BasicBox(0, 0, 0, srcPB.Width, srcPB.Height, srcPB.Depth); tex.Upload(srcPB, tempTarget); //Blit this.BlitFromTexture(tex, tempTarget, dstBox); GLES2Config.GlCheckError(this); }
public GLES2TextureBuffer(string baseName, All target, int id, int width, int height, All internalFormat, All format, int face, int level, BufferUsage usage, bool crappyCard, bool writeGamma, int fsaa) : base(0, 0, 0, PixelFormat.Unknown, usage) { this.target = target; this.textureID = id; this.face = face; this.level = level; this.softwareMipmap = crappyCard; GLES2Config.GlCheckError(this); GL.BindTexture(target, this.textureID); GLES2Config.GlCheckError(this); //Get face identifier this.faceTarget = this.target; if (this.target == All.TextureCubeMap) { this.faceTarget = All.TextureCubeMapPositiveX + face; } //Calculate the width and height of the texture at this mip level this.width = this.level == 0 ? width : (int)(width / Math.Utility.Pow(2, level)); this.height = this.level == 0 ? height : (int)(height / Math.Utility.Pow(2, level)); if (this.width < 1) { this.width = 1; } if (this.height < 1) { this.height = 1; } //Only 2D is supporte so depth is always 1 depth = 1; GlInternalFormat = internalFormat; this.format = GLES2PixelUtil.GetClosestAxiomFormat(internalFormat, format); rowPitch = this.width; slicePitch = this.height * this.width; sizeInBytes = PixelUtil.GetMemorySize(this.width, this.height, depth, this.format); //Setup a pixel box Buffer = new PixelBox(this.width, this.height, depth, this.format); if (this.width == 0 || this.height == 0 || depth == 0) { //We are invalid, do not allocat a buffer return; } if (((TextureUsage)usage & TextureUsage.RenderTarget) == TextureUsage.RenderTarget) { //Create render target for each slice for (int zoffset = 0; zoffset < depth; zoffset++) { var name = "rtt/ " + GetHashCode() + "/" + baseName; var rtarget = new GLES2SurfaceDesc { buffer = this, zoffset = zoffset }; var trt = GLES2RTTManager.Instance.CreateRenderTexture(name, rtarget, writeGamma, fsaa); this.sliceTRT.Add(trt); Core.Root.Instance.RenderSystem.AttachRenderTarget(this.sliceTRT[zoffset]); } } }
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); }
// create the texture and call the callback public void Notify() { Debug.Assert(Done); bool loaded = false; // need these in the callback for scaling images into picture frames (friendworld) int initialWidth = 0; int initialHeight = 0; try { if (sourceBuffer != null) { int imageID; // create and bind a new image Il.ilGenImages(1, out imageID); Il.ilBindImage(imageID); // Put it right side up Il.ilEnable(Il.IL_ORIGIN_SET); Il.ilSetInteger(Il.IL_ORIGIN_MODE, Il.IL_ORIGIN_UPPER_LEFT); // Keep DXTC(compressed) data if present Il.ilSetInteger(Il.IL_KEEP_DXTC_DATA, Il.IL_TRUE); // load the data into DevIL Il.ilLoadL(this.ilImageType, sourceBuffer, sourceBuffer.Length); // check for an error int ilError = Il.ilGetError(); if (ilError != Il.IL_NO_ERROR) { log.ErrorFormat("TextureFetcher: Error while decoding image data: '{0}'", Ilu.iluErrorString(ilError)); throw new Exception("TextureFetcher: Error while decoding image data: " + Ilu.iluErrorString(ilError)); } int ilFormat = Il.ilGetInteger(Il.IL_IMAGE_FORMAT); int imageType = Il.ilGetInteger(Il.IL_IMAGE_TYPE); // force conversion to 24-bit RGB image if ((imageType != Il.IL_BYTE && imageType != Il.IL_UNSIGNED_BYTE) || ilFormat != Il.IL_BGR) { ilFormat = Il.IL_BGR; imageType = Il.IL_UNSIGNED_BYTE; Il.ilConvertImage(ilFormat, imageType); } PixelFormat format = PixelFormat.R8G8B8; int width = Il.ilGetInteger(Il.IL_IMAGE_WIDTH); int height = Il.ilGetInteger(Il.IL_IMAGE_HEIGHT); int depth = Il.ilGetInteger(Il.IL_IMAGE_DEPTH); int numMipMaps = Il.ilGetInteger(Il.IL_NUM_MIPMAPS) + 1; int numFaces = Il.ilGetInteger(Il.IL_NUM_IMAGES) + 1; initialWidth = width; initialHeight = height; if (numFaces > 1 || numMipMaps > 1) { log.WarnFormat("TextureFetcher: ignoring extra faces or mipmaps: faces={0}: mipmaps={1}", numFaces, numMipMaps); } if (destHeight == 0) { destHeight = height; } if (destWidth == 0) { destWidth = width; } int scaleX; int scaleY; int topFill = 0; int bottomFill = 0; int leftFill = 0; int rightFill = 0; if (keepAspect) { float scaleWidthFactor = (float)width / (float)destWidth; float scaleHeightFactor = (float)height / (float)destHeight; if (scaleWidthFactor > scaleHeightFactor) { scaleX = destWidth; scaleY = (int)(height / scaleWidthFactor); topFill = (destHeight - scaleY) / 2; bottomFill = destHeight - scaleY - topFill; } else { scaleX = (int)(width / scaleHeightFactor); scaleY = destHeight; leftFill = (destWidth - scaleX) / 2; rightFill = destWidth - scaleX - leftFill; } } else { scaleX = destWidth; scaleY = destWidth; } // scale the image if ((scaleX != width) || (scaleY != height)) { DoScale(scaleX, scaleY); width = scaleX; height = scaleY; } int imageSize = PixelUtil.GetMemorySize(destWidth, destHeight, depth, format); // set up buffer for the decoded data byte[] buffer = new byte[imageSize]; byte fillRed = (byte)(fillColor.r * 255.0); byte fillGreen = (byte)(fillColor.g * 255.0); byte fillBlue = (byte)(fillColor.b * 255.0); if (keepAspect) { // fill top for (int y = 0; y < topFill; y++) { int offset = y * destWidth * 3; for (int x = 0; x < destWidth; x++) { buffer[offset++] = fillBlue; buffer[offset++] = fillGreen; buffer[offset++] = fillRed; } } // copy the data IntPtr srcPtr = Il.ilGetData(); int srcOffset = 0; unsafe { byte *srcBytes = (byte *)srcPtr.ToPointer(); for (int y = topFill; y < topFill + height; y++) { int offset = y * destWidth * 3; for (int x = 0; x < leftFill; x++) { buffer[offset++] = fillBlue; buffer[offset++] = fillGreen; buffer[offset++] = fillRed; } for (int x = 0; x < width; x++) { buffer[offset++] = srcBytes[srcOffset++]; buffer[offset++] = srcBytes[srcOffset++]; buffer[offset++] = srcBytes[srcOffset++]; } for (int x = 0; x < rightFill; x++) { buffer[offset++] = fillBlue; buffer[offset++] = fillGreen; buffer[offset++] = fillRed; } } } // fill bottom for (int y = topFill + height; y < destHeight; y++) { int offset = y * destWidth * 3; for (int x = 0; x < destWidth; x++) { buffer[offset++] = fillBlue; buffer[offset++] = fillGreen; buffer[offset++] = fillRed; } } } else { // copy the data IntPtr srcPtr = Il.ilGetData(); unsafe { byte *srcBytes = (byte *)srcPtr.ToPointer(); for (int i = 0; i < imageSize; i++) { buffer[i] = srcBytes[i]; } } } // Restore IL state Il.ilDisable(Il.IL_ORIGIN_SET); Il.ilDisable(Il.IL_FORMAT_SET); // we won't be needing this anymore Il.ilDeleteImages(1, ref imageID); Image resultImage = Image.FromDynamicImage(buffer, destWidth, destHeight, depth, format); TextureManager.Instance.LoadImage(textureName, resultImage); loaded = true; resultImage.Dispose(); } } catch (Exception ex) { LogUtil.LogUtil.ExceptionLog.ErrorFormat("TextureFetcher: exception while decoding image: {0}", ex); } finally { doneHandler(textureName, initialWidth, initialHeight, loaded); } return; }
protected void BlitFromMemory(PixelBox src, BasicBox dstBox, BufferResources dstBufferResources) { // for scoped deletion of conversion buffer var converted = src; var bufSize = 0; // convert to pixelbuffer's native format if necessary if (D3D9Helper.ConvertEnum(src.Format) == D3D9.Format.Unknown) { bufSize = PixelUtil.GetMemorySize(src.Width, src.Height, src.Depth, Format); var newBuffer = new byte[bufSize]; using (var data = BufferBase.Wrap(newBuffer)) { converted = new PixelBox(src.Width, src.Height, src.Depth, Format, data); } PixelConverter.BulkPixelConversion(src, converted); } int rowWidth = 0; if (PixelUtil.IsCompressed(converted.Format)) { rowWidth = converted.RowPitch / 4; // D3D wants the width of one row of cells in bytes if (converted.Format == PixelFormat.DXT1) { // 64 bits (8 bytes) per 4x4 block rowWidth *= 8; } else { // 128 bits (16 bytes) per 4x4 block rowWidth *= 16; } } else { rowWidth = converted.RowPitch * PixelUtil.GetNumElemBytes(converted.Format); } if (dstBufferResources.Surface != null) { var srcRect = ToD3DRectangle(converted); var destRect = ToD3DRectangle(dstBox); bufSize = PixelUtil.GetMemorySize(converted.Width, converted.Height, converted.Depth, converted.Format); var data = new byte[bufSize]; using (var dest = BufferBase.Wrap(data)) { Memory.Copy(converted.Data, dest, bufSize); } try { D3D9.Surface.FromMemory(dstBufferResources.Surface, data, D3D9.Filter.Default, 0, D3D9Helper.ConvertEnum(converted.Format), rowWidth, srcRect, destRect); } catch (Exception e) { throw new AxiomException("D3D9.Surface.FromMemory failed in D3D9HardwarePixelBuffer.BlitFromMemory", e); } } else if (dstBufferResources.Volume != null) { var srcBox = ToD3DBox(converted); var destBox = ToD3DBox(dstBox); var sliceWidth = 0; if (PixelUtil.IsCompressed(converted.Format)) { sliceWidth = converted.SlicePitch / 16; // D3D wants the width of one slice of cells in bytes if (converted.Format == PixelFormat.DXT1) { // 64 bits (8 bytes) per 4x4 block sliceWidth *= 8; } else { // 128 bits (16 bytes) per 4x4 block sliceWidth *= 16; } } else { sliceWidth = converted.SlicePitch * PixelUtil.GetNumElemBytes(converted.Format); } bufSize = PixelUtil.GetMemorySize(converted.Width, converted.Height, converted.Depth, converted.Format); var data = new byte[bufSize]; using (var dest = BufferBase.Wrap(data)) { Memory.Copy(converted.Data, dest, bufSize); } //TODO note sliceWidth and rowWidth are ignored.. D3D9.ImageInformation info; try { //D3D9.D3DX9.LoadVolumeFromMemory() not accessible 'cause D3D9.D3DX9 static class is not public D3D9.Volume.FromFileInMemory(dstBufferResources.Volume, data, D3D9.Filter.Default, 0, srcBox, destBox, null, out info); } catch (Exception e) { throw new AxiomException("D3D9.Volume.FromFileInMemory failed in D3D9HardwarePixelBuffer.BlitFromMemory", e); } } if (this.doMipmapGen) { GenMipmaps(dstBufferResources.MipTex); } }
protected override void createInternalResources() { //Conver to nearest power of two size if require this.width = GLES2PixelUtil.OptionalPO2(Width); this.height = GLES2PixelUtil.OptionalPO2(Height); this.depth = GLES2PixelUtil.OptionalPO2(Depth); //Adjust format if required format = TextureManager.Instance.GetNativeFormat(textureType, Format, usage); //Check requested number of mipmaps int maxMips = GLES2PixelUtil.GetMaxMipmaps(this.width, this.height, this.depth, format); if (PixelUtil.IsCompressed(format) && (mipmapCount == 0)) { requestedMipmapCount = 0; } mipmapCount = requestedMipmapCount; if (mipmapCount > maxMips) { mipmapCount = maxMips; } //Generate texture name GL.GenTextures(1, ref this.textureID); GLES2Config.GlCheckError(this); //Set texture name GL.BindTexture(this.GLES2TextureTarget, this.textureID); GLES2Config.GlCheckError(this); //Set some misc default parameters, tehse can of course be changed later GL.TexParameter(this.GLES2TextureTarget, GLenum.TextureMinFilter, (int)GLenum.Nearest); GLES2Config.GlCheckError(this); GL.TexParameter(this.GLES2TextureTarget, GLenum.TextureMagFilter, (int)GLenum.Nearest); GLES2Config.GlCheckError(this); GL.TexParameter(this.GLES2TextureTarget, GLenum.TextureWrapS, (int)GLenum.ClampToEdge); GLES2Config.GlCheckError(this); GL.TexParameter(this.GLES2TextureTarget, GLenum.TextureWrapT, (int)GLenum.ClampToEdge); GLES2Config.GlCheckError(this); //If we can do automip generation and the user desires this, do so mipmapsHardwareGenerated = Root.Instance.RenderSystem.Capabilities.HasCapability(Capabilities.HardwareMipMaps) && !PixelUtil.IsCompressed(format); //Ogre FIXME: For some reason this is crashing on iOS 5 #if !MONOTOUCH && ANDROID if ((usage & TextureUsage.AutoMipMap) == TextureUsage.AutoMipMap && requestedMipmapCount > 0 && mipmapsHardwareGenerated && (textureType != Graphics.TextureType.CubeMap)) { GL.GenerateMipmap(this.GLES2TextureTarget); GLES2Config.GlCheckError(this); } #endif //Allocate internal buffer so that glTexSubImageXD can be used //INternal format GLenum glformat = GLES2PixelUtil.GetClosestGLInternalFormat(format, hwGamma); GLenum dataType = GLES2PixelUtil.GetGLOriginDataType(format); int width = Width; int height = Height; int depth = Depth; if (PixelUtil.IsCompressed(format)) { //Compressed formats int size = PixelUtil.GetMemorySize(Width, Height, Depth, Format); // Provide temporary buffer filled with zeroes as glCompressedTexImageXD does not // accept a 0 pointer like normal glTexImageXD // Run through this process for every mipmap to pregenerate mipmap pyramid var tmpData = new IntPtr(); for (int mip = 0; mip < mipmapCount; mip++) { size = PixelUtil.GetMemorySize(width, height, depth, Format); switch (textureType) { case TextureType.OneD: case TextureType.TwoD: GL.CompressedTexImage2D(GLenum.Texture2D, mip, glformat, width, height, 0, size, tmpData); GLES2Config.GlCheckError(this); break; case TextureType.CubeMap: for (int face = 0; face < 6; face++) { GL.CompressedTexImage2D((GLenum)((int)GLenum.TextureCubeMapPositiveX + face), mip, glformat, width, height, 0, size, tmpData); GLES2Config.GlCheckError(this); } break; case TextureType.ThreeD: break; default: break; } if (width > 1) { width = width / 2; } if (height > 1) { height = height / 2; } if (depth > 1) { depth = depth / 2; } } tmpData = IntPtr.Zero; } else { //Run through this process to pregenerate mipmap pyramid for (int mip = 0; mip < mipmapCount; mip++) { //Normal formats switch (textureType) { case TextureType.OneD: case TextureType.TwoD: GL.TexImage2D(GLenum.Texture2D, mip, (int)glformat, width, height, 0, glformat, dataType, new IntPtr()); GLES2Config.GlCheckError(this); break; case TextureType.CubeMap: for (int face = 0; face < 6; face++) { GL.TexImage2D(GLenum.TextureCubeMapPositiveX + face, mip, (int)glformat, width, height, 0, glformat, dataType, new IntPtr()); GLES2Config.GlCheckError(this); } break; case TextureType.ThreeD: default: break; } if (width > 1) { width /= 2; } if (height > 1) { height /= 2; } } } this.CreateSurfaceList(); //Get final internal format base.format = this.GetBuffer(0, 0).Format; }
protected override int calculateSize() { return(FaceCount * PixelUtil.GetMemorySize(Width, Height, Depth, Format)); }
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; }
public GLTextureBuffer(string baseName, int target, int id, int face, int level, BufferUsage usage, bool softwareMipmap, BaseGLSupport glSupport, bool writeGamma, int fsaa) : base(0, 0, 0, PixelFormat.Unknown, usage) { int value; this._glSupport = glSupport; this._target = target; this._textureId = id; this._face = face; this._level = level; this._softwareMipmap = softwareMipmap; Gl.glBindTexture(this._target, this._textureId); // Get face identifier this._faceTarget = this._target; if (this._target == Gl.GL_TEXTURE_CUBE_MAP) { this._faceTarget = Gl.GL_TEXTURE_CUBE_MAP_POSITIVE_X + this._face; } // Get width Gl.glGetTexLevelParameteriv(this._faceTarget, this._level, Gl.GL_TEXTURE_WIDTH, out value); width = value; // Get height if (this._target == Gl.GL_TEXTURE_1D) { value = 1; // Height always 1 for 1D textures } else { Gl.glGetTexLevelParameteriv(this._faceTarget, this._level, Gl.GL_TEXTURE_HEIGHT, out value); } height = value; // Get depth if (this._target != Gl.GL_TEXTURE_3D) { value = 1; // Depth always 1 for non-3D textures } else { Gl.glGetTexLevelParameteriv(this._faceTarget, this._level, Gl.GL_TEXTURE_DEPTH, out value); } depth = value; // Get format Gl.glGetTexLevelParameteriv(this._faceTarget, this._level, Gl.GL_TEXTURE_INTERNAL_FORMAT, out value); GLFormat = value; format = GLPixelUtil.GetClosestPixelFormat(value); // Default rowPitch = Width; slicePitch = Height * Width; sizeInBytes = PixelUtil.GetMemorySize(Width, Height, Depth, Format); // Set up pixel box buffer = new PixelBox(Width, Height, Depth, Format); if (Width == 0 || Height == 0 || Depth == 0) { /// We are invalid, do not allocate a buffer return; } // Is this a render target? if (((TextureUsage)Usage & TextureUsage.RenderTarget) == TextureUsage.RenderTarget) { // Create render target for each slice this._sliceTRT.Capacity = Depth; for (int zoffset = 0; zoffset < Depth; ++zoffset) { String name; name = String.Format("{0}/{1}/{2}/{3}", baseName, face, this._level, zoffset); GLSurfaceDesc renderTarget; renderTarget.Buffer = this; renderTarget.ZOffset = zoffset; RenderTexture trt = GLRTTManager.Instance.CreateRenderTexture(name, renderTarget, writeGamma, fsaa); this._sliceTRT.Add(trt); Root.Instance.RenderSystem.AttachRenderTarget(this._sliceTRT[zoffset]); } } }
public override Codec.DecodeResult Decode(Stream input) { var imgData = new ImageData(); var output = new MemoryStream(); int imageID; int imageFormat, bytesPerPixel; // create and bind a new image Il.ilGenImages(1, out imageID); Il.ilBindImage(imageID); // create a temp buffer and write the stream into it var buffer = new byte[input.Length]; input.Read(buffer, 0, buffer.Length); // Put it right side up Il.ilEnable(Il.IL_ORIGIN_SET); Il.ilSetInteger(Il.IL_ORIGIN_MODE, Il.IL_ORIGIN_UPPER_LEFT); // Keep DXTC(compressed) data if present Il.ilSetInteger(Il.IL_KEEP_DXTC_DATA, Il.IL_TRUE); // load the data into DevIL Il.ilLoadL(this._ilType, buffer, buffer.Length); // check for an error var ilError = Il.ilGetError(); if (ilError != Il.IL_NO_ERROR) { throw new AxiomException("Error while decoding image data: '{0}'", Ilu.iluErrorString(ilError)); } imageFormat = Il.ilGetInteger(Il.IL_IMAGE_FORMAT); var imageType = Il.ilGetInteger(Il.IL_IMAGE_TYPE); // Convert image if imageType is incompatible with us (double or long) if (imageType != Il.IL_BYTE && imageType != Il.IL_UNSIGNED_BYTE && imageType != Il.IL_FLOAT && imageType != Il.IL_UNSIGNED_SHORT && imageType != Il.IL_SHORT) { Il.ilConvertImage(imageFormat, Il.IL_FLOAT); imageType = Il.IL_FLOAT; } // Converted paletted images if (imageFormat == Il.IL_COLOR_INDEX) { Il.ilConvertImage(Il.IL_BGRA, Il.IL_UNSIGNED_BYTE); imageFormat = Il.IL_BGRA; imageType = Il.IL_UNSIGNED_BYTE; } // populate the image data bytesPerPixel = Il.ilGetInteger(Il.IL_IMAGE_BYTES_PER_PIXEL); imgData.format = ILUtil.Convert(imageFormat, imageType); imgData.width = Il.ilGetInteger(Il.IL_IMAGE_WIDTH); imgData.height = Il.ilGetInteger(Il.IL_IMAGE_HEIGHT); imgData.depth = Il.ilGetInteger(Il.IL_IMAGE_DEPTH); imgData.numMipMaps = Il.ilGetInteger(Il.IL_NUM_MIPMAPS); if (imgData.format == PixelFormat.Unknown) { throw new AxiomException("Unsupported devil format ImageFormat={0} ImageType={1}", imageFormat, imageType); } // Check for cubemap var numFaces = Il.ilGetInteger(Il.IL_NUM_IMAGES) + 1; if (numFaces == 6) { imgData.flags |= ImageFlags.CubeMap; } else { numFaces = 1; // Support only 1 or 6 face images for now } // Keep DXT data (if present at all and the GPU supports it) var dxtFormat = Il.ilGetInteger(Il.IL_DXTC_DATA_FORMAT); if (dxtFormat != Il.IL_DXT_NO_COMP && Root.Instance.RenderSystem.Capabilities.HasCapability(Axiom.Graphics.Capabilities.TextureCompressionDXT)) { imgData.format = ILUtil.Convert(dxtFormat, imageType); imgData.flags |= ImageFlags.Compressed; // Validate that this devil version loads DXT mipmaps if (imgData.numMipMaps > 0) { Il.ilBindImage(imageID); Il.ilActiveMipmap(1); if ((uint)Il.ilGetInteger(Il.IL_DXTC_DATA_FORMAT) != dxtFormat) { imgData.numMipMaps = 0; LogManager.Instance.Write( "Warning: Custom mipmaps for compressed image were ignored because they are not loaded by this DevIL version."); } } } // Calculate total size from number of mipmaps, faces and size imgData.size = Image.CalculateSize(imgData.numMipMaps, numFaces, imgData.width, imgData.height, imgData.depth, imgData.format); // get the decoded data BufferBase BufferHandle; // Dimensions of current mipmap var width = imgData.width; var height = imgData.height; var depth = imgData.depth; // Transfer data for (var mip = 0; mip <= imgData.numMipMaps; ++mip) { for (var i = 0; i < numFaces; ++i) { Il.ilBindImage(imageID); if (numFaces > 1) { Il.ilActiveImage(i); } if (imgData.numMipMaps > 0) { Il.ilActiveMipmap(mip); } // Size of this face var imageSize = PixelUtil.GetMemorySize(width, height, depth, imgData.format); buffer = new byte[imageSize]; if ((imgData.flags & ImageFlags.Compressed) != 0) { // Compare DXT size returned by DevIL with our idea of the compressed size if (imageSize == Il.ilGetDXTCData(IntPtr.Zero, 0, dxtFormat)) { // Retrieve data from DevIL using (BufferHandle = BufferBase.Wrap(buffer)) { Il.ilGetDXTCData(BufferHandle.Pin(), imageSize, dxtFormat); BufferHandle.UnPin(); } } else { LogManager.Instance.Write("Warning: compressed image size mismatch, devilsize={0} oursize={1}", Il.ilGetDXTCData(IntPtr.Zero, 0, dxtFormat), imageSize); } } else { // Retrieve data from DevIL using (BufferHandle = BufferBase.Wrap(buffer)) { var dst = new PixelBox(width, height, depth, imgData.format, BufferHandle); ILUtil.ConvertFromIL(dst); } } // write the decoded data to the output stream output.Write(buffer, 0, buffer.Length); } // Next mip if (width != 1) { width /= 2; } if (height != 1) { height /= 2; } if (depth != 1) { depth /= 2; } } // Restore IL state Il.ilDisable(Il.IL_ORIGIN_SET); Il.ilDisable(Il.IL_FORMAT_SET); Il.ilDeleteImages(1, ref imageID); return(new DecodeResult(output, imgData)); }