Post subject: A project I'm working on... (Programmers advice please)
Joined: 6/20/2004
Posts: 292
Location: United Kingdom
I'm working on a project (unfortunately I can't say until I've finished with it) and I'm wondering if I could have some advice from people here (C++ programmers specifically). It's involved with computer games (emulator or other). What I need to be able to do is take a screenshot of the game, which I then need to know what colour each pixel is. I also need to be able to output a control to the game (like pressing a button or moving left/right on d-pad). This involves using C++ (as you've probably guessed already) and I was wondering if anyone had any ideas or advice on how to do this. Thanks a lot for whatever help you give. Edit: I have access to both Windows and Linux for this, so people from both sides are welcome.
Post subject: Re: A project I'm working on... (Programmers advice requeste
Editor, Active player (297)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
You can use libgd for portable handling of images. For an example, here is how I capture screenshots in Dega:
#include <gd.h>
static void CreatePNG(const char* beauty_fn)
{
    FILE*fp = fopen(beauty_fn, "wb");
    if(!fp) { perror(beauty_fn); return; }
    
    // xbuf, width, height
    gdImagePtr im = gdImageCreateTrueColor(width,height);
    for(unsigned y=0; y<height; ++y)
        for(unsigned x=0; x<width; ++x)
        {
            const unsigned char* pixptr = &xbuf[(x + y * width)*3];
            unsigned rr = pixptr[2];
            unsigned gg = pixptr[1];
            unsigned bb = pixptr[0];
            gdImageSetPixel(im, x,y, (rr<<16)|(gg<<8)|(bb<<0));
        }
    
    gdImagePng(im, fp);
    gdImageDestroy(im);
    fclose(fp);  
}
xbuf is here a pointer to the image rendered by the emulator; it is an array of 3-byte (BGR) pixels ordered from left to right, up to down.
Tub
Joined: 6/25/2005
Posts: 1377
it really depends on the location of your image. If you're rendering everything in software into a simple array before rendering it onto your screen (like most emulators for 2D systems do), bisqwit's solution works well. If you're using some other mechanism to render the image in video memory, it'll be a bit more work. You can still use GD to save the image, but you'll need to get a copy of the framebuffer first. How to accomplish that depends on the API(s) you used for rendering.
m00
Joined: 6/20/2004
Posts: 292
Location: United Kingdom
I'm sorry, after re-reading my post I guess it wasn't very clear at all... I was more meaning of taking a screenshot of another program. The same for the control.
Editor, Active player (297)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
AdmiralJonB wrote:
I'm sorry, after re-reading my post I guess it wasn't very clear at all... I was more meaning of taking a screenshot of another program. The same for the control.
Oh. For that there is no portable solution. It depends on the windowing system. In X11, you can loop recursively through XQueryTree() results to find a window by its name, and then XGetImage() to read the image into a buffer. If you require high speed, you can use XShmGetImage() instead, though it requires that the X server is local and supports the XShm extension. After you have the frame buffer, you can write it into a file using the code I gave earlier. A much easier solution is to call externally a program that already does the job, such as import from imagemagick. In Microsoft Windows, the API for reading the contents of different windows is different. You can find such documentation on MSDN; I don't know anything about them except that it involves a lot of capital letters. And of course other windowing systems exist too. As said, not portable method exists. And to control another window... the same thing applies here. What are you trying to, a Minesweeper cheating program? Or are you intending to creates TASes of some games by scripting the input using external program and recording the output?
HHS
Active player (286)
Joined: 10/8/2006
Posts: 356
In Windows: 1. Create a bitmap with CreateDIBSection 2. Retrieve the window handle using FindWindow 3. Use the GetDC function to retrieve a DC for the interior rectangle of the window 4. Copy the rectangle with BitBlt 5. Release the DC and delete the bitmap You control the other application's input using the SendInput function. You'll probably have to install synchronization code in the other application (with WriteProcessMemory) so that you can control its execution and ensure that the input is processed at the proper time. You also have to intercept any code that relies on time and other external variables so that you can produce a predictable result.