/******************************Module*Header*******************************\ * Module Name: logon.cxx * * Copyright (c) 1997 Microsoft Corporation * \**************************************************************************/ #include #include #include #include #include #include #include "uidemo.hxx" #include "logon.hxx" #include "logobj.hxx" //#define TEST_BITMAP 1 //#define UIDEMO_SWITCH_RES 1 MTKWIN *mtkWin; // the main window ISIZE winSize; // main window cached size and position IPOINT2D winPos; BOOL bSwapHintsEnabled; // global swap hints BOOL bSwapHints; // local use HCURSOR hNormalCursor, hHotCursor; HINSTANCE hLogonInstance; BOOL bDebugMode; BOOL bRunAgain; #if 0 BOOL bFlyWithContext = TRUE; #else BOOL bFlyWithContext = FALSE; #endif // Stuff for the banner HDC hdcMem; HBITMAP hBanner; ISIZE bannerSize = { 0, 0 }; RGBA bgColor = {0.16f, 0.234f, 0.32f, 0.0f}; // ok int nLogObj; LOG_OBJECT **pLogObj; static LOG_OBJECT *pHotObj; // currently hot object BOOL bLighting, bDepth; VIEW view; static BOOL bResSwitch; // Timing stuff AVG_UPDATE_TIMER frameRateTimer( 1.0f, 4 ); TIMER transitionTimer; // Forwards static void CleanUp(); static void GLFinish(); /**************************************************************************\ * \**************************************************************************/ float Clamp(int iters_left, float t) { if (iters_left < 3) { return 0.0f; } return (float) (iters_left-2)*t/iters_left; } void ClearWindow() { int clearMask = GL_COLOR_BUFFER_BIT; if( bDepth ) clearMask |= GL_DEPTH_BUFFER_BIT; if( !bSwapHints ) { glClear( clearMask ); return; } GLIRECT rect, *pRect; pRect = ▭ for( int i = 0; i < nLogObj; i++ ) { pLogObj[i]->GetRect( pRect ); glScissor( pRect->x, pRect->y, pRect->width, pRect->height ); glClear( clearMask ); AddSwapHintRect( pRect ); } // restore full scissor (mf : ? or just disable,since this only place used ? glScissor( 0, 0, winSize.width, winSize.height ); } void ClearAll() { static GLIRECT rect = {0}; int clearMask = GL_COLOR_BUFFER_BIT; if( bDepth ) clearMask |= GL_DEPTH_BUFFER_BIT; glScissor( 0, 0, winSize.width, winSize.height ); glClear( clearMask ); if( bSwapHints ) { rect.width = winSize.width; rect.height = winSize.height; AddSwapHintRect( &rect ); } } void ClearRect( GLIRECT *pRect, BOOL bResetScissor ) { int clearMask = GL_COLOR_BUFFER_BIT; if( bDepth ) clearMask |= GL_DEPTH_BUFFER_BIT; glScissor( pRect->x, pRect->y, pRect->width, pRect->height ); glClear( clearMask ); if( bResetScissor ) glScissor( 0, 0, winSize.width, winSize.height ); } void DrawObjects( BOOL bCalcUpdateRect ) { // Draws objects in their current positions for( int i = 0; i < nLogObj; i++ ) { pLogObj[i]->Draw( bCalcUpdateRect ); } } void Flush() { // glFlush, SwapBuffers (if doubleBuf) mtkWin->Flush(); } float MyRand(void) { return 10.0f * ( ((float) rand())/((float) RAND_MAX) - 0.5f); } static void SetDepthMode() { if( bDepth ) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST); } static void SetTextureMode() { int mode; if( bLighting ) mode = GL_MODULATE; else mode = GL_DECAL; glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, mode ); } static void SetLightingMode() { if( bLighting ) glEnable( GL_LIGHTING ); else glDisable( GL_LIGHTING ); SetTextureMode(); } void CalcObjectWindowRects() { for( int i = 0; i < nLogObj; i++ ) { pLogObj[i]->CalcWinRect(); } } //mf: VIEW class member static void SetView( ISIZE *pWinSize ) { glViewport(0, 0, pWinSize->width, pWinSize->height); view.fViewDist = 10.0f; // viewing distance view.fovy = 45.0f; // field of view in y direction (degrees) view.fAspect = (float) pWinSize->width / (float) pWinSize->height; // We'll assume width >= height glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(view.fovy, view.fAspect, 0.1, 100.0); // glOrtho( -5.0, 5.0, -5.0, 5.0, 0.0, 100.0 ); no look as good glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(0,0,view.fViewDist, 0,0,0, 0,1,0); // from, to, up... } void Reshape(int width, int height) { // Need to update main window info ISIZE *pSize = &winSize; pSize->width = width; pSize->height = height; if( !width || !height ) return; SetView( pSize ); UpdateLocalTransforms( UPDATE_ALL ); CalcObjectWindowRects(); // mf: this is kind of a hack, need a different mechanism, since get repaints // from resizes and window expose (an argument for msg loops even in mtk // programs. Of course, there's also tkDisplayFunc, which is called on PAINT, // as opposed to IdleFunc... ClearAll(); } BOOL EscKey(int key, GLenum mask) { if( bDebugMode && (key == TK_ESCAPE) ) Quit(); return FALSE; } BOOL Key(int key, GLenum mask) { if( !bDebugMode ) return FALSE; switch (key) { case TK_ESCAPE: Quit(); break; default: return AttributeKey( key, mask ); } return TRUE; } BOOL AttributeKey(int key, GLenum mask) { switch (key) { case TK_c : bFlyWithContext = !bFlyWithContext; break; case TK_d : bDepth = !bDepth; SetDepthMode(); break; case TK_l : bLighting = !bLighting; // This affects texturing mode SetLightingMode(); break; case TK_s : if( mtk_bAddSwapHintRect() ) bSwapHintsEnabled = !bSwapHintsEnabled; break; default: return FALSE; } return TRUE; } static void LoadCursors() { hNormalCursor = LoadCursor( NULL, IDC_ARROW ); hHotCursor = LoadCursor( hLogonInstance, MAKEINTRESOURCE( IDC_HOT_CURSOR ) ); } /******************** MAIN LOGON SEQUENCE *********************************\ * \**************************************************************************/ static MTKWIN *CreateLogonWindow() { MTKWIN *win; // Set window size and position bResSwitch = FALSE; UINT winConfig = 0; // Have to intially create window without cursor, so can change it later winConfig |= MTK_NOCURSOR; if( bDebugMode ) { winPos.x = 10; winPos.y = 30; #if 0 winSize.width = 400; winSize.height = 300; #else winSize.width = 800; winSize.height = 600; #endif } else { #if UIDEMO_SWITCH_RES if( mtk_ChangeDisplaySettings( 800, 600, NULL ) ) { bResSwitch = TRUE; } #endif winConfig |= MTK_FULLSCREEN | MTK_NOBORDER; winPos.x = 0; winPos.y = 0; winSize.width = GetSystemMetrics( SM_CXSCREEN ); winSize.height = GetSystemMetrics( SM_CYSCREEN ); #if 0 // debugging full screen ... winSize.width /= 4; winSize.height /= 4; #endif } win = new MTKWIN(); if( !win ) return NULL; // Configure and create the window (mf: this 2 step process of constructor // and create will allow creating 'NULL' windows #ifdef TEST_BITMAP UINT glConfig = MTK_RGB | MTK_DOUBLE | MTK_BITMAP | MTK_DEPTH16; #else UINT glConfig = MTK_RGB | MTK_DOUBLE | MTK_DEPTH16; #endif if( !bDebugMode ) glConfig |= MTK_NOBORDER; // Create the window if( ! win->Create( "Demo", &winSize, &winPos, winConfig, NULL ) ) { delete win; return NULL; } // Configure the window for OpenGL, setting ReshapeFunc to catch the // resize (can't set it before in this case, since we do various gl // calculations in the Reshape func. win->SetReshapeFunc(Reshape); win->SetFinishFunc(GLFinish); if( ! win->Config( glConfig ) ) { delete win; return NULL; } return win; } static void InitGL(void) { #if 0 static float lmodel_ambient[] = {0.0f, 0.0f, 0.0f, 0.0f}; #else static float lmodel_ambient[] = {0.2f, 0.2f, 0.2f, 0.0f}; #endif //mf: change to one sided lighting if object is closed static float lmodel_twoside[] = {(float)GL_TRUE}; static float lmodel_local[] = {(float)GL_FALSE}; static float light0_ambient[] = {0.1f, 0.1f, 0.1f, 1.0f}; static float light0_diffuse[] = {1.0f, 1.0f, 1.0f, 0.0f}; #if 1 // static float light0_position[] = {-1.0f, 1.0f, 1.0f, 0.0f}; static float light0_position[] = {-1.0f, 0.8f, 4.0f, 0.0f}; #else static float light0_position[] = {-1.0f, 1.0f, 1.0f, 0.0f}; #endif static float light0_specular[] = {1.0f, 1.0f, 1.0f, 0.0f}; static float bevel_mat_ambient[] = {0.0f, 0.0f, 0.0f, 1.0f}; static float bevel_mat_shininess[] = {40.0f}; static float bevel_mat_specular[] = {1.0f, 1.0f, 1.0f, 0.0f}; static float bevel_mat_diffuse[] = {1.0f, 1.0f, 1.0f, 0.0f}; // Set GL attributes // glEnable(GL_CULL_FACE); glEnable( GL_SCISSOR_TEST ); glCullFace(GL_BACK); glClearDepth(1.0f); glClearColor( bgColor.r, bgColor.g, bgColor.b, bgColor.a ); glLightfv(GL_LIGHT0, GL_AMBIENT, light0_ambient); glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse); glLightfv(GL_LIGHT0, GL_SPECULAR, light0_specular); glLightfv(GL_LIGHT0, GL_POSITION, light0_position); glEnable(GL_LIGHT0); glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, lmodel_local); glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside); glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient); glEnable(GL_LIGHTING); glMaterialfv(GL_FRONT, GL_AMBIENT, bevel_mat_ambient); glMaterialfv(GL_FRONT, GL_SHININESS, bevel_mat_shininess); glMaterialfv(GL_FRONT, GL_SPECULAR, bevel_mat_specular); glMaterialfv(GL_FRONT, GL_DIFFUSE, bevel_mat_diffuse); glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE); glEnable(GL_COLOR_MATERIAL); glEnable( GL_TEXTURE_2D ); // Setup viewing parameters SetView( &winSize ); // Rendering attributes bDepth = FALSE; SetDepthMode(); bLighting = FALSE; SetLightingMode(); #if 0 glShadeModel(GL_SMOOTH); #else glShadeModel(GL_FLAT); #endif #ifdef TEST_BITMAP bSwapHintsEnabled = FALSE; #else bSwapHintsEnabled = mtk_bAddSwapHintRect(); #endif // Update local copies of transforms, so we can calc 2D update rects //mf: ? protect with bSwapHints ? UpdateLocalTransforms( UPDATE_ALL ); } static HBITMAP LoadBanner() { hdcMem = CreateCompatibleDC( NULL ); HBITMAP hBanner = LoadBitmap( hLogonInstance, MAKEINTRESOURCE( IDB_BANNER ) ); BITMAPINFO bmi = {0}; bmi.bmiHeader.biSize = sizeof( BITMAPINFOHEADER ); if( ! GetDIBits( hdcMem, hBanner, 0, 0, NULL, &bmi, DIB_RGB_COLORS ) ) { SS_WARNING( "Couldn't get banner bitmap dimensions\n" ); } else { bannerSize.width = bmi.bmiHeader.biWidth; bannerSize.height = bmi.bmiHeader.biHeight; } if( !SelectObject( hdcMem, hBanner ) ) { SS_ERROR( "Couldn't select banner into DC\n" ); return 0; } return hBanner; //mf: make hdcMem global, so it and hBanner can be deleted } BOOL LoadUserTextures( TEX_RES *pUserTexRes ) { SetWindowText( mtkWin->GetHWND(), "Loading textures..." ); for (int i = 0; i < nLogObj; i++) { pLogObj[i]->SetTexture( new TEXTURE( &pUserTexRes[i], hLogonInstance ) ); //mf: also validate the textures... } glFinish(); SetWindowText( mtkWin->GetHWND(), "" ); return TRUE; } /******************** RunLogonSequence ************************************\ * \**************************************************************************/ BOOL RunLogonSequence( ENV *pEnv ) { BOOL bRet; LOG_OBJECT *pSelectedLogObj; // Create table of ptrs to LOGOBJ's, which are wrappers around the list of // users. The list of users and their bitmaps, etc, should eventually be // a parameter to this function. bDebugMode = pEnv->bDebugMode; nLogObj = pEnv->nUsers; hLogonInstance = pEnv->hInstance; pLogObj = (LOG_OBJECT **) malloc( nLogObj * sizeof(LOG_OBJECT *) ); for( int i = 0; i < nLogObj; i ++ ) { pLogObj[i] = new LOG_OBJECT(); } // Create a window to run the logon sequence in mtkWin = CreateLogonWindow(); if( !mtkWin ) return FALSE; // Do any GL init for the window InitGL(); LoadBanner(); LoadUserTextures( pEnv->pUserTexRes ); SetCursor( NULL ); LoadCursors(); mtkWin->SetReshapeFunc( Reshape ); if( bDebugMode ) { // The sequences can repeat ad infinitum //mf: pretty crazy logic while( 1 ) { if( !RunLogonInitSequence() ) // fatal break; run_hot_sequence: bRunAgain = FALSE; pSelectedLogObj = RunLogonHotSequence(); if( bRunAgain ) { continue; } if( pSelectedLogObj == NULL ) // fatal, no obect selected or window was closed break; if( ! RunLogonEndSequence( pSelectedLogObj ) ) // fatal break; if( bRunAgain ) { goto run_hot_sequence; } break; } } else { // Normal operation... //mf: ? check for fatal errors ? or if !debugMode, call Quit whenever // Exec returns false RunLogonInitSequence(); // Run 'hot' sequence, where user selects object if( !(pSelectedLogObj = RunLogonHotSequence()) ) { // No user selected, fatal CleanUp(); return FALSE; } // Set the selected user index for( i = 0; i < nLogObj; i ++ ) { if( pSelectedLogObj == pLogObj[i] ) pEnv->iSelectedUser = i; } // Run final sequence RunLogonEndSequence( pSelectedLogObj ); } // Do various clean-up CleanUp(); return TRUE; } void CleanUp() { if( mtkWin ) mtkWin->Close(); // this will call destructor for mtkWin if( bResSwitch ) mtk_RestoreDisplaySettings(); } // This function is the FinishFunc callback, and should not be called directly static void GLFinish() { // Delete textures //mf: may want to keep the selected one... , depending on what the caller wants // returned. Maybe could keep the image data around, and then create a new // TEXTURE ctor that uses this data... for( int i = 0; i < nLogObj; i++ ) { if( pLogObj[i]->pTex ) { delete pLogObj[i]->pTex; pLogObj[i]->pTex = NULL; } } } //mf: this can be called during debug mode, to terminate prematurely void Quit() { CleanUp(); mtkQuit(); }