AGLSurfaceTexture.c

/*
    File:       AGLSurfaceTexture.c
 
    Contains:   An example of the use of surface texturing from AGL
 
    Written by: ggs
 
    Copyright:  2000-2002 Apple Computer, Inc., All Rights Reserved
 
    Change History (most recent first):
 
 
    Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
                ("Apple") in consideration of your agreement to the following terms, and your
                use, installation, modification or redistribution of this Apple software
                constitutes acceptance of these terms.  If you do not agree with these terms,
                please do not use, install, modify or redistribute this Apple software.
 
                In consideration of your agreement to abide by the following terms, and subject
                to these terms, Apple grants you a personal, non-exclusive license, under Appleƕs
                copyrights in this original Apple software (the "Apple Software"), to use,
                reproduce, modify and redistribute the Apple Software, with or without
                modifications, in source and/or binary forms; provided that if you redistribute
                the Apple Software in its entirety and without modifications, you must retain
                this notice and the following text and disclaimers in all such redistributions of
                the Apple Software.  Neither the name, trademarks, service marks or logos of
                Apple Computer, Inc. may be used to endorse or promote products derived from the
                Apple Software without specific prior written permission from Apple.  Except as
                expressly stated in this notice, no other rights or licenses, express or implied,
                are granted by Apple herein, including but not limited to any patent rights that
                may be infringed by your derivative works or by other works in which the Apple
                Software may be incorporated.
 
                The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
                WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
                WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
                COMBINATION WITH YOUR PRODUCTS.
 
                IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
                CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
                GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
                OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
                (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
                ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    
*/
 
// NOTE: Requires Mac OS X 10.2
 
 
// system includes ----------------------------------------------------------
 
 
#include <math.h>
#include <stdio.h>
#include <string.h>
 
#if defined (__APPLE_CC__)
    #include <AGL/agl.h>
    #include <OpenGL/gl.h>
    #include <OpenGL/glu.h>
    #include <OpenGL/glext.h>
#else   
    #include <agl.h>
    #include <gl.h>
    #include <glu.h>
    #include <glext.h>
#endif
 
#include "stanfordbunny.h"
 
// project includes ---------------------------------------------------------
 
 
 
// prototypes ---------------------------------------------------------------
 
static void CToPStr (StringPtr outString, const char *inString);
static void ReportError (char * strError);
static GLenum aglDebugStr (void);
static GLenum glDebugStr (void);
static void DrawCube (GLfloat fSize, GLint texWidth, GLint texHeight);
 
static AGLContext SetupAGL (WindowRef win);
static void CleanupAGL (AGLContext ctx);
static void DrawGL(WindowPtr pWindow, AGLContext gDestContext);
 
void InitToolbox(void);
Boolean SetUp (void);
void DoMenu (SInt32 menuResult);
void DoKey (SInt8 theKey, SInt8 theCode);
void DoUpdate (WindowPtr pWindow);
pascal void IdleTimer (EventLoopTimerRef inTimer, void* userData);
EventLoopTimerUPP GetTimerUPP (void);
void DoEvent (void);
void CleanUp (void);
 
 
// statics/globals (internal only) ------------------------------------------
 
// Menu defs
enum 
{
    kMenuApple = 128,
    kMenuFile = 129,
    
    kAppleAbout = 1,
    kFileShowHideST = 1,
    kFileQuit = 2
};
 
enum 
{
    kForegroundSleep = 10,
    kBackgroundSleep = 10000
};
EventLoopTimerRef gTimer = NULL;
 
enum 
{
    kTextureSize = 256
};
 
SInt32 gSleepTime = kForegroundSleep;
Boolean gDone = false, gfFrontProcess = true;
Boolean gRectTexture = false;
 
AGLContext gSurfaceTextureContext = 0;
GLint gSurfaceTexName = 0;
WindowPtr gSurfaceTextureWindowPtr = NULL;
AGLContext gDestContext = 0;
WindowPtr gDestWindowPtr = NULL;
 
GLboolean gLines = GL_FALSE;
GLboolean gPolygons = GL_TRUE;
 
// simple cube data
GLint cube_num_vertices = 8;
GLfloat cube_vertices [8][3] = {
{1.0, 1.0, 1.0}, {1.0, -1.0, 1.0}, {-1.0, -1.0, 1.0}, {-1.0, 1.0, 1.0},
{1.0, 1.0, -1.0}, {1.0, -1.0, -1.0}, {-1.0, -1.0, -1.0}, {-1.0, 1.0, -1.0} };
 
GLint num_faces = 6;
short cube_faces [6][4] = {
{3, 2, 1, 0}, {2, 3, 7, 6}, {0, 1, 5, 4}, {3, 0, 4, 7}, {1, 2, 6, 5}, {4, 5, 6, 7} };
short cube_texCoords [2][4] = {
{0.0, 0.0, 1.0, 1.0}, {0.0, 1.0, 1.0, 0.0} };
 
GLuint gBunnyWireList = NULL;
GLuint gBunnySolidList = NULL;
GLboolean gBunnyLines = GL_FALSE;
 
// functions (internal/private) ---------------------------------------------
 
// Copy C string to Pascal string
 
static void CToPStr (StringPtr outString, const char *inString)
{   
    unsigned char x = 0;
    do {
        *(((char*)outString) + x + 1) = *(inString + x); x++;
    } while ((*(inString + x) != 0)  && (x < 256));
    *((char*)outString) = (char) x;                                 
}
 
// --------------------------------------------------------------------------
 
static void ReportError (char * strError)
{
    char errMsgCStr [256];
    Str255 strErr;
 
    sprintf (errMsgCStr, "%s", strError); 
 
    // out as debug string
    CToPStr (strErr, errMsgCStr);
    DebugStr (strErr);
}
 
//-----------------------------------------------------------------------------------------------------------------------
 
// if error dump agl errors to debugger string, return error
 
static GLenum aglDebugStr (void)
{
    GLenum err = aglGetError();
    if (AGL_NO_ERROR != err)
        ReportError ((char *)aglErrorString(err));
    return err;
}
 
//---------------------------------------------------------------------------
 
// if error dump agl errors to debugger string, return error
 
static GLenum glDebugStr (void)
{
    GLenum err = glGetError();
    if (GL_NO_ERROR != err)
        ReportError ((char *) gluErrorString(err));
    return err;
}
 
// --------------------------------------------------------------------------
 
static void DrawCube (GLfloat fSize, GLint texWidth, GLint texHeight)
{
    long f, i;
    if (gPolygons)
    {
        glBegin (GL_QUADS);
        for (f = 0; f < num_faces; f++)
            for (i = 0; i < 4; i++)
            {
                glVertex3f(cube_vertices[cube_faces[f][i]][0] * fSize, cube_vertices[cube_faces[f][i]][1] * fSize, cube_vertices[cube_faces[f][i]][2] * fSize);
                glTexCoord2i (cube_texCoords [0][i] * (gRectTexture ? texWidth : 1.0f), 
                              cube_texCoords [1][i] * (gRectTexture ? texHeight : 1.0f));
            }
        glEnd ();
    }
    if (gLines)
    {
        glDisable(gRectTexture ? GL_TEXTURE_RECTANGLE_EXT : GL_TEXTURE_2D);
        glColor3f (0.0, 1.0, 1.0);
        for (f = 0; f < num_faces; f++)
        {
            glBegin (GL_LINE_LOOP);
                for (i = 0; i < 4; i++)
                    glVertex3f(cube_vertices[cube_faces[f][i]][0] * fSize, cube_vertices[cube_faces[f][i]][1] * fSize, cube_vertices[cube_faces[f][i]][2] * fSize);
            glEnd ();
        }
    }
}
 
//---------------------------------------------------------------------------
 
void SetLighting(void)
{
    GLfloat mat_ambient[] = {0.329412, 0.223529, 0.027451, 1.0};
    GLfloat mat_diffuse[] = {0.780392, 0.568627, 0.113725, 1.0};
    GLfloat mat_specular[] = {0.992157, 0.941176, 0.807843, 1.0};
    GLfloat mat_shininess[] = {27.8974};
 
    GLfloat position[4] = {7.0,-7.0,12.0,0.0};
    GLfloat ambient[4]  = {0.2,0.2,0.2,1.0};
    GLfloat diffuse[4]  = {0.9,0.9,0.9,1.0};
    GLfloat specular[4] = {1.0,1.0,1.0,1.0};
    
    glMaterialfv (GL_FRONT, GL_AMBIENT, mat_ambient);
    glMaterialfv (GL_FRONT, GL_DIFFUSE, mat_diffuse);
    glMaterialfv (GL_FRONT, GL_SPECULAR, mat_specular);
    glMaterialfv (GL_FRONT, GL_SHININESS, mat_shininess);
    
    glLightfv(GL_LIGHT0,GL_POSITION,position);
    glLightfv(GL_LIGHT0,GL_AMBIENT,ambient);
    glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuse);
    glLightfv(GL_LIGHT0,GL_SPECULAR,specular);
    glEnable(GL_LIGHT0);
}
 
 
#pragma mark -
//-----------------------------------------------------------------------------------------------------------------------
#pragma mark --- AGL Setup Code ---
 
// OpenGL Simple Setup
 
static AGLContext SetupAGL (WindowRef win)
{
    GLint          attrib[] = { AGL_RGBA, AGL_DOUBLEBUFFER, AGL_DEPTH_SIZE, 16, AGL_NONE };
    AGLPixelFormat  fmt;
    AGLContext      ctx;
    short fNum;
 
    if ((Ptr) kUnresolvedCFragSymbolAddress == (Ptr) aglChoosePixelFormat) // check for existance of OpenGL
    {
        ReportError("OpenGL not installed");
        return NULL;
    }   
 
    fmt = aglChoosePixelFormat(NULL, 0, attrib);            // get an appropriate pixel format
    aglDebugStr ();
    if (NULL == fmt) 
    {
        ReportError("Could not find valid pixel format");
        return NULL;
    }
    
    ctx = aglCreateContext (fmt, NULL);                         // Create an AGL context
    aglDebugStr ();
    if (NULL == ctx)
    {
        ReportError ("Could not create context");
        return NULL;
    }
    
    if (!aglSetDrawable (ctx, GetWindowPort (win)))                             // attach the CGrafPtr to the context
        aglDebugStr ();
    else if (!aglSetCurrentContext (ctx))                       // make the context the current context
    {
        aglDebugStr ();
        aglSetDrawable (ctx, NULL);
    }
 
    aglDestroyPixelFormat(fmt);                                 // pixel format is no longer needed
 
    { // set up viewport and projection    
        GLfloat fAspect;
        short w, h;
        Rect rectPort;
 
        GetWindowPortBounds(win, &rectPort);
        w = rectPort.right - rectPort.left;
        h = rectPort.bottom - rectPort.top;
        
        // Prevent a divide by zero
        if(h == 0)
            h = 1;
        fAspect = (GLfloat) w / (GLfloat) h;
 
        // Set Viewport to window dimensions
        glViewport (0, 0, (GLsizei) w, (GLsizei) h);
        glMatrixMode (GL_PROJECTION);
    
        // Reset coordinate system
        glLoadIdentity ();
    
        // Setup perspective for viewing
        gluPerspective (45.0, fAspect, 0.1, 15);
 
        glDebugStr (); // check for errors
    }
 
    { // do we have rectangular textures
        const GLubyte * strExtension = glGetString (GL_EXTENSIONS); // get extension string
        gRectTexture = (NULL != strstr ((const char *) strExtension, "GL_EXT_texture_rectangle"));
        glDebugStr (); // check for errors
    }
    
    // initial GL settings
    glShadeModel (GL_SMOOTH);
 
    glEnable(GL_DEPTH_TEST);    // Hidden surface removal
    glEnable(GL_CULL_FACE); // Do not draw inside of cube
    glFrontFace(GL_CCW);    // Counter clock-wise polygons face out
    
    gBunnySolidList = GenStanfordBunnySolidList ();
    gBunnyWireList = GenStanfordBunnyWireList ();
 
    glPolygonOffset (1.0,1.0);
    glEnable(GL_POLYGON_OFFSET_FILL);
    glClearColor (0.2f, 0.2f, 0.4f, 1.0f);  
    glPointSize (3.0);
    glDebugStr (); // check for errors
 
    GetFNum("\pMonaco", &fNum);                                 // build font
    
    return ctx;
}
 
//-----------------------------------------------------------------------------------------------------------------------
 
// OpenGL Cleanup
 
static void CleanupAGL(AGLContext ctx)
{
    aglSetCurrentContext (ctx);
    aglSetDrawable(ctx, NULL);
    aglSetCurrentContext(NULL);
    aglDestroyContext(ctx);
    aglDebugStr (); // check for errors
}
 
//-----------------------------------------------------------------------------------------------------------------------
 
// OpenGL Drawing
 
static void DrawGL(WindowPtr pWindow, AGLContext aglContext)
{
    static GLfloat fRot [3] = { 0.0, 0.0, 0.0 };
    static GLfloat fVel [3] = { 0.3, 0.1, 0.2 };
    static GLfloat fAccel [3] = { 0.003, -0.005, 0.004 };
    GLfloat fVMax = 1.0;
    short i;
    
    if (!pWindow || !aglContext)
        return;
    // do spin velocities
    for (i = 0; i < 3; i++)
    {
        fVel[i] += fAccel[i];
        if (fVel[i] > fVMax)
        {
            fAccel[i] *= -1.0;
            fVel[i] = fVMax;
        }
        else if (fVel[i] < -fVMax)
        {
            fAccel[i] *= -1.0;
            fVel[i] = -fVMax;
        }
        fRot[i] += fVel[i];
        while (fRot[i] > 360.0)
            fRot[i] -= 360.0;
        while (fRot[i] < -360.0)
            fRot[i] += 360.0;
    }
 
    aglSetCurrentContext (aglContext);
    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
    // Viewing transformation
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    if (pWindow == gSurfaceTextureWindowPtr) // if we are drawing the source for the surface texture
        glTranslatef(0.0, 0.0, -2.0);
    else if (pWindow == gDestWindowPtr)
        glTranslatef(0.0, 0.0, -8.0);
 
    glRotatef (fRot[0], 1.0, 0.0, 0.0);
    glRotatef (fRot[1], 0.0, 1.0, 0.0);
    glRotatef (fRot[2], 0.0, 0.0, 1.0);
    glDebugStr (); // check for errors
 
#pragma mark --- Drawing Code ---
    // determine whether we are rendering to the source texture or the destination window
    if (pWindow == gSurfaceTextureWindowPtr) { // if we are drawing the source for the surface texture
        // fill surface texture, this could be any GL content...
        glClearColor (0.2f, 0.2f, 0.4f, 1.0f);  // clear the surface
        glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glDisable(gRectTexture ? GL_TEXTURE_RECTANGLE_EXT : GL_TEXTURE_2D); // disable texturing
        glDebugStr (); // check for errors
        glEnable(GL_LIGHTING);
        glCallList (gBunnySolidList);
        glDebugStr (); // check for errors
    } else if (pWindow == gDestWindowPtr) {
        // draw destination content using surface texture
        // clear buffer
        glClearColor (0.2f, 0.2f, 0.2f, 1.0f);  
        glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        // enable surface texturing
        if (gSurfaceTextureContext) {
            glEnable(gRectTexture ? GL_TEXTURE_RECTANGLE_EXT : GL_TEXTURE_2D); // enable texturing 
#pragma mark === aglSurfaceTexture ===
            if (0 == gSurfaceTexName) {
                glGenTextures (1, &gSurfaceTexName);
                glBindTexture (gRectTexture ? GL_TEXTURE_RECTANGLE_EXT : GL_TEXTURE_2D, gSurfaceTexName);
                glTexParameterf (gRectTexture ? GL_TEXTURE_RECTANGLE_EXT : GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
                aglSurfaceTexture (gDestContext, gRectTexture ? GL_TEXTURE_RECTANGLE_EXT : GL_TEXTURE_2D, GL_RGBA8, gSurfaceTextureContext); // draw with surface texture
            } else {
                glBindTexture (gRectTexture ? GL_TEXTURE_RECTANGLE_EXT : GL_TEXTURE_2D, gSurfaceTexName);
            }
            glColor3f (1.0, 1.0, 1.0); // no coloring
        } else { // disable if no surface texture context
            glDisable(gRectTexture ? GL_TEXTURE_RECTANGLE_EXT : GL_TEXTURE_2D);
            glColor3f (0.8f, 0.1f, 0.1f); // red cube
            glDebugStr (); // check for errors
        }
        gLines = true; // draw edges
        DrawCube(2.0, kTextureSize, kTextureSize); // draw a cube with the faces textured with surface texture
        glDebugStr (); // check for errors
    }
    glBindTexture (gRectTexture ? GL_TEXTURE_RECTANGLE_EXT : GL_TEXTURE_2D, 0); // unbind from the pbuffer (stability fix for pre-release Panther)
    aglSwapBuffers(aglContext); // send swap command
    aglDebugStr (); // check for errors
}
 
#pragma mark -
// --------------------------------------------------------------------------
// super basic toolbox stuff
 
static pascal OSErr QuitAppleEventHandler( const AppleEvent *appleEvt, AppleEvent* reply, SInt32 refcon )
{
    #pragma unused (appleEvt, reply, refcon)
    gDone =  true;
    return false;
}
 
//-----------------------------------------------------------------------------------------------------------------------
 
void InitToolbox(void)
{
    MenuHandle menu;
    long response;
    OSStatus err;
    
    InitCursor();
    
    // Init Menus
    menu = NewMenu (kMenuApple, "\p\024");          // new  apple menu
    InsertMenu (menu, 0);                           // add menu to end
 
    menu = NewMenu (kMenuFile, "\pFile");           // new menu
    InsertMenu (menu, 0);                           // add menu to end
    
    AppendMenu (menu, "\pShow Hide Surface Texture/S"); // add show/hide surface texture
 
    // add quit if not under Mac OS X
    err = Gestalt (gestaltMenuMgrAttr, &response);
    if ((err == noErr) && !(response & gestaltMenuMgrAquaLayoutMask))
            AppendMenu (menu, "\pQuit/Q");                  // add quit
 
    DrawMenuBar();
    {
        err = AEInstallEventHandler( kCoreEventClass, kAEQuitApplication, NewAEEventHandlerUPP(QuitAppleEventHandler), 0, false );
        if (err != noErr)
            ExitToShell();
    }
    
    DrawMenuBar();
} 
 
// --------------------------------------------------------------------------
 
Boolean SetUp (void)
{
    InitToolbox ();
 
#pragma mark --- Window Setup Code ---
    {
        // build surface texture window (ensure size is compatible with texture mode
        Rect rectWin = {100, 100, 100 + kTextureSize, 100 + kTextureSize};
        gSurfaceTextureWindowPtr = (WindowPtr) NewCWindow (NULL, &rectWin, "\pSource Surface", true, kWindowDocumentProc, (WindowPtr)-1, 0, 0);
        gSurfaceTextureContext = SetupAGL (gSurfaceTextureWindowPtr);
        SetLighting();
        glEnable(GL_LIGHTING);
        DoUpdate (gSurfaceTextureWindowPtr); // force off screen surface texture window to update
        
        // build destination windwo
        rectWin.left = rectWin.right + 50;
        rectWin.right = rectWin.left + 600;
        rectWin.bottom = rectWin.top + 600;
        gDestWindowPtr = (WindowPtr) NewCWindow (NULL, &rectWin, "\pTarget", true, kWindowFullZoomGrowDocumentProc, (WindowPtr)-1, 0, 0);
        gDestContext = SetupAGL (gDestWindowPtr);
        
        // ensure the windows animate (max 100 fps)
        InstallEventLoopTimer (GetCurrentEventLoop(), 0, 0.01, GetTimerUPP (), 0, &gTimer);
    }
    return true;
}
 
// --------------------------------------------------------------------------
 
void DoMenu (SInt32 menuResult)
{
    SInt16 theMenu;
    SInt16 theItem;
    MenuRef theMenuHandle;
        
    theMenu = HiWord(menuResult);
    theItem = LoWord(menuResult);
    theMenuHandle = GetMenuHandle(theMenu);
 
    switch (theMenu)
    {
        case kMenuApple:
            switch (theItem)
            {
                case kAppleAbout:
                    break;
                default:
                    break;
            }
            break;
        case kMenuFile:
            switch (theItem)
            {
                case kFileShowHideST:
                    ShowHide (gSurfaceTextureWindowPtr, !MacIsWindowVisible (gSurfaceTextureWindowPtr));
                    break;
                case kFileQuit:
                    gDone = true;
                    break;
            }
            break;
    }
    HiliteMenu(0);
    DrawMenuBar();
}
 
// --------------------------------------------------------------------------
 
void DoKey (SInt8 theKey, SInt8 theCode)
{
    #pragma unused (theCode, theKey)
    // do nothing
}
 
// --------------------------------------------------------------------------
 
void DoUpdate (WindowPtr pWindow)
{
    #pragma unused (pWindow)
#pragma mark --- Update Code ---
    // update the surafce texture
    if ((pWindow == gSurfaceTextureWindowPtr) && gSurfaceTextureContext)
        DrawGL (pWindow, gSurfaceTextureContext);
    // update the destiantion window (these do not have to linked but for simplicity they are in this case)
    if ((pWindow == gDestWindowPtr) && gDestContext)
        DrawGL (pWindow, gDestContext);
}
 
// --------------------------------------------------------------------------
 
pascal void IdleTimer (EventLoopTimerRef inTimer, void* userData)
{
    #pragma unused (inTimer, userData)
    DoUpdate (gSurfaceTextureWindowPtr);
    DoUpdate (gDestWindowPtr);
}
 
// --------------------------------------------------------------------------
 
EventLoopTimerUPP GetTimerUPP (void)
{
    static EventLoopTimerUPP    sTimerUPP = NULL;
    
    if (sTimerUPP == NULL)
        sTimerUPP = NewEventLoopTimerUPP (IdleTimer);
    
    return sTimerUPP;
}
 
// --------------------------------------------------------------------------
 
void DoEvent (void)
{
    EventRecord theEvent;
    Rect rectGrow;
    SInt32 menuResult;
    WindowRef whichWindow = NULL;
    GrafPtr pGrafSave;
    long grow;
    SInt16 whatPart;
    SInt8 theKey;
    SInt8 theCode;
    
    if (WaitNextEvent(everyEvent, &theEvent, gSleepTime, NULL)) {
        switch (theEvent.what) {
            case mouseDown:
                whatPart = FindWindow(theEvent.where, &whichWindow);
                if (whichWindow != NULL)
                    SelectWindow (whichWindow);
                switch (whatPart) {
                    case inGoAway:
                        break;
                    case inMenuBar:
                        DrawMenuBar();
                        menuResult = MenuSelect(theEvent.where);
                        if (HiWord(menuResult) != 0)
                            DoMenu(menuResult);
                        break;
                    case inDrag: {
                            BitMap  screenBits;
                            DragWindow(whichWindow, theEvent.where, &GetQDGlobalsScreenBits(&screenBits)->bounds);
                        if (gSurfaceTextureWindowPtr == whichWindow)
                            aglUpdateContext (gSurfaceTextureContext);
                        if (gDestWindowPtr == whichWindow)
                            aglUpdateContext (gDestContext);
                    }
                        break;
                    case inGrow: {
                        if (whichWindow == gDestWindowPtr) {
                            SetRect (&rectGrow, 100, 100, 20000, 20000);
                            grow = GrowWindow (whichWindow, theEvent.where, &rectGrow);
                            if (grow) {
                                Rect tempRect;
                                SizeWindow (whichWindow, grow & 0x0000FFFF, grow >> 16, true);
                                // do content stuff here
                                SetPort((GrafPtr) GetWindowPort(whichWindow));
                                InvalWindowRect(whichWindow, GetWindowPortBounds(whichWindow, &tempRect));
                                {
                                    // handle window size updates for GL
                                    GLfloat fAspect;
                                    short w, h;
                                    Rect rectPort;
 
                                    aglSetCurrentContext (gDestContext);
                                    aglUpdateContext (gDestContext);
                                    GetWindowPortBounds(whichWindow, &rectPort);
                                    w = rectPort.right - rectPort.left;
                                    h = rectPort.bottom - rectPort.top;
                                    
                                    // Prevent a divide by zero
                                    if(h == 0)
                                        h = 1;
                                    fAspect = (GLfloat) w / (GLfloat) h;
 
                                    // Set Viewport to window dimensions
                                    glViewport (0, 0, (GLsizei) w, (GLsizei) h);
 
                                    glMatrixMode (GL_PROJECTION);
 
                                    // Reset coordinate system
                                    glLoadIdentity ();
 
                                    // Setup perspective for viewing
                                    gluPerspective (45.0, fAspect, 3, 20);
                                }
                            }
                        }
                        break;
                    }
                }
                break;
            case keyDown:
            case autoKey:
                theKey = theEvent.message & charCodeMask;
                theCode = (theEvent.message & keyCodeMask) >> 8;
                if ((theEvent.modifiers & cmdKey) != 0) {
                    menuResult = MenuKey(theKey);
                    if (HiWord(menuResult) != 0)
                        DoMenu (menuResult);
                } else
                    DoKey (theKey, theCode);
                break;
            case activateEvt:
                break;
            case updateEvt:
                whichWindow = (WindowRef) theEvent.message;
                GetPort (&pGrafSave);
                SetPort ((GrafPtr) whichWindow);
                BeginUpdate(whichWindow);
                DoUpdate(whichWindow);
                SetPort ((GrafPtr) whichWindow);
                EndUpdate(whichWindow);
                SetPort (pGrafSave);
                break;
            case diskEvt:
                break;
            case osEvt:
                if (theEvent.message & 0x01000000)  {   //  Suspend/resume event
                    if (theEvent.message & 0x00000001) {    //  Resume
                        gSleepTime = kForegroundSleep;
                        if (gDestWindowPtr)
                            DoUpdate (gDestWindowPtr);
                        if (gSurfaceTextureWindowPtr)
                            DoUpdate (gSurfaceTextureWindowPtr);
                        gfFrontProcess = true;
                    } else {
                        gSleepTime = kBackgroundSleep;  //  Suspend
                        gfFrontProcess = false;
                    }
                }
                break;
 
            case kHighLevelEvent:
                AEProcessAppleEvent(&theEvent);
                break;
        }
    }
}
 
// --------------------------------------------------------------------------
 
void CleanUp (void)
{
    MenuHandle hMenu;
 
    RemoveEventLoopTimer(gTimer);
    gTimer = NULL;
    
    // ensure surface texture is not being used on exit
    aglSetCurrentContext (gDestContext);
    if (gSurfaceTexName)
        glDeleteTextures (1, &gSurfaceTexName);
    glFlush ();
    CleanupAGL (gSurfaceTextureContext);
    gSurfaceTextureContext = NULL;
    CleanupAGL (gDestContext);
    gDestContext = NULL;
 
    if (gSurfaceTextureWindowPtr)
        DisposeWindow ((WindowPtr) gSurfaceTextureWindowPtr);
    gSurfaceTextureWindowPtr = NULL;
    if (gDestWindowPtr)
        DisposeWindow ((WindowPtr) gDestWindowPtr);
    gDestWindowPtr = NULL;
 
    hMenu = GetMenuHandle (kMenuFile);
    DeleteMenu (kMenuFile);
    DisposeMenu (hMenu);
 
    hMenu = GetMenuHandle (kMenuApple);
    DeleteMenu (kMenuApple);
    DisposeMenu (hMenu);
    
}
 
// --------------------------------------------------------------------------
 
int main (void)
{
    UInt32 response;
    if ((Gestalt (gestaltSystemVersion, (SInt32 *) &response) == noErr) && (response < 0x01020)) {
        ReportError ("Must have Mac OS v10.2 or later to use aglSurfaceTexture");
        return 1;
    } else {
        if (SetUp ())   
            while (!gDone) 
                DoEvent ();
        CleanUp ();
        return 0;
    }
}