I am trying to load a set of Map Tiles to fill up a background. Each tile is a 256x256 PNG image file with the same format.
I have 3 classes currently. A MapTile class that contains the file location of the png file for the tile as well as coordinate information for displaying the tile. A DXDirect3D class which handles my DX objects, and finally a DXTexture which maintains my DirectX Textures.
Currently my program searches through a specified set of directories and builds a MapTile for each PNG file located in there. The naming scheme of the tiles correlates to the X,Y screen position of my images. I maintain a complete list of each of these tile objects.
After creating these objects, I initialize my DXDirect3D class, then initialize my Direct3D as follows:
HRESULT TDXDirect3D::InitD3D (int resWidth, int resHeight, D3DFORMAT resFormat, HWND hWnd, BOOL bWindowedMode){ //------------------- WinHandle = hWnd; //------------------- Make Direct3D object d3d = Direct3DCreate9(D3D_SDK_VERSION); //------------------- Make sure NULL pointer was not returned if (!d3d) return false; //------------------- Get device capabilities ZeroMemory (&d3dCaps, sizeof(d3dCaps)); hr = d3d->GetDeviceCaps (D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &d3dCaps); if (FAILED(hr)) return hr; //------------------- Setup present parameters ZeroMemory(&d3dPresent,sizeof(d3dPresent)); d3dPresent.SwapEffect = D3DSWAPEFFECT_FLIP; d3dPresent.hDeviceWindow = hWnd; d3dPresent.BackBufferCount = 1; //------------------- Check if windowed if (bWindowedMode) // Windowed Mode { //------------------- D3DDISPLAYMODE d3ddm; RECT rWindow; //------------------- Get display mode d3d->GetAdapterDisplayMode (D3DADAPTER_DEFAULT, &d3ddm); //------------------- Get window bounds GetClientRect (hWnd, &rWindow); //------------------- Setup screen dimensions resWidth = rWindow.right - rWindow.left; resHeight = rWindow.bottom - rWindow.top; //------------------- Setup backbuffer d3dPresent.Windowed = true; d3dPresent.BackBufferFormat = d3ddm.Format; d3dPresent.BackBufferWidth = rWindow.right - rWindow.left; d3dPresent.BackBufferHeight = rWindow.bottom - rWindow.top; //------------------- format = d3ddm.Format; //------------------- } // if (bWindowedMode) else // FullScreen { //------------------- d3dPresent.Windowed = false; d3dPresent.BackBufferWidth = resWidth; d3dPresent.BackBufferHeight = resHeight; d3dPresent.BackBufferFormat = resFormat; //------------------- } // End else //------------------- Check if hardware vertex processing is available if (d3dCaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) { //------------------- Create device with hardware vertex processing hr = d3d->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL, hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dPresent, &d3dDevice); //------------------- } else { //------------------- Create device with software vertex processing hr = d3d->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dPresent, &d3dDevice); //------------------- } //------------------- Make sure device was created if (FAILED(hr)) return hr; //------------------- Set vertex shader d3dDevice->SetVertexShader(NULL); d3dDevice->SetFVF (D3DFVF_TLVERTEX); //------------------- Create vertex buffer hr = d3dDevice->CreateVertexBuffer(sizeof(textured_vertex) * 4, NULL, D3DFVF_TLVERTEX, D3DPOOL_MANAGED, &vertexBuffer, NULL); if (FAILED(hr)) return hr; //------------------- Set as stream source hr = d3dDevice->SetStreamSource (0, vertexBuffer, 0, sizeof(textured_vertex)); if (FAILED(hr)) return hr; //------------------- Setup rendering states d3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE); d3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); d3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); d3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); d3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); //------------------- Setup the Sprite hr = D3DXCreateSprite(d3dDevice, &d3dSprite); if (FAILED(hr)) return hr; //------------------- Successfully initalized Direct3D return hr; //-------------------}
After that is done I make a call to:
IDirect3DDevice9->BeginScene()
Assuming that succeeds I then proceed to go through each of my MapTile objects. If the MapTileObject should be visible in the current viewport, I perform the following.
I call:
DXTexture Texture(&MainForm->Direct3D);
Which simply Initializes a Texture from my DXTexture class and sets its TDXDirect3D instance to that of my main form, the one I initialized above.
If that succeeds I call:
Texture.Init(fileLoc.c_str())
Calling the Init function of my Texture class which is defined as follows:
bool DXTexture::Init(std::string sFilename){ //------------------- D3DSURFACE_DESC surfaceDesc; LOADEDTEXTURE* newTexture; //------------------- std::list<LOADEDTEXTURE*>::iterator itTextures; //------------------- Make sure texture is not already loaded if (bLoaded) return FALSE; //------------------- Convert filename to lowercase letters sFilename = strlwr((char *)sFilename.c_str ()); //------------------- Check if texture is in the loaded list for (itTextures = loadedTextures.begin (); itTextures != loadedTextures.end (); itTextures++) if ((*itTextures)->sFilename == sFilename) { //------------------- Get LOADEDTEXTURE Object texture = *itTextures; //------------------- Increment Reference Counter (*itTextures)->referenceCount++; //------------------- Set Loaded Flag bLoaded = TRUE; //------------------- Successfully found texture return TRUE; //------------------- } //------------------- Texture was not in the list, make a new texture newTexture = new LOADEDTEXTURE; //------------------- Load texture from file newTexture->texture = DXDirect3D->LoadTexture((char*)sFilename.c_str()); //------------------- Make sure texture was loaded if (!newTexture->texture) return FALSE; //------------------- Get texture dimensions newTexture->texture->GetLevelDesc(0, &surfaceDesc); //------------------- Set new texture parameters newTexture->referenceCount = 1; newTexture->sFilename = sFilename; newTexture->width = surfaceDesc.Width; newTexture->height = surfaceDesc.Height; //------------------- Push new texture onto list loadedTextures.push_back (newTexture); //------------------- Setup current texture instance texture = loadedTextures.back(); bLoaded = TRUE; //------------------- Successfully loaded texture return TRUE; //-------------------}
What this does is check to see if the texture has already been created, if it hasn't it creates a new LOADEDTEXTURE and calls the DXDirect3D->LoadTexture((char*)sFilename.c_str()) function from my DXDirect3D class which is defined as:
IDirect3DTexture9 *TDXDirect3D::LoadTexture(char *fileName){ //------------------- IDirect3DTexture9 *d3dTexture; D3DXIMAGE_INFO SrcInfo; //------------------- Use a magenta colourkey D3DCOLOR colorkey = 0xFFFF00FF; //------------------- Load image from file if (FAILED(D3DXCreateTextureFromFileEx (d3dDevice, fileName, 0, 0, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, D3DX_FILTER_NONE, D3DX_DEFAULT, colorkey, &SrcInfo, NULL, &d3dTexture))) return NULL; //------------------- Return the newly made texture return d3dTexture; //-------------------}
As you can see, this calls D3DXCreateTextureFromFileEx loading the PNG's file location and setting the texture property of my LOADEDTEXTURE to this newly created Texture.
My next step calls:
Texture.Blit(xValue, yValue, vertexColour, 0)
Which calls this function:
HRESULT DXTexture::Blit (int X, int Y, D3DCOLOR vertexColour, float rotate){ //------------------- RECT rDest; //------------------- Setup destination rectangle rDest.left = X; rDest.right = X + texture->width; rDest.top = Y; rDest.bottom = Y + texture->height; //------------------- Draw texture hr = DXDirect3D->BlitD3D (texture->texture, &rDest, vertexColour, rotate); //-------------------}
This sets up the Destination Rect before calling the DXDirect3D->BlitD3D which is defined as follows:
HRESULT TDXDirect3D::BlitD3D (IDirect3DTexture9 *texture, RECT *rDest, D3DCOLOR vertexColour, float rotate){ //------------------- textured_vertex* vertices; //------------------- Lock the vertex buffer vertexBuffer->Lock(0, 0, (void **)&vertices, NULL); //------------------- Setup vertices // A -0.5f modifier is applied to vertex coordinates to match texture and screen coords // Some drivers may compensate for this automatically, but on others texture alignment errors are introduced // More information on this can be found in the Direct3D 9 documentation //------------------- vertices[0].colour = vertexColour; vertices[0].x = (float) rDest->left - 0.5f; vertices[0].y = (float) rDest->top - 0.5f; vertices[0].z = 0.0f; vertices[0].rhw = 1.0f; vertices[0].u = 0.0f; vertices[0].v = 0.0f; //------------------- vertices[1].colour = vertexColour; vertices[1].x = (float) rDest->right - 0.5f; vertices[1].y = (float) rDest->top - 0.5f; vertices[1].z = 0.0f; vertices[1].rhw = 1.0f; vertices[1].u = 1.0f; vertices[1].v = 0.0f; //------------------- vertices[2].colour = vertexColour; vertices[2].x = (float) rDest->right - 0.5f; vertices[2].y = (float) rDest->bottom - 0.5f; vertices[2].z = 0.0f; vertices[2].rhw = 1.0f; vertices[2].u = 1.0f; vertices[2].v = 1.0f; //------------------- vertices[3].colour = vertexColour; vertices[3].x = (float) rDest->left - 0.5f; vertices[3].y = (float) rDest->bottom - 0.5f; vertices[3].z = 0.0f; vertices[3].rhw = 1.0f; vertices[3].u = 0.0f; vertices[3].v = 1.0f; /* OMITTED //------------------- Handle rotation if (rotate != 0) { //------------------- RECT rOrigin; float centerX, centerY; //------------------- Find center of destination rectangle centerX = (float)(rDest->left + rDest->right) / 2; centerY = (float)(rDest->top + rDest->bottom) / 2; //------------------- Translate destination rect to be centered on the origin rOrigin.top = rDest->top - (int)(centerY); rOrigin.bottom = rDest->bottom - (int)(centerY); rOrigin.left = rDest->left - (int)(centerX); rOrigin.right = rDest->right - (int)(centerX); //------------------- Rotate vertices about the origin bufferVertices[index].x = rOrigin.left * cosf(rotate) - rOrigin.top * sinf(rotate); bufferVertices[index].y = rOrigin.left * sinf(rotate) + rOrigin.top * cosf(rotate); //------------------- bufferVertices[index + 1].x = rOrigin.right * cosf(rotate) - rOrigin.top * sinf(rotate); bufferVertices[index + 1].y = rOrigin.right * sinf(rotate) + rOrigin.top * cosf(rotate); //------------------- bufferVertices[index + 2].x = rOrigin.right * cosf(rotate) - rOrigin.bottom * sinf(rotate); bufferVertices[index + 2].y = rOrigin.right * sinf(rotate) + rOrigin.bottom * cosf(rotate); //------------------- bufferVertices[index + 3].x = rOrigin.left * cosf(rotate) - rOrigin.bottom * sinf(rotate); bufferVertices[index + 3].y = rOrigin.left * sinf(rotate) + rOrigin.bottom * cosf(rotate); //------------------- Translate vertices to proper position bufferVertices[index].x += centerX; bufferVertices[index].y += centerY; bufferVertices[index + 1].x += centerX; bufferVertices[index + 1].y += centerY; bufferVertices[index + 2].x += centerX; bufferVertices[index + 2].y += centerY; bufferVertices[index + 3].x += centerX; bufferVertices[index + 3].y += centerY; //------------------- } */ //------------------- Unlock the vertex buffer vertexBuffer->Unlock(); //------------------- Set texture hr = d3dDevice->SetTexture (0, texture); if (FAILED(hr)) return hr; //------------------- Draw image hr = d3dDevice->DrawPrimitive (D3DPT_TRIANGLEFAN, 0, 2); //------------------- return hr; //-------------------}
Which sets up the Vertices for the Texture, calls the SetTexture of my IDirect3DDevice9 followed by the DrawPrimitive of my IDirect3DDevice9.
I then call:
d3dDevice->EndScene();d3dDevice->Present(NULL, NULL, NULL, NULL);
Yet I end up with absolutely nothing being displayed. I tried calling Sprite->Draw instead of Blitting; however, Draw always fails. What am I doing wrong here?