Sign in to follow this  
Thevenin

[.net] DirectX Textures from Bitmaps.

Recommended Posts

I'm really confused, and rather frustrated atm. I'm trying to get minimaps rendered dynamically for my MMORPG (to ditch dependence on prerendered minimaps, etc). Since C# doesn't let you do anything raw, I figured I would just create a directX texture every frame (the texture is like 30x30, so it should be small enough to not matter). Since I cannot plot to the DirectX texture, I plotted to a Bitmap object, and than converted it into a DirectX texture on every frame. My problem is, I don't really know how to do this. I could convert the Bitmap to a Stream and use the DirectX TextureLoader.FromStream() function, or the Texture = new Texture(Device,Bitmap,Usage,Pool). But the later of the two seems to be INCREDIBLY slow!
Texture TheTexture = new Texture(MyDirectX.MyDevice, MyMinimap,
           Usage.None, Pool.Managed);
I found it was 14x faster to load a 512x512 bitmap (from my Assembly().Reflection) as a stream from the TextureLoader class in DirectX. What should I do? Does anyone know how to convert a Bitmap to a stream, or how to get the new Texture() command to work properly? Edit: Jeeze, even this doesn't work; it throws an illegal operation error when the TextureLoader reads it.
Stream TheStream = new MemoryStream();
MyMinimap.Save(TheStream, ImageFormat.Png);
Texture TheTexture = TextureLoader.FromStream(MyDirectX.MyDevice, TheStream);
[Edited by - Thevenin on November 7, 2006 4:49:23 PM]

Share this post


Link to post
Share on other sites
Found the problem, and a subsequent problem.

        Stream TheStream = new MemoryStream();
MyMinimap.Save(TheStream, ImageFormat.Png);
TheStream.Position = 0;
MyMinimapTex = TextureLoader.FromStream(MyDirectX.MyDevice, TheStream);


I had to set the stream.position to 0. Inaddition, it was cumulating alot of memory, so I had to dispose the texture after the EndDraw() command.

Share this post


Link to post
Share on other sites
You could create a texture and lock it/unlock it when you need to update it. I use the following code to update a texture. It has to be created in the Pool.Managed pool, I think (as opposed to the Pool.Default pool). It might be less memory intensive that creating and disposing a texture each frame. Whether that makes a difference, I don't know.


756 public override void WritePixels(PixelBuffer buffer)
757 {
758 Direct3D.Surface surf = mTexture.GetSurfaceLevel(0);
759
760 int pitch;
761 int pixelPitch = mDisplay.GetPixelPitch(surf.Description.Format);
762 PixelFormat pixelFormat = mDisplay.GetPixelFormat(surf.Description.Format);
763
764 surf.Dispose();
765
766 GraphicsStream stm = mTexture.LockRectangle(0, 0, out pitch);
767
768 if (buffer.PixelFormat != pixelFormat)
769 buffer = buffer.ConvertTo(pixelFormat);
770
771
772 for (int i = 0; i < SurfaceHeight; i++)
773 {
774 int startIndex = buffer.GetPixelIndex(0, i);
775 int rowStride = buffer.RowStride;
776 IntPtr dest = (IntPtr)((int)stm.InternalData + i * pitch);
777
778 Marshal.Copy(buffer.Data, startIndex, dest, rowStride);
779 }
780
781 mTexture.UnlockRectangle(0);
782
783 }

Share this post


Link to post
Share on other sites
I would suggest you follow kanato's advice and lock/unlock the texture, creating/destroying a texture every frame would be a pretty slow operation, even for a small image. However, I would suggest you use the C# unsafe keyword and use raw pointers to write to the texture, I've found this to be faster than writing to the stream provided by the GraphicsStream. It's pretty easy to get the pointer to the locked data:


GraphicsStream stream = null;
IntPtr bufferPointer = IntPtr.Zero;

stream = yourTexture.LockRectangle(...);
bufferPointer = stream.InternalData; // This is our pointer.

unsafe
{
byte *buffer = (byte *)bufferPointer.ToPointer();

// Write to the texture using the buffer pointer....
}

yourTexture.UnlockRectangle(...);




Disclaimer:
I'm recalling this stuff from memory, so it may not be 100% accurate.

Share this post


Link to post
Share on other sites
I tried both methods posted, but they throw null reference exceptions when I try to LockRectangle. I have a feeling its due to the way I create the Texture (I don't use new Texture(), I use the TextureLoader, because new Texture() always throws an error).

How do I can I create a texture?

Edit: Oops, I'm an idiot. I had left the MyMinimapTex.Dispose() in my code from my previous code. I still don't know how to create textures without loading Textureloader though. =/

Share this post


Link to post
Share on other sites
Quote:
Original post by Tape_Worm
I would suggest you follow kanato's advice and lock/unlock the texture, creating/destroying a texture every frame would be a pretty slow operation, even for a small image. However, I would suggest you use the C# unsafe keyword and use raw pointers to write to the texture, I've found this to be faster than writing to the stream provided by the GraphicsStream. It's pretty easy to get the pointer to the locked data:

*** Source Snippet Removed ***

Disclaimer:
I'm recalling this stuff from memory, so it may not be 100% accurate.


I used a slightly modified version of your code (shown below for people who later google this topic).

    public unsafe void sDrawMinimap()
{
int TheMapSize = MyMinimap.Width;
GraphicsStream TheStream = null;
IntPtr TheBufferPointer = IntPtr.Zero;

TheStream = MyMinimapTex.LockRectangle(0, LockFlags.None);
TheBufferPointer = TheStream.InternalData;

unsafe
{
uint* TheBuffer = (uint*)TheBufferPointer.ToPointer();

/* Write to the texture using the buffer pointer.... */
for (int TheY = 0; TheY < TheMapSize; TheY++)
for (int TheX = 0; TheX < TheMapSize; TheX++)
{
*TheBuffer = (uint)Color.Purple.ToArgb();
TheBuffer++;
}
}
MyMinimapTex.UnlockRectangle(0);

}




It works quite nicely. [smile]

Thanks kanato, for the managed solution aswell. I'll likey use your managed solution for the client app, and the unsafe solution for the map editor (because the minimap on the client app is signficantly smaller).

Edit: Switched 'TheX' and 'TheY'. Forgot that its stored row by row in memory.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this