|
S60 3rd Edition SDK for Symbian OS Example Applications Guide |
00001 /* 00002 * ============================================================================== 00003 * Name : Shadows.cpp 00004 * Part of : OpenGLEx / Shadows 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 // INCLUDES 00017 #include <e32std.h> 00018 #include <e32math.h> 00019 00020 #include "Shadows.h" 00021 00022 // LOCAL MACROS 00023 #define MATERIAL_MAX (1 << 16) 00024 #define LIGHT_MAX (1 << 16) 00025 00026 #define cameraDistance 150.0 00027 00028 00029 #define MATERIALCOLOR(r, g, b, a) \ 00030 (GLfixed)(r * MATERIAL_MAX), \ 00031 (GLfixed)(g * MATERIAL_MAX), \ 00032 (GLfixed)(b * MATERIAL_MAX), \ 00033 (GLfixed)(a * MATERIAL_MAX) 00034 00035 #define LIGHTCOLOR(r, g, b, a) \ 00036 (GLfixed)(r * LIGHT_MAX), \ 00037 (GLfixed)(g * LIGHT_MAX), \ 00038 (GLfixed)(b * LIGHT_MAX), \ 00039 (GLfixed)(a * LIGHT_MAX) 00040 00041 00042 // CONSTANTS 00043 /** Vertice coordinates for the ground plane */ 00044 static const GLbyte planeVertices[4 * 3] = 00045 { 00046 1,-1,0, 00047 1,1,0, 00048 -1,1,0, 00049 -1,-1,0 00050 }; 00051 00052 /** Indices for drawing the triangles of the ground plane */ 00053 static const GLubyte planeTriangles[2 * 3] = 00054 { 00055 0,1,2, 00056 0,2,3 00057 }; 00058 00059 /** Vertice coordinates for the shadow object */ 00060 static const GLbyte objVertices[48 * 3] = 00061 { 00062 /* Front */ 00063 /* Outer ring */ 00064 0,0,0, // 0 00065 0,10,0, // 1 00066 0,10,10, // 2 00067 0,0,10, // 3 00068 /* Inner ring */ 00069 0,2,2, // 4 00070 0,8,2, // 5 00071 0,8,8, // 6 00072 0,2,8, // 7 00073 00074 /* Right */ 00075 /* Outer ring */ 00076 0,10,0, // 8 00077 -10,10,0, // 9 00078 -10,10,10, // 10 00079 0,10,10, // 11 00080 /* Inner ring */ 00081 -2,10,2, // 12 00082 -8,10,2, // 13 00083 -8,10,8, // 14 00084 -2,10,8, // 15 00085 00086 /* Back */ 00087 /* Outer ring */ 00088 -10,10,0, // 16 00089 -10,0,0, // 17 00090 -10,0,10, // 18 00091 -10,10,10, // 19 00092 /* Inner ring */ 00093 -10,8,2, // 20 00094 -10,2,2, // 21 00095 -10,2,8, // 22 00096 -10,8,8, // 23 00097 00098 /* Left */ 00099 /* Outer ring */ 00100 -10,0,0, // 24 00101 0,0,0, // 25 00102 0,0,10, // 26 00103 -10,0,10, // 27 00104 /* Inner ring */ 00105 -8,0,2, // 28 00106 -2,0,2, // 29 00107 -2,0,8, // 30 00108 -8,0,8, // 31 00109 00110 /* Top */ 00111 /* Outer ring */ 00112 0,0,10, // 32 00113 0,10,10, // 33 00114 -10,10,10, // 34 00115 -10,0,10, // 35 00116 /* Inner ring */ 00117 -2,2,10, // 36 00118 -2,8,10, // 37 00119 -8,8,10, // 38 00120 -8,2,10, // 39 00121 00122 /* Bottom */ 00123 /* Outer ring */ 00124 -10,0,0, // 40 00125 -10,10,0, // 41 00126 0,10,0, // 42 00127 0,0,0, // 43 00128 /* Inner ring */ 00129 -8,2,0, // 44 00130 -8,8,0, // 45 00131 -2,8,0, // 46 00132 -2,2,0 // 47 00133 }; 00134 00135 /** Indices for drawing the triangles of the shadow object */ 00136 static const GLubyte objTriangles[48 * 3] = 00137 { 00138 /* Front */ 00139 0,5,4, 00140 0,1,5, 00141 1,6,5, 00142 1,2,6, 00143 2,7,6, 00144 2,3,7, 00145 3,4,7, 00146 3,0,4, 00147 /* Right */ 00148 8,13,12, 00149 8,9,13, 00150 9,14,13, 00151 9,10,14, 00152 10,15,14, 00153 10,11,15, 00154 11,12,15, 00155 11,8,12, 00156 /* Back */ 00157 16,21,20, 00158 16,17,21, 00159 17,22,21, 00160 17,18,22, 00161 18,23,22, 00162 18,19,23, 00163 19,20,23, 00164 19,16,20, 00165 /* Left */ 00166 24,29,28, 00167 24,25,29, 00168 25,30,29, 00169 25,26,30, 00170 26,31,30, 00171 26,27,31, 00172 27,28,31, 00173 27,24,28, 00174 /* Top */ 00175 32,37,36, 00176 32,33,37, 00177 33,38,37, 00178 33,34,38, 00179 34,39,38, 00180 34,35,39, 00181 35,36,39, 00182 35,32,36, 00183 /* Bottom */ 00184 40,45,44, 00185 40,41,45, 00186 41,46,45, 00187 41,42,46, 00188 42,47,46, 00189 42,43,47, 00190 43,44,47, 00191 43,40,44 00192 00193 }; 00194 00195 /** Normals for the shadow object */ 00196 static const GLbyte objNormals[48 * 3] = 00197 { 00198 /* Front */ 00199 1,0,0, 00200 1,0,0, 00201 1,0,0, 00202 1,0,0, 00203 1,0,0, 00204 1,0,0, 00205 1,0,0, 00206 1,0,0, 00207 /* Right */ 00208 0,1,0, 00209 0,1,0, 00210 0,1,0, 00211 0,1,0, 00212 0,1,0, 00213 0,1,0, 00214 0,1,0, 00215 0,1,0, 00216 /* Back */ 00217 -1,0,0, 00218 -1,0,0, 00219 -1,0,0, 00220 -1,0,0, 00221 -1,0,0, 00222 -1,0,0, 00223 -1,0,0, 00224 -1,0,0, 00225 /* Left */ 00226 0,-1,0, 00227 0,-1,0, 00228 0,-1,0, 00229 0,-1,0, 00230 0,-1,0, 00231 0,-1,0, 00232 0,-1,0, 00233 0,-1,0, 00234 /* Top */ 00235 0,0,1, 00236 0,0,1, 00237 0,0,1, 00238 0,0,1, 00239 0,0,1, 00240 0,0,1, 00241 0,0,1, 00242 0,0,1, 00243 /* Bottom */ 00244 0,0,-1, 00245 0,0,-1, 00246 0,0,-1, 00247 0,0,-1, 00248 0,0,-1, 00249 0,0,-1, 00250 0,0,-1, 00251 0,0,-1 00252 }; 00253 00254 00255 /** Diffuse material definition for the shadow object. */ 00256 static const GLfixed objDiffuseFront[4] = { MATERIALCOLOR(1.0, 0.5, 0.0, 1.0) }; 00257 /** Ambient material definition for the shadow object. */ 00258 static const GLfixed objAmbientFront[4] = { MATERIALCOLOR(1.0, 0.5, 0.0, 1.0) }; 00259 00260 /** Global ambient light. */ 00261 static const GLfixed globalAmbient[4] = { LIGHTCOLOR(0.2, 0.2, 0.2, 1.0) }; 00262 00263 /** Lamp diffuse parameters. */ 00264 static const GLfixed lightDiffuseLamp[4] = { LIGHTCOLOR(0.7, 0.7, 0.7, 1.0) }; 00265 /** Lamp ambient parameters. */ 00266 static const GLfixed lightAmbientLamp[4] = { LIGHTCOLOR(0.3, 0.3, 0.3, 1.0) }; 00267 00268 00269 // ============================= LOCAL FUNCTIONS =============================== 00270 00271 // ----------------------------------------------------------------------------- 00272 // sin 00273 // ----------------------------------------------------------------------------- 00274 /** 00275 * Calculates the sine of the given float. 00276 * @param aRad Angle in radians. 00277 * @return Sine value of the angle. 00278 */ 00279 GLfloat sin(GLfloat aRad) 00280 { 00281 TReal trg, src = (TReal)aRad; 00282 if ( Math::Sin(trg, src) == KErrNone ) 00283 { 00284 return (GLfloat)trg; 00285 } 00286 return 0; 00287 } 00288 00289 // ----------------------------------------------------------------------------- 00290 // cos 00291 // ----------------------------------------------------------------------------- 00292 /** 00293 * Calculates the cosine of the given float. 00294 * @param aRad Angle in radians. 00295 * @return Cosine value of the angle. 00296 */ 00297 GLfloat cos(GLfloat aRad) 00298 { 00299 TReal trg, src = (TReal)aRad; 00300 if ( Math::Cos(trg, src) == KErrNone ) 00301 { 00302 return (GLfloat)trg; 00303 } 00304 return 0; 00305 } 00306 00307 00308 // ============================ MEMBER FUNCTIONS =============================== 00309 00310 // ----------------------------------------------------------------------------- 00311 // CShadows::CShadows 00312 // C++ default constructor can NOT contain any code, that 00313 // might leave. 00314 // ----------------------------------------------------------------------------- 00315 // 00316 CShadows::CShadows( TUint aWidth, TUint aHeight ) 00317 :iScreenWidth(aWidth), iScreenHeight(aHeight) 00318 { 00319 } 00320 00321 00322 // ----------------------------------------------------------------------------- 00323 // CShadows::ConstructL 00324 // Symbian 2nd phase constructor can leave. 00325 // ----------------------------------------------------------------------------- 00326 // 00327 void CShadows::ConstructL( void ) 00328 { 00329 } 00330 00331 00332 // ----------------------------------------------------------------------------- 00333 // CShadows::NewL 00334 // Two-phased constructor. 00335 // ----------------------------------------------------------------------------- 00336 // 00337 CShadows* CShadows::NewL( TUint aWidth, TUint aHeight ) 00338 { 00339 /* Symbian 2-phase constructor. Calls both the default 00340 C++ constructor and Symbian ConstructL methods */ 00341 CShadows* self = new (ELeave) CShadows( aWidth, aHeight ); 00342 CleanupStack::PushL( self ); 00343 self->ConstructL(); 00344 CleanupStack::Pop(); 00345 00346 return self; 00347 } 00348 00349 00350 // Destructor. 00351 CShadows::~CShadows() 00352 { 00353 } 00354 00355 00356 // ----------------------------------------------------------------------------- 00357 // CShadows::AppInit 00358 // Initialize OpenGL ES. 00359 // ----------------------------------------------------------------------------- 00360 // 00361 void CShadows::AppInit( void ) 00362 { 00363 // Set the screen background color. 00364 glClearColor( 0.f, 0.4f, 0.7f, 1.f ); 00365 00366 // Enable auto normalization for object's normals. 00367 glEnable( GL_NORMALIZE ); 00368 00369 // Initialize viewport and projection. 00370 glViewport( 0, 0, iScreenWidth, iScreenHeight ); 00371 glMatrixMode( GL_PROJECTION ); 00372 00373 // Calculate the view frustrum 00374 GLfloat aspectRatio = (GLfloat)(iScreenWidth) / (GLfloat)(iScreenHeight); 00375 glFrustumf( FRUSTUM_LEFT * aspectRatio, FRUSTUM_RIGHT * aspectRatio, 00376 FRUSTUM_BOTTOM, FRUSTUM_TOP, 00377 FRUSTUM_NEAR, FRUSTUM_FAR ); 00378 00379 glMatrixMode( GL_MODELVIEW ); 00380 00381 // Enable vertex and normal arrays. 00382 glEnableClientState( GL_VERTEX_ARRAY ); 00383 glEnableClientState( GL_NORMAL_ARRAY ); 00384 00385 // Set shadow object's front and back materials. 00386 glMaterialxv( GL_FRONT_AND_BACK, GL_AMBIENT, objAmbientFront ); 00387 glMaterialxv( GL_FRONT_AND_BACK, GL_DIFFUSE, objDiffuseFront ); 00388 00389 // Set the normal pointer. 00390 glNormalPointer( GL_BYTE, 0, objNormals ); 00391 00392 // Set up global ambient light. 00393 glLightModelxv( GL_LIGHT_MODEL_AMBIENT, globalAmbient ); 00394 00395 // Do not use perspective correction 00396 glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST ); 00397 00398 // Set up lamp. 00399 glEnable( GL_LIGHT0 ); 00400 glLightxv( GL_LIGHT0, GL_DIFFUSE, lightDiffuseLamp ); 00401 glLightxv( GL_LIGHT0, GL_AMBIENT, lightAmbientLamp ); 00402 glLightxv( GL_LIGHT0, GL_SPECULAR, lightDiffuseLamp ); 00403 00404 glPointSize( 5.0 ); // For drawing the lamp object 00405 00406 // Initial position of the lamp 00407 iLightRadius = 10.0; 00408 iLightAngle = 0.0; 00409 iLightPosX = iLightRadius * cos(iLightAngle); // 10.0 00410 iLightPosY = iLightRadius * sin(iLightAngle); // 0.0 00411 iLightPosZ = 50.0; 00412 00413 iLightPos[0] = iLightPosX; 00414 iLightPos[1] = iLightPosY; 00415 iLightPos[2] = iLightPosZ; 00416 iLightPos[3] = 0.0; 00417 00418 iIsLightRotatedLeft = EFalse; 00419 iIsLightRotatedRight = EFalse; 00420 00421 } 00422 00423 00424 // ----------------------------------------------------------------------------- 00425 // CShadows::AppExit 00426 // Release any allocations made in AppInit. 00427 // ----------------------------------------------------------------------------- 00428 // 00429 void CShadows::AppExit( void ) 00430 { 00431 } 00432 00433 00434 // ----------------------------------------------------------------------------- 00435 // CShadows::DrawPlane 00436 // Draw the ground plane. 00437 // ----------------------------------------------------------------------------- 00438 // 00439 void CShadows::DrawPlane( void ) 00440 { 00441 glColor4f( 255.f, 255.f, 255.f, 255.f ); // White 00442 glVertexPointer( 3, GL_BYTE, 0, planeVertices ); 00443 glDrawElements( GL_TRIANGLES, 2 * 3, GL_UNSIGNED_BYTE, planeTriangles ); 00444 } 00445 00446 00447 // ----------------------------------------------------------------------------- 00448 // CShadows::DrawLamp 00449 // Draw the lamp. 00450 // ----------------------------------------------------------------------------- 00451 // 00452 void CShadows::DrawLamp( void ) 00453 { 00454 /* The lamp is drawn using one vertex from the shadow object 00455 vertex list. The lamp is drawn as a single point. */ 00456 00457 glColor4f( 255.f, 255.f, 0.f, 255.f ); // Yellow 00458 glVertexPointer( 3, GL_BYTE, 0, objVertices ); 00459 glDrawElements( GL_POINTS, 1, GL_UNSIGNED_BYTE, objTriangles ); 00460 } 00461 00462 00463 // ----------------------------------------------------------------------------- 00464 // CShadows::DrawShadowObject 00465 // Draw shadows. 00466 // ----------------------------------------------------------------------------- 00467 // 00468 void CShadows::DrawShadowObject( void ) 00469 { 00470 glColor4f( 0.f, 0.f, 0.f, 255.f ); // Black 00471 glVertexPointer( 3, GL_BYTE, 0, objVertices ); 00472 glDrawElements( GL_TRIANGLES, 48 * 3, GL_UNSIGNED_BYTE, objTriangles ); 00473 } 00474 00475 00476 // ----------------------------------------------------------------------------- 00477 // CShadows::DrawObject 00478 // Draw the shadow object. 00479 // ----------------------------------------------------------------------------- 00480 // 00481 void CShadows::DrawObject( void ) 00482 { 00483 glDrawElements( GL_TRIANGLES, 48 * 3, GL_UNSIGNED_BYTE, objTriangles ); 00484 } 00485 00486 00487 // ----------------------------------------------------------------------------- 00488 // CShadows::CalculateProjectionMatrix 00489 // Calculate proper shadow matrix. 00490 // ----------------------------------------------------------------------------- 00491 // 00492 void CShadows::CalculateProjectionMatrix( void ) 00493 { 00494 /* Shadows are calculated using appropriate projection matrix, which is 00495 defined, e.g., in OpenGL Programming Guide on page 584, or in Jim Blinn's 00496 Corner: A Trip Down the Graphics Pipeline on page 60. The latter also 00497 includes localized light sources as in our case. The general modelview 00498 matrix for creating a planar shadow can be expressed as: 00499 00500 shadowMat = 00501 00502 [ dtop-l[0]*g[0], -l[1]*g[0], -l[2]*g[0], -l[3]*g[0], 00503 -l[0]*g[1], dotp-l[1]*g[1], -l[2]*g[1], -l[3]*g[1], 00504 -l[0]*g[2], -l[1]*g[2], dotp-l[2]*g[2], -l[3]*g[2], 00505 -l[0]*g[3], -l[1]*g[3], -l[2]*g[3], dotp-l[3]*g[3] ], 00506 00507 where l - list(4) - light position 00508 g - list(4) - ground plane equation in form Ax + By + Cz + d = 0 00509 dotp = l[0]*g[0]+l[1]*g[1]+l[2]*g[2]+l[3]*g[3] 00510 00511 Note that in this example the ground plane is a x-y-plane in origin, i.e., 00512 the plane equation is g = [0,0,1,0]. Therefore the matrix can be written 00513 using only the light position parameters. 00514 00515 Note that if you have a local light source, then g[2] = 1. In the case of 00516 directional light g[2] = 0. 00517 */ 00518 00519 GLfloat shadowMat_local[16] = { iLightPosZ, 0.0, 0.0, 0.0, \ 00520 0.0, iLightPosZ, 0.0, 0.0, \ 00521 -iLightPosX, -iLightPosY, 0.0, -1.0, \ 00522 0.0, 0.0, 0.0, iLightPosZ }; 00523 00524 for ( int i=0;i<16;i++ ) 00525 { 00526 iShadowMat[i] = shadowMat_local[i]; 00527 } 00528 00529 } 00530 00531 00532 // ----------------------------------------------------------------------------- 00533 // CShadows::AppCycle 00534 // Draws and animates the objects. 00535 // ----------------------------------------------------------------------------- 00536 // 00537 void CShadows::AppCycle( TInt aFrame ) 00538 { 00539 /* The order of rendering in our case is following: 00540 1. Draw all the ground object, i.e., the plane 00541 2. Draw shadows. If we have multiple ground object, each would have 00542 to be rendered separately with each different light sources. 00543 3. Draw the shadow objects. */ 00544 00545 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); 00546 00547 // Update light position 00548 if ( iIsLightRotatedLeft ) 00549 { 00550 iLightAngle += (GLfloat)0.1; 00551 } 00552 00553 if ( iIsLightRotatedRight ) 00554 { 00555 iLightAngle -= (GLfloat)0.1; 00556 } 00557 00558 iLightPosX = iLightRadius * cos( iLightAngle ); 00559 iLightPosY = iLightRadius * sin( iLightAngle ); 00560 iLightPos[0] = iLightPosX; 00561 iLightPos[1] = iLightPosY; 00562 00563 00564 // Move camera 00565 glLoadIdentity(); 00566 glTranslatef( 0.0, -20.0, -cameraDistance ); 00567 glRotatef( -75.0, 1.0, 0.0, 0.0 ); 00568 00569 glDisable( GL_LIGHTING ); // Plane, lamp, and shadows don't need lighting 00570 glShadeModel( GL_FLAT ); // Plane, lamp, and shadows are single colored 00571 00572 // Draw plane 00573 glPushMatrix(); 00574 glScalef( 80.0, 60.0, 1.0 ); 00575 DrawPlane(); 00576 glPopMatrix(); 00577 00578 // Draw the lamp 00579 glLightfv( GL_LIGHT0, GL_POSITION, iLightPos ); // Update lamp position 00580 glPushMatrix(); 00581 glTranslatef( iLightPosX, iLightPosY, iLightPosZ ); 00582 DrawLamp(); 00583 glPopMatrix(); 00584 00585 glDisable( GL_DEPTH_TEST ); // Disable depth test while drawing shadows 00586 // To ensure that shadows are drawn on top 00587 // of the ground plane 00588 CalculateProjectionMatrix(); // Calculate/update shadowMat 00589 glPushMatrix(); // Store the current modelview for drawing 00590 // the actual objects after shadows are drawn 00591 // modelview = M_camera 00592 glMultMatrixf( iShadowMat ); // Multiply shadow matrix with current 00593 // modelview after camera xforms and before 00594 // model xforms 00595 00596 // Draw shadows 00597 glTranslatef( 0.0, 0.0, 30.0 ); // Translate object above the ground plane 00598 glRotatef( float(aFrame), 1.0, 0.0, 0.0 ); // Rotate object 00599 glRotatef( float(aFrame), 0.0, 1.0, 0.0 ); 00600 glRotatef( float(aFrame), 0.0, 0.0, 1.0 ); 00601 glTranslatef( 5.0, -5.0, -5.0 ); // Move origin to the middle of the 00602 // shadow object 00603 00604 DrawShadowObject(); // Draw shadows, i.e., draw the shadow object with the 00605 // correct modelview matrix: 00606 // modelview = M_camera * M_shadow * M_object 00607 glPopMatrix(); // modelview = M_camera 00608 00609 glEnable( GL_DEPTH_TEST ); // Shadows are drawn -> enable depth test 00610 glEnable( GL_LIGHTING ); // Enable lighting for drawing the objects 00611 glShadeModel( GL_SMOOTH ); // To make the lighting work properly 00612 00613 // Draw shadow object 00614 glTranslatef( 0.0, 0.0, 30.0 ); 00615 glRotatef( float(aFrame), 1.0, 0.0, 0.0 ); 00616 glRotatef( float(aFrame), 0.0, 1.0, 0.0 ); 00617 glRotatef( float(aFrame), 0.0, 0.0, 1.0 ); 00618 glTranslatef( 5.0, -5.0, -5.0 ); 00619 DrawObject(); 00620 00621 } 00622 00623 00624 //---------------------------------------------------------- 00625 // The following methods are called by the CShadowsAppUi 00626 // class when handling the incoming menu events. 00627 //---------------------------------------------------------- 00628 00629 00630 // ----------------------------------------------------------------------------- 00631 // CShadows::RotateLightLeft 00632 // Rotates light to left. 00633 // ----------------------------------------------------------------------------- 00634 // 00635 void CShadows::RotateLightLeft( void ) 00636 { 00637 iIsLightRotatedLeft = !iIsLightRotatedLeft; 00638 } 00639 00640 00641 // ----------------------------------------------------------------------------- 00642 // CShadows::RotateLightRight 00643 // Rotates light to right. 00644 // ----------------------------------------------------------------------------- 00645 // 00646 void CShadows::RotateLightRight( void ) 00647 { 00648 iIsLightRotatedRight = !iIsLightRotatedRight; 00649 } 00650 00651 // ----------------------------------------------------------------------------- 00652 // CShadows::SetScreenSize 00653 // Reacts to the dynamic screen size change during execution of this program. 00654 // ----------------------------------------------------------------------------- 00655 // 00656 void CShadows::SetScreenSize( TUint aWidth, TUint aHeight ) 00657 { 00658 iScreenWidth = aWidth; 00659 iScreenHeight = aHeight; 00660 00661 // Reinitialize viewport and projection. 00662 glViewport( 0, 0, iScreenWidth, iScreenHeight ); 00663 00664 // Recalculate the view frustrum 00665 glMatrixMode( GL_PROJECTION ); 00666 glLoadIdentity(); 00667 GLfloat aspectRatio = (GLfloat)(iScreenWidth) / (GLfloat)(iScreenHeight); 00668 glFrustumf( FRUSTUM_LEFT * aspectRatio, FRUSTUM_RIGHT * aspectRatio, 00669 FRUSTUM_BOTTOM, FRUSTUM_TOP, 00670 FRUSTUM_NEAR, FRUSTUM_FAR ); 00671 glMatrixMode( GL_MODELVIEW ); 00672 }
|
© Nokia 2006 |