620 lines
15 KiB
C++
620 lines
15 KiB
C++
|
/******************************Module*Header*******************************\
|
||
|
* Module Name: logon.cxx
|
||
|
*
|
||
|
* Copyright (c) 1997 Microsoft Corporation
|
||
|
*
|
||
|
\**************************************************************************/
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <string.h>
|
||
|
#include <math.h>
|
||
|
#include <sys/types.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <time.h>
|
||
|
|
||
|
#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();
|
||
|
}
|