Game Development Community

dev|Pro Game Development Curriculum

Screenshots don't overwrite existing

by Josh Moore · 04/11/2006 (2:02 pm) · 4 comments

The current screenshot system uses saved pref variables for naming so that the code doesn't create new screenshots to overwrite existing files(and to give your screenshots some kind of order). The problem with this is that sometimes the prefs do not get saved, and sometimes they get deleted. This resource will make a call to screenshot(...); fail if there's a file with the same name already in existance, and will attempt 3 more screenshots automaticly.

So first of all, open engine/game/game.cc and find:
ConsoleFunction(screenShot, void.......

and replace the entire function with:
ConsoleFunction(screenShot, bool, 3, 3, "(string file, string format)"
                "Take a screenshot.\n\n"
                "@param format One of JPEG or PNG.")
{
   // Added so screenshots cannot overwrite previous ones - JM
   if(Platform::isFile(argv[1]))
      return false;

   FileStream fStream;
   if(!fStream.open(argv[1], FileStream::Write))
   {
      Con::printf("Failed to open file '%s'.", argv[1]);
      return false;
   }

   glReadBuffer(GL_FRONT);

   Point2I extent = Canvas->getExtent();
   U8 * pixels = new U8[extent.x * extent.y * 3];
   glReadPixels(0, 0, extent.x, extent.y, GL_RGB, GL_UNSIGNED_BYTE, pixels);

   GBitmap * bitmap = new GBitmap;
   bitmap->allocateBitmap(U32(extent.x), U32(extent.y));

   // flip the rows
   for(U32 y = 0; y < extent.y; y++)
      dMemcpy(bitmap->getAddress(0, extent.y - y - 1), pixels + y * extent.x * 3, U32(extent.x * 3));

   if ( dStrcmp( argv[2], "JPEG" ) == 0 )
      bitmap->writeJPEG(fStream);
   else if( dStrcmp( argv[2], "PNG" ) == 0)
      bitmap->writePNG(fStream);
   else
      bitmap->writePNG(fStream);

   fStream.close();
   delete [] pixels;
   delete bitmap;

   return true;
}

As you can tell, I've changed the return type of screenshot(...); to a boolean and added a Platform::isFile check to the function(as well as adding the proper returns where needed).

Save and compile.


OK, so now your screenshots will not overwrite existing ones. Great, so how can we make it so it'll at least try to take the screenie if it fails at first?

Easy, open up common/client/screenshot.cs and replace:
if($pref::Video::screenShotFormat $= "JPEG")
         screenShot($name @ ".jpg", "JPEG");
      else
         if($pref::Video::screenShotFormat $= "PNG")
            screenShot($name @ ".png", "PNG");
      	 else
            screenShot($name @ ".png", "PNG");

with:
if($pref::Video::screenShotFormat $= "JPEG") {
         if(!screenShot($name @ ".jpg", "JPEG")) {
            error("Screenshot failed! Attempting 3 more times.");
            // Screenshot failed, try 3 more times
            for(%i = 0; %i < 3; %i++) {
                $name = "screenshot_" @ formatSessionNumber($pref::Video::screenShotSession) @ "-" @ formatImageNumber($screenshotNumber++);
                if(screenShot($name @ ".jpg", "JPEG")) break;
                error("Screenshot("@ %i+1 @") failed!");
            }
         }
      }
      else {
         if(!screenShot($name @ ".png", "PNG")) {
            error("Screenshot failed! Attempting 3 more times.");
            // Screenshot failed, try 3 more times
            for(%i = 0; %i < 3; %i++) {
                $name = "screenshot_" @ formatSessionNumber($pref::Video::screenShotSession) @ "-" @ formatImageNumber($screenshotNumber++);
                if(screenShot($name @ ".png", "PNG")) break;
                error("Screenshot("@ %i+1 @") failed!");
            }
         }
      }

Now it will try to take the shot 3 extra times if it fails at first, awesome.

#1
04/11/2006 (5:23 pm)
Note that the script stuff is not needed, I just included it as I'm using it.
#2
06/01/2006 (12:03 pm)
Well I hadn't gotten to this yet, but thank you in advance.
#3
01/29/2007 (11:16 pm)
Great Work!!!
#4
03/04/2012 (8:53 pm)
Still useful in 2012!