/* (c) Copyright 2001 convergence integrated media GmbH. All rights reserved. Written by Denis Oliver Kropp <dok@convergence.de> and Andreas Hundt <andi@convergence.de>. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include <stdlib.h> #include <stdio.h> #include <string.h> #include <math.h> #include <directfb.h> #include <GL/glu.h> #include <GL/directfbgl.h> #include "util/showbuffer.c" #include "util/readtex.c" /* the super interface */ IDirectFB *dfb; /* the primary surface (surface of primary layer) */ IDirectFBSurface *primary; /* the GL context */ IDirectFBGL *primary_gl; /* our font */ IDirectFBFont *font; /* event buffer */ IDirectFBEventBuffer *events; /* macro for a safe call to DirectFB functions */ #define DFBCHECK(x...) \ { \ err = x; \ if (err != DFB_OK) { \ fprintf( stderr, "%s <%d>:\n\t", __FILE__, __LINE__ ); \ DirectFBErrorFatal( #x, err ); \ } \ } static int screen_width, screen_height; static unsigned long T0 = 0; static GLint Frames = 0; static GLfloat fps = 0; static inline unsigned long get_millis() { struct timeval tv; gettimeofday (&tv, NULL); return (tv.tv_sec * 1000 + tv.tv_usec / 1000); } /*******************************/ #define DEG2RAD (3.14159/180.0) #define TABLE_TEXTURE "../images/tile.rgb" static GLint ImgWidth, ImgHeight; static GLenum ImgFormat; static GLubyte *Image = NULL; #define MAX_OBJECTS 2 static GLint table_list; static GLint objects_list[MAX_OBJECTS]; static GLfloat xrot, yrot; static GLfloat spin; static GLint Width = 400, Height = 300; static GLenum ShowBuffer = GL_NONE; static void make_table( void ) { static GLfloat table_mat[] = { 1.0, 1.0, 1.0, 0.6 }; static GLfloat gray[] = { 0.4, 0.4, 0.4, 1.0 }; table_list = glGenLists(1); glNewList( table_list, GL_COMPILE ); /* load table's texture */ glMaterialfv( GL_FRONT, GL_AMBIENT_AND_DIFFUSE, table_mat ); /* glMaterialfv( GL_FRONT, GL_EMISSION, gray );*/ glMaterialfv( GL_FRONT, GL_DIFFUSE, table_mat ); glMaterialfv( GL_FRONT, GL_AMBIENT, gray ); /* draw textured square for the table */ glPushMatrix(); glScalef( 4.0, 4.0, 4.0 ); glBegin( GL_POLYGON ); glNormal3f( 0.0, 1.0, 0.0 ); glTexCoord2f( 0.0, 0.0 ); glVertex3f( -1.0, 0.0, 1.0 ); glTexCoord2f( 1.0, 0.0 ); glVertex3f( 1.0, 0.0, 1.0 ); glTexCoord2f( 1.0, 1.0 ); glVertex3f( 1.0, 0.0, -1.0 ); glTexCoord2f( 0.0, 1.0 ); glVertex3f( -1.0, 0.0, -1.0 ); glEnd(); glPopMatrix(); glDisable( GL_TEXTURE_2D ); glEndList(); } static void make_objects( void ) { GLUquadricObj *q; static GLfloat cyan[] = { 0.0, 1.0, 1.0, 1.0 }; static GLfloat green[] = { 0.2, 1.0, 0.2, 1.0 }; static GLfloat black[] = { 0.0, 0.0, 0.0, 0.0 }; q = gluNewQuadric(); gluQuadricDrawStyle( q, GLU_FILL ); gluQuadricNormals( q, GLU_SMOOTH ); objects_list[0] = glGenLists(1); glNewList( objects_list[0], GL_COMPILE ); glMaterialfv( GL_FRONT, GL_AMBIENT_AND_DIFFUSE, cyan ); glMaterialfv( GL_FRONT, GL_EMISSION, black ); gluCylinder( q, 0.5, 0.5, 1.0, 15, 1 ); glEndList(); objects_list[1] = glGenLists(1); glNewList( objects_list[1], GL_COMPILE ); glMaterialfv( GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green ); glMaterialfv( GL_FRONT, GL_EMISSION, black ); gluCylinder( q, 1.5, 0.0, 2.5, 15, 1 ); glEndList(); } static void init( void ) { make_table(); make_objects(); Image = LoadRGBImage( TABLE_TEXTURE, &ImgWidth, &ImgHeight, &ImgFormat ); if (!Image) { printf("Couldn't read %s\n", TABLE_TEXTURE); exit(0); } gluBuild2DMipmaps(GL_TEXTURE_2D, 3, ImgWidth, ImgHeight, ImgFormat, GL_UNSIGNED_BYTE, Image); 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_MIN_FILTER, GL_NEAREST ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); xrot = 30.0; yrot = 50.0; spin = 0.0; glShadeModel( GL_FLAT ); glEnable( GL_LIGHT0 ); glEnable( GL_LIGHTING ); glClearColor( 0.5, 0.5, 0.9, 0.0 ); glEnable( GL_NORMALIZE ); } static void reshape(int w, int h) { GLfloat yAspect = 2.5; GLfloat xAspect = yAspect * (float) w / (float) h; Width = w; Height = h; glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum( -xAspect, xAspect, -yAspect, yAspect, 10.0, 30.0 ); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } static void draw_objects( GLfloat eyex, GLfloat eyey, GLfloat eyez ) { (void) eyex; (void) eyey; (void) eyez; #ifndef USE_ZBUFFER if (eyex<0.5) { #endif glPushMatrix(); glTranslatef( 1.0, 1.5, 0.0 ); glRotatef( spin, 1.0, 0.5, 0.0 ); glRotatef( 0.5*spin, 0.0, 0.5, 1.0 ); glCallList( objects_list[0] ); glPopMatrix(); glPushMatrix(); glTranslatef( -1.0, 0.85+3.0*fabs( cos(0.01*spin) ), 0.0 ); glRotatef( 0.5*spin, 0.0, 0.5, 1.0 ); glRotatef( spin, 1.0, 0.5, 0.0 ); glScalef( 0.5, 0.5, 0.5 ); glCallList( objects_list[1] ); glPopMatrix(); #ifndef USE_ZBUFFER } else { glPushMatrix(); glTranslatef( -1.0, 0.85+3.0*fabs( cos(0.01*spin) ), 0.0 ); glRotatef( 0.5*spin, 0.0, 0.5, 1.0 ); glRotatef( spin, 1.0, 0.5, 0.0 ); glScalef( 0.5, 0.5, 0.5 ); glCallList( objects_list[1] ); glPopMatrix(); glPushMatrix(); glTranslatef( 1.0, 1.5, 0.0 ); glRotatef( spin, 1.0, 0.5, 0.0 ); glRotatef( 0.5*spin, 0.0, 0.5, 1.0 ); glCallList( objects_list[0] ); glPopMatrix(); } #endif } static void draw_table( void ) { glCallList( table_list ); } static void draw( void ) { static GLfloat light_pos[] = { 0.0, 20.0, 0.0, 1.0 }; GLfloat dist = 20.0; GLfloat eyex, eyey, eyez; glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); eyex = dist * cos(yrot*DEG2RAD) * cos(xrot*DEG2RAD); eyez = dist * sin(yrot*DEG2RAD) * cos(xrot*DEG2RAD); eyey = dist * sin(xrot*DEG2RAD); /* view from top */ glPushMatrix(); gluLookAt( eyex, eyey, eyez, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0 ); glLightfv( GL_LIGHT0, GL_POSITION, light_pos ); /* draw table into stencil planes */ glDisable( GL_DEPTH_TEST ); glEnable( GL_STENCIL_TEST ); glStencilFunc( GL_ALWAYS, 1, 0xffffffff ); glStencilOp( GL_REPLACE, GL_REPLACE, GL_REPLACE ); glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE ); draw_table(); glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE ); glEnable( GL_DEPTH_TEST ); /* render view from below (reflected viewport) */ /* only draw where stencil==1 */ if (eyey>0.0) { glPushMatrix(); glStencilFunc( GL_EQUAL, 1, 0xffffffff ); /* draw if ==1 */ glStencilOp( GL_KEEP, GL_KEEP, GL_KEEP ); glScalef( 1.0, -1.0, 1.0 ); /* Reposition light in reflected space. */ glLightfv(GL_LIGHT0, GL_POSITION, light_pos); draw_objects(eyex, eyey, eyez); glPopMatrix(); /* Restore light's original unreflected position. */ glLightfv(GL_LIGHT0, GL_POSITION, light_pos); } glDisable( GL_STENCIL_TEST ); glEnable( GL_BLEND ); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); glEnable( GL_TEXTURE_2D ); draw_table(); glDisable( GL_TEXTURE_2D ); glDisable( GL_BLEND ); /* view from top */ glPushMatrix(); draw_objects(eyex, eyey, eyez); glPopMatrix(); glPopMatrix(); if (ShowBuffer == GL_DEPTH) { ShowDepthBuffer(Width, Height, 1.0, 0.0); } else if (ShowBuffer == GL_STENCIL) { ShowStencilBuffer(Width, Height, 255.0, 0.0); } else if (ShowBuffer == GL_ALPHA) { ShowAlphaBuffer(Width, Height); } } /*******************************/ int main( int argc, char *argv[] ) { int quit = 0; DFBResult err; DFBSurfaceDescription dsc; DFBCHECK(DirectFBInit( &argc, &argv )); /* create the super interface */ DFBCHECK(DirectFBCreate( &dfb )); /* create an event buffer for all devices with these caps */ DFBCHECK(dfb->CreateInputEventBuffer( dfb, DICAPS_ALL, DFB_FALSE, &events )); /* set our cooperative level to DFSCL_FULLSCREEN for exclusive access to the primary layer */ dfb->SetCooperativeLevel( dfb, DFSCL_FULLSCREEN ); /* get the primary surface, i.e. the surface of the primary layer we have exclusive access to */ dsc.flags = DSDESC_CAPS; dsc.caps = (DFBSurfaceCapabilities)(DSCAPS_PRIMARY | DSCAPS_DOUBLE); DFBCHECK(dfb->CreateSurface( dfb, &dsc, &primary )); /* get the size of the surface and fill it */ DFBCHECK(primary->GetSize( primary, &screen_width, &screen_height )); DFBCHECK(primary->FillRectangle( primary, 0, 0, screen_width, screen_height )); /* create the default font and set it */ DFBCHECK(dfb->CreateFont( dfb, NULL, NULL, &font )); DFBCHECK(primary->SetFont( primary, font )); /* get the GL context */ DFBCHECK(primary->GetGL( primary, &primary_gl )); DFBCHECK(primary_gl->Lock( primary_gl )); init(); reshape(screen_width, screen_height); DFBCHECK(primary_gl->Unlock( primary_gl )); T0 = get_millis(); while (!quit) { DFBInputEvent evt; unsigned long t; DFBCHECK(primary_gl->Lock( primary_gl )); draw(); DFBCHECK(primary_gl->Unlock( primary_gl )); if (fps) { char buf[64]; sprintf(buf, "%4.1f FPS\n", fps); primary->SetColor( primary, 0xff, 0, 0, 0xff ); primary->DrawString( primary, buf, -1, screen_width - 5, 5, DSTF_TOPRIGHT ); } primary->Flip( primary, NULL, (DFBSurfaceFlipFlags)0 ); Frames++; t = get_millis(); if (t - T0 >= 1000) { GLfloat seconds = (t - T0) / 1000.0; fps = Frames / seconds; T0 = t; Frames = 0; } while (events->GetEvent( events, DFB_EVENT(&evt) ) == DFB_OK) { switch (evt.type) { case DIET_KEYPRESS: switch (DFB_LOWER_CASE(evt.key_symbol)) { case DIKS_ESCAPE: quit = 1; break; case DIKS_CURSOR_UP: xrot += 3.0; if ( xrot > 85 ) xrot = 85; break; case DIKS_CURSOR_DOWN: xrot -= 3.0; if ( xrot < 5 ) xrot = 5; break; case DIKS_CURSOR_LEFT: yrot += 3.0; break; case DIKS_CURSOR_RIGHT: yrot -= 3.0; break; case DIKS_SMALL_D: ShowBuffer = GL_DEPTH; break; case DIKS_SMALL_S: ShowBuffer = GL_STENCIL; break; case DIKS_SMALL_A: ShowBuffer = GL_ALPHA; break; default: ShowBuffer = GL_NONE; } break; case DIET_AXISMOTION: if (evt.flags & DIEF_AXISREL) { switch (evt.axis) { case DIAI_X: yrot += evt.axisrel / 2.0; break; case DIAI_Y: xrot += evt.axisrel / 2.0; break; default: ; } } break; default: ; } } spin += 2.0; yrot += 3.0; } /* release our interfaces to shutdown DirectFB */ primary_gl->Release( primary_gl ); primary->Release( primary ); font->Release( font ); events->Release( events ); dfb->Release( dfb ); return 0; }