[WinRT Metro + MDX] Text -> Bitmap -> Texture


  • Under advisement, I'm crossposting this from the Metro Style Apps forum. I'm not building a game, per-se, but DirectX seems to be the crux of my problem. I'm working in C# & XAML using SharpDX to create a Metro application. I'd like to be able to do something which I've found very straightforward in OGL / Android / iOS / Java: I'd like to print some text into a bitmap, and then use that bitmap as a texture. I need to be able to build this bitmap at runtime, in memory, offscreen. I'm happy if I can do this by wiring a D2D surface up to a D3DTexture also, but I'd prefer to write the bitmap once and be done with it.

    After several days of banging my head against the wall, I've got some sections of code that create textures based on byte arrays, but I'm unable to get D2D to render into these bitmaps. I think I'm missing some fundamental concept about what causes a D2D buffer to get written-to. I'm no directX expert, and any advice would be greatly appreciated. Thanks for your time. :)

    //_target is a bunch of information about the current ->D3D11<- target in which the texture will finally be used.
    public Object AllocateTexture(DrawingSize drawingSize, DXDelegates.RenderD2DDelegate renderDelegate)
                var pitch = drawingSize.Width * 4;
                var size = pitch * drawingSize.Height;            
                var bufferArray = new Byte[size];
                var dataStream = SharpDX.DataStream.Create(bufferArray, true, true);
                var dataRectangle = new SharpDX.DataRectangle(dataStream.DataPointer, pitch);            
                var wicBitmap = new SharpDX.WIC.Bitmap(_target.DeviceManager.WICFactory, 
                var properties = new RenderTargetProperties();
                properties.DpiX = _target.DeviceManager.Dpi;
                properties.DpiY = _target.DeviceManager.Dpi;
                properties.PixelFormat = new SharpDX.Direct2D1.PixelFormat(SharpDX.DXGI.Format.R8G8B8A8_UNorm, SharpDX.Direct2D1.AlphaMode.Premultiplied);
                properties.Type = RenderTargetType.Default;
                var wicRenderTarget = new WicRenderTarget(_target.DeviceManager.FactoryDirect2D, wicBitmap, properties);
                renderDelegate.Invoke(wicRenderTarget, _target.DeviceManager);
                dataStream.Seek(0, SeekOrigin.Begin);
                return TextureLoader.CreateTexture2DFromBitmap(_d3dDevice, drawingSize.Width, drawingSize.Height, dataStream);
            public Object AllocateTexture2(DrawingSize drawingSize, DXDelegates.RenderD2DDelegate renderDelegate)
                var pitch = drawingSize.Width * 4;
                var size = pitch * drawingSize.Height;            
                var localD2DContext = ToDispose(new SharpDX.Direct2D1.DeviceContext(_target.DeviceManager.DeviceDirect2D, SharpDX.Direct2D1.DeviceContextOptions.EnableMultithreadedOptimizations));            
                //Copy the bitmap properties out of the current target as much as possible.
                var bitmapProperties = new BitmapProperties1();
                bitmapProperties.DpiX = _target.DeviceManager.Dpi;
                bitmapProperties.DpiY = _target.DeviceManager.Dpi;
                bitmapProperties.PixelFormat = new SharpDX.Direct2D1.PixelFormat(SharpDX.DXGI.Format.R8G8B8A8_UNorm, SharpDX.Direct2D1.AlphaMode.Premultiplied);
                bitmapProperties.BitmapOptions = BitmapOptions.Target | BitmapOptions.CannotDraw;            
                //Allocate a buffer and wrap a Surface-Compatible bitmap aroun it.
                var backingBuffer = new DataStream(size, true, true);                
                var renderTargetBitmap = new Bitmap1(localD2DContext, drawingSize, backingBuffer, pitch, bitmapProperties);
                localD2DContext.Target = renderTargetBitmap;
                //Scribble in the buffer so we can see what is and isn't working.
                var rand = new Random();
                var randBuffer = new byte[size];
                for (int i = 0; i < randBuffer.Length; i++)
                    randBuffer[i] = (byte)rand.Next(0, 255);
                backingBuffer.Write(randBuffer, 0, size);
                backingBuffer.Seek(0, SeekOrigin.Begin);
                //Create a render target
                //This is unneccesary, perhaps?        
                RenderTargetProperties properties = new RenderTargetProperties();
                properties.DpiX = bitmapProperties.DpiX;
                properties.DpiY = bitmapProperties.DpiY;
                properties.PixelFormat = bitmapProperties.PixelFormat;
                properties.Type = RenderTargetType.Default;
                RenderTarget bitmapRenderTarget = new RenderTarget(_target.DeviceManager.FactoryDirect2D, renderTargetBitmap.Surface, properties);
                //All the actual D2D drawing happens in the delegate.            
                renderDelegate.Invoke(bitmapRenderTarget, _target.DeviceManager);            
                //Blit the buffer into a texture.
                var texture2D = TextureLoader.CreateTexture2DFromBitmap(_d3dDevice, drawingSize.Width, drawingSize.Height, backingBuffer);
                return new ShaderResourceView(_d3dDevice, texture2D);                       


     public static SharpDX.Direct3D11.Texture2D CreateTexture2DFromBitmap(SharpDX.Direct3D11.Device device, int width, int height, SharpDX.DataStream dataStream)
                return new SharpDX.Direct3D11.Texture2D(device, 
                                                        standardTexture2D(width, height), 
                                                        new SharpDX.DataRectangle(dataStream.DataPointer, width * 4));     

    //D2D Drawing Delegate

    DXDelegates.RenderD2DDelegate renderDelegate = delegate(RenderTarget target, DeviceManager deviceManager)
                    var textFormat = new TextFormat(deviceManager.FactoryDirectWrite, "Calibri", 96 * drawingSize.Width / 1920) { TextAlignment = TextAlignment.Center, ParagraphAlignment = ParagraphAlignment.Center };
                    var blueBrush = new SolidColorBrush(target, Colors.SteelBlue); 
                    var whiteBrush = new SolidColorBrush(target, Colors.White);
                    var rr = new RoundedRect();
                    rr.RadiusX = 20;
                    rr.RadiusY = 10;
                    rr.Rect = new RectangleF(30f, 30f, 200f, 200f);
                    target.DrawRoundedRectangle(rr, whiteBrush);
                    target.DrawText("Hello Label!", textFormat, new RectangleF(-drawingSize.Width / 2.0f, -drawingSize.Height / 2.0f, drawingSize.Width / 2.0f, drawingSize.Height / 2.0f), blueBrush);

    Saturday, June 16, 2012 2:06 AM

All replies

  • For C++, use DirectWrite , render to D2D bitmap which shared with D3D texture.

    C++ DX11

    Saturday, June 16, 2012 2:37 AM