Jump to content
  • Advertisement
Sign in to follow this  

OpenGL Capturing screen and creating an opengl texture

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

Hello, for the purpose of my game, I need to capture the entire screen and generate an opengl texture out of it. Currently, I am using GDI to do the work, the code is as follows: (sorry for the length of the code, but I think you need to see what's happening, I explain what I am doing after the code block.)
HBITMAP DesktopCapturer::captureScreen()

	HDC         hScrDC, hMemDC;         // screen DC and memory DC     
	int         nX, nY, nX2, nY2;       // coordinates of rectangle to grab     
	int         nWidth, nHeight;        // DIB width and height     
	int         xScrn, yScrn;           // screen resolution      

	HGDIOBJ     hOldBitmap , hBitmap;
   // create a DC for the screen and create     
   // a memory DC compatible to screen DC          

   hScrDC = CreateDC("DISPLAY", NULL, NULL, NULL);     
   hMemDC = CreateCompatibleDC(hScrDC);      // get points of rectangle to grab  
   DisplayMode desktop = Graphics().GetDesktopDisplayMode();

   nX = 0;
   nY = 0;
   nX2 = desktop.Width;
   nY2 = desktop.Height;
   nWidth = nX2 - nX;     
   nHeight = nY2 - nY;      
   // create a bitmap compatible with the screen DC     
   hBitmap = CreateCompatibleBitmap(hScrDC, nWidth, nHeight);      
   // select new bitmap into memory DC     
   hOldBitmap =   SelectObject (hMemDC, hBitmap);      
   // bitblt screen DC to memory DC     
   BitBlt(hMemDC, 0, 0, nWidth, nHeight, hScrDC, nX, nY, SRCCOPY | CAPTUREBLT);     
   // select old bitmap back into memory DC and get handle to     
   // bitmap of the screen          
   hBitmap = SelectObject(hMemDC, hOldBitmap);      
   // clean up      
   // return handle to the bitmap      
   return (HBITMAP)hBitmap; 

bool DesktopCapturer::convertToDib(HBITMAP &hBitmap)
	bool bConverted = false;
  BITMAP stBitmap;
  if (GetObject(hBitmap, sizeof(stBitmap), 
            &stBitmap) && !stBitmap.bmBits)
    // that is a DFB. Now we attempt to create

    // a DIB with the same sizes and pixel format.

    HDC hScreen = GetDC(NULL);
    if (hScreen)
      union {
        BITMAPINFO stBitmapInfo;
        BYTE pReserveSpace[sizeof(BITMAPINFO) 
                     + 0xFF * sizeof(RGBQUAD)];
      ZeroMemory(pReserveSpace, sizeof(pReserveSpace));
      stBitmapInfo.bmiHeader.biSize = sizeof(stBitmapInfo.bmiHeader);
      stBitmapInfo.bmiHeader.biWidth = stBitmap.bmWidth;
      stBitmapInfo.bmiHeader.biHeight = stBitmap.bmHeight;
      stBitmapInfo.bmiHeader.biPlanes = 1;
      stBitmapInfo.bmiHeader.biBitCount = stBitmap.bmBitsPixel;
      stBitmapInfo.bmiHeader.biCompression = BI_RGB;

      if (stBitmap.bmBitsPixel <= 8)
        stBitmapInfo.bmiHeader.biClrUsed = 
                        1 << stBitmap.bmBitsPixel;
        // This image is paletted-managed.

        // Hence we have to synthesize its palette.

      stBitmapInfo.bmiHeader.biClrImportant = 

      PVOID pBits;
      HBITMAP hDib = CreateDIBSection(hScreen, 
        &stBitmapInfo, DIB_RGB_COLORS, &pBits, NULL, 0);

      if (hDib)
        // ok, we're lucky. Now we have

        // to transfer the image to the DFB.

        HDC hMemSrc = CreateCompatibleDC(NULL);
        if (hMemSrc)
          HGDIOBJ hOldSrc = SelectObject(hMemSrc, hBitmap);
          if (hOldSrc)
            HDC hMemDst = CreateCompatibleDC(NULL);
            if (hMemDst)
              HGDIOBJ hOldDst = SelectObject(hMemDst, hDib);
              if (hOldDst)
                if (stBitmap.bmBitsPixel <= 8)
                  // take the DFB's palette and set it to our DIB

                  HPALETTE hPalette = 
                    (HPALETTE) GetCurrentObject(hMemSrc, OBJ_PAL);
                  if (hPalette)
                    PALETTEENTRY pPaletteEntries[0x100];
                    UINT nEntries = GetPaletteEntries(hPalette, 
                                    0, stBitmapInfo.bmiHeader.biClrUsed, 
                    if (nEntries)
                      for (UINT nIndex = 0; nIndex < nEntries; nIndex++)
                        pPaletteEntries[nEntries].peFlags = 0;
                      SetDIBColorTable(hMemDst, 0, 
                        nEntries, (RGBQUAD*) pPaletteEntries) == nEntries;


                // transfer the image using BitBlt function.

                // It will probably end in the

                // call to driver's DrvCopyBits function.

                if (BitBlt(hMemDst, 0, 0, stBitmap.bmWidth, 
                      stBitmap.bmHeight, hMemSrc, 0, 0, SRCCOPY))
                  bConverted = true; // success

                SelectObject(hMemDst, hOldDst);
            SelectObject(hMemSrc, hOldSrc);

        if (bConverted)
          DeleteObject(hBitmap); // it's no longer needed

          hBitmap = hDib;
      ReleaseDC(NULL, hScreen);
  return bConverted;


void DesktopCapturer::Init()
        gdi_bitmap = captureScreen();

	convertToDib (gdi_bitmap);
	GetObject (gdi_bitmap, sizeof(BITMAP), &gdi_bitmap_data);

	data_size = gdi_bitmap_data.bmWidth * gdi_bitmap_data.bmHeight * 4;
	// convert from BGR to RGB:
	for (int i=0; i<data_size; i+=4)
		unsigned char tmp = ((unsigned char*)gdi_bitmap_data.bmBits);
		((unsigned char*)gdi_bitmap_data.bmBits) = ((unsigned char*)gdi_bitmap_data.bmBits)[i+2];
		((unsigned char*)gdi_bitmap_data.bmBits)[i+2] = tmp;

What the above code does is to take a screenshot of the whole screen, convert it to DIB format, and use this DIB BITMAP for generating a texture from the bmBits field. Before creating the texture, I convert the BGRA to RGBA for use with SOIL. The method called to capture the desktop is "Init", at the program start. After that, I use SOIL library to create an opengl texture from the bmBits member of the gdi_bitmap_data, which works excellent on my 2 Windows 7 machines. The problem comes when I run the program on Windows XP SP3, with an 9800GT. Given the fact that the texture loading happens correctly in both cases, I think it's something to do with the GDI capture code. Here is a screenshot of the problem. You see that not all the colours are displayed. More importantly, it seems that only the icons are captured, the rest is black, as I see it. problematic: Free Image Hosting at www.ImageShack.us normal desktop: Free Image Hosting at www.ImageShack.us And here is a working screenshot, from a Windows 7 system (GMA950). Free Image Hosting at www.ImageShack.us That's it, I am sorry for the post length again. I hope you can help me out here. Thank you

Share this post

Link to post
Share on other sites
Just look at the color of the Quicktime icon. It used to be blue but in your crapped version its orange. That leads me to the assumption that you store the pixels in a different order such as ARGB written to RGBA without changing the color layout. Hence you most likely screw the alpha value and get a black color due to either OpenGL color blending settings or the mixed up pixel color is just this black color.

Make sure you read and store the RGBA color components in the necessary formats.

Share this post

Link to post
Share on other sites
Could the capturing mode using the above GDI method produce different pixel formats in different systems?
If so, how can I check that and make the correct conversions?

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.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!