OpenGLUT Documentation
Introduction | Documentation | Examples | Proposals | Authors | Copying | Todo | Bugs | Links

offscreen.c File Reference


Detailed Description

OpenGLUT offscreen rendering demo.

Usage:

offscreen [standard GLUT options] [filename]

      Touch-type
          on the teapot
      with me.
      

Normal printable ASCII characters work as might be expected. The return and backspace keys also work for editing.

^S Saves a PNM image of the window to filename

The filename specifies the output PNM image file, the default is "offscreen.pnm".

PNM files are widely supported in image editing and viewing appliations such as The Gimp.

Some suggested uses for GLUT_OFFSCREEN:

Author:
Copyright (C) 2004, the OpenGLUT project contributors.
openglut_offscreen.png

OpenGLUT Offscreen Rendering Demonstration

#include <GL/openglut.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int offscreen_id;
int onscreen_id;

/*
 * The filename to which to save PNM screenshots.
 * Can be overridden by a commandline option.
 *
 * Save images with a ^S.
 */
const char *save_file_name = "offscreen.pnm";

static GLuint texName;

double theta = 0;


/*
 * Our text block.  80x25 is standard for a console, so why not?
 * Though with a 15-pixel font, you get more like 28x8.  The
 * terminal size should probably be computed at runtime from the
 * texture dimensions, which should be a user parameter.  Oh well.
 */
#define ROWS 25
#define COLS 80
char text[ ROWS ][ COLS+2 ];
#define OFFSCREEN_W 256
#define OFFSCREEN_H 128

void write_raw_pnm( const char *fname, char *pixels, int w, int h )
{
    FILE *f;

    f = fopen( fname, "wb" );
    if( !f )
        printf( "Ouch!  Cannot create file.\n" );
    else
    {
        int row;

        fprintf( f, "P6\n" );
        fprintf( f, "# CREATOR: offscreen freeglut demo\n" );
        fprintf( f, "%d %d\n", w, h );
        fprintf( f, "255\n" );

        /*
         * Write the rows in reverse order because OpenGL's 0th row
         * is at the bottom.
         */
        for( row = h; row; --row )
            fwrite( pixels + ((row - 1)*w*3), 1, 3 * w, f );

        fclose( f );
    }
}

void save_window( const char *file_name )
{
    char *pixels;
    int width  = glutGet( GLUT_WINDOW_WIDTH );
    int height = glutGet( GLUT_WINDOW_HEIGHT );
    pixels = malloc( 3 * width * height);
    if( pixels )
    {
        glPixelStorei( GL_PACK_ALIGNMENT, 1 );
        glReadPixels(
            0, 0, width, height,
            GL_RGB, GL_UNSIGNED_BYTE, (GLvoid *)pixels
        );
        write_raw_pnm( file_name, pixels, width, height );
    }
}


void cb_idle( void )
{
    glutSetWindow( onscreen_id );
    glutPostRedisplay( );
}

void cb_offscreen_display( void )
{
    static char pixels [OFFSCREEN_W * OFFSCREEN_H * 3];
    int i;

    glEnable( GL_DEPTH_TEST );

    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
    glColor3d( 1.0, 0, 0 );
    glPushMatrix( );
    glRotated( .0071234 * glutGet( GLUT_ELAPSED_TIME ), 0, 1, 0 );
    glutSolidTorus( .2, .6, 20, 20 );
    glPopMatrix( );

    glDisable( GL_LIGHTING );
    glMatrixMode( GL_PROJECTION );
    glPushMatrix( );
    glLoadIdentity( );
    glColor3d( 0.0, 1.0, 0.0 );
    glRasterPos2f( -1, 1 - ( ( 2.0 * 10 ) / OFFSCREEN_H ) );
    glNormal3d( 0, 0, 1 );
    for( i = 7; i > -1; --i )
        glutBitmapString( GLUT_BITMAP_9_BY_15, text[ i ] );
    
    glPopMatrix( );
    glMatrixMode( GL_MODELVIEW );
    glEnable( GL_LIGHTING );

    glReadPixels(
        0, 0, OFFSCREEN_W, OFFSCREEN_H,
        GL_RGB, GL_UNSIGNED_BYTE, (GLvoid *)pixels
    );
    glutSetWindow( onscreen_id );
    glBindTexture( GL_TEXTURE_2D, texName );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
    glTexImage2D (
        GL_TEXTURE_2D, 0, GL_RGB, OFFSCREEN_W, OFFSCREEN_H,
        0, GL_RGB, GL_UNSIGNED_BYTE, (void *)pixels
    );
    glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
    glDisable( GL_DEPTH_TEST );
}

void cb_onscreen_display( void )
{
    const static GLfloat flip_it_matrix[ 16 ] =
        { -1, 0, 0, 0,
          0, -1, 0, 0,
          0,  0, 1, 0,
          0,  0, 0, 1
        };

    glutSetWindow( offscreen_id );
    cb_offscreen_display( );

    glEnable( GL_DEPTH_TEST );
    glDisable( GL_LIGHTING );
    glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT );
    glColor3d( 1.0, 0.0, 0.0 );
    glBegin( GL_LINE_LOOP );
    glVertex2d( 0.0, 0.0 );
    glVertex2d( 0.5, 0.0 );
    glVertex2d( 0.5, 0.5 );
    glVertex2d( 0.0, 0.5 );
    glVertex2d( 0.0, 0.0 );
    glEnd( );
    glColor3d( 1.0, 1.0, 1.0 );
    glRasterPos2d( -2.0, 0.8 );
    glutBitmapString(
        GLUT_BITMAP_TIMES_ROMAN_24, "Press ^S to Send to"
    );
    glRasterPos2d( -1.8, 0.6 );
    glutBitmapString( GLUT_BITMAP_TIMES_ROMAN_24, "'" );
    glutBitmapString(
        GLUT_BITMAP_9_BY_15, save_file_name );
    glutBitmapString( GLUT_BITMAP_TIMES_ROMAN_24, "'" );
    glRasterPos2d( -2.0, 0.3 );
    glutBitmapString(
        GLUT_BITMAP_TIMES_ROMAN_24, "Press Esc to quit."
    );

    glEnable( GL_TEXTURE_2D );
    glBindTexture( GL_TEXTURE_2D, texName );
    glBegin( GL_QUADS );
      glNormal3f( 0, 0, -1 );
      glTexCoord2i( 0, 0 ); glVertex3i( -9, -9, -4 );
      glTexCoord2i( 1, 0 ); glVertex3i(  9, -9, -4 );
      glTexCoord2i( 1, 1 ); glVertex3i(  9,  9, -4 );
      glTexCoord2i( 0, 1 ); glVertex3i( -9,  9, -4 );
      glTexCoord2i( 0, 0 ); glVertex3i( -9, -9, -4 );
    glEnd( );

    glEnable( GL_LIGHTING );
    glDisable( GL_LIGHTING );
    glPushMatrix( );
    theta = .01 * glutGet( GLUT_ELAPSED_TIME );
    glRotated( theta, 0, 1, 0 );
    glMatrixMode( GL_TEXTURE );
    glLoadMatrixf( flip_it_matrix );
    glMatrixMode( GL_MODELVIEW );
    glutSolidTeapot( 1.0 );
    glMatrixMode( GL_TEXTURE );
    glLoadIdentity( );
    glMatrixMode( GL_MODELVIEW );
    glDisable( GL_TEXTURE_2D );
    glPopMatrix( );
    glDisable( GL_DEPTH_TEST );

    glutSwapBuffers( );
}




static int cursor;
void vscroll( void )
{
    int i;
    for( i = ROWS-1; i; --i )
        strcpy( text[ i ], text[ i-1 ] );
    cursor = 0;
    text[ 0 ][ 0 ] = '\n';
    text[ 0 ][ 1 ] = 0;
}
void hscroll( void )
{
    int i = 0;
    if( text[ 0 ][ 0 ] )
        for( i = 0; i < COLS; ++i )
            text[ 0 ][ i ] = text[ 0 ][ i+1 ];
    text[ 0 ][ COLS ] = 0;
    --cursor;
    text[ 0 ][ cursor ] = '\n';
}
void add_char( char c )
{
    text[ 0 ][ cursor++ ] = c;
    text[ 0 ][ cursor   ] = '\n';
    text[ 0 ][ cursor+1 ] = 0;
    if( COLS <= cursor )
        hscroll( );
}



void cb_onscreen_keyboard( unsigned char key, int x, int y )
{
    int texture_updated = 1;

    switch( key )
    {
    case '\n':
    case '\r':
        vscroll( );
    case 'R' - '@': /* ^R */
        break;

    case 'S' - '@': /* ^S */
        save_window( save_file_name );
        texture_updated = 0;
        break;

    case '\x08': /* backspace */
        if( cursor )
        {
            --cursor;
            text[ 0 ][ cursor+1 ] = 0;
            text[ 0 ][ cursor   ] = '\n';
        }
        break;

    case '\x1b':
            exit( 0 );
        break;

    default:
        add_char( key );
        break;
    }
    glutSetWindow( offscreen_id );
    glutPostRedisplay( );
}


void cb_onscreen_reshape( int w, int h)
{
    double ar = w * 1.0/h;
    glEnable( GL_CULL_FACE );
    glCullFace( GL_BACK );
    glViewport( 0, 0, w, h );
    glMatrixMode( GL_PROJECTION );
    glLoadIdentity( );
    if( ar > 1 )
        glFrustum( -ar, ar, -1, 1, 2, 30 );
    else
        glFrustum( -1, 1, -1/ar, 1/ar, 2, 30 );
    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity( );
    glTranslated( 0, 0, -5 );
}
void cb_offscreen_reshape( int w, int h)
{
    static GLfloat light_1_loc[ 3 ] = { 3, 4, 5 };
    static GLfloat light_1_col[ 3 ] = { 1, 1, 1 };
    static GLfloat material_diff[ 3 ] = { 1, 0, 0 };
    static GLfloat material_spec[ 3 ] = { 1, 1, 1 };
    double ar = w * 1.0/h;

    glEnable( GL_CULL_FACE );
    glViewport( 0, 0, w, h );
    glMatrixMode( GL_PROJECTION );
    glLoadIdentity( );
    if( ar > 1 )
        glFrustum( -ar, ar, -1, 1, 2, 30 );
    else
        glFrustum( -1, 1, -1/ar, 1/ar, 2, 30 );
    glTranslated( 0, 0, -3 );
    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity( );
    glEnable( GL_LIGHT1 );
    glEnable( GL_LIGHTING );
    glLightfv( GL_LIGHT1, GL_POSITION, light_1_loc );
    glLightfv( GL_LIGHT1, GL_DIFFUSE, light_1_col );
    glLightfv( GL_LIGHT1, GL_SPECULAR, light_1_col );
    glMaterialfv( GL_FRONT_AND_BACK, GL_DIFFUSE, material_diff );
    glMaterialfv( GL_FRONT_AND_BACK, GL_SPECULAR, material_spec );
    glMaterialf( GL_FRONT_AND_BACK, GL_SHININESS, 90 );
}

int main( int argc, char **argv )
{
    glutInit( &argc, argv );
    if( argv[ 1 ] )
        save_file_name = argv[ 1 ];

    strcpy( text[ 4 ], "Touch type,\n" );
    strcpy( text[ 3 ], "on the\n" );
    strcpy( text[ 2 ], "teapot\n" );
    strcpy( text[ 1 ], "with me.\n" );
    strcpy( text[ 0 ], "\n" );
    glutInitDisplayMode( GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE );
    onscreen_id = glutCreateWindow( "Offscreen demo" );
    glutDisplayFunc( cb_onscreen_display );
    glutKeyboardFunc( cb_onscreen_keyboard );
    glutReshapeFunc( cb_onscreen_reshape );

    glutInitDisplayMode(
        GLUT_RGB | GLUT_SINGLE | GLUT_DEPTH | GLUT_OFFSCREEN
    );
    glutInitWindowSize( OFFSCREEN_W, OFFSCREEN_H );
    offscreen_id = glutCreateWindow( "" );
    glutDisplayFunc( cb_offscreen_display );
    cb_offscreen_reshape(  OFFSCREEN_W, OFFSCREEN_H );

    glGenTextures( 1, &texName );
    glBindTexture( GL_TEXTURE_2D, texName );

    glutIdleFunc( cb_idle );

    glutMainLoop( );
    return EXIT_SUCCESS;
}




OpenGLUT Development @ Sourceforge
Homepage | Summary | Files | CVS | Forums | Lists | Bugs | RFE

Generated on Sat Feb 5 01:47:21 2005 for OpenGLUT by doxygen 1.3.9.1
The OpenGLUT project is hosted by sourceforge.net.