S60 3rd Edition SDK for Symbian OS
Example Applications Guide

MultiTex.cpp

00001 /*
00002 * ==============================================================================
00003 *  Name        : MultiTex.cpp
00004 *  Part of     : OpenGLEx / MultiTex
00005 *  Interface   : 
00006 *  Description : 
00007 *  Version     : 
00008 *
00009 *  Copyright (c) 2004-2006 Nokia Corporation.
00010 *  This material, including documentation and any related 
00011 *  computer programs, is protected by copyright controlled by 
00012 *  Nokia Corporation.
00013 * ==============================================================================
00014 */
00015 
00016 
00017 // INCLUDE FILES
00018 #include <e32std.h>
00019 #include <e32math.h>
00020 #include "MultiTex.h"
00021 #include "MultiTexContainer.h"  // For accessing the contexts etc.
00022 #include "model.h"
00023 
00024 // CONSTANTS
00025 
00026 /* Define vertice coordinates for the triangles */
00027 static const GLbyte LightVertices[8 * 3] =
00028 {
00029     -10,  10,  0,
00030     -10, -10,  0,
00031      10,  10,  0,
00032      10, -10,  0,
00033     
00034     -10,  10,  0,
00035     -10, -10,  0,
00036      10,  10,  0,
00037      10, -10,  0
00038 };
00039 
00040 
00041 /* Macro for changing the input texture coordinate values from
00042    GLubyte [0,255] to GLbyte [-128,127]. See more info below. */
00043 #define tex(u,v) (GLbyte)( (u) - 128 ) , (GLbyte)( (v) - 128 )
00044 
00045 static const GLbyte LightTexCoords[8 * 2] = 
00046 {
00047     // Red light
00048     tex(0,0),
00049     tex(0,255),
00050     tex(127,0),
00051     tex(127,255),
00052 
00053     // Green light
00054     tex(127,0),
00055     tex(127,255),
00056     tex(255,0),
00057     tex(255,255)
00058 };
00059 
00060 
00061 // ============================= LOCAL FUNCTIONS ===============================
00062 
00063 // -----------------------------------------------------------------------------
00064 // sin
00065 // -----------------------------------------------------------------------------
00066 GLfloat sin( GLfloat aRad )
00067 {
00068     TReal trg, src = (TReal)aRad;
00069     if ( Math::Sin(trg, src) == KErrNone )
00070     {
00071         return (GLfloat)trg;
00072     }
00073     return 0;
00074 }
00075 
00076 // -----------------------------------------------------------------------------
00077 // cos
00078 // -----------------------------------------------------------------------------
00079 GLfloat cos( GLfloat aRad )
00080 {
00081     TReal trg, src = (TReal)aRad;
00082     if ( Math::Cos(trg, src) == KErrNone )
00083     {
00084         return (GLfloat)trg;
00085     }
00086     return 0;
00087 }
00088 
00089 
00090 // ============================ MEMBER FUNCTIONS ===============================
00091 
00092 // -----------------------------------------------------------------------------
00093 // CMultiTex::NewL
00094 // 
00095 // The usual Symbian NewL implementation. 
00096 // Creates the object, pushes it to cleanup stack and calls ContructL.
00097 // Returns the contructed object or leaves.
00098 // -----------------------------------------------------------------------------
00099 //
00100 
00101 CMultiTex* CMultiTex::NewL( TUint aWidth, TUint aHeight )
00102 {
00103     /* Symbian 2-phase constructor. Calls both the default 
00104        C++ constructor and Symbian ConstructL methods */
00105     CMultiTex* self = new (ELeave) CMultiTex( aWidth, aHeight );
00106     CleanupStack::PushL( self );
00107     self->ConstructL();
00108     CleanupStack::Pop();
00109     
00110     return self;
00111 }
00112 
00113 // -----------------------------------------------------------------------------
00114 // CMultiTex::CMultiTex
00115 // 
00116 // C++ constructor. Initializes the size instance variables from arguments.
00117 // -----------------------------------------------------------------------------
00118 //
00119 
00120 CMultiTex::CMultiTex( TUint aWidth, TUint aHeight ) : 
00121     CFiniteStateMachine(),
00122     iScreenWidth( aWidth ),
00123     iScreenHeight( aHeight )
00124 {
00125     if ( iScreenHeight != 0 )
00126     {
00127         iAspectRatio = (GLfloat)iScreenWidth / (GLfloat)iScreenHeight;
00128     }
00129     else
00130     {
00131         iAspectRatio = 1.0;
00132     }
00133     iCameraDistance = 200;
00134 }
00135 
00136 // -----------------------------------------------------------------------------
00137 // CMultiTex::~CMultiTex
00138 // 
00139 // C++ destructor.
00140 // -----------------------------------------------------------------------------
00141 //
00142 
00143 CMultiTex::~CMultiTex()
00144 {
00145 }
00146 
00147 // -----------------------------------------------------------------------------
00148 // CMultiTex::ConstructL
00149 // 
00150 // 2nd phase constructor.
00151 // -----------------------------------------------------------------------------
00152 //
00153 
00154 void CMultiTex::ConstructL( void )
00155 {
00156 }
00157 
00158 // -----------------------------------------------------------------------------
00159 // CMultiTex::CalculateEnvLightsL
00160 // 
00161 // Texture map consist of two lights: red and green.
00162 // Alpha is calculated so that is gradually goes from 255 to zero starting
00163 // from the center of the spotlight.
00164 // -----------------------------------------------------------------------------
00165 //
00166 void CMultiTex::CalculateLightsL( void )
00167 {
00168     // Reserve memory for light texture
00169     iLightTex = new (ELeave) TUint8[64*32*4];
00170     if ( !iLightTex )
00171     {
00172         User::LeaveNoMemory();
00173     }
00174 
00175     TInt d         = 0;   // distance from the center of the spot
00176     GLfloat alpha = 0.f;  // alpha value
00177 
00178     for ( TInt i = 0; i < 32; i++ )
00179     {
00180         for ( TInt j = 0; j < 32; j++ )
00181         {
00182             // distance from the center of spotlight 
00183             d = (i-16)*(i-16) + (j-16)*(j-16);
00184             
00185             // simple linear attenuation used for alpha 
00186             alpha = 255.f*(1.f-(1.f/250.f)*(GLfloat)(d));
00187             
00188             // alpha < 0 corresponds to spotlight cut-off value 
00189             if ( alpha < 0.f )
00190             {
00191                 iLightTex[64*4*i+4*j]   = 255;      //r
00192                 iLightTex[64*4*i+4*j+1] = 0;        //g
00193                 iLightTex[64*4*i+4*j+2] = 0;        //b
00194                 iLightTex[64*4*i+4*j+3] = 0;        //a
00195 
00196                 iLightTex[64*4*i+4*j+32*4]   = 0;   //r
00197                 iLightTex[64*4*i+4*j+1+32*4] = 255; //g
00198                 iLightTex[64*4*i+4*j+2+32*4] = 0;   //b
00199                 iLightTex[64*4*i+4*j+3+32*4] = 0;   //a
00200             }
00201             // inside the cut-off, set alpha as calculated above/
00202             else
00203             {
00204                 iLightTex[64*4*i+4*j]   = 255;                   //r
00205                 iLightTex[64*4*i+4*j+1] = 0;                     //g
00206                 iLightTex[64*4*i+4*j+2] = 0;                     //b
00207                 iLightTex[64*4*i+4*j+3] = (GLubyte)(alpha);      //a
00208 
00209                 iLightTex[64*4*i+4*j+32*4]   = 0;                //r
00210                 iLightTex[64*4*i+4*j+1+32*4] = 255;              //g
00211                 iLightTex[64*4*i+4*j+2+32*4] = 0;                //b
00212                 iLightTex[64*4*i+4*j+3+32*4] = (GLubyte)(alpha); //a
00213             }
00214         }
00215     }
00216 }
00217 
00218 
00219 // -----------------------------------------------------------------------------
00220 // CMultiTex::AppInit
00221 // 
00222 // Initializes OpenGL ES, sets the vertex and color arrays and pointers, 
00223 // and selects the shading mode.
00224 // -----------------------------------------------------------------------------
00225 //
00226 
00227 void CMultiTex::AppInitL( TAny* aInstance )
00228 {
00229     
00230     CMultiTexContainer* instance = (CMultiTexContainer*) aInstance;
00231 
00232     /*=========================================================================*/
00233     /*===================== Initialize Pbuffer context ========================*/
00234     /*=========================================================================*/
00235 
00236     /* Bind the pbuffer context to the current rendering thread and surface.*/
00237     eglMakeCurrent( instance->iEglDisplay, instance->iEglPbufferSurface, 
00238                     instance->iEglPbufferSurface, instance->iEglPbufferContext );
00239     
00240     /* Create light texture map */
00241     CalculateLightsL();
00242     const GLvoid *texPtr = iLightTex;
00243     
00244     // Set the screen background color (black). 
00245     glClearColor( 0.f, 0.f, 0.f, 1.f );
00246     
00247     // Initialize viewport and projection. 
00248     glViewport( 0, 0, 128, 128 );
00249     glMatrixMode( GL_PROJECTION );
00250     glFrustumf( -1.f, 1.f, -1.f, 1.f, 3.f, 1000.f );
00251 
00252     /* Initialize appropriate texture matrix. First we have to translate the
00253        input texture coordinate values to be within a range of [0,255]. Hence
00254        we translate the x- and y-coordinate values by 128. Recall that the 
00255        values in nokTexCoords are between [-128,127], now they are in a range 
00256        of [0,255]. After that we scale the values by 1/255 to make the values 
00257        to be in range [0,1]. */
00258     glMatrixMode( GL_TEXTURE );
00259     glLoadIdentity();
00260     glScalef(     1.0f/255.0f, 1.0f/255.0f, 1.0f );
00261     glTranslatef( 128.0f,      128.0f,      0.0f );
00262     
00263     // Remember to change the matrix mode to modelview. 
00264     glMatrixMode( GL_MODELVIEW );
00265     
00266     // Enable back face culling, texturing and blending. 
00267     glEnable( GL_CULL_FACE  );
00268     glEnable( GL_TEXTURE_2D );
00269     glEnable( GL_BLEND );
00270     glBlendFunc( GL_SRC_ALPHA, GL_ONE );
00271     
00272     // Enable vertex arrays. 
00273     glEnableClientState( GL_VERTEX_ARRAY );
00274     glEnableClientState( GL_TEXTURE_COORD_ARRAY );
00275     
00276     // Set array pointers. 
00277     glVertexPointer( 3, GL_BYTE, 0, LightVertices );
00278     glTexCoordPointer( 2, GL_BYTE, 0, LightTexCoords );
00279     
00280     // Set the initial shading mode 
00281     glShadeModel( GL_FLAT ); 
00282     
00283     /* Create texture names */
00284     glGenTextures( 2, iLightTexObjects );
00285     
00286     // Bind and set the light texture.
00287     glBindTexture( GL_TEXTURE_2D, iLightTexObjects[0] );
00288     glTexImage2D(  GL_TEXTURE_2D, 0, GL_RGBA, 64, 32, 
00289                    0, GL_RGBA, GL_UNSIGNED_BYTE, texPtr );
00290     glTexEnvx( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD );
00291     
00292     /* We can now free the memory reserved for light texture,
00293        since it's loaded inside OpenGL ES */
00294     delete[] iLightTex;
00295     iLightTex = NULL;
00296 
00297     /* Bind and set the environment map texture. We pass NULL as pixels,
00298        since we use glCopyTexImage2D later to initialize the texture memory. */
00299     glBindTexture( GL_TEXTURE_2D, iLightTexObjects[1] );
00300     glTexImage2D(  GL_TEXTURE_2D, 0, GL_RGB, 128, 128, 
00301                    0, GL_RGB, GL_UNSIGNED_BYTE, NULL );
00302     glTexEnvx( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
00303     
00304     // Do not use perspective correction 
00305     glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST );
00306   
00307 
00308     /*=========================================================================*/
00309     /*====================== Initialize Window context ========================*/
00310     /*=========================================================================*/
00311 
00312 
00313     // Bind the Window context to the current rendering thread and surface.
00314     eglMakeCurrent( instance->iEglDisplay, instance->iEglSurface, 
00315                     instance->iEglSurface, instance->iEglContext );
00316     
00317     // Set the screen background color. 
00318     glClearColor( 0.f, 0.f, 0.4f, 1.f );
00319     
00320     /* Enable depth testing and back face culling. */
00321     glEnable( GL_DEPTH_TEST );
00322     glEnable( GL_CULL_FACE  );
00323     glEnable( GL_TEXTURE_2D );
00324 
00325     // Initialize viewport and projection. 
00326     glViewport( 0, 0, iScreenWidth, iScreenHeight );
00327     glMatrixMode( GL_PROJECTION );
00328 
00329     // Calculate the view frustrum
00330     glFrustumf( FRUSTUM_LEFT * iAspectRatio, FRUSTUM_RIGHT * iAspectRatio,
00331                 FRUSTUM_BOTTOM, FRUSTUM_TOP,
00332                 FRUSTUM_NEAR, FRUSTUM_FAR );
00333 
00334 
00335     // Initialize appropriate texture matrix
00336     glMatrixMode( GL_TEXTURE );
00337     glLoadIdentity();
00338     glScalef(     1.0f/32767.0f, 1.0f/32767.0f, 1.0f );
00339     
00340     // Remember to change the matrix mode to modelview. 
00341     glMatrixMode( GL_MODELVIEW );
00342     
00343     // Set shading mode
00344     glShadeModel( GL_FLAT ); 
00345     
00346     // Do not use perspective correction 
00347     glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST );
00348 
00349 
00350         // Construct a texture manager that uses the application's private
00351         // directory as the location for all textures.
00352     iTextureManager = CTextureManager::NewL ( iScreenWidth, iScreenWidth,
00353                                               iAspectRatio*1.f, iAspectRatio*-1.f, 1.f, -1.f, 3.f,                               
00354                                               this );
00355 
00356     // Pushing the textures into the loading queue.
00357     _LIT(KWorldTexture, "world.jpg");
00358     iTextureManager->RequestToLoad(KWorldTexture, &iWorldTexture );
00359 
00360     //Start to load the textures.
00361     iTextureManager->DoLoadL();
00362     
00363 }
00364 
00365 // -------------------------------------------------------------------------------------------------------
00366 // CBillboard::OnStartLoadingTextures()
00367 // Called for a MTextureLoadingListener by the texture manager when texture loading operation starts 
00368 // -------------------------------------------------------------------------------------------------------
00369 
00370 void CMultiTex::OnStartLoadingTexturesL()
00371         {
00372     SetStateL( ELoadingTextures );
00373         }
00374 
00375 // ------------------------------------------------------------------------------------------------------------
00376 // CBillboard::OnEndLoadingTextures()
00377 // Called for a MTextureLoadingListener by the texture manager when texture loading operation is completed
00378 // ------------------------------------------------------------------------------------------------------------
00379 void CMultiTex::OnEndLoadingTexturesL()
00380         {
00381     /* TEXTURE0 is used for Marble texture */
00382     glActiveTexture( GL_TEXTURE0 );
00383     glClientActiveTexture( GL_TEXTURE0 );
00384     
00385     // Enable texturing
00386     glEnable( GL_TEXTURE_2D );
00387     
00388     // Enable vertex and texture coordinates arrays. 
00389     glEnableClientState( GL_VERTEX_ARRAY );
00390     glEnableClientState( GL_TEXTURE_COORD_ARRAY );
00391     
00392     // Set array pointers. 
00393     glVertexPointer( 3, GL_SHORT, 0, objVertex );
00394     glTexCoordPointer( 2, GL_SHORT, 0, objTexCoords );
00395     
00396     /* Bind the marble.jpg texture to iWorldTexture, set the texture 
00397        to the texPtr defined above, and set the texture environment. */
00398     glBindTexture( GL_TEXTURE_2D, iWorldTexture.iID );
00399     glTexEnvx( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
00400     
00401     /* Texture to TEXTURE1 is taken from Pbuffer 
00402        context, i.e, iLightTexObjects[1] */
00403     glActiveTexture( GL_TEXTURE1 );
00404     glClientActiveTexture( GL_TEXTURE1 );
00405     
00406     // Enable texturing
00407     glEnable( GL_TEXTURE_2D );
00408     
00409     // Enable vertex and texture coordinates arrays. 
00410     glEnableClientState( GL_VERTEX_ARRAY );
00411     glEnableClientState( GL_TEXTURE_COORD_ARRAY );
00412     
00413     // Set array pointers. 
00414     glVertexPointer( 3, GL_SHORT, 0, objVertex );
00415     glTexCoordPointer( 3, GL_SHORT, 0, envNormals );
00416     
00417     /* Bind the environment map texture created with Pbuffer context.
00418        Actual creation and updating is done in AppCycle. */
00419     glBindTexture( GL_TEXTURE_2D, iLightTexObjects[1] );
00420 
00421     // Set the texture env mode for environment map texture 
00422     glTexEnvx( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD );
00423 
00424         if ( GetState() == ELoadingTextures )
00425                 {
00426                 SetStateL( ERunning );
00427                 }
00428         }
00429 
00430 // ---------------------------------------------------------
00431 // CBillboard::OnEnterState( TInt aState )
00432 // Called by TFiniteStateMachine when the f.s.m enters a new state
00433 // ---------------------------------------------------------
00434 
00435 void CMultiTex::OnEnterStateL( TInt /*aState*/ )
00436         {
00437             // Nothing to do here...
00438         }
00439 
00440 // -----------------------------------------------------------------------------
00441 // CMultiTex::AppExit
00442 // 
00443 // Release any allocations made in AppInit.
00444 // -----------------------------------------------------------------------------
00445 //
00446 
00447 void CMultiTex::AppExit( void )
00448 {
00449     delete iTextureManager;
00450 }
00451 
00452 // -----------------------------------------------------------------------------
00453 // CMultiTex::DrawLight
00454 // 
00455 // Draws lights.
00456 // -----------------------------------------------------------------------------
00457 //
00458 
00459 void CMultiTex::DrawLights( TInt iFrame )
00460 {
00461     // Draw red light 
00462     glPushMatrix();
00463     glTranslatex(( 2 << 16) + (GLint) (sin(iFrame * 0.10f) * 5 * 65536) , (2 << 16) + (GLint) (cos(iFrame * 0.13f) * 5 * 65536) , 0 );
00464     glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 );
00465     glPopMatrix();
00466     
00467     // Draw green light 
00468     glPushMatrix();
00469     glTranslatex( (-2 << 16) + (GLint) (sin(iFrame * 0.10f) * 5 * 65536) , (-2 << 16) + (GLint) (cos(iFrame * 0.10f) * 8 * 65536) , 0 );
00470     glDrawArrays( GL_TRIANGLE_STRIP, 4, 4 );
00471     glPopMatrix();
00472     
00473 }
00474 
00475 // -----------------------------------------------------------------------------
00476 // CMultiTex::AppCyclePbuffer
00477 // 
00478 // Create a dynamic environment map, where two spot lights (red, green) moves
00479 // -----------------------------------------------------------------------------
00480 //
00481 
00482 void CMultiTex::AppCyclePbuffer( TInt iFrame )
00483 {
00484     glClear( GL_COLOR_BUFFER_BIT );
00485     
00486     // Bind the light texture as current 
00487     glBindTexture( GL_TEXTURE_2D, iLightTexObjects[0] );
00488     
00489     /* Animate and draw lights */
00490     glLoadIdentity();
00491     glTranslatex( 0 , 0 , -iCameraDistance << 16 );
00492     glScalex( 2 << 16, 2 << 16, 2 << 16 );
00493     DrawLights( iFrame );
00494     
00495     // Bind the environment map texture as current 
00496     glBindTexture( GL_TEXTURE_2D, iLightTexObjects[1] );
00497  
00498     // Copy the content of the pbuffer to the currently bound texture 
00499     glCopyTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, 0, 0, 128, 128, 0 );
00500 }
00501 
00502 // -----------------------------------------------------------------------------
00503 // CMultiTex::AppCycleWindow
00504 // 
00505 // Draw the sphere with Marble and dynamic environment textures
00506 // -----------------------------------------------------------------------------
00507 //
00508 
00509 void CMultiTex::AppCycleWindow( TInt iFrame )
00510 {
00511     // Set the TEXTURE1 unit as active (env map texture) 
00512     glActiveTexture( GL_TEXTURE1 );
00513     glClientActiveTexture( GL_TEXTURE1 );
00514     
00515     // Set the correct texture matrix 
00516     glMatrixMode( GL_TEXTURE );
00517     glLoadIdentity();
00518     glTranslatef( 0.5f, 0.5f, 0.5f );
00519     glRotatex( 180 << 16, 0, 0, 1 << 16 );
00520     glRotatex( iFrame << 16, 0, 1 << 16, 0 );
00521     glScalef( 1.0f/65534.0f, 1.0f/65534.0f, 1.0f/65534.0f );
00522     
00523     glMatrixMode( GL_MODELVIEW );
00524     
00525     glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
00526     
00527     glLoadIdentity();
00528     glTranslatex( 0 , 0 , -iCameraDistance << 16 );
00529     glRotatex( 180 << 16, 0, 0, 1 << 16 );
00530     glRotatex( iFrame << 16, 0, 1 << 16, 0 );
00531     
00532     // Scale the world model to fit the screen. 
00533     glScalex( 1 << 9, 1 << 9, 1 << 9 );
00534     glDrawElements( GL_TRIANGLES, objFaces * 3, 
00535                     GL_UNSIGNED_SHORT, objIndices );
00536 }
00537 
00538 // -----------------------------------------------------------------------------
00539 // CMultiTex::SetScreenSize
00540 // Reacts to the dynamic screen size change during execution of this program.
00541 // -----------------------------------------------------------------------------
00542 //
00543 void CMultiTex::SetScreenSize( TUint aWidth, TUint aHeight )
00544     {
00545     iScreenWidth  = aWidth;
00546     iScreenHeight = aHeight;
00547     
00548     // Notify the texture manager of screen size change
00549     iTextureManager->SetScreenSize( aWidth, aHeight );
00550 
00551     // Reinitialize viewport and projection.
00552     glViewport( 0, 0, iScreenWidth, iScreenHeight );
00553 
00554     // Recalculate the view frustrum
00555     if ( iScreenHeight != 0 )
00556         {
00557         iAspectRatio = (GLfloat)iScreenWidth / (GLfloat)iScreenHeight;
00558         }
00559     else
00560         {
00561         iAspectRatio = 1.0;
00562         }
00563         
00564     glMatrixMode( GL_PROJECTION );
00565     glLoadIdentity();
00566     glFrustumf( FRUSTUM_LEFT * iAspectRatio, FRUSTUM_RIGHT * iAspectRatio,
00567                 FRUSTUM_BOTTOM, FRUSTUM_TOP,
00568                 FRUSTUM_NEAR, FRUSTUM_FAR );
00569     glMatrixMode( GL_PROJECTION );
00570 
00571     }
00572 
00573 
00574 // End of File  

© Nokia 2006

Back to top