Sign in to follow this  
nlraley

DirectX9 - How to Copy a smaller Surface into a section of a Larger Surface

Recommended Posts

nlraley    126
How would I accomplish this?

Say I have several 256x256 tiles that are going into a 1024x1024 Surface. How would I go about loading each of the tiles into the larger surface?

Does LoadSurfaceFromSurface completely replace the destination Surface with that of the Source?

Or do I need to load these into a Texture instead? Basically I am wanting to do the equivalent of the old blit to copy the section of the smaller surface into the larger one, but not sure what the new methods to do so are...

Any help would be greatly appreciated.

Share this post


Link to post
Share on other sites
Aardvajk    13207
IDirect3DDevice9::StretchRect may be what you are looking for. You can specify NULL for the source RECT and the position you want the tile for the destination RECT.

The method name is a bit misleading since there are lots of restrictions on actually stretching but as long as your destination RECT is the same size as your source image, it is effectively equivalent to BitBlt() should work on any kind of surface.

Share this post


Link to post
Share on other sites
Evil Steve    2017
1. What are you using surfaces for? There's a reasonable chance you shouldn't be using surfaces, and should use textures instead.

2. What pool are the surfaces in? System memory, default, or managed?

3. Similar to #1, what exactly are you doing? Is this a once-off, load time thing, or something you intend to do every frame?

Share this post


Link to post
Share on other sites
nlraley    126
It will most likely end up being loading every frame.

Right now I am working on constructing the backdrop, but there will be sprites eventually that will need their position updated and I'll also need to update the backdrop when the user pans as I will need to fetch different tiles.

I could just as easily use textures to do it I suppose. Through reading I am fairly certain I have the texture and surface creation down pat, I just have no idea how to display it.

Right now here is some bits of what I have:

My MapTile is a class with Information regarding to the location and positioning of the tile including tile X,Y location and pixel X,Y location. Tile location is used for my naming scheme and pixel is where the tiles would be located in an x,y location for my map. Here I cycle through my MapTiles and see if it falls whithin the display boundaries and if so, where it would be displayed at.

MainForm->DX3D.BeginRender();
while (Data->MapTiles.whileNext())
{
//-----------------------
if ( (Data->MapTiles.i->MapTileInfo.srTilesY >= MainForm->MapTile.Bounds.TopLeft.Tile.Y
&& Data->MapTiles.i->MapTileInfo.srTilesY <= MainForm->MapTile.Bounds.BtmRight.Tile.Y)
&&
(Data->MapTiles.i->MapTileInfo.srTilesX >= MainForm->MapTile.Bounds.TopLeft.Tile.X
&& Data->MapTiles.i->MapTileInfo.srTilesX <= MainForm->MapTile.Bounds.BtmRight.Tile.X) )
{
//----------------------- Storing the x and y Values
long int xValue = 0, yValue = 0;
//----------------------- Storing Pixel and Tile Coordinates
PixelValues tempP_tl;
TileValues tempT_tl;
//----------------------- Get the Location of the Tile
tempT_tl.X = Data->MapTiles.i->MapTileInfo.srTilesX;
tempT_tl.Y = Data->MapTiles.i->MapTileInfo.srTilesY;
//----------------------- Get the Location Tile in Respect to Map Top Left Bounds
tempT_tl.X -= MainForm->MapTile.Bounds.TopLeft.Tile.X;
tempT_tl.Y -= MainForm->MapTile.Bounds.TopLeft.Tile.Y;
//----------------------- Convert from Tile to Pixels
TileXYtoPixelXY(tempT_tl, tempP_tl);
//----------------------- Get the X and Y Pixel Coordinates
xValue = tempP_tl.X;
yValue = tempP_tl.Y;
//----------------------- Adjust for Map Size
if ( xValue != 0 )
xValue -= xAdj;
if ( yValue != 0 )
yValue -= yAdj;
//----------------------- Check for Trimming of the Tile Edges - Width
if ( Data->MapTiles.i->MapTileInfo.srTilesX == MainForm->MapTile.Bounds.TopLeft.Tile.X )
{ xAdj = (MainForm->xmapBox->Width % 256) / 2; bmpWidth = 256 - xAdj; }
else if ( Data->MapTiles.i->MapTileInfo.srTilesX == MainForm->MapTile.Bounds.BtmRight.Tile.X )
{ bmpWidth = 256 - ((MainForm->xmapBox->Width % 256) / 2); xAdj = 0; }
else
{ bmpWidth = 256; xAdj = 0; }
//----------------------- Check for Trimming of the Tile Edges - Height
if ( Data->MapTiles.i->MapTileInfo.srTilesY == MainForm->MapTile.Bounds.TopLeft.Tile.Y )
{ yAdj = (MainForm->xmapBox->Height % 256) / 2; bmpHeight = 256 - yAdj; }
else if ( Data->MapTiles.i->MapTileInfo.srTilesY == MainForm->MapTile.Bounds.BtmRight.Tile.Y )
{ bmpHeight = 256 - ((MainForm->xmapBox->Height % 256) / 2); yAdj = 0; }
else
{ bmpHeight = 256; yAdj = 0;}
//----------------------- Get the Location of the File
fileLoc = Data->MapTiles.i->MapTileInfo.tileBaseDirectory;
fileLoc += Data->MapTiles.i->MapTileInfo.tileTypeDirectory + "\\";
fileLoc += Data->MapTiles.i->MapTileInfo.tileZoomDirectory + "\\";
fileLoc += AnsiString((int)Data->MapTiles.i->MapTileInfo.srTilesY) + "\\";
fileLoc += AnsiString((int)Data->MapTiles.i->MapTileInfo.srTilesX);
fileLoc += Data->MapTiles.i->MapTileInfo.srExtension;
//Data->MapTiles.i->DXSurface.Create(bmpWidth, bmpHeight);
//-----------------------
hr = Data->MapTiles.i->DX3Surface.CreateSurfaceFromFile((LPCTSTR)fileLoc.c_str(), bmpWidth, bmpHeight, xAdj, yAdj);
if FAILED(hr)
DebugLog("Failed Creating Surface From File!");
//-----------------------
if (Data->MapTiles.i->DX3Surface.Surface)
{
//-----------------------
Data->MapTiles.i->DX3Surface.destRect.left = xValue;
Data->MapTiles.i->DX3Surface.destRect.top = yValue;
Data->MapTiles.i->DX3Surface.destRect.bottom = yValue + bmpHeight;
Data->MapTiles.i->DX3Surface.destRect.right = xValue + bmpWidth;
//-----------------------
hr = MainForm->DX3D.D3Device->StretchRect(
Data->MapTiles.i->DX3Surface.Surface, // Source Surface
&Data->MapTiles.i->DX3Surface.destRect, // Source Rectangle
MainForm->DX3D.BackBuffer, // Destination Surface
&MainForm->DX3D.srcRect, // Destination Rectangle
D3DTEXF_LINEAR // Filter
);
if FAILED(hr)
DebugLog("Failed loading Tile Surface into BackBuffer!");
//-----------------------
//Data->MapTiles.i->DX3Surface.CreateSurfaceFromSurface( *MainForm->DX3DOffscreen.Surface, *Data->MapTiles.i->DX3Surface.Surface );
//-----------------------
}
//-----------------------
}
//-----------------------
MainForm->DX3D.EndRender();



My Begin and End Render functions are as follows:

void TDX3D::BeginRender()
{
//-------------------
if ( NULL == D3Device )
return;
//-------------------
D3Device->Clear(
0,
NULL,
D3DCLEAR_TARGET,
D3DCOLOR_XRGB(0, 0, 0),
1.0f,
0
);
//-------------------
D3Device->BeginScene();
//-------------------
}
//---------------------------------------------------------------------------

void TDX3D::EndRender()
{
//-------------------
D3Device->EndScene();
D3Device->Present( NULL, NULL, NULL, NULL);
//-------------------
}



I initialize my D3D as follows:

bool TDX3D::InitDirect3D(HWND tWinHandle)
{
//-------------------
D3DDISPLAYMODE dspMode;
D3DPRESENT_PARAMETERS pp;
//-------------------
D3Draw = Direct3DCreate9( D3D_SDK_VERSION);
if ( !D3Draw )
return false;
//-------------------
D3Draw->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &dspMode);
Format = dspMode.Format;
//-------------------
ZeroMemory(&pp, sizeof(D3DPRESENT_PARAMETERS));
//-------------------
pp.BackBufferCount = 1; // We only need a single back buffer
pp.MultiSampleType = D3DMULTISAMPLE_NONE; // No multi-sampling
pp.MultiSampleQuality = 0; // No multi-sampling
pp.SwapEffect = D3DSWAPEFFECT_DISCARD; // Throw away previous frames, we don't need them
pp.hDeviceWindow = tWinHandle; // This is our main (and only) window
pp.Flags = 0; // No flags to set
pp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT; // Default Refresh Rate
pp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; // Default Presentation rate
pp.BackBufferFormat = Format; // Display format
pp.EnableAutoDepthStencil = FALSE; // No depth/stencil buffer
pp.Windowed = TRUE; // Window Mode
//-------------------
hr = D3Draw->CheckDeviceType(
D3DADAPTER_DEFAULT, //Adapter
D3DDEVTYPE_HAL, //DeviceType
Format, //DisplayFormat
Format, //BackBufferFormat
false); //Windowed
//-------------------
if (!SUCCEEDED(hr))
return false;
//-------------------
hr = D3Draw->CreateDevice(
D3DADAPTER_DEFAULT, // The default adapter, on a multi-monitor system there can be more than one.
D3DDEVTYPE_HAL, // Use hardware acceleration rather than the software renderer Our Window
tWinHandle, // Our Window
D3DCREATE_SOFTWARE_VERTEXPROCESSING, // Process vertices in software. This is slower than in hardware, but will work on all graphics cards.
&pp, // Our D3DPRESENT_PARAMETERS structure, so it knows what we want to build
&D3Device); // This will be set to point to the new device
//-------------------
if ( FAILED(hr) )
{
return false;
}
return true;
}



I initialize the Surface with this function:

HRESULT TDX3D::InitSurface( int pWidth, int pHeight)
{
//-------------------
hr = MainForm->DX3D.D3Device->CreateOffscreenPlainSurface(
pWidth, // Surface width
pHeight, // Surface height
Format, // Surface format
D3DPOOL_DEFAULT, // Create it in the default memory pool
&pBackBuffer, // The pointer to our surface
NULL
);
//-------------------
}
[\source]

Then I load my surface from file as such:

HRESULT TDX3D::CreateSurfaceFromFile(LPCTSTR location)
{
//-------------------
D3DXIMAGE_INFO imageInfo;
D3DFORMAT format;
//-------------------
int height, width;
//-------------------
hr = D3DXGetImageInfoFromFile(location, &imageInfo);
if FAILED(hr)
return false;
//-------------------
height = imageInfo.Height;
width = imageInfo.Width;
format = imageInfo.Format;
//-------------------
hr = MainForm->DX3D.D3Device->CreateOffscreenPlainSurface(
width, // Surface width
height, // Surface height
format, // Surface format
D3DPOOL_DEFAULT, // Create it in the default memory pool
&pSurface, // The pointer to our surface
NULL
);
//-------------------
if FAILED(hr)
return false;
//-------------------
hr = D3DXLoadSurfaceFromFile(
pSurface, // The surface we just created
NULL, // Palette entry, NULL for non 256 color formats
NULL, // Dest rect, NULL for the whole surface
location, // The file we wish to load
NULL, // Source Rect, NULL for the whole file
D3DX_DEFAULT, // Filter
0, // Color key, color that should be used as transparent - 0 Disables.
NULL // Pointer to a D3DXIMAGE_INFO structure, for holding info about the image.
);
//-------------------
if FAILED(hr)
return false;
//-------------------
return hr;
//-------------------
}


And before I go through my MapTiles I perform the following to get started:

DX3D = TDX3D();
DX3DOffscreen = TDX3Image();
//------------------- Init the Direct3D
if (!DX3D.InitDirect3D(MainForm->scrollMap->Handle))
DebugLog("Failed to Initialize Direct3D");
//------------------- Init the Primary and Offscreen Surfaces - Creates Primary and Offscreen Surfaces
DX3D.InitSurface(xmapBox->Width, xmapBox->Height);
//-------------------
DX3D.D3Device->GetBackBuffer(
0, // Swap Chain
0, // BackBuffer Index
D3DBACKBUFFER_TYPE_MONO, // Stereo View - Not Supported in DX9 - Use D3DBACKBUFFER_TYPE_MONO
&DX3D.BackBuffer // Surface
);
//-------------------
DX3D.srcRect.left = 0;
DX3D.srcRect.top = 0;
DX3D.srcRect.bottom = xmapBox->Height;
DX3D.srcRect.right = xmapBox->Width;
//-------------------



So I initialize with this part here and then go through my MapTiles function at the very top. Any idea what I did wrong? My StretchRect call is failing and nothing is getting loaded.

[Edited by - nlraley on November 5, 2010 11:09:18 AM]

Share this post


Link to post
Share on other sites
Aardvajk    13207
Modern GPUs are set up to render textured triangles, not blit rectangles.

Render each tile as a textured quad (ideally using an index buffer so you only need four vertices per quad rather than six to reduce main memory to graphics memory traffic).

If you can also use a texture atlas to store all the tiles, you can batch a large amount of tiles over in one go. You want a dynamic vertex buffer to maximise performance so you need to be careful to release and recreate the buffer on device restore.

If any of that is gibberish, post back.

Share this post


Link to post
Share on other sites
nlraley    126
I am assuming StretchRect is not working due to the fact that my Destination Surface is 1024x512 and the fact that the Surface I am trying to put into the Destination surface is approximately 256x256.

Share this post


Link to post
Share on other sites
nlraley    126
Yea, it's gibberish atm. Nothing I have read as of yet mentions any of that. I'll start looking into it but if you can point me in the right direction I'd appreciate it as I am having a hard time finding documentation specific enough to what I am trying to accomplish.

Share this post


Link to post
Share on other sites
Aardvajk    13207
Quote:
Original post by nlraley
I am assuming StretchRect is not working due to the fact that my Destination Surface is 1024x512 and the fact that the Surface I am trying to put into the Destination surface is approximately 256x256.


No, that should be fine but forget about StretchRect for this and see above. StretchRect should really only be used for composing images at load time or changing the aspect of a video stream. It is not a good choice for calling multiple times per frame.

Share this post


Link to post
Share on other sites
Evil Steve    2017
As Aardvajk said; what you're doing isn't going to be particularly fast. You'd be much better using ID3DXSprite - it'd be faster and likely easier to use.

You could still create a texture atlas (Again, as Aardvajk said) to get all of the textures on one or two larger ones, but I wouldn't bother with that until you have your scene rendering.

Share this post


Link to post
Share on other sites
nlraley    126
I am working on creating and doing this through a texture following a guide I found online, hopefully I get it up and running in a bit. I'll keep you guys posted as I'll probably have a few more questions once I finish compiling and debugging this.

And I'll definitely be looking into sprites that I will be displaying over this backdrop, so thanks for the link to that.

Share this post


Link to post
Share on other sites
nlraley    126
My original plan was going to be to load all the tiles as one big backdrop; however, using the old direct7 method of doing this I ran out of memory VERY fast. I am assuming not enough has changed to where I'd be able to load approximately 1000 256x256 pngs at one time would it?

Share this post


Link to post
Share on other sites
Evil Steve    2017
Quote:
Original post by nlraley
My original plan was going to be to load all the tiles as one big backdrop; however, using the old direct7 method of doing this I ran out of memory VERY fast. I am assuming not enough has changed to where I'd be able to load approximately 1000 256x256 pngs at one time would it?
You're creating all your surfaces in D3DPOOL_DEFAULT, which pretty much means video memory. The source format the images are in (PNG) doesn't matter, because they're uncompressed when they're loaded, and D3D is probably using D3DFMT_A8R8G8B8 - I.e. 32 bits per pixel. A 256x256 image therefore takes up 256KB (Not including any additional overhead the driver might have), so 1000 of them will take up 250MB of video memory.

First, you should put all of your images into D3DPOOL_MANAGED - that basically means that D3D will load the images into system memory, which there's lots of (And it's backed by the page file, so you have up to 4GB of it on a 32-bit system, no matter how much RAM your PC has). When you actually render one of the textures, D3D will create a default pool copy of the resource, upload the system memory copy to it, and then use that copy to render. The default pool copy will stay in memory until D3D fills up VRAM (Or you lose your device or flush managed textures), at which point it will start removing the least recently used managed resources to make room for new ones.
D3D is very efficient at using the managed pool, and you shouldn't have any problems in using 250MB of managed resources, but if you have much more, you might have to go for something more complex, like streaming the tiles you need from hard disk into memory.

Once you have all your resources in the managed pool, you should just render whatever tiles are visible every frame (I.e. don't try to copy everything to an off screen surface and then draw just that surface like you would with double buffering in DirectDraw). I'd use ID3DXSprite to the actual rendering, since it's about as fast as you're going to get, and it'll be the least work to implement.

In general, doing things the DirectDraw way is no longer the fastest way - hardware these days is optimised to redraw the enter scene every frame, unlike DirectDraw where it was common to use a backbuffer which is then copied to the frontbuffer ever frame. The video memory capacity is slightly increased, but you still can't ordinarily throw thousands and thousands of textures at the graphics card.

Share this post


Link to post
Share on other sites
nlraley    126
Sounds like a solid approach, and with that in mind once I have this loading I'll switch it over to that memory pool and see what I can get accomplished there.

I've started from scratch and have been developing my classes using textures and a guide I found here:
http://www.gamedev.net/reference/articles/article1972.asp
However, I am having some difficulty and not sure where my problem is at.

I create the textures just fine, or it appears to be as it is not failing in any of the steps during this process; however, it appears to be rendering/loading a blank, all grey, screen.

I'll include my classes in the next 2 posts and maybe one of you can tell me where I'm getting hung up at.

Share this post


Link to post
Share on other sites
nlraley    126
My DXDirect3D class
.cpp

//---------------------------------------------------------------------------


#pragma hdrstop

#include "DXDirect3D.h"

#include "DX9\d3dx9.h"
#include "DX9\d3d9.h"
#include "DX9\d3dx9tex.h"
//---------------------------------------------------------------------------

#pragma package(smart_init)

//---------------------------------------------------------------------------

#include "DXTexture.h"

//---------------------------------------------------------------------------

//Initialize Direct3D
bool TDXDirect3D::InitD3D (int resWidth, int resHeight, D3DFORMAT resFormat, HWND hWnd, BOOL bWindowedMode)
{
//------------------- 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));
if (FAILED(d3d->GetDeviceCaps (D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &d3dCaps)))
return FALSE;
//------------------- 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 FALSE;
//------------------- Set vertex shader
d3dDevice->SetVertexShader(NULL);
d3dDevice->SetFVF (D3DFVF_TLVERTEX);
//------------------- Create vertex buffer and set as stream source
d3dDevice->CreateVertexBuffer(sizeof(textured_vertex) * 4, NULL, D3DFVF_TLVERTEX, D3DPOOL_MANAGED,
&vertexBuffer, NULL);
d3dDevice->SetStreamSource (0, vertexBuffer, 0, sizeof(textured_vertex));
//------------------- 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);
//------------------- Successfully initalized Direct3D
return TRUE;
//-------------------
}
//---------------------------------------------------------------------------

bool TDXDirect3D::Present () { return d3dDevice->Present (NULL, NULL, NULL, NULL); }
//---------------------------------------------------------------------------

bool TDXDirect3D::BeginDrawing () { return d3dDevice->BeginScene (); }
//---------------------------------------------------------------------------

bool TDXDirect3D::EndDrawing () { return d3dDevice->EndScene (); }
//---------------------------------------------------------------------------

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;
//-------------------
}
//---------------------------------------------------------------------------

void 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
d3dDevice->SetTexture (0, texture);
//------------------- Draw image
d3dDevice->DrawPrimitive (D3DPT_TRIANGLEFAN, 0, 2);
//-------------------
}
//---------------------------------------------------------------------------

void TDXDirect3D::BlitExD3D (IDirect3DTexture9 *texture, RECT *rDest, D3DCOLOR *vertexColours /* -> D3DCOLOR[4] */,
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 = vertexColours[0];
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 = vertexColours[1];
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 = vertexColours[2];
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 = vertexColours[3];
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
d3dDevice->SetTexture (0, texture);
//------------------- Draw image
d3dDevice->DrawPrimitive (D3DPT_TRIANGLEFAN, 0, 2);
//-------------------
}
//---------------------------------------------------------------------------



[Edited by - nlraley on November 5, 2010 11:50:41 AM]

Share this post


Link to post
Share on other sites
nlraley    126
My DXTexture class
.cpp

//---------------------------------------------------------------------------


#pragma hdrstop

#include "DXTexture.h"
#include "DXDirect3D.h"
#include <list>

//---------------------------------------------------------------------------

#pragma package(smart_init)

//---------------------------------------------------------------------------
std::list <LOADEDTEXTURE*> DXTexture::loadedTextures;
//---------------------------------------------------------------------------
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;
//-------------------
}
//---------------------------------------------------------------------------

void 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
DXDirect3D->BlitD3D (texture->texture, &rDest, vertexColour, rotate);
//-------------------
}
//---------------------------------------------------------------------------

void DXTexture::BlitEx (int X, int Y, D3DCOLOR* vertexColours, 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
DXDirect3D->BlitExD3D (texture->texture, &rDest, vertexColours, rotate);
//-------------------
}
//---------------------------------------------------------------------------



[Edited by - nlraley on November 5, 2010 11:51:01 AM]

Share this post


Link to post
Share on other sites
nlraley    126
Okay, now what I have done was in my MainForm I have a reference to the class DXDirect3D. I have initialized it there.

I then load up the directory structure of my MapTiles in my MapTiles class. After this is done I call LoadDirectXTiles. This is what I perform there:

bool TMapTiles::LoadDirectXTiles()
{
//-----------------------
AnsiString fileLoc;
//-----------------------
int bmpWidth = 0, bmpHeight = 0;
int xAdj = (MainForm->xmapBox->Width % 256) / 2;
int yAdj = (MainForm->xmapBox->Height % 256) / 2;
//-----------------------
HRESULT hr;
//-----------------------
//MainForm->DX3D.BeginRender();
//-----------------------
Data->MapTiles.whileFirst();
//----------------------- Load the Tiles into Memory
while (Data->MapTiles.whileNext())
{
//-----------------------
if ( (Data->MapTiles.i->MapTileInfo.srTilesY >= MainForm->MapTile.Bounds.TopLeft.Tile.Y
&& Data->MapTiles.i->MapTileInfo.srTilesY <= MainForm->MapTile.Bounds.BtmRight.Tile.Y)
&&
(Data->MapTiles.i->MapTileInfo.srTilesX >= MainForm->MapTile.Bounds.TopLeft.Tile.X
&& Data->MapTiles.i->MapTileInfo.srTilesX <= MainForm->MapTile.Bounds.BtmRight.Tile.X) )
{
//----------------------- Storing the x and y Values
long int xValue = 0, yValue = 0;
//----------------------- Storing Pixel and Tile Coordinates
PixelValues tempP_tl;
TileValues tempT_tl;
//----------------------- Get the Location of the Tile
tempT_tl.X = Data->MapTiles.i->MapTileInfo.srTilesX;
tempT_tl.Y = Data->MapTiles.i->MapTileInfo.srTilesY;
//----------------------- Get the Location Tile in Respect to Map Top Left Bounds
tempT_tl.X -= MainForm->MapTile.Bounds.TopLeft.Tile.X;
tempT_tl.Y -= MainForm->MapTile.Bounds.TopLeft.Tile.Y;
//----------------------- Convert from Tile to Pixels
TileXYtoPixelXY(tempT_tl, tempP_tl);
//----------------------- Get the X and Y Pixel Coordinates
xValue = tempP_tl.X;
yValue = tempP_tl.Y;
//----------------------- Adjust for Map Size
if ( xValue != 0 )
xValue -= xAdj;
if ( yValue != 0 )
yValue -= yAdj;
//----------------------- Check for Trimming of the Tile Edges - Width
if ( Data->MapTiles.i->MapTileInfo.srTilesX == MainForm->MapTile.Bounds.TopLeft.Tile.X )
{ xAdj = (MainForm->xmapBox->Width % 256) / 2; bmpWidth = 256 - xAdj; }
else if ( Data->MapTiles.i->MapTileInfo.srTilesX == MainForm->MapTile.Bounds.BtmRight.Tile.X )
{ bmpWidth = 256 - ((MainForm->xmapBox->Width % 256) / 2); xAdj = 0; }
else
{ bmpWidth = 256; xAdj = 0; }
//----------------------- Check for Trimming of the Tile Edges - Height
if ( Data->MapTiles.i->MapTileInfo.srTilesY == MainForm->MapTile.Bounds.TopLeft.Tile.Y )
{ yAdj = (MainForm->xmapBox->Height % 256) / 2; bmpHeight = 256 - yAdj; }
else if ( Data->MapTiles.i->MapTileInfo.srTilesY == MainForm->MapTile.Bounds.BtmRight.Tile.Y )
{ bmpHeight = 256 - ((MainForm->xmapBox->Height % 256) / 2); yAdj = 0; }
else
{ bmpHeight = 256; yAdj = 0;}
//----------------------- Get the Location of the File
fileLoc = Data->MapTiles.i->MapTileInfo.tileBaseDirectory;
fileLoc += Data->MapTiles.i->MapTileInfo.tileTypeDirectory + "\\";
fileLoc += Data->MapTiles.i->MapTileInfo.tileZoomDirectory + "\\";
fileLoc += AnsiString((int)Data->MapTiles.i->MapTileInfo.srTilesY) + "\\";
fileLoc += AnsiString((int)Data->MapTiles.i->MapTileInfo.srTilesX);
fileLoc += Data->MapTiles.i->MapTileInfo.srExtension;
//Data->MapTiles.i->DXSurface.Create(bmpWidth, bmpHeight);
//-----------------------
DXTexture Texture(&MainForm->Direct3D);
D3DCOLOR vertexColour = 0xFFFFFFFF;
Texture.Init(fileLoc.c_str());
Texture.Blit(xValue, yValue, vertexColour, 0);
}
}
}



I didn't understand the concept in the BlitD3D where the example was calling bufferVertices, I am assuming it is just a simple array? Index was also not defined... Neither were defined anywhere in the example.

Any ideas/pointers?

[Edited by - nlraley on November 5, 2010 11:55:17 AM]

Share this post


Link to post
Share on other sites
nlraley    126
After creating the Texture instead of Calling Blit I am going to try to use a sprite to display the Texture. I'll let you know how it goes.

Share this post


Link to post
Share on other sites
nlraley    126
Okay, I've added the two functions:
in DXTexture

void DXTexture::DrawSprite (int X, int Y, D3DCOLOR vertexColours)
{
//-------------------
RECT rDest;
//------------------- Setup destination rectangle
rDest.left = X;
rDest.right = X + texture->width;
rDest.top = Y;
rDest.bottom = Y + texture->height;
//------------------- Draw texture
DXDirect3D->DrawSprite (texture->texture, &rDest, vertexColours);
//-------------------
}



in DXDirect3D

void TDXDirect3D::DrawSprite (IDirect3DTexture9 *texture, RECT *rDest, D3DCOLOR vertexColour)
{
//-------------------
textured_vertex* vertices;
D3DXVECTOR3 pos;
//-------------------
d3dSprite->Begin(D3DFILL_SOLID);
//-------------------
pos.x = rDest->left;
pos.y = rDest->top;
pos.z = 0.0f;
//------------------- Draw the Sprite
hr = d3dSprite->Draw(
texture,
NULL,
NULL,
&pos,
vertexColour
);
if (FAILED(hr))
return;
//------------------- Draw image
d3dSprite->End();
//-------------------
}



I added the following to my init function:

hr = D3DXCreateSprite(d3dDevice, &d3dSprite);
if (FAILED(hr))
return false;


Which Succeeds.

Then instead of calling:
Texture.Blit(xValue, yValue, vertexColour, 0);
I call:
Texture.DrawSprite(xValue, yValue, vertexColour);

However, that fails on the Draw. What am I doing wrong here?

[Edited by - nlraley on November 5, 2010 11:17:38 AM]

Share this post


Link to post
Share on other sites
nlraley    126
Okay, I am at a loss here. I can't figure out what I'm doing wrong.

I call Direct3D.InitD3D which initializes my d3dDevice.

I fetch all my tiles from their directories, store them in a MapTile object.

I then call BeginDrawing which calls d3dDevice->BeginScene().

I beging going through my Map Tiles.

I create a Texture Object from the Texture Class.

Initializing the Texture.
Check if the Texture is in my list, if not it creates a new Texture.
Call LoadTexture in DXDirect3D Class
Call D3DXCreateTextureFromFileEx
Push newly Created Texture to my Texture list.

Call Blit function of the Texture Class.
Create the Destination Rectangle based on X,Y position on the screen. This is the pixel X,Y not in terms of 0.0-1.0.
Call BlitD3D of the DXDirect3D Class
Lock the VertexBuffer
Take the Dest Rectangle and Converts to Vertex coordinates.
Unlock the VertexBuffer
Set the Texture to the Direct3D Device
Call DrawPrimitive for the Direct3D Device

Repeat for Each MapTile.

Call EndDrawing which calls d3dDevice->EndScene().

Call Present which calls d3dDevice->Present().

Now after all this nothing shows up. What am I doing wrong?

Share this post


Link to post
Share on other sites
nlraley    126
Quick question since you guys have been so much help thus far.

I took this home this weekend and started going through the DirectX tutorials included in the SDK and built a project in Visual Studio 2010 using Visual C++, you have no idea how nice it was getting to do something back in VS again. Just having intelli-sense in the IDE again was a nice change and it actually supporting the DirectX was really nice.

Anyway, going through the examples I was able to Setup the Direct3D, Create and Initialize the Device, Creating my Sprite and Initializing, and Creating a Texture and Vertex buffer.

I was able to create and display a triangle and square, but was unable to load the Texture into the quad without using a sprite for some reason. But using a sprite I was able to get multiple tiles up and displaying.

My questions are this:
How can I get it to where I can drag and move the background around to display different tiles? Right now I'm drawing directly into a window and can resize the window, but have no dragging capabilites. Am I going to be stuck creating controls to manually move? Or can I load these textures into a larger object, other than the regular Window created with CreateWindow, that will allow me to drag and move around in my environment to show other areas of my background?

The way I was picturing originally doing this was to load probably 2x the viewable area and change the viewable area based on where the using was viewing at. Lets say load my sprites all into a larger texture that instead of being 1024x512 was 2048x1024 and only having a 1024x512 area of the larger texture being viewable. The user drags and changes the view, the texture's position is merely changed instead of having to reload all the tiles and whatnot.

I'm just sort of confused conceptually with how/where to take this part now that I have everything starting to piece together.

Next, loading partial tiles. I'll have certain viewpoints that are going to require partial tile loads from along the edges. Say for instance I need to omit 56 pixels out of my top left tile. I have position and center coordinates for the sprite. Would the proper way be to set the Center to (0,0) and the position of the sprite to (-56,0)? Or would setting the center to (56,0) and the position to (0,0) be the correct way?

And finally, with what you were saying about managed. I should create all the tiles I need during startup and use the managed, this way they are all preloaded into the system memory/page file and then whenever I call draw for the sprite they are automatically moved to the video memory right?

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