Game Development Community

dev|Pro Game Development Curriculum

Save a portion of the screen

by Dave Young · 04/24/2008 (8:56 am) · 7 comments

In game.cc, after the console screenshot function, add in:

ConsoleFunction(saveBitmapXY, void, 3, 3, "(string file, coords startx starty extentx extenty)"
                "Save a portion of the screen, must be in powers of 2.")
{
   Point2I tstart;
   Point2I tend;
   Point2I extent;
   dSscanf(argv[2],"%d %d %d %d",&tstart.x,&tstart.y,&extent.x,&extent.y);

   if(isPow2(extent.x)==false || isPow2(extent.y)==false)
   {
	   Con::errorf("Height and width must be power of 2");
	   return;
   }

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

   U8 * pixels = new U8[extent.x * extent.y * 3];
   glReadPixels(tstart.x, tstart.y, extent.x, extent.y, GL_RGB, GL_UNSIGNED_BYTE, pixels);

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

   // 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));

   bitmap->writePNG(fStream);

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

Recompile, and add lemon.

Usage: SaveBitmapXY("newpicture.png","10 10 256 256"); Coordinates are from lower left!

The height and width must be in powers of 2 but don't have to be square.

In the version below, the coordinates are from upper left origin, and it will bump up the allocated bitmap automatically to be pow2.

ConsoleFunction(saveBitmapXY, void, 3, 3, "(string file, coords startx starty extentx extenty)"
                "Save a portion of the screen, from upper left")
{
   Point2I tstart;
   Point2I extent;
   dSscanf(argv[2],"%d %d %d %d",&tstart.x,&tstart.y,&extent.x,&extent.y);
   Point2I cextent = Canvas->getExtent();

   //Con::errorf("Incoming size %d %d",extent.x, extent.y);

   if(isPow2(extent.x)==false || isPow2(extent.y)==false)
   {
	   //Con::errorf("Height and width must be power of 2");
	   extent.x = getNextPow2(extent.x);
	   extent.y = getNextPow2(extent.y);
	   //Con::errorf("Revised size %d %d",extent.x, extent.y);
	   //return;
   }

   //Make the starting point relative to lower left corner
   tstart.y = cextent.y - extent.y - tstart.y;

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

   U8 * pixels = new U8[extent.x * extent.y * 3];

   GBitmap * bitmap = new GBitmap;
   bitmap->allocateBitmap(U32(extent.x), U32(extent.y),false,GBitmap::RGB);
   glReadPixels(tstart.x, tstart.y, extent.x, extent.y, GL_RGB, GL_UNSIGNED_BYTE, pixels);

   // 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));

   bitmap->writePNG(fStream);

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

#1
04/24/2008 (9:52 am)
A handy addition to a feature like this is a simple wrapper which takes a snapshot of exactly the region covered by a particular guiControl.

eg
supporting console method:
in GuiControl.cc, somewhere near the ConsoleMethod resize(), add:
ConsoleMethod( GuiControl, getScreenPosition, const char*, 2, 2, "")
{
   char *retBuffer = Con::getReturnBuffer(64);
   Point2I pos = object->localToGlobalCoord(Point2I(0, 0));
   dSprintf(retBuffer, 64, "%d %d", pos.x, pos.y);
   return retBuffer;
}

and here's a script wrapper.
this is script, so can go nearly anywhere,
but a reasonable place might be at the bottom of common/client/screenshot.cs:
function GuiControl::SaveBitmap(%this, %filename)
{
   %start  = %this.getScreenPosition();
   %extent = %this.getExtent();
   return saveBitmapXY(%filename, %start SPC %extent);
}

we use this in vSide to give the user a camera w/ a resizable view-finder to let them take snapshots of various parts of the screen.
#2
04/24/2008 (3:37 pm)
Sounds interesting, one problem though
Quote:In game.cs

Shouldn't that be game.cc?
#3
04/24/2008 (5:13 pm)
Aye Nathan, it should be ;) Thanks. Good tip Orion. I've expanded my usage for a few specific things, this is one of them :)
#4
05/03/2008 (2:54 pm)
This is great. Thanks!!!
#5
05/06/2008 (2:46 am)
@Orion: good addiction... since I'm really really a noob... where I have to put those pieces of code?

Tnx :)
#6
05/06/2008 (9:12 am)
joz - added some suggested locations to my post, above.
#7
05/06/2008 (2:25 pm)
Tnx Orion :-)
Really I think you are on the top list of the post I looked to... :-D