Jump to content
  • Advertisement
Sign in to follow this  
Nads

Screenshot Problem (Missing HUD images)

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

Hi Guys, Recently I incorporated a Screenshot function into my tech demo. The problem I am having is that when I take a screenshot everything is copied into the created .png image apart from any HUD images/textures I have set on the screen (these are also .png). It seems like it is only drawing the 3d scene into the screenshot and leaving out 2d stuff. I am taking a screenshot of the backbuffer, is this my problem? If so how can I solve it? Heres my code:
  // Save the screen shot
  if(!screenShotSaved && KEY_DOWN(VK_SNAPSHOT))
  {
     D3DDISPLAYMODE display;
     d3ddev->GetDisplayMode(0, &display);

     // Create the off screen surface with the same info as the back buffer
     d3ddev->CreateOffscreenPlainSurface(display.Width, display.Height, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, 
										 &ScreenShotSurface, NULL);

     // Save the back buffer to the surface
     d3ddev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &ScreenShotSurface);
     sprintf_s(screenshotdir,"Screenshots/Screenshot%d.png",i);
     D3DXSaveSurfaceToFile(screenshotdir, D3DXIFF_PNG, ScreenShotSurface, NULL, NULL);
     // Increase i for next screenshot (Only allow up to 10 screenshots max for memory safety)
    if(i>=10)
      i = 1;
    else
      i++;

    screenShotSaved = true;
  }


thanks.

Share this post


Link to post
Share on other sites
Advertisement
First, that's a resource leak - GetBackBuffer() returns a pointer to a surface, so you newly created surface is lost. You're also not Release()ing the backbuffer pointer GetBackBuffer() gives you.

As for the actual problem, where are you calling that function? The correct place is after the last EndScene() call (and therefore after any ID3DXSprite::End() calls too), but before Present().

You should be using the Debug Runtimes, which will point out any obvious problems, and will show that memory leak I mentioned.

Share this post


Link to post
Share on other sites
Hi EvilSteve,

thanks for taking out the time to help me.


I forgot to mention I am releasing it in my CleanD3D() function:


if(ScreenShotSurface != NULL)
{
ScreenShotSurface->Release();
ScreenShotSurface = NULL;
}




and as for the screenshot function i am calling it:


AH DAMN!! THanks Steve, just realised when I was going to actually copy the code here that I am calling it before I draw the HUD in my render function.
I will change it to appear just before Present!

Another question I wanted to ask was about the FPS, I am calling my FPS function straight after:

d3ddev->Present(NULL, NULL, NULL, NULL);
// This will get the frames per second
GetFPS();

I will show my FPS function below, but what my problem is that I am getting around the region of 33 fps everytime? All I am doing in my program is calling a few .x meshes and rotating them. Is their a reason why my FPS is low?
Because I have seen similar tutorial demos, and in them I get FPS of about 220 or even one demo at 700fps.

I know this question is probably very awkward to answer as it depends on a lot of things but do you have any sujjesstions?

Here is my code:


// Gets and displays the Frames Per Second
void GetFPS()
{
// Hold the number of frames per second in between seconds
static float FPS = 0.0f;

// Check if a second has passed
float nextSecond = 0.0f;

// Last second that occured
static float prevSecond = 0.0f;

// Add to the frames per second every time this function is called
FPS++;

// Get the second in millisecond then convert to seconds (by multiplying 0.001)
nextSecond = GetTickCount() * 0.001f;

// If the time we have now substracted from the previous second is greater than
// or equal to 1 (i.e. if a second has passed) then we display the FPS number
if(nextSecond - prevSecond > 1.0f)
{
// Make the second we just got the previous second for next time the function is called
prevSecond = nextSecond;

// Display the FPS
sprintf_s(frames,"FPS: %d",int(FPS));

// Reset the FPS counter
FPS = 0;
}
}//End GetFPS



thanks alot for your help.

Share this post


Link to post
Share on other sites
Quote:
Original post by Nads
Hi EvilSteve,

thanks for taking out the time to help me.


I forgot to mention I am releasing it in my CleanD3D() function:

*** Source Snippet Removed ***

Why? Since you're not using it after you take the screenshot, you may as well release it as soon as you're done with it. This will also help prevent any mistakes; for example if you forget to call CleanD3D() every time you take a screenshot.

Share this post


Link to post
Share on other sites
GetTickCount() is extremely inaccurate, it's only got a granularity of about 25ms. So if a frame takes under 25ms, it'll report a time of 0ms.

You should use QueryPerformanceCounter instead, or timeGetTime (QPC has it's own issues).

Here's my timer class (Which may have bugs of its own [smile]):

Header:

//============================================================================
// PTimer.h - Timer class
//============================================================================

#ifndef __PTIMER_H__
#define __PTIMER_H__

#include <windows.h>

class PTimer
{
public:
PTimer();
~PTimer();

// Get the time taken for the last frame in ms
float GetFrameTime() const { return m_fFrameTime; }
//========================================================================

void BeginFrame();
void EndFrame();

protected:
float m_fFrameTime;

DWORD m_dwStartTime;
size_t m_nIndex;
bool m_bFirstLoop;

LARGE_INTEGER m_liFreq;
LARGE_INTEGER m_liStart;

static const size_t ms_nFramesAverage = 16;
float m_fFrameTimes[ms_nFramesAverage];
};

#endif // __PTIMER_H__




Source code:

//============================================================================
// PTimer.cpp - Timer class
//============================================================================
#include "PTimer.h"
#include <mmsystem.h>

#pragma comment(lib, "winmm.lib")

// Max time one frame can take (Clamped to this max value)
static const DWORD s_dwMaxFrameTime = 1000;

// Frame time threshold (in ms) under which QPC result is used
static const DWORD s_dwQPCThreshold = 5;

//============================================================================

PTimer::PTimer() :
m_dwStartTime(0),
m_nIndex(0),
m_bFirstLoop(true)
{
timeBeginPeriod(1);
QueryPerformanceFrequency(&m_liFreq);
m_liStart.QuadPart = 0;

for(size_t i=0; i<ms_nFramesAverage; ++i)
m_fFrameTimes = 0.0f;
}

PTimer::~PTimer()
{
timeEndPeriod(1);
}

//============================================================================

void PTimer::BeginFrame()
{
m_dwStartTime = timeGetTime();
QueryPerformanceCounter(&m_liStart);
}

void PTimer::EndFrame()
{
// Get frame time (via QPC and timeGetTime())
LARGE_INTEGER liFrameTime;
QueryPerformanceCounter(&liFrameTime);
liFrameTime.QuadPart -= m_liStart.QuadPart;
DWORD dwFrameTime = timeGetTime() - m_dwStartTime;
bool bUseTimeGetTime;
float fTime = 0.0f;

// If this was a fast frame, use QPC, and check results with timeGetTime
if(dwFrameTime < s_dwQPCThreshold)
{
fTime = ((float)(liFrameTime.QuadPart*1000) / (float)m_liFreq.QuadPart);

// Validate nonsense answers
if(fTime > (float)s_dwQPCThreshold)
bUseTimeGetTime = true;
else
bUseTimeGetTime = false;
}
else
bUseTimeGetTime = true;

// This was a slow frame, don't care what QPC says, use timeGetTime
if(bUseTimeGetTime)
{
if(dwFrameTime > s_dwMaxFrameTime)
dwFrameTime = s_dwMaxFrameTime;
fTime = (float)dwFrameTime;
}

// Record frame
m_fFrameTimes[m_nIndex++] = fTime;
if(m_nIndex >= ms_nFramesAverage)
{
m_bFirstLoop = false;
m_nIndex = 0;
}

// Calculate total
float fTotal = m_fFrameTimes[0];
for(size_t i=1; i<ms_nFramesAverage; ++i)
fTotal += m_fFrameTimes;

// Average
if(m_bFirstLoop)
m_fFrameTime = fTotal / (float)m_nIndex;
else
m_fFrameTime = fTotal / (float)ms_nFramesAverage;
}

//============================================================================




It's a bit complicated, but it uses QPC for quick frames (Since it's more accurate), and timeGetTime for slower ones. If QPC returns rubbish (Which it can do on dual-core CPUs with no CPU driver, and laptops), it falls back to timeGetTime(). And it also averages the FPS over 16 frames to stop it jumping around wildly.

Share this post


Link to post
Share on other sites
Quote:
Original post by Sc4Freak
Quote:
Original post by Nads
Hi EvilSteve,

thanks for taking out the time to help me.


I forgot to mention I am releasing it in my CleanD3D() function:

*** Source Snippet Removed ***

Why? Since you're not using it after you take the screenshot, you may as well release it as soon as you're done with it. This will also help prevent any mistakes; for example if you forget to call CleanD3D() every time you take a screenshot.



thanks, I will change that.

Share this post


Link to post
Share on other sites
Quote:
Original post by Evil Steve
GetTickCount() is extremely inaccurate, it's only got a granularity of about 25ms. So if a frame takes under 25ms, it'll report a time of 0ms.

You should use QueryPerformanceCounter instead, or timeGetTime (QPC has it's own issues).

Here's my timer class (Which may have bugs of its own [smile]):

Header:
*** Source Snippet Removed ***

Source code:
*** Source Snippet Removed ***

It's a bit complicated, but it uses QPC for quick frames (Since it's more accurate), and timeGetTime for slower ones. If QPC returns rubbish (Which it can do on dual-core CPUs with no CPU driver, and laptops), it falls back to timeGetTime(). And it also averages the FPS over 16 frames to stop it jumping around wildly.


Thanks Steve.

I did try using timeGetTime aswell last night, but it gave me the same result!

Your timer class looks highly complicated, but when I get home tonight (currently at work) I will try it out and see if I can understand and incorporate it into my demo.

Are you actually calling your begin and end functions in the render function, like how I called mine after ->Present()?

Do you use this timer class just for the FPS, or is it used for other things too?

Also in your header file you have:

PTimer();
~PTimer();

its probably a very beginner question but whats the ~ stand for?

Thanks.

Share this post


Link to post
Share on other sites
Quote:
Original post by Nads
Thanks Steve.

I did try using timeGetTime aswell last night, but it gave me the same result!
Did you call timeBeginPeriod(1); ? That increases the accuracy of timeGetTime() (Called from the constructor in my class).

Quote:
Original post by Nads
Your timer class looks highly complicated, but when I get home tonight (currently at work) I will try it out and see if I can understand and incorporate it into my demo.

Are you actually calling your begin and end functions in the render function, like how I called mine after ->Present()?

Do you use this timer class just for the FPS, or is it used for other things too?
Yeah, my main loop is:

void PApp::MainLoop()
{
do
{
m_timer.BeginFrame();
Loop(true);
m_timer.EndFrame();
} while(!ShouldExit());
}


Where Loop() does all the game logic and rendering. I only use the timer for keeping track of FPS currently, but there's no reason it couldn't be used for anything else - although you'd probably want to remove the frame time averaging code.


Quote:
Original post by Nads
Also in your header file you have:

PTimer();
~PTimer();

its probably a very beginner question but whats the ~ stand for?
The first function is the constructor, which is called when the object is created (And used to initialise any member variables and state). The second one (~PTimer) is the destructor, which is called when the object is destroyed (When it goes out of scope or it's deleted), and is used to clean up after the object.
For example, a rendering class might call IDirect3DDevice9::Release() from the destructor to make sure that the device was always cleaned up.

Share this post


Link to post
Share on other sites


Thanks again Steve.

Quote:
Did you call timeBeginPeriod(1); ? That increases the accuracy of timeGetTime() (Called from the constructor in my class).


No I didnt try that but will do tonight. But even then how much can it increase it by?? As I mentioned earlier I was getting about 33FPS, where I am expecting atleast over 100FPS. To me it just feels like I was doing the function wrong although i did take tips from many tutorials. Hence I dont think timeBeginPeriod(1) could fix it by that much (although I could be wrong and therefore will try it!)

Thanks for explaining about the deconstructor, it isnt something I had come across before but will also read up on it now that i know what it is.

Share this post


Link to post
Share on other sites
Quote:
Original post by Nads
No I didnt try that but will do tonight. But even then how much can it increase it by?? As I mentioned earlier I was getting about 33FPS, where I am expecting atleast over 100FPS. To me it just feels like I was doing the function wrong although i did take tips from many tutorials. Hence I dont think timeBeginPeriod(1) could fix it by that much (although I could be wrong and therefore will try it!)
From the timeGetTime docs: "Windows NT/2000: The default precision of the timeGetTime function can be five milliseconds or more, depending on the machine." 5ms would give you a max FPS of 200FPS though, so I would have thought the default should be fine.

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.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!