Jump to content
  • Advertisement
Sign in to follow this  
nlraley

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

This topic is 2800 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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
Advertisement
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
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
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
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
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
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
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
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
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
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!