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.
DirectX9 - How to Copy a smaller Surface into a section of a Larger Surface
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.
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.
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?
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?
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.
My Begin and End Render functions are as follows:
I initialize my D3D as follows:
I initialize the Surface with this function:
And before I go through my MapTiles I perform the following to get started:
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]
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]
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.
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.
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.
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.
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.
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.
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.
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.
And I'll definitely be looking into sprites that I will be displaying over this backdrop, so thanks for the link to that.
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement