# Tile-based game with DirectX - issues with transparency and StretchRect

In my current project I have a class which loads a map file and then it should load all associated tilesets (no transparent tiles - I used to work with magenta as a colorkey) and precreate a surface for each static layer of the map so I only have to display one bigger image per frame rather then iterating over all of my tiles. For each tileset I have a loop which loads them successfully like this

 IDirect3DSurface9 *pTilesetSurface = nullptr;
// Create surface
HRESULT hResult = Engine::GetInstance()->GraphicsDevice->CreateOffscreenPlainSurface(
pTileset->GetImage()->GetWidth(),
pTileset->GetImage()->GetHeight(),
D3DFMT_A8R8G8B8,
D3DPOOL_DEFAULT,
&pTilesetSurface,
nullptr);
if(!SUCCEEDED(hResult))
return FALSE;

std::wstring strTilesetSource(
pTileset->GetImage()->GetSource().begin(),
pTileset->GetImage()->GetSource().end());
strTilesetSource = strPathToMap + strTilesetSource;
pTilesetSurface,
nullptr,
nullptr,
strTilesetSource.c_str(),
nullptr,
D3DX_FILTER_LINEAR,
D3DCOLOR_ARGB(255, 255, 0, 255),
nullptr);
if(!SUCCEEDED(hResult))
return FALSE;

this->m_vTilesets.push_back(pTilesetSurface);


After this loop I am iterating over every layer of the map and trying to build a surface for each layer with the associated tiles like this.

IDirect3DSurface9 *pLayerSurface = nullptr;
HRESULT hResult = Engine::GetInstance()->GraphicsDevice->CreateOffscreenPlainSurface(
pLayer->GetWidth() * 16,
pLayer->GetHeight() * 16,
D3DFMT_A8R8G8B8,
D3DPOOL_DEFAULT,
&pLayerSurface,
nullptr);
if(!SUCCEEDED(hResult))
return FALSE;
Engine::GetInstance()->GraphicsDevice->ColorFill(
pLayerSurface,
nullptr,
D3DCOLOR_ARGB(0, 0, 0, 0));
for(int x = 0; x < pLayer->GetWidth(); ++x) {
for(int y = 0; y < pLayer->GetHeight(); ++y) {
const Tmx::MapTile tile = pLayer->GetTile(x, y);
if(tile.tilesetId != -1) {
int dwTilesetWidth =
this->m_pTmxFile->GetTileset(tile.tilesetId)->GetImage()->GetWidth() / 16;
std::div_t tileCoords = std::div(tile.id, dwTilesetWidth);
RECT srcRect = { tileCoords.rem * 16, tileCoords.quot * 16,
tileCoords.rem * 16 + 16, tileCoords.quot * 16 + 16 };
RECT destRect = { x * 16, y * 16, x * 16 + 16, y * 16 + 16 };
Engine::GetInstance()->GraphicsDevice->StretchRect(
this->m_vTilesets[tile.tilesetId],
&srcRect,
pLayerSurface,
&destRect,
D3DTEXF_NONE);
}
}
}


A call to D3DXSaveSurfaceToFile for debugging purposes creates transparent png files which can be layered correctly in Photoshop etc. but when I render these surfaces with this loop

for(auto iter = this->m_vLayers.begin(); iter != this->m_vLayers.end(); ++iter) {
Engine::GetInstance()->GraphicsDevice->StretchRect(
*iter,
nullptr,
Engine::GetInstance()->Backbuffer,
nullptr,
D3DTEXF_NONE);
}


then I have some wrong output which you can see here: .

All the blacks areas should be transparent such that one can see the layer below. Has anyone an idea what I might be doing wrong?

PS: I have read about the IDirect3DTexture9 and ID3DXSprite interfaces which could be helpful, but I haven't used them yet as I did not find any information on how to rebuild a map with tiles like I did here with usual surfaces. If anyone has suggestions about this, I would be glad to here them!

• Do you actualy have a ground tile? beacuse, trancparancy is otherwise black, or the same color as your clear color of your target Feb 5 '13 at 14:33
• In my loop where I create all layers, I dump all surfaces to png files to be able to debug. And I get two files, one background and one foreground. You can fetch the output files here: imgur.com/a/AnEHI Feb 5 '13 at 14:37
• well, then it looks correct. lets say your first layer is the background, and the second is the trees and houses. The trancparency is still black. since you need to blend them together to get what you want. since 1 + 0 ( 0 equals the trancaprecny ), you will fill that area with your background color. Feb 5 '13 at 14:41
• I am sorry, but I cannot follow what you are saying. Could you explain how to blend the two layers together? - EDIT: Are you suggesting that I should not create surfaces for each layer, but iterate throught each layer and fill only one surface? Feb 5 '13 at 14:45
• To your backbuffer, which are displaying the image. You have to 1 draw the background, then after that, just add on the other image. what you are doing now is, render the first image, and the render the second image over the first image. you need to add the second ontop of the first. ( im trying to find the correct call for that in dx9 right now. ) Feb 5 '13 at 14:49

• As mentioned in my question I have read about IDirect3DTexture9 and ID3DXSprite which could come in handy - is this something I should take a look at? And furthermore, do you know which functions I can use to create the layers from my tileset? Feb 5 '13 at 14:59
With the hint of mh01 and some trial and error I succeeded in drawing my map. I am still loading the tilesets as IDirect3DSurface9 objects but creating IDirect3DTexture9 objects for each layer. With a call to IDirect3DTexture9::GetSurfaceLevel() I retrieve a pointer to the underlying IDirect3DSurface9 of the texture which can be used for StretchRect. However when I want to draw the layers I must not use StretchRect as it does not render but merely copy all contents. Therefore I am relying on a ID3DXSprite object which handles this for me successfully.