protected static void FromD3DLock(PixelBox rval, DX.DataBox lbox) { var bpp = PixelUtil.GetNumElemBytes(rval.Format); var size = 0; if (bpp != 0) { rval.RowPitch = lbox.RowPitch / bpp; rval.SlicePitch = lbox.SlicePitch / bpp; Debug.Assert((lbox.RowPitch % bpp) == 0); Debug.Assert((lbox.SlicePitch % bpp) == 0); size = lbox.RowPitch * rval.Height; } else if (PixelUtil.IsCompressed(rval.Format)) { rval.RowPitch = rval.Width; rval.SlicePitch = rval.Width * rval.Height; size = rval.Width * rval.Height; } else { throw new AxiomException("Invalid pixel format"); } rval.Data = BufferBase.Wrap(lbox.DataPointer, size); }
///<summary> /// Util functions to convert a D3D locked rectangle to a pixel box ///</summary> protected static void FromD3DLock(PixelBox rval, int pitch, GraphicsStream stream) { rval.RowPitch = pitch / PixelUtil.GetNumElemBytes(rval.Format); rval.SlicePitch = rval.RowPitch * rval.Height; Debug.Assert((pitch % PixelUtil.GetNumElemBytes(rval.Format)) == 0); rval.Data = stream.InternalData; }
protected void Download() { #if !AXIOM_SAFE_ONLY unsafe #endif { using (var pDst = BufferBase.Wrap(this.mData, mData.Length * sizeof(float))) { var pDstPtr = pDst.ToFloatPointer(); var pDstIdx = 0; //download data var box = new BasicBox(0, 0, this.mBuffer.Width, this.mBuffer.Height); var pBox = this.mBuffer.Lock(box, BufferLocking.ReadOnly); var pSrc = pBox.Data.ToBytePointer(); var pSrcIdx = (int)this.mChannelOffset; var srcInc = PixelUtil.GetNumElemBytes(this.mBuffer.Format); for (var y = box.Top; y < box.Bottom; ++y) { for (var x = box.Left; x < box.Right; ++x) { pDstPtr[pDstIdx++] = (float)((pSrc[pSrcIdx]) / 255.0f); pSrcIdx += srcInc; } } this.mBuffer.Unlock(); } } }
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); } }
public virtual void SetFormat(PixelFormat pf) { this.format = pf; this.desiredFormat = pf; this.srcFormat = pf; srcBpp = PixelUtil.GetNumElemBytes(pf); }
///<summary> /// Util functions to convert a D3D LockedBox to a pixel box ///</summary> protected static void FromD3DLock(PixelBox rval, D3D.LockedBox lbox, GraphicsStream stream) { rval.RowPitch = lbox.RowPitch / PixelUtil.GetNumElemBytes(rval.Format); rval.SlicePitch = lbox.SlicePitch / PixelUtil.GetNumElemBytes(rval.Format); Debug.Assert((lbox.RowPitch % PixelUtil.GetNumElemBytes(rval.Format)) == 0); Debug.Assert((lbox.SlicePitch % PixelUtil.GetNumElemBytes(rval.Format)) == 0); rval.Data = stream.InternalData; }
public XnaImageCodecStream(WriteableBitmap texture) { ImageData.width = texture.PixelWidth; ImageData.height = texture.PixelHeight; ImageData.format = PixelFormat.A8B8G8R8; var buffer = new byte[ImageData.width * ImageData.height * PixelUtil.GetNumElemBytes(ImageData.format)]; Buffer.BlockCopy(texture.Pixels, 0, buffer, 0, buffer.Length); _stream = new MemoryStream(buffer); ImageData.numMipMaps = 1; ImageData.size = buffer.Length; }
public XnaImageCodecStream(Texture2D texture) { ImageData.width = texture.Width; ImageData.height = texture.Height; ImageData.format = XnaHelper.Convert(texture.Format); var buffer = new byte[ImageData.width * ImageData.height * PixelUtil.GetNumElemBytes(ImageData.format)]; texture.GetData(buffer); _stream = new MemoryStream(buffer); ImageData.numMipMaps = 1; ImageData.size = buffer.Length; }
public void WriteContentsToFile(string fileName) { var pf = SuggestPixelFormat(); var data = new byte[Width * Height * PixelUtil.GetNumElemBytes(pf)]; var buf = BufferBase.Wrap(data); var pb = new PixelBox(Width, Height, 1, pf, buf); CopyContentsToMemory(pb); (new Image()).FromDynamicImage(data, Width, Height, 1, pf, false, 1, 0).Save(fileName); buf.Dispose(); }
public HardwarePixelBuffer(int width, int height, int depth, Axiom.Media.PixelFormat format, BufferUsage usage, bool useSystemMemory, bool useShadowBuffer) : base(usage, useSystemMemory, useShadowBuffer) { this.width = width; this.height = height; this.depth = depth; this.format = format; // Default this.rowPitch = width; this.slicePitch = height * width; sizeInBytes = height * width * PixelUtil.GetNumElemBytes(format); }
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); } }
public void Update() { if (this.mData != null && this.mDirty) { using (var mDataBuf = BufferBase.Wrap(this.mData, mData.Length * sizeof(float))) { var pSrcBase = mDataBuf + (this.mDirtyBox.Top * this.mBuffer.Width + this.mDirtyBox.Left); var pDstBase = this.mBuffer.Lock(this.mDirtyBox, BufferLocking.Normal).Data; pDstBase += this.mChannelOffset; var dstInc = PixelUtil.GetNumElemBytes(this.mBuffer.Format); #if !AXIOM_SAFE_ONLY unsafe #endif { for (int y = 0; y < this.mDirtyBox.Height; ++y) { var pSrc = (pSrcBase + (y * this.mBuffer.Width) * sizeof(float)).ToFloatPointer(); var pDst = pDstBase + (y * this.mBuffer.Width * dstInc); for (int x = 0; x < this.mDirtyBox.Width; ++x) { pDst.ToBytePointer()[0] = (byte)(pSrc[x] * 255); pDst += dstInc; } } } this.mBuffer.Unlock(); this.mDirty = false; } // make sure composite map is updated // mDirtyBox is in image space, convert to terrain units var compositeMapRect = new Rectangle(); var blendToTerrain = (float)this.mParent.Size / (float)this.mBuffer.Width; compositeMapRect.Left = (long)(this.mDirtyBox.Left * blendToTerrain); compositeMapRect.Right = (long)(this.mDirtyBox.Right * blendToTerrain + 1); compositeMapRect.Top = (long)((this.mBuffer.Height - this.mDirtyBox.Bottom) * blendToTerrain); compositeMapRect.Bottom = (long)((this.mBuffer.Height - this.mDirtyBox.Top) * blendToTerrain + 1); this.mParent.DirtyCompositeMapRect(compositeMapRect); this.mParent.UpdateCompositeMapWithDelay(); } }
public EditableImage(string name, int width, int height, PixelFormat format, ColorEx color, int numMipMaps, bool isAlpha) { this.width = width; this.height = height; this.format = format; this.textureName = name; this.numMipMaps = numMipMaps; this.isAlpha = isAlpha; bytesPerPixel = PixelUtil.GetNumElemBytes(format); stride = bytesPerPixel * width; pixelData = new byte[width * height * bytesPerPixel]; // this will pin the buffer image = Image.FromDynamicImage(pixelData, width, height, format); Fill(0, 0, width, height, color); }
///<summary> /// Call this to associate a Xna Texture2D with this pixel buffer ///</summary> public void Bind(GraphicsDevice device, Texture2D surface, ushort miplevel, bool update) { this.device = device; this.surface = surface; mipLevel = miplevel; 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 * PixelUtil.GetNumElemBytes(Format); slicePitch = Height * RowPitch; sizeInBytes = PixelUtil.GetMemorySize(Width, Height, Depth, Format); if (((int)usage & (int)TextureUsage.RenderTarget) != 0) { CreateRenderTextures(update); } }
public TerrainLayerBlendMap(Terrain parent, byte layerIdx, HardwarePixelBuffer buf) { this.mParent = parent; this.mLayerIdx = layerIdx; this.mChannel = (byte)((this.mLayerIdx - 1) % 4); this.mDirty = false; this.mBuffer = buf; this.mData = new float[this.mBuffer.Width * this.mBuffer.Height * sizeof(float)]; // we know which of RGBA we need to look at, now find it in the format // because we can't guarantee what precise format the RS gives us PixelFormat fmt = this.mBuffer.Format; var rgbaShift = PixelUtil.GetBitShifts(fmt); this.mChannelOffset = (byte)(rgbaShift[this.mChannel] / 8); // /8 convert to bytes #if AXIOM_BIG_ENDIAN // invert (dealing bytewise) mChannelOffset = (byte)(PixelUtil.GetNumElemBytes(fmt) - mChannelOffset - 1); #endif Download(); }
/// <summary> /// Get an appropriately defined 'null' texture, ie one which will always /// result in no shadows. /// </summary> public Texture GetNullShadowTexture(PixelFormat format) { foreach (Texture tex in nullTextureList) { if (format == tex.Format) { // Ok, a match return(tex); } } // not found, create a new one // A 1x1 texture of the correct format, not a render target string baseName = "Axiom/ShadowTextureNull"; string targName = baseName + count++; Texture shadowTex = TextureManager.Instance.CreateManual( targName, TextureType.TwoD, 1, 1, 1, 0, format, TextureUsage.Default); nullTextureList.Add(shadowTex); // Populate the texture based on format int byteCount = PixelUtil.GetNumElemBytes(format); unsafe { byte [] bytes = new byte[byteCount]; for (int i = 0; i < byteCount; i++) bytes[i] = 0xff; fixed(byte *fixedBytes = &bytes[0]) { PixelBox bytesPixelBox = new PixelBox(1, 1, 1, format, new IntPtr(fixedBytes)); shadowTex.GetBuffer().BlitFromMemory(bytesPixelBox); } } return(shadowTex); }
protected override void Download(PixelBox data) { #if GL_NV_get_tex_image if (data.Width != Width || data.Height != Height || data.Depth != Depth) { throw new Core.AxiomException("only download of entire buffer is supported by GL"); } GL.BindTexture(this.target, this.textureID); if (PixelUtil.IsCompressed(data.Format)) { if (data.Format != format || !data.IsConsecutive) { throw new Core.AxiomException("Compressed images must be consecutive, in the source format"); } GL.GetCompressedTexImageNV(this.faceTarget, this.level, data.Data); } else { if ((data.Width * PixelUtil.GetNumElemBytes(data.Format) & 3) != 0) { //Standard alignment of 4 is not right GL.PixelStore(Glenum.PackAlignment, 1); } //We can only get the entire texture GL.GetTexImageNV(this.faceTarget, this.level, GLES2PixelUtil.GetGLOriginFormat(data.Format), GLES2PixelUtil.GetGLOriginDataType(data.Format), data.Data); //Restore defaults GL.PixelStore(Glenum.PackAlignment, 4); } #else throw new Core.AxiomException("Downloading texture buffers is not supported by OpenGL ES"); #endif }
internal static unsafe void ClearTexture(Texture texture, Colour colour) { using (HardwarePixelBufferSharedPtr hbuf = texture.GetBuffer()) { hbuf.Lock(HardwareBuffer.LockOptions.HBL_NORMAL); PixelBox pb = hbuf.CurrentLock; byte *destData = (byte *)pb.data; uint destPixelSize = PixelUtil.GetNumElemBytes(pb.format); uint destRowPitchBytes = pb.rowPitch * destPixelSize; ColourValue cv = new ColourValue(colour.Red / 255f, colour.Green / 255f, colour.Blue / 255f, colour.Alpha / 255f); for (uint i = 0; i < texture.Height; i++) { for (uint j = 0; j < texture.Width; j++) { uint offset = (i * destRowPitchBytes) + (j * destPixelSize); PixelUtil.PackColour(cv, pb.format, &destData[offset]); } } hbuf.Unlock(); } }
public override Codec.DecodeResult Decode(Stream input) { // Buffer stream into memory (TODO: override IO functions instead?) var data = new byte[(int)input.Length]; input.Read(data, 0, data.Length); FI.FIMEMORY fiMem; FI.FREE_IMAGE_FORMAT ff; FI.FIBITMAP fiBitmap; using (var datPtr = BufferBase.Wrap(data)) { fiMem = FI.FreeImage.OpenMemory(datPtr.Pin(), (uint)data.Length); datPtr.UnPin(); ff = (FI.FREE_IMAGE_FORMAT) this._freeImageType; fiBitmap = FI.FreeImage.LoadFromMemory((FI.FREE_IMAGE_FORMAT) this._freeImageType, fiMem, FI.FREE_IMAGE_LOAD_FLAGS.DEFAULT); } if (fiBitmap.IsNull) { throw new AxiomException("Error decoding image"); } var imgData = new ImageData(); imgData.depth = 1; // only 2D formats handled by this codec imgData.width = (int)FI.FreeImage.GetWidth(fiBitmap); imgData.height = (int)FI.FreeImage.GetHeight(fiBitmap); imgData.numMipMaps = 0; // no mipmaps in non-DDS // Must derive format first, this may perform conversions var imageType = FI.FreeImage.GetImageType(fiBitmap); var colorType = FI.FreeImage.GetColorType(fiBitmap); var bpp = (int)FI.FreeImage.GetBPP(fiBitmap); switch (imageType) { case FI.FREE_IMAGE_TYPE.FIT_UNKNOWN: case FI.FREE_IMAGE_TYPE.FIT_COMPLEX: case FI.FREE_IMAGE_TYPE.FIT_UINT32: case FI.FREE_IMAGE_TYPE.FIT_INT32: case FI.FREE_IMAGE_TYPE.FIT_DOUBLE: default: throw new AxiomException("Unknown or unsupported image format"); case FI.FREE_IMAGE_TYPE.FIT_BITMAP: // Standard image type // Perform any colour conversions for greyscale if (colorType == FI.FREE_IMAGE_COLOR_TYPE.FIC_MINISWHITE || colorType == FI.FREE_IMAGE_COLOR_TYPE.FIC_MINISBLACK) { var newBitmap = FI.FreeImage.ConvertToGreyscale(fiBitmap); // free old bitmap and replace FI.FreeImage.Unload(fiBitmap); fiBitmap = newBitmap; // get new formats bpp = (int)FI.FreeImage.GetBPP(fiBitmap); colorType = FI.FreeImage.GetColorType(fiBitmap); } // Perform any colour conversions for RGB else if (bpp < 8 || colorType == FI.FREE_IMAGE_COLOR_TYPE.FIC_PALETTE || colorType == FI.FREE_IMAGE_COLOR_TYPE.FIC_CMYK) { var newBitmap = FI.FreeImage.ConvertTo24Bits(fiBitmap); // free old bitmap and replace FI.FreeImage.Unload(fiBitmap); fiBitmap = newBitmap; // get new formats bpp = (int)FI.FreeImage.GetBPP(fiBitmap); colorType = FI.FreeImage.GetColorType(fiBitmap); } // by this stage, 8-bit is greyscale, 16/24/32 bit are RGB[A] switch (bpp) { case 8: imgData.format = PixelFormat.L8; break; case 16: // Determine 555 or 565 from green mask // cannot be 16-bit greyscale since that's FIT_UINT16 if (FI.FreeImage.GetGreenMask(fiBitmap) == FI.FreeImage.FI16_565_GREEN_MASK) { imgData.format = PixelFormat.R5G6B5; } else { // FreeImage doesn't support 4444 format so must be 1555 imgData.format = PixelFormat.A1R5G5B5; } break; case 24: // FreeImage differs per platform // PixelFormat.BYTE_BGR[A] for little endian (== PixelFormat.ARGB native) // PixelFormat.BYTE_RGB[A] for big endian (== PixelFormat.RGBA native) if (FI.FreeImage.IsLittleEndian()) { imgData.format = PixelFormat.BYTE_BGR; } else { imgData.format = PixelFormat.BYTE_RGB; } break; case 32: if (FI.FreeImage.IsLittleEndian()) { imgData.format = PixelFormat.BYTE_BGRA; } else { imgData.format = PixelFormat.BYTE_RGBA; } break; } ; break; case FI.FREE_IMAGE_TYPE.FIT_UINT16: case FI.FREE_IMAGE_TYPE.FIT_INT16: // 16-bit greyscale imgData.format = PixelFormat.L16; break; case FI.FREE_IMAGE_TYPE.FIT_FLOAT: // Single-component floating point data imgData.format = PixelFormat.FLOAT32_R; break; case FI.FREE_IMAGE_TYPE.FIT_RGB16: imgData.format = PixelFormat.SHORT_RGB; break; case FI.FREE_IMAGE_TYPE.FIT_RGBA16: imgData.format = PixelFormat.SHORT_RGBA; break; case FI.FREE_IMAGE_TYPE.FIT_RGBF: imgData.format = PixelFormat.FLOAT32_RGB; break; case FI.FREE_IMAGE_TYPE.FIT_RGBAF: imgData.format = PixelFormat.FLOAT32_RGBA; break; } var srcPitch = (int)FI.FreeImage.GetPitch(fiBitmap); // Final data - invert image and trim pitch at the same time var dstPitch = imgData.width * PixelUtil.GetNumElemBytes(imgData.format); imgData.size = dstPitch * imgData.height; // Bind output buffer var outputData = new byte[imgData.size]; using (var srcData = BufferBase.Wrap(FI.FreeImage.GetBits(fiBitmap), imgData.height * srcPitch)) { var pDst = BufferBase.Wrap(outputData); for (var y = 0; y < imgData.height; ++y) { using (var pSrc = srcData + (imgData.height - y - 1) * srcPitch) { Memory.Copy(pSrc, pDst, dstPitch); pDst += dstPitch; } } pDst.Dispose(); } FI.FreeImage.Unload(fiBitmap); FI.FreeImage.CloseMemory(fiMem); return(new Codec.DecodeResult(new MemoryStream(outputData), imgData)); }
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); }
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); }
private void CreateTileData() { if (textureName.Equals("zero.png")) { textureName = string.Format("{0}_x{1}y{2}.{3}", parent.BaseName, m_tileLocationX, m_loadTileZ, parent.MosaicDesc.FileExt); } Image textureImage; Texture texture = TextureManager.Instance.GetByName(textureName); if (ResourceManager.HasCommonResourceData(textureName)) { Stream s = ResourceManager.FindCommonResourceData(textureName); textureImage = Image.FromStream(s, parent.MosaicDesc.FileExt); s.Close(); } else { // Create a new image int bpp = PixelUtil.GetNumElemBytes(DEFAULT_IMAGE_FORMAT); byte[] buffer = new byte[tileSizeSamples * tileSizeSamples * bpp]; textureImage = Image.FromDynamicImage(buffer, tileSizeSamples, tileSizeSamples, DEFAULT_IMAGE_FORMAT); Modified = true; } // Cause the texture image to get refreshed dirtyImage = true; dirtyArea.X = 0; dirtyArea.Y = 0; dirtyArea.Width = textureImage.Width; dirtyArea.Height = textureImage.Height; // Popupate the tileData from the image switch (textureImage.Format) { case PixelFormat.A8: case PixelFormat.L8: tileData = new TileData8(textureImage); break; case PixelFormat.L16: tileData = new TileData16(textureImage); break; case PixelFormat.R8G8B8: case PixelFormat.B8G8R8: tileData = new TileData24(textureImage); break; case PixelFormat.A8B8G8R8: case PixelFormat.A8R8G8B8: case PixelFormat.B8G8R8A8: case PixelFormat.R8G8B8A8: case PixelFormat.X8R8G8B8: case PixelFormat.X8B8G8R8: tileData = new TileData32(textureImage); break; default: throw new InvalidDataException("Unexpected pixel format: " + textureImage.Format); } }
public void RefreshTexture() { if (tileData != null && dirtyImage) { EnsureTextureIsDynamic(); // Unload texture & recreate if needed Texture texture = TextureManager.Instance.GetByName(textureName); if (texture == null) { // We couldn't find the texture. It might be that we're in // the midst of swapping them at the DirectX level (this is // only speculation) return; } if (texture is D3DTexture) { // Turns out that to get performance, not only did I have to go // straight to DirectX, unsafe code is much faster as well. What // we're doing here is keeping a temporary surface around that we // can lock and draw to at our leisure, then copying the surface // over to the correct texture data when we're done. To do this, // the easiest way is to lock the desired rectangle on the temp // surface, and get a graphics stream object back from it. You // might think you could then use byte arrays, or even ask for // an Array of bytes back from LockRectangle, but not only was // that slower, it also produced unpredictable results, possibly // due to storing the array in row order vs. column order in the // native vs. managed areas. // // The temporary surface is necessary because, well, I could // never seem to acquire the lock on the real surface. However, // an offscreen plain surface (as used above) seems to lock fine. // // Next caveat: The pointer on the graphics stream points to the // start of the row of the locked rectangle. You'd be surprised // how long it took me to figure that one out. Further, it's // important to use the pitch returned by LockRectangle to adjust // your row array position, as the pitch may or may not be your // surface width in bytes. (Some drivers store extra data on the // ends of the rows, it seems.) Rectangle lockRect = new Rectangle(); lockRect.X = dirtyArea.X; lockRect.Y = dirtyArea.Y; lockRect.Width = dirtyArea.Width; lockRect.Height = dirtyArea.Height; D3D.Texture t = (texture as D3DTexture).DXTexture as D3D.Texture; int pitch; int bpp = PixelUtil.GetNumElemBytes(texture.Format); D3D.Surface dst = t.GetSurfaceLevel(0); DX.GraphicsStream g = dynamicSurface.LockRectangle(lockRect, D3D.LockFlags.NoSystemLock, out pitch); unsafe { uint *dstArray = (uint *)g.InternalDataPointer; pitch /= sizeof(uint); for (int z = 0; z < lockRect.Height; z++) { for (int x = 0; x < lockRect.Width; x++) { uint data = GetData(x + lockRect.X, z + lockRect.Y); uint converted = ConvertPixel(data, INTERNAL_DATA_FORMAT, texture.Format); dstArray[z * pitch + x] = converted; } } } dynamicSurface.UnlockRectangle(); D3D.SurfaceLoader.FromSurface(dst, dynamicSurface, D3D.Filter.None, 0); } else { #if false // following code is for blitting only the dirty rectangle BasicBox destBox = new BasicBox(dirtyArea.X, dirtyArea.Y, dirtyArea.X + dirtyArea.Width, dirtyArea.Y + dirtyArea.Height); PixelBox srcPixel = textureImage.GetPixelBox(0, 0); BasicBox srcBox = new BasicBox(0, 0, dirtyArea.Width, dirtyArea.Height); PixelBox trimmedSrcPixel = srcPixel.GetSubVolume(srcBox); buffer.BlitFromMemory(trimmedSrcPixel, destBox); #endif } // Clean up dirty bit dirtyImage = false; dirtyArea.X = 0; dirtyArea.Y = 0; dirtyArea.Width = 0; dirtyArea.Height = 0; } }
protected override void Upload(PixelBox data, BasicBox dest) { GL.BindTexture(this.target, this.textureID); GLES2Config.GlCheckError(this); if (PixelUtil.IsCompressed(data.Format)) { if (data.Format != format || !data.IsConsecutive) { var glFormat = GLES2PixelUtil.GetClosestGLInternalFormat(format); //Data must be consecutive and at beginning of buffer as PixelStore is not allowed //for compressed formats if (dest.Left == 0 && dest.Top == 0) { GL.CompressedTexImage2D(this.faceTarget, this.level, glFormat, dest.Width, dest.Height, 0, data.ConsecutiveSize, data.Data.Pin()); GLES2Config.GlCheckError(this); } else { GL.CompressedTexSubImage2D(this.faceTarget, this.level, dest.Left, dest.Top, dest.Width, dest.Height, glFormat, data.ConsecutiveSize, data.Data.Pin()); GLES2Config.GlCheckError(this); } } } else if (this.softwareMipmap) { if (data.Width != data.RowPitch) { //Ogre TODO throw new Core.AxiomException("Unsupported texture format"); } if (data.Height * data.Width != data.SlicePitch) { //Ogre TODO throw new Core.AxiomException("Unsupported texture format"); } GL.PixelStore(All.UnpackAlignment, 1); GLES2Config.GlCheckError(this); this.BuildMipmaps(data); } else { if (data.Width != data.RowPitch) { //Ogre TODO throw new Core.AxiomException("Unsupported texture format"); } if (data.Height * data.Width != data.SlicePitch) { //Ogre TODO throw new Core.AxiomException("Unsupported texture format"); } if ((data.Width * PixelUtil.GetNumElemBytes(data.Format) & 3) != 0) { //Standard alignment of 4 is not right GL.PixelStore(All.UnpackAlignment, 1); GLES2Config.GlCheckError(this); } var dataPtr = data.Data.Pin(); GL.TexImage2D(this.faceTarget, this.level, (int)GLES2PixelUtil.GetClosestGLInternalFormat(data.Format), data.Width, data.Height, 0, GLES2PixelUtil.GetGLOriginFormat(data.Format), GLES2PixelUtil.GetGLOriginDataType(data.Format), dataPtr); //GL.TexSubImage2D( this.faceTarget, this.level, dest.Left, dest.Top, dest.Width, dest.Height, GLES2PixelUtil.GetGLOriginFormat( data.Format ), GLES2PixelUtil.GetGLOriginDataType( data.Format ), dataPtr ); data.Data.UnPin(); GLES2Config.GlCheckError(this); } GL.PixelStore(All.UnpackAlignment, 4); GLES2Config.GlCheckError(this); }
/// <summary> /// </summary> /// <param name="data"> </param> /// <param name="dest"> </param> protected override void Upload(PixelBox data, BasicBox dest) { OpenGL.BindTexture(this._target, this._textureId); GLESConfig.GlCheckError(this); if (PixelUtil.IsCompressed(data.Format)) { if (data.Format != Format || !data.IsConsecutive) { throw new AxiomException("Compressed images must be consecutive, in the source format"); } if (data.Format != Format || !data.IsConsecutive) { throw new AxiomException("Compressed images must be consecutive, in the source format."); } All format = GLESPixelUtil.GetClosestGLInternalFormat(Format); // Data must be consecutive and at beginning of buffer as PixelStorei not allowed // for compressed formats if (dest.Left == 0 && dest.Top == 0) { OpenGL.CompressedTexImage2D(All.Texture2D, this._level, format, dest.Width, dest.Height, 0, data.ConsecutiveSize, data.Data); } else { OpenGL.CompressedTexSubImage2D(All.Texture2D, this._level, dest.Left, dest.Top, dest.Width, dest.Height, format, data.ConsecutiveSize, data.Data); } GLESConfig.GlCheckError(this); } else if (this._softwareMipmap) { if (data.Width != data.RowPitch) { //TODO throw new AxiomException("Unsupported Texture format!"); } if (data.Height * data.Width != data.SlicePitch) { //TODO throw new AxiomException("Unsupported Texture format!"); } OpenGL.PixelStore(All.UnpackAlignment, 1); GLESConfig.GlCheckError(this); BuildMipmaps(data); } else { if (data.Width != data.RowPitch) { //TODO throw new AxiomException("Unsupported Texture format!"); } if (data.Height * data.Width != data.SlicePitch) { //TODO throw new AxiomException("Unsupported Texture format!"); } if (((data.Width * PixelUtil.GetNumElemBytes(data.Format)) & 3) != 0) { // Standard alignment of 4 is not right OpenGL.PixelStore(All.UnpackAlignment, 1); GLESConfig.GlCheckError(this); } All form = GLESPixelUtil.GetGLOriginFormat(data.Format); All pix = GLESPixelUtil.GetGLOriginDataType(data.Format); GLESConfig.GlCheckError(this); GL.TexSubImage2D(this._faceTarget, this._level, dest.Left, dest.Top, dest.Width, dest.Height, GLESPixelUtil.GetGLOriginFormat(data.Format), GLESPixelUtil.GetGLOriginDataType(data.Format), data.Data); GLESConfig.GlCheckError(this); } OpenGL.PixelStore(All.UnpackAlignment, 4); GLESConfig.GlCheckError(this); }
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."); } var device = Driver.XnaDevice; //in 3.1, this was ResolveTexture2D, an actual RenderTarget provides the exact same //functionality, especially seeing as RenderTarget2D is a texture now. //the difference is surface is actually set on the device -DoubleA RenderTarget2D surface; var data = new byte[dst.ConsecutiveSize]; var pitch = 0; if (buffer == FrameBuffer.Auto) { buffer = FrameBuffer.Front; } #if SILVERLIGHT var mode = ((XnaRenderSystem)Root.Instance.RenderSystem).DisplayMode; surface = new RenderTarget2D(device, mode.Width, mode.Height, false, SurfaceFormat.Color, DepthFormat.Depth24Stencil8); #else var mode = device.DisplayMode; surface = new RenderTarget2D(device, mode.Width, mode.Height, false, SurfaceFormat.Rgba64, DepthFormat.Depth24Stencil8); #endif //ResolveTexture2D( device, mode.Width, mode.Height, 0, SurfaceFormat.Rgba32 ); #if !SILVERLIGHT if (buffer == FrameBuffer.Front) { // get the entire front buffer. This is SLOW!! device.SetRenderTarget(surface); if (IsFullScreen) { if ((dst.Left == 0) && (dst.Right == Width) && (dst.Top == 0) && (dst.Bottom == Height)) { surface.GetData(data); } else { var rect = new Rectangle(); rect.Left = dst.Left; rect.Right = dst.Right; rect.Top = dst.Top; rect.Bottom = dst.Bottom; surface.GetData(0, XnaHelper.ToRectangle(rect), data, 0, 255); } } #if !(XBOX || XBOX360 || WINDOWS_PHONE) else { var srcRect = new Rectangle(); srcRect.Left = dst.Left; srcRect.Right = dst.Right; srcRect.Top = dst.Top; srcRect.Bottom = dst.Bottom; // Adjust Rectangle for Window Menu and Chrome var point = new Point(); point.X = (int)srcRect.Left; point.Y = (int)srcRect.Top; var control = Control.FromHandle(_windowHandle); point = control.PointToScreen(point); srcRect.Top = (long)point.Y; srcRect.Left = (long)point.X; srcRect.Bottom += (long)point.Y; srcRect.Right += (long)point.X; surface.GetData(0, XnaHelper.ToRectangle(srcRect), data, 0, 255); } #endif } else { device.SetRenderTarget(surface); if ((dst.Left == 0) && (dst.Right == Width) && (dst.Top == 0) && (dst.Bottom == Height)) { surface.GetData(data); } else { var rect = new Rectangle(); rect.Left = dst.Left; rect.Right = dst.Right; rect.Top = dst.Top; rect.Bottom = dst.Bottom; surface.GetData(0, XnaHelper.ToRectangle(rect), data, 0, 255); } } #endif var format = XnaHelper.Convert(surface.Format); if (format == PixelFormat.Unknown) { throw new Exception("Unsupported format"); } var dataPtr = Memory.PinObject(data); var src = new PixelBox(dst.Width, dst.Height, 1, format, dataPtr); src.RowPitch = pitch / PixelUtil.GetNumElemBytes(format); src.SlicePitch = surface.Height * src.RowPitch; PixelConverter.BulkPixelConversion(src, dst); Memory.UnpinObject(data); surface.Dispose(); }
private static void _ilToAxiomInternal <T>(BufferBase tar, PixelFormat fmt, T r, T g, T b, T a) { if (!typeof(T).IsPrimitive) { throw new AxiomException("Invalid type!"); } var ilfmt = Il.ilGetInteger(Il.IL_IMAGE_FORMAT); var src = Il.ilGetData(); var srcend = Il.ilGetData().Offset(Il.ilGetInteger(Il.IL_IMAGE_SIZE_OF_DATA)); var elemSize = PixelUtil.GetNumElemBytes(fmt); while ((int)src < (int)srcend) { using (var srcBuf = BufferBase.Wrap(src, (int)srcend - (int)src)) { var srcPtr = srcBuf as ITypePointer <T>; switch (ilfmt) { case Il.IL_RGB: r = srcPtr[0]; g = srcPtr[1]; b = srcPtr[2]; src = src.Offset(3); break; case Il.IL_BGR: b = srcPtr[0]; g = srcPtr[1]; r = srcPtr[2]; src = src.Offset(3); break; case Il.IL_LUMINANCE: r = srcPtr[0]; g = srcPtr[0]; b = srcPtr[0]; src = src.Offset(1); break; case Il.IL_LUMINANCE_ALPHA: r = srcPtr[0]; g = srcPtr[0]; b = srcPtr[0]; a = srcPtr[1]; src = src.Offset(2); break; case Il.IL_RGBA: r = srcPtr[0]; g = srcPtr[1]; b = srcPtr[2]; a = srcPtr[3]; src = src.Offset(4); break; case Il.IL_BGRA: b = srcPtr[0]; g = srcPtr[1]; r = srcPtr[2]; a = srcPtr[3]; src = src.Offset(4); break; default: return; } ; _packI <T>(r, g, b, a, fmt, tar); tar += elemSize; } } }
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); } }