views:

462

answers:

6

I am writing a map editing program for a 2D game using XNA. To create a Texture2D for all of the tiles that a map requires takes too long.

Are there any alternatives to using textures for drawing with XNA?

I attempted to create just one texture per tile set instead of a texture for every tile in a tile set, but there is a limit to the size of textures and I could not fit all the tiles of a tile set into one texture.

Currently the program contains all the would-be textures in memory as Bitmap objects. Is there a way to simply draw a Bitmap object to the screen in XNA? I have searched but I cannot find any information on this. This approach would avoid having to create textures altogether, however any tinting or effects I would have to do to the bitmap directly.

Any help would be very much appreciated.

Thanks

A: 

Assuming all the tiles that a map require existing images that are simply placing on a screen to lay out a tile map? Or are you making images in this map editor and want to save them out?

I read this, and your other post about textures - If they are all ready defined images that you want to use in your game couldnt you just include them in the content folder and reference them there? This allows XNA to compile the textures in the xnb format and you shouldn't have the problems you are explaining.

However if we are talking completely dynamic - or you are crafting one big image from the layout of the tiles (instead of doing something like a tile map) then I am not sure how to approach the issue.

David Larrabee
Hi, thanks for your response. The problem with simply adding the image files to the content folder is that they are custom-format images - my map editor is for an existing game that uses these images. I was hoping to be able to code the editor using C# and XNA, however it is now looking likely that I will have to start again and use C++ and DirectX to accomplish it, as I know that textures from bitmaps is very fast in DirectX. The main reason I used C# was because I wanted the ease of designing the UI, however if I can't use C# then I will look into using something like Qt.
Matthew Bowen
that was the reason i hesitated at first, I figured there must have been a reason you couldnt just use them in the content directory of your game and your editor - sorry I dont have a better answer for ya!
David Larrabee
A: 

If multiple tiles use the same texture, it will be enough to load it just once.

If the user includes textures in some file format, you could automatically convert it to a texture/image format which is faster for your needs.

codymanix
Thanks for your response. Unfortunately I only load each required texture once. I discovered that simply addingTexture2D tx = new Texture2D(device, width, height);to my code for each texture required increases the loading time for a map from 2.7 seconds to 74 seconds! Note that the 2.7 seconds includes creating Bitmaps holding the textures needed. Texture2D just seems to be too slow for creating textures on-the-fly.
Matthew Bowen
+1  A: 

Since you need to use a custom image format, if you want (for speed) you can attempt to write custom content pipeline importers and processors for XNA (http://msdn.microsoft.com/en-us/library/bb447754.aspx), but this may be overkill for what you need to do.

I see you want to design the GUI as easily as possible, even if these issues force you to use a language like C++ so you can use DirectX. In Visual C++ you should still be able to take advantage of visual Windows Forms layout if you are using Visual Studio.

Eliot
A: 

Unfortunately, as far as I know, there is no way to directly draw a bitmap to the screen in XNA; it requires that everything is mapped to the Texture objects, which are by default buffered to the graphics card. It sounds like you're talking about a lot of tiles, though, if they won't all fit on the maximum allowed texture (I can't remember whether that was 1024 or 4096 square...) - have you tried having an unbuffered texture for speed purposes? Another alternative would be to lazy-load your tilesets into textures so the user didn't have to wait for them all to load - for an editor, using a bright pink fallback color is usually acceptable while it loads.

Also, is there anything inherently required to write your tool in XNA? Since it sounds like you're writing the tool separately from the game engine itself, you may find some very acceptable solutions in WPF, including drawing directly from BitmapSources and some utilities for your UI.

mattdekrey
Thanks for the response, there is nothing that requires me to use XNA, no. Right now I have gone back to working on a C++ and DirectX version of the tool. My problem was that textures in XNA seem to be incredibly slow. What takes over 100 seconds using XNA Texture2Ds takes 0.3 seconds using DirectX textures. Thanks for the directness - primarily what I wanted to know is that there is no way to directly draw a bitmap to the screen.
Matthew Bowen
A: 

Are you trying draw them all using a single thread of execution?

Try multi-threading your game. Threading in C# is quite easy and is supported by XNA.

Instead of looking at your screen as a whole, try splitting it into two (or more) portions. You may need to re-write the function you're using to Draw (I sure hope you didn't just dump everything directly in your Draw() method!!) to take in coordinates setting the boundaries of your draw regions.

baultista
My program is already multi-threaded. One thread takes care of handling window messages whilst a child thread attempts to load the tiles and create textures from them. At the time of writing this question I hadn't added a Draw method yet as I first needed to have a method of loading the textures in a reasonable timeframe.
Matthew Bowen
A: 

Is there any reason you haven't considered loading the image one time and then passing in x and y offset coordinates to the pixel shader?

You would basically set the C# up like this:

myGraphicsDevice.Textures[0] = whateverYourGiantMapTextureIs;

foreach(MapChunk chunk in mapChunks) {
    myShader.Effect.Parameters["xOffset"] = chunk.XOffset;
    myShader.Effect.Parameters["yOffset"] = chunk.YOffset;

    myGraphicsDevice.DrawIndexedPrimitives( your chunk drawing code here );
}

And then the shader code like this:

float4x4 World; 
float4x4 View; 
float4x4 Projection;

float xOffset;
float yOffset;

sampler TextureSampler; 

struct VS_INPUT { 
    float4 Position : POSITION0; 
    float4 Color    : COLOR0;
};

VS_INPUT Transform(VS_INPUT Input) { 
    VS_INPUT Output; 

    float4 worldPosition = mul(Input.Position, World); 
    float4 viewPosition = mul(worldPosition, View); 
    Output.Position = mul(viewPosition, Projection); 
    Output.Color = Input.Color;

    return Output; 
} 

float4 ColorTexture(VS_INPUT Input) : COLOR0{ 
    return Input.Color.rgba * tex2D(TextureSampler, float2(xOffset, yOffset));
} 

technique TransformColorTexture { 
    pass P0 { 
        VertexShader = compile vs_2_0 Transform(); 
        PixelShader = compile ps_2_0 ColorTexture(); 
    } 
}

The shader code might need some fitting into your existing code but otherwise it should do the trick.

mikeschuld