2007-02-23

Google project hosting

I was getting tired of waiting for shell service to come back to sourceforget so I searched for blogs talking about it, maybe they knew something I didn't- instead I found this entry http://icolor2.blogspot.com/2007/02/sourceforge-downtime.html which pointed me to google project hosting.

Almost immediately I created my own project http://code.google.com/p/binarymillenium/ and started uploading code. Initially I thought there was no support for screenshots but I then realized screenshots could be uploaded to svn and linked to from the wiki, although it automatically creates image for 'jpg' extensions but not 'JPG'.

I'm ready to quit sourceforge entirely, and leave all its frustrating user interface problems behind. It's one of those facets of the internet where big sites start up and then become sort of fossilized in whatever web technology was the state of the art or popular at the time, and then a new generation will rise up and replace them with superior web stuff- google web toolkit is the current new thing.

2007-02-21

Render-to-texture feedback with OSG

This actually doesn't use any of the screen capture code from the last post ( I'm still working out how to best use that) - it just does a good old fashioned glReadPixels to current the current opengl screen.


OSG Feedback from binarymillenium on Vimeo.

2007-02-19

Screen Capture with wxWindows

For reasons that will become clear when I post some more software and video, I need to have a general method of capturing any part of the screen and using it as a texture in custom applications.

Google searches for 'screen capture' 'capture screen' or 'screen grab' turn up a lot of other peoples shareware screen grab stuff, and lots of mailing lists where screen captures are provided of one thing or another but it's hardly ever about the code that did the work. How to find some usable code to do what I needed? The answer turned out to be sourceforge, where I found sseditor:

wxWin32ScreenShot.cpp

I was hoping there would have been a platform independent method where you just ask the video card to give you all the pixels, but it turns out to be windowing platform specific. This instance used Windows and wxWindows. I compiled wxWindows 2.8.0 for Cygwin and saw that the examples work. I then copied the screengrab code out of sseditor and put it in a wxWindows sample called 'drawing'. That worked after a little tweaking.

I then took the code and put it into a custom OSG application. There were lots of problems, and I was worried the wxWindows libraries or just using wxWindows in OSG at all was causing instability. I then ran into a problem where calling 'CreateCompatibleBitmap' failed after exactly 153 calls, but it turned out I needed to call DeleteObject on the HBITMAP before calling CreateCompatible repeatedly, I was using up graphics memory and not freeing it.

Also, I had to call wxInitialize() and wxUninitialize() at the beginning and end of my program.



void wxScreenCapture(wxDC& dc)
{
int sizeX = 0;
int sizeY = 0;
sizeX = tex_width; //GetSystemMetrics(SM_CXSCREEN);
sizeY = tex_height; //GetSystemMetrics(SM_CYSCREEN);

compat_counter++;

bmp->SetHeight(sizeY);
bmp->SetWidth(sizeX);


HDC mainWinDC = GetDC(GetDesktopWindow());
HDC memDC = CreateCompatibleDC(mainWinDC);

if (bitmap != NULL) DeleteObject(bitmap);

bitmap = CreateCompatibleBitmap(mainWinDC,tex_width,tex_height);

if (bitmap == NULL) {
std::cerr << "CreateCompatibleBitmap failed at " <<
compat_counter << ", " <<
mainWinDC << " " << tex_width << " " <<
tex_height << std::endl;
exit(1);
return;
}

HGDIOBJ hOld = SelectObject(memDC,bitmap);
BitBlt(memDC, 0, 0,sizeX,sizeY, mainWinDC, 20, 20, SRCCOPY);
SelectObject(memDC, hOld);
DeleteDC(memDC);
ReleaseDC(GetDesktopWindow(), mainWinDC);
bmp->SetHBITMAP((WXHBITMAP)bitmap);
if (bmp->Ok() ) {
//dc.DrawText( _T("BMP ok"), 30, 20 );

} else {
//dc.DrawText( _T("BMP not ok"), 30, 20 );
std::cerr << "bmp not ok" << std::endl;
return;
}

if (savewximage) {
bmp->SaveFile( wxT("/cygdrive/b/text.bmp"), wxBITMAP_TYPE_BMP);
}



My other problem was that I didn't know how to translate between the wxBitmap format of wxWindows and the texture format of the osg::Image. The first way I made it work was by writing the bitmap to disk using a wxWindows function then loading that bmp to a texturing in OSG- this worked but was hard on the disk drive for high rate screen capturing, but writing to a ramdisk can fix that.

But the seeming right way to do it:


/// get image from desktop in wxBitmap format,
// convert it to osg::Image format
wxAlphaPixelData rawbmp(*bmp, wxPoint(0,0),
wxSize(tex_width, tex_height));
wxAlphaPixelData::Iterator p(rawbmp);

image->allocateImage(tex_width, tex_height,
1, GL_RGBA, GL_FLOAT);

/// image is an osg::Image
float* img_data = (float*)image->data();
for (unsigned i = 0; (i < tex_height); i++) {
for (unsigned j = 0; (j < tex_width); j++) {

int ind = i*tex_width + j;

bool flip = ((i > tex_height/4-1) && (i < 3*tex_height/4)
&& (j > tex_width/4-1) && (j < 3*tex_width/4));

img_data[ind*4] = flip ? 1.0 - p.Red()/255.0 : p.Red()/255.0;

img_data[ind*4+1] = flip ? 1.0 - p.Green()/255.0 : p.Green()/255.0;

img_data[ind*4+2] = flip ? 1.0 - p.Blue()/255.0 : p.Blue()/255.0;

img_data[ind*4+3] = 1.0;

p.MoveTo(rawbmp, j, tex_height-1-i);
}
}



The flip code seems really wierd, but it was necessary.

Anyway, after all that I felt pretty proud of myself for hacking a working screencap together over a couple of days, not knowing anything about windowing toolkits before that (I've always known enough about them to try and avoid them like the plague, there's no uglier code than window gui widget code).

The only libraries needed for wxWindows are -lwx_base-2.8 and -lwx_msw_core-2.8, though there will be warnings about other wx libs getting auto imported.