how to save the opengl scene to a bitmap?

how to save the opengl scene to a bitmap?

I am new to opengl, i want save my current opengl scene to a bitmap. I checked the "red book", and i know i should use "glReadPixels" to read pixels from "pixel buffer",but
i don't know how to swap "frame buffer"  to "pixel buffer". Could you give me some code?
thank you.
bloodbirdAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Ferruccio AccalaiSenior developer, analyst and customer assistance Commented:
Take a look a this thread, just like a point of start http://www.mofeel.net/312-comp-graphics-api-opengl/3919.aspx
0
ikeworkCommented:
Hi bloodbird,

Once I wrote a class, that does the job. The usage is as easy as this:

    CBitmap24 bitmap;
    if( !bitmap.CreateFromCurrentGLContext() ) return false;
    if( !bitmap.Save( "c:/y.bmp" ) ) return false;

Hope it helps. Feel free to ask for details :)

Below is the header, just add appropriate typedefs for the used types
#ifndef DAGL_BITMAP24BGR_INCLUDED
#define DAGL_BITMAP24BGR_INCLUDED

/*

http://web.uccs.edu/wbahn/ECE1021/STATIC/REFERENCES/bmpfileformat.htm

The pixel data in a BMP file is scan line padded to a 32-bit (4-byte) boundary. 
What this means is that if you have a 1071x363 24-bit image, that each scan line 
(one row of data in the image) consists of 363 pixels each of which requires 
3-bytes (24-bits) to encode. Thus you have 1,089 bytes of data per line. 
The format requires that scan lines be multiples of 4-bytes so 3 null bytes 
(value is zero) are added to the end of the data for each line to make a total 
of 1,092 (4x273) bytes per line.
*/

#include <cassert>

namespace dagl
{

    class CBitmap24
    {
    public:
        CBitmap24();
        virtual ~CBitmap24();

        enum ByteOrder
        {
            BO_Unknown = -1,
            BO_RGB = 0,
            BO_BGR
        };

        virtual void    Destroy();
        bool            Init( uint32 width, uint32 height );

        bool            CreateFromBitmapData( uint32 width, uint32 height, myubyte *pData );

        bool            CreateFromCurrentGLContext();
        void            ReverseByteOrder();

        bool            Load( const char *pszFileName );

        bool            Save( const char *pszFileName ) const;
        bool            WriteBitmapFileIntoBuffer( myubyte *pBuffer ) const;

        ByteOrder       GetByteOrder() const { return m_ByteOrder; }
        uint32          GetBitmapFileSize() const;
        uint32          GetWidth() const { return m_ui32Width; }
        uint32          GetHeight() const { return m_ui32Height; }
        uint32          GetDataSize() const { return m_ui32DataSize; }
        uint32          GetPaddedRowSize() const { return m_ui32PaddedRowSize; }
        bool            IsEmpty() const { return (bool)( m_pData == NULL ); }
        myubyte const*  GetDataPtr() const { return m_pData; }

        virtual bool    Copy( CBitmap24 const &b );

        static uint32   GetPaddedRowSize( uint32 width );

    protected:
        myubyte*        GetDataPtr() { return m_pData; }
        void            SetByteOrder( ByteOrder b ) { assert( b == BO_RGB || b == BO_BGR ); m_ByteOrder = b; }

    private:
        ByteOrder   m_ByteOrder;
        // number of pixel in x
        uint32      m_ui32Width;
        // number of pixel in y
        uint32      m_ui32Height;
        // one row (in x) is padded to 4 byte
        uint32      m_ui32PaddedRowSize;
        uint32      m_ui32DataSize;
        uint32      m_ui32BitmapFileSize;
        myubyte     *m_pData;

        static uint16 const ms_ui16Planes;
        static uint16 const ms_ui16Bpp;
        static uint32 const ms_ui32BitmapFileDataOffset;
        static uint32 const ms_ui32InfoHeaderSize;
        static myubyte const ms_unusedColorInfo[ 16 ];
    };

    inline
    uint32 CBitmap24::GetBitmapFileSize() const
    {
        assert( m_pData );
        return m_ui32BitmapFileSize;
    }

}

#endif // #ifndef DAGL_BITMAP24BGR_INCLUDED

Open in new window

0
ikeworkCommented:
And here is the source-file:
#include <dagl/bitmap24.h>

#if defined( WIN32 )
#  define WIN32_LEAN_AND_MEAN
#  include <windows.h>
#endif
#include <GL/gl.h>

using namespace dagl;

#define EFFICIENT_SIZE( x, efficient_alignment ) ((int)(((((int)(x))-1)|(((int)(efficient_alignment))-1))+1))
#define ALIGN_SIZE( x, alignment ) EFFICIENT_SIZE( (x), (alignment) )

uint16 const CBitmap24::ms_ui16Planes = 1;
uint16 const CBitmap24::ms_ui16Bpp = 24;
uint32 const CBitmap24::ms_ui32BitmapFileDataOffset = 0x36;
uint32 const CBitmap24::ms_ui32InfoHeaderSize = 0x28;
myubyte const CBitmap24::ms_unusedColorInfo[ 16 ] =
{

                                        0x12, 0x0B,
    0x00, 0x00, 0x12, 0x0B, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};


CBitmap24::CBitmap24()
: m_ByteOrder( BO_Unknown ),
  m_ui32Width( 0 ),
  m_ui32Height( 0 ),
  m_ui32DataSize( 0 ),
  m_ui32BitmapFileSize( 0 ),
  m_pData( NULL )
{
}

CBitmap24::~CBitmap24()
{
    Destroy();
}

void CBitmap24::Destroy()
{
    if( m_pData )
    {
        delete[] m_pData;
        m_pData = NULL;

        m_ByteOrder = BO_Unknown;
        m_ui32Width = m_ui32Height = m_ui32DataSize = m_ui32BitmapFileSize = 0;
    }
}

void CBitmap24::ReverseByteOrder()
{
    assert( m_ByteOrder != BO_Unknown );

    GLubyte temp;
    GLubyte *pCol, *pUpper;
    GLubyte const *pColEnd;
    size_t rowDataLen = m_ui32Width * 3;
    GLubyte *pRow = m_pData;
    GLubyte const *const pRowEnd = m_pData + m_ui32DataSize;
    for( ; pRow < pRowEnd; pRow += m_ui32PaddedRowSize )
    {
        pCol = pRow;
        pColEnd = pRow + rowDataLen;
        for( ; pCol < pColEnd; pCol += 3 )
        {
            pUpper = pCol + 2;
            temp = *pCol;
            *pCol = *pUpper;
            *pUpper = temp;
        }
    }
    if( m_ByteOrder == BO_RGB ) m_ByteOrder = BO_BGR;
    else m_ByteOrder = BO_RGB;
}

/*
The pixel data in a BMP file is scan line padded to a 32-bit (4-byte) boundary. 
What this means is that if you have a 1071x363 24-bit image, that each scan line 
(one row of data in the image) consists of 363 pixels each of which requires 
3-bytes (24-bits) to encode. Thus you have 1,089 bytes of data per line. 
The format requires that scan lines be multiples of 4-bytes so 3 null bytes 
(value is zero) are added to the end of the data for each line to make a total 
of 1,092 (4x273) bytes per line.
*/

bool CBitmap24::CreateFromCurrentGLContext()
{
    Destroy();

    GLint viewport[ 4 ];
    glGetIntegerv( GL_VIEWPORT, viewport );

    int const intWidth = viewport[ 2 ];
    int const intHeight = viewport[ 3 ];

    // width must be an even number
    //assert( !( intWidth % 2 ) );

    if( !Init( intWidth, intHeight ) ) return false;

    //glPixelStorei( GL_PACK_ALIGNMENT, 1 );
    glPixelStorei( GL_PACK_ALIGNMENT, 4 );
    //glRasterPos2i( 0, 0 );
    glReadPixels( 0, 0, intWidth, intHeight,
                  GL_RGB, GL_UNSIGNED_BYTE, m_pData );

    m_ByteOrder = BO_RGB;

//  GL_BGR not supported by my version ;(
//  glReadPixels( 0, 0, intWidth, intHeight,
//      GL_BGR, GL_UNSIGNED_BYTE, bitmap.pImage );

    // bitmap needs format bgr...
    ReverseByteOrder();

    assert( glGetError() == GL_NO_ERROR );

    return true;
}

bool CBitmap24::Copy( CBitmap24 const &b )
{
    // needs to be destroyed before !!!
    assert( !m_pData );

    if( b.m_ui32DataSize )
    {
        m_pData = new myubyte[ b.m_ui32DataSize ];
        if( !m_pData ) return false;
        memcpy( m_pData, b.m_pData, b.m_ui32DataSize );
    }

    m_ByteOrder = b.m_ByteOrder;
    m_ui32Width = b.m_ui32Width;
    m_ui32Height = b.m_ui32Height;
    m_ui32PaddedRowSize = b.m_ui32PaddedRowSize;
    m_ui32DataSize = b.m_ui32DataSize;
    m_ui32BitmapFileSize = b.m_ui32BitmapFileSize;

    return true;
}

uint32 CBitmap24::GetPaddedRowSize( uint32 width )
{
    return ALIGN_SIZE( width * 3, 4 );
}

bool CBitmap24::Init( uint32 width, uint32 height )
{
    assert( !m_pData );

    // align line to 4 byte
    uint32 ui32PaddedRowSize = GetPaddedRowSize( width );
    uint32 ui32DataSize = ui32PaddedRowSize * height;

    m_pData = new myubyte[ ui32DataSize ];
    if( !m_pData ) return false;

    m_ui32Width = width;
    m_ui32Height = height;
    m_ui32PaddedRowSize = ui32PaddedRowSize;
    m_ui32DataSize = ui32DataSize;
    m_ui32BitmapFileSize = ms_ui32BitmapFileDataOffset + m_ui32DataSize;

    return true;
}

bool CBitmap24::WriteBitmapFileIntoBuffer(
    myubyte *pBuffer ) const
{
    static const uint32 s_ui32Zero = 0;
    assert( pBuffer );

    memcpy( pBuffer, "BM", 2 );
    pBuffer += 2;
    memcpy( pBuffer, &m_ui32BitmapFileSize, 4 );
    pBuffer += 4;
    memcpy( pBuffer, &s_ui32Zero, 4 );
    pBuffer += 4;
    memcpy( pBuffer, &ms_ui32BitmapFileDataOffset, 4 );
    pBuffer += 4;
    memcpy( pBuffer, &ms_ui32InfoHeaderSize, 4 );
    pBuffer += 4;
    memcpy( pBuffer, &m_ui32Width, 4 );
    pBuffer += 4;
    memcpy( pBuffer, &m_ui32Height, 4 );
    pBuffer += 4;
    memcpy( pBuffer, &ms_ui16Planes, 2 );
    pBuffer += 2;
    memcpy( pBuffer, &ms_ui16Bpp, 2 );
    pBuffer += 2;
    memcpy( pBuffer, &s_ui32Zero, 4 );
    pBuffer += 4;
    memcpy( pBuffer, &m_ui32DataSize, 4 );
    pBuffer += 4;
    memcpy( pBuffer, ms_unusedColorInfo, 16 );
    pBuffer += 16;

    memcpy( pBuffer, m_pData, m_ui32DataSize );

    return true;
}

bool CBitmap24::CreateFromBitmapData( uint32 width, uint32 height, myubyte *pData )
{
    // needs to be destroyed before !!!
    assert( !m_pData );

    if( !Init( width, height ) ) return false;

    memcpy( m_pData, pData, m_ui32DataSize );

    m_ByteOrder = BO_RGB;

    return true;
}

bool CBitmap24::Load( const char *pszFileName )
{
    // needs to be destroyed before !!!
    assert( !m_pData );

    FILE *pFile = fopen( pszFileName, "rb" );
    if( !pFile ) return false;

    bool blnResult = false;
    size_t ui32OffsetData;
    uint32 width, height;
    uint32 file_size;

    if( fseek( pFile, 2, SEEK_CUR ) ) goto close_file;
    if( ( fread( &file_size, 4, 1, pFile ) ) != 1 ) goto close_file;

    if( fseek( pFile, 4, SEEK_CUR ) ) goto close_file;
    if( ( fread( &ui32OffsetData, 4, 1, pFile ) ) != 1 ) goto close_file;

    if( fseek( pFile, 4, SEEK_CUR ) ) goto close_file;
    // read the width
    if( ( fread( &width, 4, 1, pFile ) ) != 1 ) goto close_file;
    // read the height 
    if( ( fread( &height, 4, 1, pFile ) ) != 1 ) goto close_file;

    if( !Init( width, height ) ) goto close_file;
    
    // read bitmap data
    if( fseek( pFile, ui32OffsetData, SEEK_SET ) ) goto close_file;
    if( fread( m_pData, m_ui32DataSize, 1, pFile ) != 1 ) goto close_file; 

    m_ByteOrder = BO_BGR;

    blnResult = true;

close_file:
    fclose( pFile );

    return blnResult;
}

bool CBitmap24::Save( const char *pszFileName ) const
{
    static const uint32 s_ui32Zero = 0;

    assert( m_pData );
    // bmp-format needs data in BGR
    assert( m_ByteOrder == BO_BGR );

    FILE *pFile = fopen( pszFileName, "wb" );
    if( !pFile ) return false;

    fwrite( "BM", 2, 1, pFile );
    fwrite( &m_ui32BitmapFileSize, 4, 1, pFile );
    fwrite( &s_ui32Zero, 4, 1, pFile );
    fwrite( &ms_ui32BitmapFileDataOffset, 4, 1, pFile );
    fwrite( &ms_ui32InfoHeaderSize, 4, 1, pFile );
    fwrite( &m_ui32Width, 4, 1, pFile );
    fwrite( &m_ui32Height, 4, 1, pFile );
    fwrite( &ms_ui16Planes, 2, 1, pFile );
    fwrite( &ms_ui16Bpp, 2, 1, pFile );
    fwrite( &s_ui32Zero, 4, 1, pFile );
    fwrite( &m_ui32DataSize, 4, 1, pFile );
    fwrite( ms_unusedColorInfo, 16, 1, pFile );
    fwrite( m_pData, m_ui32DataSize, 1, pFile );

    fclose( pFile );

    return true;
}

Open in new window

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Game Programming

From novice to tech pro — start learning today.