Jump to content
  • Advertisement

Archived

This topic is now archived and is closed to further replies.

Possibility

back buffers and primary buffers in directX

This topic is 6777 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

Hey, I have created a tile based game, and I have this idea for how to completely cut down the required processing power, but I dont know how to implement it. Here is my situation. I am making a tile based game (like Civ2), the map size is a 100x100 but only an area of 10x10 actually fits on the monitor, so what I do EVERY game loop is have to calculate which tiles are to be displayed, along with what buildings, structures, terrain enhancements, units, unit color indicators, and unit powerbars along with city names, and the user interface. Now this is RE-calculated every single game loop, which is running over 100fps (one fps is 1 execution of the game loop in my game), but if for example nothing is happening like the game player is just sitting there and not doing anything, all of those calculations are still being performed, every 1/100th of a second. But they dont need to be, but that is not the important stuff. If the user has a unit selected, and he moves that unit around the map, but he doesnt cause the map to scroll, then the only thing that is visually changing is that single unit. So what I want to be able to do is do a calculation for everything that appears on the screen Except that single unit, then blit all of that to the back buffer, then make a copy of that back buffer which will be stored (we will call the copy backbuffer2, the original is backbuffer1). Then calculate where the selected unit is and blit its image to backbuffer1, and then flip backbuffer1 with the primary buffer which then gets displayed on the screen. Then along comes the next game loop (1/100th of a second later) and this time, instead of RE-calculating where everything is, we just calculate where that single selected unit is. After that calculation is done, we copy backbuffer2 onto backbuffer1 and then blit the unit onto backbuffer1 and then flip backbuffer1 with the primary again. What this effectively should do is stop all those uneeded calculations of what appears on the monitor. Of course, if the user where to scroll the map, then we would need to do a recalculation, and make a new backbuffer2 image. So my problem is, how do I make this backbuffer2? I have been able to create 2 back buffers, but the second one gets put into the flipping chain, so for example, you have back1, back2, and the primary, then when you do a flip, the back1 becomes the primary, back2 becomes back1, and the primary becomes back2. How do I prevent back2 from being in the flipping chain? This has stumped me for sometime, so thanks for anyhelp anyone can provide. Possibility

Share this post


Link to post
Share on other sites
Advertisement
You don''t need a second backbuffer, you need a seperate surface. Just blit all the tiles to the surface, and then blit that to the backbuffer for use in the display. Then when the image is scrolled, you just redraw that surface. As you are going to be using this surface a lot, try to put it in video memory.

Share this post


Link to post
Share on other sites
So how do I create a surface like you described, where I can blit multiple images to it. When I create the surfaces, they are loaded up when the program starts and each image is its own little surface basically. But I didnt know you could blit to those, I will have to look into that.

Possibility

Share this post


Link to post
Share on other sites
quote:
Original post by Possibility

So how do I create a surface like you described, where I can blit multiple images to it.
Possibility


Just create a surface (like you would for the small tiles) except size it to be your resolution size. You can blit back and forth to any dx surface any which way you want to. Except the primary... not a good idea.

Share this post


Link to post
Share on other sites
My question is HOW do you do that. When I load in an image of a tile I use:

terrains_surf[1] = bitmap_surface("terrain1.bmp", (rct);//&the rct gets the deminsions of the image

if (!terrains_surf[1])
{
ErrStr=Err_LoadImageBackGround;
return FALSE;
}

so in order to create that surface, it uses the bitmap_surface function to load in an image file. And I have tried blitting to one of these surfaces, and that does work, like:

terrains_surf[1]->BltFast(650, 300, terrains_surf[0], &rct, DDBLTFAST_WAIT / DDBLTFAST_SRCCOLORKEY);

it will effectively change terrain type 1 to type 0, and so I guess I could just load up a 1024x768 blank .bmp file and use that as my second back buffer, but then I have the question of would this surface be stored in video memory, and is it as fast as using a real back buffer? But I would love to know how to create a real back buffer for what i want, but I dont think anyone knows how.

Thanks though for letting me know I can BltFast to any surface, even loaded up images.

Possibility

Share this post


Link to post
Share on other sites
> it will effectively change terrain type 1 to type 0, and
> so I guess I could just load up a 1024x768 blank .bmp file
> and use that as my second back buffer, but then I have the
> question of would this surface be stored in video memory,
> and is it as fast as using a real back buffer? But I would
> love to know how to create a real back buffer for what i
> want, but I dont think anyone knows how.

It is very easy for DirectDraw programmers, but you are using some type of graphics library (bitmap_surface is not part of DirectDraw) that does not let you create surfaces out of nothing. In DirectDraw, you basically just ask the DirectDraw object for a new surface, with the following call:

// declare your surface object
LPDIRECTDRAWSURFACE lpSurface;

// fill in the ddsd (Direct Draw surface descriptor) with
// all the atributes you want of the new surface, like size
// and so on. In particular, you tell where in memory it
// resides with the following part of the ddsd:

// This will force the surface into regular memory
ddsd.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY / other_flags;
// This will put the surface into video memory if there is room
ddsd.ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY / other flags;

// now ask the DirectDraw object (dd) for a new surface:
hrRetVal = lpdd->CreateSurface(&ddsd, &lpSurface, NULL);

I skipped lots of steps that are needed, and if you are using modern versions of DirectX you will need to get a later version of LPDIRECTDRAWSURFACE, but this is the basic idea. Look in your DirectDraw books or other documentation for better samples and more information.


---
Grandpa Simpson - "I never thought I could shoot down a German plane, but last year I proved myself wrong!"

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
So if the user is doing nothing you have a blazing fast FPS. What happens when the user starts scroller the screen constantly and your AI controlled NPC''s are moving around, etc, etc. ? Your FPS will start dropping and you ill have inconsistant frame-rate. What ever your plan is it should be configured for the lowest common denominator (worst case)

2-cents.

Share this post


Link to post
Share on other sites

//this assumes lpdd is the correctly set up DDraw7 interface

DDSURFACEDESC2 ddsd; // working description
LPDIRECTDRAWSURFACE7 lpdds; // surface

memset(&ddsd,0,sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS / DDSD_WIDTH / DDSD_HEIGHT;
ddsd.dwWidth = width; //screen width
ddsd.dwHeight = height; //screen height.
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
//offscreenplain will be in video, if it can fit, then pushed
//into system memory.

lpdd->CreateSurface(&ddsd,&lpdds,NULL);


this will create the surface you want. Then just blt this to the primary the part hat you need to. Neither will be erased in the process.

Share this post


Link to post
Share on other sites
Anonymous Poster: My general idea was to minimize all unnecessary calculations when ever possible. Even when the user is doing nothing, the AI players are still moving and other things are going on, but that stuff is mostlikely happening off screen.

spejic: I do use what you are talking about, here is the way my current setup works:

these are declared globaly
LPDIRECTDRAW7 lpDD=NULL;
LPDIRECTDRAWSURFACE7 lpDDSPrimary=NULL;
LPDIRECTDRAWSURFACE7 lpDDSBack=NULL;
LPDIRECTDRAWSURFACE7 interface_surf=NULL; //the interface
LPDIRECTDRAWSURFACE7 terrains_surf[3]={NULL,NULL,NULL}; //the tile pics


//------ Function to Load a Bitmap into a DirectDraw Surface ------//
LPDIRECTDRAWSURFACE7 bitmap_surface(LPCTSTR file_name,RECT *dims=NULL)
{
HDC hdc;
HBITMAP bit;
LPDIRECTDRAWSURFACE7 surf;


//load the interface bitmap
bit = (HBITMAP) LoadImage (NULL, file_name, IMAGE_BITMAP, 0, 0,
LR_DEFAULTSIZE/LR_LOADFROMFILE);

if (!bit)
return NULL; //failed to load, return failure to caller



// getting the bitmap dimensions
BITMAP bitmap;
GetObject (bit, sizeof(BITMAP), &bitmap);
int surf_width = bitmap.bmWidth;
int surf_height = bitmap.bmHeight;



// create the surface
HRESULT ddrval;
DDSURFACEDESC2 ddsd;
ZeroMemory (&ddsd, sizeof(ddsd));
ddsd.dwSize = sizeof(DDSURFACEDESC2);
ddsd.dwFlags = DDSD_CAPS / DDSD_WIDTH / DDSD_HEIGHT ;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
ddsd.dwWidth = surf_width;
ddsd.dwHeight = surf_height;



// attempt to create the surface
ddrval = lpDD->CreateSurface (&ddsd, &surf, NULL);



// created ok?
if (ddrval != DD_OK)
{
DeleteObject (bit); // if not created, release the bitmap and return
return NULL; // failure to caller
}
else
{
surf->GetDC (&hdc); //if created, get a DC for the surface



// generate a compatible DC
HDC bit_dc = CreateCompatibleDC (hdc);



// blit the interface to the surface
SelectObject (bit_dc, bit);
BitBlt (hdc, 0, 0, surf_width, surf_height, bit_dc, 0, 0, SRCCOPY);




// releasing the DCs
surf->ReleaseDC (hdc);
DeleteDC (bit_dc);



// save the dimensions if rectangle pointer provided
if (dims)
{
dims->left=0;
dims->top=0;
dims->right=surf_width;
dims->bottom=surf_height;
}
}

// clear the bitmap
DeleteObject (bit);



//return pointer to caller
return surf;
}

BOOL load_images()
{
RECT rct;

//load the interface image
interface_surf = bitmap_surface("interface.bmp");
if (!interface_surf)
{
ErrStr=Err_LoadImageInterface;
return FALSE;
}

//load the terrain images in the same manner
}



//------ Function to Initialize DirectDraw/DirectInput/DirecSound and the Application ------//
static BOOL Init (HINSTANCE hInstance, int nCmdShow)
{
WNDCLASS wc;
HRESULT ddrval;
LPDIRECTDRAW pDD;

// Create the main DirectDraw object
ddrval = DirectDrawCreate(NULL, &pDD, NULL);
if (ddrval != DD_OK)
{
ErrStr = Err_DirectDrawCreate;
return FALSE;
}


// Fetch DirectDraw4 interface
ddrval = pDD->QueryInterface(IID_IDirectDraw4, (LPVOID *) & lpDD);
if (ddrval != DD_OK) {
ErrStr=Err_Query;
return FALSE;
}


////////////////////////////////////////////////////////////////////////
// Create the primary surface
DDSURFACEDESC2 ddsd;
DDSCAPS2 ddscaps;
ZeroMemory(&ddsd,sizeof(ddsd));
ddsd.dwSize = sizeof( ddsd );
ddsd.dwFlags = DDSD_CAPS / DDSD_BACKBUFFERCOUNT;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE /
DDSCAPS_FLIP /
DDSCAPS_COMPLEX;
ddsd.dwBackBufferCount = 1;
ddrval = lpDD->CreateSurface( &ddsd, &lpDDSPrimary, NULL );

if (ddrval!=DD_OK)
{
ErrStr=Err_CreatePrimarySurf;
return FALSE;
}

// Create the primary back buffer interface
ddscaps.dwCaps=DDSCAPS_BACKBUFFER;
ddrval=lpDDSPrimary->GetAttachedSurface(&ddscaps,&lpDDSBack);
if (ddrval!= DD_OK)
{
ErrStr=Err_CreateBackSurf;
return FALSE;
}
////////////////////////////////////////////////////////////////////////
}


I have tried in vain in many attempts to figure out that ddsd.ddsCaps.dwCaps which is the last few lines of all that code listed above.

What I think I basically need is to get a complete list of the possible flags one can use when setting up a DD surface. I have looked in the DirectX 7 SDK help thing but that damn thing is cryptic with no comments and such brief explanations that only a 10yr veteran of DirectX programming could only understand it. When i see that stuff its like reading latin to me MS needs to write clearer explanations/comments still.

Possibility

Share this post


Link to post
Share on other sites
PRIMARYSURFACE means that this surface is the primary surface.
COMPLEX means that it is in a chain of surfaces.
FLIP means that you want the chain of surfaces to be flipable. If you don''t know what that means, pick up a good book.

Then you set 1 backbuffer, so it knows how many surfaces it has in the chain.

Then you create the backbuffer, and add it to the chain by attaching it to the primary surface you just created.
This is trivial stuff, but you have to know it.

The other flags, besides primarysurface complex flip and backbuffer, are offscreen systemmemory and videomemory (or something like that). You use those to create offscreen surfaces for bitmaps and such.


The_Minister

Share this post


Link to post
Share on other sites

  • Advertisement
×

Important Information

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

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!