OpenGL - render directly to bitmap

前端 未结 1 513
旧巷少年郎
旧巷少年郎 2021-02-06 12:33

I am making an application that has a bunch of small windows and controls in it (2D rendering), and I would like to render each window and control to its own bitmap. This is wha

相关标签:
1条回答
  • 2021-02-06 12:50

    OpenGL contexts must be created matching the target device context. For windows they're created in a different way than for bitmaps. See http://msdn.microsoft.com/en-us/library/windows/desktop/dd368826(v=vs.85).aspx notably the dwFlags, where there are among others

    PFD_DRAW_TO_WINDOW The buffer can draw to a window or device surface.

    PFD_DRAW_TO_BITMAP The buffer can draw to a memory bitmap.

    However you shouldn rush ahead and create a render context for your DIB DC. Why? Because it will be slow as hell, as OpenGL render contexts on a DIB section will use a software rasterizer supporting only OpenGL-1.1 running on the CPU.

    Instead you should create a Framebuffer Object, attach a color renderbuffer attachment and when finished to a glReadPixels into your DIBSection. Much easier, much faster.

    Update due to comment request

    (I have no idea why StackOverflow doesn't get the syntax coloring right, i.e. figuring out where's a comment and where not)

    // flushes the OpenGL error queue and
    // counts the total number of errors
    int flushGLErrors(void)
    {
        int i = 0;
        while( glGetError() != GL_NO_ERROR ) {
            i++;
        }
    
        return i;
    }
    
    // returns a HBITMAP or NULL.
    // The HBITMAP must be freed using DeleteObject 
    HBITMAP ReadPixelsToHBITMAP(
        int x,
        int y,
        int width,
        int height )
    {
        void *pdata = NULL;
    
        /* Note that this values only makes sense if we know a target
         * output size like if we put the image to paper. */ 
        const int physical_resolution = 2835; /* 72 DPI */
    
        BITMAPINFOHEADER bmih = {
            /* .biSize          = */ sizeof(bmih),
            /* .biWidth         = */ width,
            /* .bi.Height       = */ height,
            /* .biPlanes        = */ 1,                   /* mandatory */
            /* .biBitCount      = */ 24,                  /* 8 bits per pixel */
            /* .biCompression   = */ BI_RGB,              /* uncompressed */
            /* .biSizeImage     = */ 0,                   /* implicit */
            /* .biXPelsPerMeter = */ physical_resolution, /* ignored */
            /* .biYPelsPerMeter = */ physical_resolution, /* ignored */
            /* .biClrUsed       = */ 0,                   /* no palette */
            /* .biClrImportant  = */ 0
        };
    
        HBITMAP hbm = CreateDIBSection(
            hdc, /* may be different than the DC used for OpenGL */
            (PBITMAPINFO)&bmih, /* can do this cast, because no palette is used */
            DIB_RGB_COLORS,
            &pdata,
            NULL,
            0
        );
    
        if( !hbm ) {
            return NULL;
        }
    
        flushGLErrors();
    
        glPixelStorei(GL_PACK_SWAP_BYTES,   GL_FALSE);
        glPixelStorei(GL_PACK_LSB_FIRST,    GL_TRUE);
        glPixelStorei(GL_PACK_ROW_LENGTH,   0);
        glPixelStorei(GL_PACK_IMAGE_HEIGHT, 0);
        glPixelStorei(GL_PACK_SKIP_PIXELS,  0);
        glPixelStorei(GL_PACK_SKIP_ROWS,    0);
        glPixelStorei(GL_PACK_ALIGNMENT,    1);
    
        if( glGetError() != GL_NO_ERROR ) {
            DeleteObject(hbm);
            return NULL;
        }
    
        glReadPixels(x, y, width, height, GL_BGR, GL_UNSIGNED_BYTE, pdata);
    
        if( glGetError() != GL_NO_ERROR ) {
            DeleteObject(hbm);
            return NULL;
        }
    
        return hbm;
    }
    
    0 讨论(0)
提交回复
热议问题