Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a faster alternative to using textures in XNA?

Tags:

c#

xna

textures

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.

like image 655
Matthew Bowen Avatar asked May 20 '10 12:05

Matthew Bowen


3 Answers

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.

like image 68
mikeschuld Avatar answered Sep 21 '22 23:09

mikeschuld


Using one texture per tile is not very efficient. Especially since it means you cannot do batching (in any real sense).

If you NEED to have them as separate textures in your content-project for some reason (easier to edit one tile, etc), you can quite easily compile them into tilemaps after loading. How you do this is basicly:

1: Load a number of tiles (lets say 40 32*32 tiles for now)

2: Figure out a nice texture-size for the tilemap: square root of 40 is 6.something, so we round up to 7. 7*32 is 224, which is nice, but 256 is nicer, so lets make the texture 256x256. (you can make code that figures out this on the fly)

3: Create a Rendertarget2D which is the desired size.

4: Activate rendertarget.

5: Render tiles on rendertarget:

int x, y = 0;
foreach (var tile in allTiles)
{
    RenderTile(tile, x*32, y*32);
    x++;

    if (x >= 8)
    {
        x = 0;
        y++;
    }
}

To betch-render you have a vertex-buffer with 4 * 40 vertices. each set of 4 has a value indicating index of the quad it belongs to (0,1,2,etc...). In your shader you have an array of matrixes[40] for position of the tiles, as well as an array of tileIndex (int[40]) for knowing which tile to render from the tilemap.

I'm sorry, but I don't have time to write all the shader-code right now :s

An other trick I have used in our games is pre-rendering the level onto large tiles (640x360), which reduces the number of draw-calls by a great deal, especially when dealing with 5+ layers of tiles from different tilesets. Only thing is that it does not work with dynamic tiles (animated tiles, etc), but you can mark those and render them normally if you want...

like image 24
Stig-Rune Skansgård Avatar answered Sep 19 '22 23:09

Stig-Rune Skansgård


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.

like image 45
Eliot Avatar answered Sep 21 '22 23:09

Eliot