Carbon SetupGL/Carbon_SetupGL_Test.c

/*
    File:       SetupGL Main Windowed.c
 
    Contains:   An example of the use of the SeupGL utility code for windowed applications.
 
    Written by: Geoff Stahl
 
    Copyright:  2000 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.
    
         <10>    4/20/01    ggs     add menu command and code to demonstrate shared texturing
         <9>     9/3/00     ggs     Multi-window handling
         <8>     3/22/00    ggs     Carbon take one
 
         <7>     2/24/00    ggs     Windowed mode support 
         <6>     1/26/00    ggs     Add preflight support, handle failure conditions throughout app
                                    better
         <5>     1/24/00    ggs     fixed Apple menu selection, fixed aglfont texture row length
                                    problem, fixed suspend/resume, fixed update
         <4>    12/18/99    ggs     Fix headers
         <3>    12/18/99    ggs     Added window/fullscreen toggle support and error window
         <2>    11/28/99    ggs     Standard toolbox application
         <1>    11/28/99    ggs     Initial Add
         <6>     9/14/99    GGS     Corrected buffer rect handling and cleaned up code
         <5>     7/14/99    GGS     Fixed multi-monitor window centering
         <4>     7/13/99    GGS     Add work around for over zealous checking in single buffer DSp context attributes
         <3>     7/5/99     GGS     Now correctly handle multi-monitor (DSp front buffer for single device; Window on top of context for multiple devices)
         <2>     5/28/99    GGS     Added better multi-monitor support, clean code, corrected blanking bug, added timing, correct pixel formats
         <1>        ?        ?      Initial build
*/
 
 
// system includes ----------------------------------------------------------
 
#ifdef __APPLE_CC__
    #include "Carbon_Include.h"
    #include <Carbon/Carbon.h>
#else
    #include <Devices.h>
    #include <Dialogs.h>
    #include <DriverServices.h>
    #include <Events.h>
    #include <Gestalt.h>
    #include <LowMem.h>
    #include <PictUtils.h>
    #include <TextEdit.h>
    #include <ToolUtils.h>
    #include <QDOffscreen.h>
    #include <Windows.h>
#endif
 
#include <math.h>
#include <stdio.h>
#include <string.h>
 
#ifdef __APPLE_CC__
    #include <OpenGL/gl.h>
#else
    #include <gl.h>
#endif
 
// project includes ---------------------------------------------------------
 
#include "aglString.h"
#include "Carbon_SetupGL.h"
#include "Carbon_Error_Handler.h"
 
// prototypes ---------------------------------------------------------------
 
static void IntializeWindowList (void); // zeroize list's WindowPtrs (does not dispose)
static long FindFirstFreeWindowIndex (void); // return index of first free WindowPtr
static void DisposeGLWindow (WindowPtr pWindow); // Dispose a single window and it's GL context
static void DisposeGLWindowList (void); // Dispose entire window list and GL contexts
 
void LoadTextureRes (short resID, GLbyte ** ppBuffer, short * pWidth, short * pHeight);
 
void InitToolbox(void);
void CreateGLWindow (void);
Boolean SetUp (void);
void DoMenu (SInt32 menuResult);
void DoKey (SInt8 theKey, SInt8 theCode);
void DoUpdate (WindowPtr pWindow);
void DoEvent (void);
void CleanUp (void);
 
void drawGL(WindowPtr pWindow);
 
#if TARGET_API_MAC_CARBON
pascal void IdleTimer (EventLoopTimerRef inTimer, void* userData);
EventLoopTimerUPP GetTimerUPP (void);
#endif
 
// statics/globals (internal only) ------------------------------------------
 
struct structWindowInfo
{
    structGLWindowInfo glInfo;
    AGLContext aglContext;
    GLuint fontList;
    char strContext [256];
};
typedef struct structWindowInfo structWindowInfo;
typedef struct structWindowInfo * structWindowInfoPtr;
 
 
// Menu defs
enum 
{
    kMaxWindows = 200,
    
    kMenuApple = 128,
    kMenuFile = 129,
    
    kAppleAbout = 1,
    kFileNew = 1,
    kFileClose,
    kFileBufferRect,
    kFileTexture,
    kFileFlipTexture,
    kFileQuit
};
 
#if TARGET_API_MAC_CARBON
enum 
{
    kForegroundSleep = 10,
    kBackgroundSleep = 10000
};
EventLoopTimerRef gTimer = NULL;
#else
enum 
{
    kForegroundSleep = 0,
    kBackgroundSleep = 100
};
#endif
 
SInt32 gSleepTime = kForegroundSleep;
Boolean gDone = false, gfFrontProcess = true;
 
Rect rectWin, rectInitWin = {50, 5, 150, 105}; // initial window rectangle
 
WindowPtr gpWindowList [kMaxWindows];
char gStringWindow [kMaxWindows][32];
long gFrameWindow [kMaxWindows];
AbsoluteTime gTimeWindow [kMaxWindows];
float gRotation [kMaxWindows];
 
Boolean gBufferRect = false;
Boolean gTexture = false;
GLuint nameTexture[2] = { 0, 0 };
short gFirstTexture = 0;
 
Boolean gMenu = false;
 
AGLContext gTextureSharingContext [2] = { NULL, NULL };
 
 
// functions (internal/private) ---------------------------------------------
 
static void IntializeWindowList (void) // zeroize list's WindowPtrs (does not dispose)
{
    long i;
    for (i = 0; i < kMaxWindows; i++)
        gpWindowList[i] = NULL;
}
 
// --------------------------------------------------------------------------
 
static long FindFirstFreeWindowIndex (void) // return index of first free WindowPtr
{
    long i = 0;
    while ((gpWindowList[i] != NULL) && (kMaxWindows > i))
        i++;
    if (kMaxWindows == i)
        return -1;
    else
        return i;
}
 
// --------------------------------------------------------------------------
 
static void DisposeGLWindow (WindowPtr pWindow) // Dispose a single window and it's GL context
{
    if (pWindow)
    {
        structWindowInfoPtr pWindowInfo = (structWindowInfoPtr) GetWRefCon (pWindow);
        SetWRefCon (pWindow, NULL);
        if (pWindowInfo)
        {
            DeleteFontGL (pWindowInfo->fontList);
            // must clean up failure to do so will result in an Unmapped Memory Exception
            if (gTextureSharingContext[0] == pWindowInfo->aglContext) // insure we do not try to share textures from invalid context
                gTextureSharingContext[0] = NULL;
            if (gTextureSharingContext[1] == pWindowInfo->aglContext) // insure we do not try to share textures from invalid context
                gTextureSharingContext[1] = NULL;
            DestroyGLFromWindow (&pWindowInfo->aglContext, &pWindowInfo->glInfo);
            DisposePtr ((Ptr) pWindowInfo);
        }
        DisposeWindow (pWindow);
    }
}
 
// --------------------------------------------------------------------------
 
static void DisposeGLWindowList (void) // Dispose entire window list and GL contexts
{
    long i;
    for (i = 0; i < kMaxWindows; i++)
    {
        DisposeGLWindow (gpWindowList[i]);
        gpWindowList[i] = NULL;
    }
}
 
// --------------------------------------------------------------------------
#pragma mark -
 
void LoadTextureRes (short resID, GLbyte ** ppBuffer, short * pWidth, short * pHeight)
{
    PicHandle hPic = NULL;
    PictInfo thePictInfo;
    GWorldPtr pGW = NULL;
    long stride = 0;
    char * baseaddr = NULL;
    short i, j;
 
    GDHandle saveDevice;
    CGrafPtr saveWorld;
 
    GetGWorld (&saveWorld, &saveDevice);
 
    hPic = GetPicture (resID); // get background picture
    if (hPic)
    {
        GetPictInfo (hPic, &thePictInfo, 0, 0, 0, 0); 
        NewGWorld (&pGW, 32, &(thePictInfo.sourceRect), NULL, NULL, 0 );
        if (pGW && LockPixels (GetGWorldPixMap (pGW)))
        {
            SetGWorld (pGW, NULL);
            DrawPicture (hPic, &(thePictInfo.sourceRect));
 
            SetGWorld (saveWorld, saveDevice); //ensure gdevice is restored
            
            *pWidth = thePictInfo.sourceRect.right - thePictInfo.sourceRect.left;
            *pHeight = thePictInfo.sourceRect.bottom - thePictInfo.sourceRect.top;
            stride = GetPixRowBytes (GetGWorldPixMap (pGW));
            baseaddr = GetPixBaseAddr (GetGWorldPixMap (pGW));
            *ppBuffer = (signed char *)NewPtr (3 * *pWidth * *pHeight);
            if (*ppBuffer)
            {
                for (i = 0; i < *pHeight; i++)
                    for (j = 0; j < *pWidth; j++)
                    {
                        *(*ppBuffer + (i * *pWidth  + j) * 3 + 0) = *(baseaddr + (i * stride) + j * 4 + 1);
                        *(*ppBuffer + (i * *pWidth  + j) * 3 + 1) = *(baseaddr + (i * stride) + j * 4 + 2);
                        *(*ppBuffer + (i * *pWidth  + j) * 3 + 2) = *(baseaddr + (i * stride) + j * 4 + 3);
                    }
            }
        }
    }
    DisposeGWorld (pGW);
    ReleaseResource ((Handle) hPic);
}
 
// --------------------------------------------------------------------------
#pragma mark -
 
static pascal OSErr QuitAppleEventHandler( const AppleEvent *appleEvt, AppleEvent* reply, SInt32 refcon )
{
    #pragma unused (appleEvt, reply, refcon)
    gDone =  true;
    return false;
}
 
// --------------------------------------------------------------------------
 
void InitToolbox(void)
{
    OSErr err;
    long response;
    MenuHandle menu;
    
#if !TARGET_API_MAC_CARBON
    MaxApplZone ();
 
    InitGraf((Ptr) &qd.thePort);
    InitFonts();
    InitWindows();
    InitMenus();
    TEInit();
    InitDialogs(nil);
#endif
 
    InitCursor();
    
#if !TARGET_API_MAC_CARBON
    qd.randSeed =  TickCount(); // ? Carbon Equivalent ?
#endif
 
    // Init Menus
    menu = NewMenu (kMenuApple, "\p\024");          // new  apple menu
    InsertMenu (menu, 0);                           // add menu to end
 
#if !TARGET_API_MAC_CARBON
    AppendResMenu(menu, 'DRVR');
#endif
    
    menu = NewMenu (kMenuFile, "\pFile");           // new menu
    InsertMenu (menu, 0);                           // add menu to end
 
    // insert application menus here
    AppendMenu (menu, "\pNew Window/N");
    AppendMenu (menu, "\pClose Window/W");
    AppendMenu (menu, "\pToggle Buffer Rect/B");
    AppendMenu (menu, "\pToggle Texturing/T");
    AppendMenu (menu, "\pFlip Textures/F");
    
    // 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();
    }
        
    rectWin = rectInitWin;
    IntializeWindowList ();
    { // initialize frame timing
        long i;
        for (i = 0; i < kMaxWindows; i++)
        {
            gFrameWindow [i] = 0;
            gTimeWindow [i].hi = 0;
            gTimeWindow [i].lo = 0;
            gRotation [i] = 0.0;
        }
    }
}
 
// --------------------------------------------------------------------------
 
void CreateGLWindow (void)
{
    short i;
    long indexWin;
    short fNum;
    
    indexWin = FindFirstFreeWindowIndex ();
    if (indexWin >= 0) // valid index
    {
        GDHandle hGDWindow;
        Rect rectSect;
        structWindowInfoPtr pWindowInfo = (structWindowInfoPtr) NewPtrClear (sizeof (structWindowInfo));
#if TARGET_API_MAC_CARBON
        if (noErr != CreateNewWindow (kDocumentWindowClass, kWindowStandardDocumentAttributes, &rectWin, &(gpWindowList [indexWin])))
        {
            DebugStr ("\pCreate window error");
            return;
        }
#else
        gpWindowList [indexWin] = (WindowPtr) NewCWindow (NULL, &rectWin, "\pWindow", false, kWindowFullZoomGrowDocumentProc, (WindowPtr)-1, true, 0);
#endif
        // offset next window rectangle
        OffsetRect (&rectWin, 120, 30);
        FindGDHandleFromRect (&rectWin, &hGDWindow);
        SectRect (&rectWin, &(**hGDWindow).gdRect, &rectSect);
        if (!EqualRect (&rectWin, &rectSect))
        {
            OffsetRect (&rectInitWin, 30, 7);
            FindGDHandleFromRect (&rectInitWin, &hGDWindow);
            SectRect (&rectInitWin, &(**hGDWindow).gdRect, &rectSect);
            if (!EqualRect (&rectInitWin, &rectSect))
                SetRect (&rectInitWin, 5, 50, 505, 450);
            rectWin = rectInitWin;
        }
        { // set title to indicate index number
            Str255 pstrTitle = "\p";
            NumToString (indexWin, pstrTitle);
            SetWTitle (gpWindowList [indexWin], pstrTitle);
        }
        SetWRefCon (gpWindowList [indexWin], (long) pWindowInfo);
        ShowWindow (gpWindowList [indexWin]);
        SetPortWindowPort (gpWindowList [indexWin]);
        
        pWindowInfo->glInfo.fAcceleratedMust = false;   // must renderer be accelerated?
        pWindowInfo->glInfo.VRAM = 0 * 1048576;         // minimum VRAM (if not zero this is always a required minimum)
        pWindowInfo->glInfo.textureRAM = 0 * 1048576;   // minimum texture RAM (if not zero this is always a required minimum)
        if (!CheckMacOSX ()) // this is false on Mac OS 9 since Mac OS 9 does not support dragging conttexts with shared txtures between to different vendor's renderers.
            pWindowInfo->glInfo.fDraggable = false;         // should a pixel format that supports all monitors be chosen?
        else
            pWindowInfo->glInfo.fDraggable = true;      // should a pixel format that supports all monitors be chosen?
        pWindowInfo->glInfo.fmt = 0;                    // output pixel format
        
        i = 0;
        pWindowInfo->glInfo.aglAttributes [i++] = AGL_RGBA;
        pWindowInfo->glInfo.aglAttributes [i++] = AGL_DOUBLEBUFFER;
        pWindowInfo->glInfo.aglAttributes [i++] = AGL_ACCELERATED;
        pWindowInfo->glInfo.aglAttributes [i++] = AGL_NO_RECOVERY;
        pWindowInfo->glInfo.aglAttributes [i++] = AGL_DEPTH_SIZE;
        pWindowInfo->glInfo.aglAttributes [i++] = 16;
        pWindowInfo->glInfo.aglAttributes [i++] = AGL_NONE;
        BuildGLFromWindow (gpWindowList [indexWin], &pWindowInfo->aglContext, &pWindowInfo->glInfo, gTextureSharingContext [indexWin & 0x01]);
        if (!pWindowInfo->aglContext)
        {
            DestroyGLFromWindow (&pWindowInfo->aglContext, &pWindowInfo->glInfo);
            sprintf (pWindowInfo->strContext, "No context");            
        }
        else
        {
            Rect rectPort;
            
#if TARGET_API_MAC_CARBON
            GetWindowPortBounds (gpWindowList [indexWin], &rectPort);
#else
            rectPort = gpWindowList [indexWin]->portRect;
#endif // TARGET_API_MAC_CARBON
            aglSetCurrentContext (pWindowInfo->aglContext);
            aglReportError ();
            aglUpdateContext (pWindowInfo->aglContext);
            aglReportError ();
 
            // Set Texture mapping parameters
            glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S, GL_REPEAT);
            glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T, GL_REPEAT);
            glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR);
            glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 
            glClearColor(0.15f, 0.15f, 0.15f, 1.0f);                    // Clear color buffer to dark grey
            glClear (GL_COLOR_BUFFER_BIT);
            glReportError ();
            aglSwapBuffers (pWindowInfo->aglContext);
            aglReportError ();
 
            if (gBufferRect)
            {
                GLint bufferRect[4] = {0, 0, 0, 0};
                bufferRect [0] = 10; bufferRect [1] = 10;
                bufferRect [2] = rectPort.right - rectPort.left - 20; bufferRect [3] = rectPort.bottom - rectPort.top - 20;
                aglSetInteger (pWindowInfo->aglContext, AGL_BUFFER_RECT, bufferRect);
                aglReportError ();
                aglEnable (pWindowInfo->aglContext, AGL_BUFFER_RECT);
                aglReportError ();
                glViewport (0, 0, bufferRect [2], bufferRect [3]);
                glReportError ();
                sprintf (pWindowInfo->strContext, "%ld x %ld", bufferRect [2], bufferRect [3]);         
            }
            else
            {
                aglDisable (pWindowInfo->aglContext, AGL_BUFFER_RECT);
                aglReportError ();
                glViewport (0, 0, rectPort.right - rectPort.left, rectPort.bottom - rectPort.top);
                glReportError ();
                sprintf (pWindowInfo->strContext, "%d x %d", rectPort.right - rectPort.left, rectPort.bottom - rectPort.top);           
            }
            GetFNum("\pMonaco", &fNum);                                 // build font
                pWindowInfo->fontList = BuildFontGL (pWindowInfo->aglContext, fNum, normal, 9);
 
            aglUpdateContext (pWindowInfo->aglContext);
            aglReportError ();
            
            
            if (NULL == gTextureSharingContext [indexWin & 0x01] )
                gTextureSharingContext [indexWin & 0x01] = pWindowInfo->aglContext;
        }       
    }
}
 
// --------------------------------------------------------------------------
 
Boolean SetUp (void)
{
    InitToolbox ();
    if (PreflightGL (false))
        CreateGLWindow ();
#if TARGET_API_MAC_CARBON
    if (!gTimer)
        InstallEventLoopTimer (GetCurrentEventLoop(), 0, 0.000001, GetTimerUPP (), 0, &gTimer);
#endif
    return true;
}
 
// --------------------------------------------------------------------------
 
void DoMenu (SInt32 menuResult)
{
#if !TARGET_API_MAC_CARBON
    Str255 daName;
#endif
    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:
#if !TARGET_API_MAC_CARBON
                    GetMenuItemText (theMenuHandle, theItem, daName);
                    OpenDeskAcc(daName);
#endif
                    break;
            }
            break;
        case kMenuFile:
            switch (theItem)
            {
                case kFileNew:
                    CreateGLWindow ();
                    break;
                case kFileClose:
                {
                    WindowPtr whichWindow = FrontWindow ();
                    long i = 0;
                    while ((whichWindow != gpWindowList[i]) && (kMaxWindows > i)) {i++;}
                    if (kMaxWindows != i)
                    {
                        DisposeGLWindow (gpWindowList[i]);
                        gpWindowList[i] = NULL;
                        gFrameWindow [i] = 0;
                        gTimeWindow [i].hi = 0;
                        gTimeWindow [i].lo = 0;
                        gRotation [i] = 0.0;
                    }
                }
                    break;
                case kFileBufferRect:
                {
                    long i = 0;
                    gBufferRect = 1 - gBufferRect;
                    for (i = 0; kMaxWindows > i; i++)
                    {
                        if (gpWindowList[i] != NULL)
                        {
                            Rect rectPort;
                            structWindowInfoPtr pWindowInfo = (structWindowInfoPtr) GetWRefCon (gpWindowList [i]);                      
#if TARGET_API_MAC_CARBON
                            GetWindowPortBounds (gpWindowList [i], &rectPort);
#else
                            rectPort = gpWindowList [i]->portRect;
#endif // TARGET_API_MAC_CARBON
                            aglSetCurrentContext(pWindowInfo->aglContext);
                            if (gBufferRect)
                            {
                                GLint bufferRect[4] = {0, 0, 0, 0};
                                bufferRect [0] = 10; bufferRect [1] = 10;
                                bufferRect [2] = rectPort.right - rectPort.left - 20; bufferRect [3] = rectPort.bottom - rectPort.top - 20;
                                aglSetInteger (pWindowInfo->aglContext, AGL_BUFFER_RECT, bufferRect);
                                aglEnable (pWindowInfo->aglContext, AGL_BUFFER_RECT);
                                glViewport (0, 0, bufferRect [2], bufferRect [3]);
                                sprintf (pWindowInfo->strContext, "%ld x %ld", bufferRect [2], bufferRect [3]);         
                            }
                            else
                            {
                                aglDisable (pWindowInfo->aglContext, AGL_BUFFER_RECT);
                                glViewport (0, 0, rectPort.right - rectPort.left, rectPort.bottom - rectPort.top);
                                sprintf (pWindowInfo->strContext, "%d x %d", rectPort.right - rectPort.left, rectPort.bottom - rectPort.top);           
                            }
                            aglUpdateContext (pWindowInfo->aglContext);
                        }
                    }
                }
                    break;
                case kFileTexture: // enable shared texturing.  For mac OS X 10.0.1 and earlier this requires creating all contexts first
                {
                    long i = 0;
                    GLbyte * pBuffer = NULL;
                    short width = 0, height = 0;
                    gTexture = 1 - gTexture;
                    if (gTexture)
                    {
                        if (gpWindowList[0] != NULL) // load the texture for the first window
                        {
                            structWindowInfoPtr pWindowInfo = (structWindowInfoPtr) GetWRefCon (gpWindowList [0]);                      
                            aglSetCurrentContext(pWindowInfo->aglContext);
                            
                            glEnable (GL_TEXTURE_2D);
                            if (nameTexture [0])
                                glDeleteTextures (2, nameTexture);
                            glGenTextures (2, nameTexture);
                            // load first texture
                            glBindTexture(GL_TEXTURE_2D, nameTexture[0]);
                            LoadTextureRes (1000 + gFirstTexture, &pBuffer, &width, &height);
                            glTexImage2D (GL_TEXTURE_2D, 0, 3, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, pBuffer);
                            DisposePtr ((Ptr)pBuffer);
                        }
                        if (gpWindowList[1] != NULL) // load the texture for the first window
                        {
                            structWindowInfoPtr pWindowInfo = (structWindowInfoPtr) GetWRefCon (gpWindowList [1]);                      
                            aglSetCurrentContext (pWindowInfo->aglContext);
                            
                            glEnable (GL_TEXTURE_2D);
                            // load second texture
                            glBindTexture(GL_TEXTURE_2D, nameTexture [1]);
                            LoadTextureRes (1000 + 1 - gFirstTexture, &pBuffer, &width, &height);
                            glTexImage2D (GL_TEXTURE_2D, 0, 3, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, pBuffer);
                            DisposePtr ((Ptr)pBuffer);
                        }
                    }
                    for (i = 0; kMaxWindows > i; i++) // enable texturing for all windows but do not load texture again
                    {
                        if (gpWindowList[i] != NULL)
                        {
                            structWindowInfoPtr pWindowInfo = (structWindowInfoPtr) GetWRefCon (gpWindowList [i]);                      
                            aglSetCurrentContext(pWindowInfo->aglContext);
                            if (gTexture)
                            {
                                glEnable (GL_TEXTURE_2D);
                                glBindTexture(GL_TEXTURE_2D, nameTexture[i & 0x01]);
                            }
                            else
                                glDisable (GL_TEXTURE_2D);
                        }
                    }
                }
                    break;
                case kFileFlipTexture: // enable shared texturing.  For mac OS X 10.0.1 and earlier this requires creating all contexts first
                {
                    long i = 0;
                    GLbyte * pBuffer = NULL;
                    short width = 0, height = 0;
                    gFirstTexture = 1 - gFirstTexture;
                    if (gTexture)
                    {
                        if (gpWindowList[0] != NULL) // load the texture for the first window
                        {
                            structWindowInfoPtr pWindowInfo = (structWindowInfoPtr) GetWRefCon (gpWindowList [0]);                      
                            aglSetCurrentContext(pWindowInfo->aglContext);
                            
                            glEnable (GL_TEXTURE_2D);
                            // load first texture
                            glBindTexture(GL_TEXTURE_2D, nameTexture[0]);
                            LoadTextureRes (1000 + gFirstTexture, &pBuffer, &width, &height);
                            glTexImage2D (GL_TEXTURE_2D, 0, 3, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, pBuffer);
                            DisposePtr ((Ptr)pBuffer);
                        }
                        if (gpWindowList[1] != NULL) // load the texture for the first window
                        {
                            structWindowInfoPtr pWindowInfo = (structWindowInfoPtr) GetWRefCon (gpWindowList [1]);                      
                            aglSetCurrentContext (pWindowInfo->aglContext);
                            
                            glEnable (GL_TEXTURE_2D);
                            // load second texture
                            glBindTexture(GL_TEXTURE_2D, nameTexture [1]);
                            LoadTextureRes (1000 + 1 - gFirstTexture, &pBuffer, &width, &height);
                            glTexImage2D (GL_TEXTURE_2D, 0, 3, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, pBuffer);
                            DisposePtr ((Ptr)pBuffer);
                        }
                    }
                    for (i = 0; kMaxWindows > i; i++) // enable texturing for all windows but do not load texture again
                    {
                        if (gpWindowList[i] != NULL)
                        {
                            structWindowInfoPtr pWindowInfo = (structWindowInfoPtr) GetWRefCon (gpWindowList [i]);                      
                            aglSetCurrentContext(pWindowInfo->aglContext);
                            if (gTexture)
                            {
                                glEnable (GL_TEXTURE_2D);
                                glBindTexture (GL_TEXTURE_2D, nameTexture[i & 0x01]);
                            }
                            else
                                glDisable (GL_TEXTURE_2D);
                        }
                    }
                }
                    break;
                case kFileQuit:
                    gDone = true;
                    break;
            }
            break;
    }
    HiliteMenu(0);
    DrawMenuBar();
}
 
// --------------------------------------------------------------------------
 
void DoKey (SInt8 theKey, SInt8 theCode)
{
    #pragma unused (theCode, theKey)
    // do nothing
}
 
// --------------------------------------------------------------------------
 
#if TARGET_API_MAC_CARBON
pascal void IdleTimer (EventLoopTimerRef inTimer, void* userData)
{
    #pragma unused (inTimer, userData)
    long i;
    if (!gMenu)
        for (i = 0; i < kMaxWindows; i++)
            if (gpWindowList[i])
                DoUpdate (gpWindowList[i]);
}
 
// --------------------------------------------------------------------------
 
EventLoopTimerUPP GetTimerUPP (void)
{
    static EventLoopTimerUPP    sTimerUPP = NULL;
    
    if (sTimerUPP == NULL)
        sTimerUPP = NewEventLoopTimerUPP (IdleTimer);
    
    return sTimerUPP;
}
#endif
 
// --------------------------------------------------------------------------
 
void DoUpdate (WindowPtr pWindow)
{
    if (pWindow)
    {
        structWindowInfoPtr pWindowInfo = (structWindowInfoPtr) GetWRefCon (pWindow);
        if (pWindowInfo)
        {
            aglSetCurrentContext (pWindowInfo->aglContext);
            if (gMenu)
                aglUpdateContext (pWindowInfo->aglContext);
            drawGL (pWindow);
        }
    }
}
 
// --------------------------------------------------------------------------
 
void DoEvent (void)
{
    EventRecord theEvent;
    Rect rectTemp;
    WindowRef whichWindow;
    SInt16 whatPart;
    
    if (WaitNextEvent(everyEvent, &theEvent, gSleepTime, NULL))
    {
        {
            switch (theEvent.what)
            {
                case mouseDown:
                    whatPart = FindWindow (theEvent.where, &whichWindow);
                    switch (whatPart)
                    {
                        case inContent:
                            if (whichWindow != FrontWindow()) 
                                SelectWindow (whichWindow);
                            break;
                        case inMenuBar:
                        {
                            SInt32 menuResult;
                            gMenu = true;
                            menuResult = MenuSelect (theEvent.where);
                            gMenu = false;
                            if (HiWord (menuResult) != 0)
                                DoMenu (menuResult);
                        }
                            break;
                        case inDrag:
                            {
#if !TARGET_API_MAC_CARBON
                                DragWindow (whichWindow, theEvent.where, &(**LMGetGrayRgn()).rgnBBox);
#else
                                GetRegionBounds(GetGrayRgn(), &rectTemp);
                                SetPort((GrafPtr) GetWindowPort(whichWindow));
                                DragWindow(whichWindow, theEvent.where, &rectTemp);
#endif // !TARGET_API_MAC_CARBON
                                
                                
                                aglUpdateContext (((structWindowInfoPtr) GetWRefCon (whichWindow))->aglContext);
                            }
                            break;
                        case inGrow:
                        {
                            long grow;
                            SetRect (&rectTemp, 100, 100, 20000, 20000);
                            grow = GrowWindow (whichWindow, theEvent.where, &rectTemp);
                            if (grow)
                            {
                                structWindowInfoPtr pWindowInfo = (structWindowInfoPtr) GetWRefCon (whichWindow);
                                SizeWindow (whichWindow, grow & 0x0000FFFF, grow >> 16, true);
                                // do content stuff here
                                SetPort ((GrafPtr) GetWindowPort(whichWindow));
#if !TARGET_API_MAC_CARBON
                                InvalRect (&whichWindow->portRect);             // redraw all
#else
                                InvalWindowRect (whichWindow, GetWindowPortBounds (whichWindow, &rectTemp));
#endif // !TARGET_API_MAC_CARBON
                                if ((pWindowInfo) && (pWindowInfo->aglContext))
                                {
                                    if (gBufferRect)
                                    {
                                        GLint bufferRect[4] = {0, 0, 0, 0};
#if TARGET_API_MAC_CARBON
                                        GetWindowPortBounds (whichWindow, &rectTemp);
#else
                                        rectTemp = whichWindow->portRect;
#endif // TARGET_API_MAC_CARBON
                                        bufferRect [0] = 10; bufferRect [1] = 10;
                                        bufferRect [2] = rectTemp.right - rectTemp.left - 20; bufferRect [3] = rectTemp.bottom - rectTemp.top - 20;
                                        aglSetCurrentContext (pWindowInfo->aglContext); // ensure the context we are working with is current
                                        aglSetInteger (pWindowInfo->aglContext, AGL_BUFFER_RECT, bufferRect);
                                        aglUpdateContext (pWindowInfo->aglContext);
                                        glViewport (0, 0, bufferRect [2], bufferRect [3]);
                                        sprintf (pWindowInfo->strContext, "%ld x %ld", bufferRect [2], bufferRect [3]);         
                                    }
                                    else
                                    {
#if TARGET_API_MAC_CARBON
                                        GetWindowPortBounds (whichWindow, &rectTemp);
#else
                                        rectTemp = whichWindow->portRect;
#endif // TARGET_API_MAC_CARBON
                                        aglSetCurrentContext (pWindowInfo->aglContext); // ensure the context we are working with is current
                                        aglUpdateContext (pWindowInfo->aglContext);
                                        glViewport (0, 0, rectTemp.right - rectTemp.left, rectTemp.bottom - rectTemp.top);
                                        sprintf (pWindowInfo->strContext, "%d x %d", rectTemp.right - rectTemp.left, rectTemp.bottom - rectTemp.top);           
                                    }
                                }
                            }
                        }
                            break;
                        case inGoAway:
                        {
                            long i = 0;
                            while ((whichWindow != gpWindowList[i]) && (kMaxWindows > i)) {i++;}
                            if (kMaxWindows == i)
                                DisposeWindow (whichWindow);
                            else
                            {
                                DisposeGLWindow (gpWindowList[i]);
                                gpWindowList[i] = NULL;
                                gFrameWindow [i] = 0;
                                gTimeWindow [i].hi = 0;
                                gTimeWindow [i].lo = 0;
                                gRotation [i] = 0.0;
 
                            }
                        }
                            break;
                        case inZoomIn:
                        case inZoomOut:
                        {
                            if (TrackBox (whichWindow, theEvent.where, whatPart)) 
                            {
                                structWindowInfoPtr pWindowInfo = (structWindowInfoPtr) GetWRefCon (whichWindow);
                                SetPort ((GrafPtr) GetWindowPort (whichWindow));   // window must be current port
#if TARGET_API_MAC_CARBON
                                EraseRect (GetWindowPortBounds (whichWindow, &rectTemp));   // inval/erase because of ZoomWindow bug
                                ZoomWindow (whichWindow, whatPart, true);
                                InvalWindowRect (whichWindow, GetWindowPortBounds (whichWindow, &rectTemp));    
#else
                                EraseRect (&whichWindow->portRect);   // inval/erase because of ZoomWindow bug
                                ZoomWindow (whichWindow, whatPart, true);
                                InvalRect (&whichWindow->portRect); 
#endif // TARGET_API_MAC_CARBON
                                if ((pWindowInfo) && (pWindowInfo->aglContext))
                                {
                                    if (gBufferRect)
                                    {
                                        GLint bufferRect[4] = {0, 0, 0, 0};
#if TARGET_API_MAC_CARBON
                                        GetWindowPortBounds (whichWindow, &rectTemp);
#else
                                        rectTemp = whichWindow->portRect;
#endif // TARGET_API_MAC_CARBON
                                        bufferRect [0] = 10; bufferRect [1] = 10;
                                        bufferRect [2] = rectTemp.right - rectTemp.left - 20; bufferRect [3] = rectTemp.bottom - rectTemp.top - 20;
                                        aglSetCurrentContext (pWindowInfo->aglContext); // ensure the context we are working with is current
                                        aglSetInteger (pWindowInfo->aglContext, AGL_BUFFER_RECT, bufferRect);
                                        aglUpdateContext (pWindowInfo->aglContext);
                                        glViewport (0, 0, bufferRect [2], bufferRect [3]);
                                        sprintf (pWindowInfo->strContext, "%ld x %ld", bufferRect [2], bufferRect [3]);         
                                    }
                                    else
                                    {
#if TARGET_API_MAC_CARBON
                                        GetWindowPortBounds (whichWindow, &rectTemp);
#else
                                        rectTemp = whichWindow->portRect;
#endif // TARGET_API_MAC_CARBON
                                        aglSetCurrentContext (pWindowInfo->aglContext); // ensure the context we are working with is current
                                        aglUpdateContext (pWindowInfo->aglContext);
                                        glViewport (0, 0, rectTemp.right - rectTemp.left, rectTemp.bottom - rectTemp.top);
                                        sprintf (pWindowInfo->strContext, "%d x %d", rectTemp.right - rectTemp.left, rectTemp.bottom - rectTemp.top);           
                                    }
                                }
                            }
                        }
                            break;
                        case inSysWindow:
#if !TARGET_API_MAC_CARBON
                            SystemClick(&theEvent, whichWindow);
#endif // !TARGET_API_MAC_CARBON
                            break;
                    }
                    break;
                case keyDown:
                case autoKey:
                {
                    SInt8 theKey;
                    SInt8 theCode;
                    theKey = theEvent.message & charCodeMask;
                    theCode = (theEvent.message & keyCodeMask) >> 8;
                    if ((theEvent.modifiers & cmdKey) != 0)
                    {
                        SInt32 menuResult = MenuKey (theKey);
                        if (HiWord(menuResult) != 0)
                            DoMenu (menuResult);
                    }
                    else
                        DoKey (theKey, theCode);
                }
                    break;
                case activateEvt:
                    break;
                case updateEvt:
                {
                    GrafPtr pGrafSave;
                    whichWindow = (WindowRef) theEvent.message;
                    GetPort (&pGrafSave);
                    SetPort((GrafPtr) GetWindowPort(whichWindow));
                    BeginUpdate(whichWindow);
                    DoUpdate(whichWindow);
                    SetPort((GrafPtr) GetWindowPort(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;  
                            gfFrontProcess = true;
                        }
                        else
                        {
                            gSleepTime = kBackgroundSleep;  //  Suspend
                            gfFrontProcess = false;
                        }
                    }
                    break;
 
                case kHighLevelEvent:
                    AEProcessAppleEvent (&theEvent);
                    break;
            }
        }
    }
#if !TARGET_API_MAC_CARBON
    else
    {
        long i;
        for (i = 0; i < kMaxWindows; i++)
            if (gpWindowList[i])
                DoUpdate (gpWindowList[i]);
    }
#endif // !TARGET_API_MAC_CARBON
}
 
// --------------------------------------------------------------------------
 
void CleanUp (void)
{
    MenuHandle hMenu;
 
    DisposeGLWindowList ();
 
#if TARGET_API_MAC_CARBON
    if (gTimer)
    {
        RemoveEventLoopTimer(gTimer);
        gTimer = NULL;
    }
#endif // TARGET_API_MAC_CARBON
    
    hMenu = GetMenuHandle (kMenuFile);
    DeleteMenu (kMenuFile);
    DisposeMenu (hMenu);
 
    hMenu = GetMenuHandle (kMenuApple);
    DeleteMenu (kMenuApple);
    DisposeMenu (hMenu);
}
 
// --------------------------------------------------------------------------
 
int main (void)
{
    if (SetUp ())   
        while (!gDone) 
            DoEvent ();
    CleanUp ();
    return 0;
}
 
 
#pragma mark -
//-----------------------------------------------------------------------------------------------------------------------
 
// OpenGL Drawing
 
void drawGL(WindowPtr pWindow)
{
    float f = 0.0;
    structWindowInfoPtr pWindowInfo = (structWindowInfoPtr) GetWRefCon (pWindow);
    long indexWindow = 0;
 
    // find which window in list to match frame time and number
    while ((pWindow != gpWindowList [indexWindow]) && (kMaxWindows > indexWindow)) {indexWindow++;}
    if (kMaxWindows == indexWindow) // not in list
        indexWindow = -1;
 
    glClearColor(0.25f, 0.25f, 0.25f, 1.0f);                // Clear color buffer to dark grey
    glClear(GL_COLOR_BUFFER_BIT);
    
    if (0 <= indexWindow)
    {
        gRotation [indexWindow] += 0.5;
        f = gRotation [indexWindow];
    }
    glMatrixMode (GL_MODELVIEW);
    glLoadIdentity ();
    glRotated (f, 0.0, 0.0, 1.0);
    glEnable (GL_TEXTURE_2D);
    glBegin(GL_QUADS);                                          // Draw textured polygon
        if (gTexture)
        {
                glTexCoord2f(0.0, 0.0);
                glColor3d(1.0, 1.0, 1.0);
                glVertex3d(0.7, 0.7, 0.0);
 
                glTexCoord2f(0.0, 1.0);
                glColor3d(1.0, 1.0, 1.0);
                glVertex3d(-0.7, 0.7, 0.0);
 
                glTexCoord2f(1.0, 1.0);
                glColor3d(1.0, 1.0, 1.0);
                glVertex3d(-0.7, -0.7, 0.0);
 
                glTexCoord2f(1.0, 0.0);
                glColor3d(1.0, 1.0, 1.0);
                glVertex3d(0.7, -0.7, 0.0);
        }
        else
        {
                glColor3d(1.0, 0.0, 0.0);
                glVertex3d(0.7, 0.7, 0.0);
 
                glColor3d(0.0, 1.0, 0.0);
                glVertex3d(-0.7, 0.7, 0.0);
 
                glColor3d(0.0, 0.0, 1.0);
                glVertex3d(-0.7, -0.7, 0.0);
 
                glColor3d(0.7, 0.7, 0.7);
                glVertex3d(0.7, -0.7, 0.0);
        }
    glEnd();
 
    glDisable (GL_TEXTURE_2D);
    // draw info
    {
        Rect rectPort;
        GLint matrixMode;
#if TARGET_API_MAC_CARBON
        GetWindowPortBounds (pWindow, &rectPort);
#else
        rectPort = pWindow->portRect;
#endif // TARGET_API_MAC_CARBON
        glGetIntegerv (GL_MATRIX_MODE, &matrixMode);
        glMatrixMode (GL_PROJECTION);
        glPushMatrix();
            glLoadIdentity ();
            glMatrixMode (GL_MODELVIEW);
            glPushMatrix();
                glLoadIdentity ();
                glScalef (2.0 / (rectPort.right - rectPort.left), -2.0 /  (rectPort.bottom - rectPort.top), 1.0);
                glTranslatef (-(rectPort.right - rectPort.left) / 2.0, -(rectPort.bottom - rectPort.top) / 2.0, 0.0);
                glColor3f (1.0, 1.0, 1.0);
                glRasterPos3d (10, 12, 0); 
                if (0 <= indexWindow)
                    MultiWinDrawFrameRate (pWindowInfo->fontList, gStringWindow[indexWindow], &gFrameWindow[indexWindow], &gTimeWindow[indexWindow]);
                glRasterPos3d (10, 24, 0); 
                DrawCStringGL (pWindowInfo->strContext, pWindowInfo->fontList);
                glRasterPos3d (10, (rectPort.bottom - rectPort.top) - 15, 0); 
                DrawCStringGL ((char*) glGetString (GL_VENDOR), pWindowInfo->fontList);
                glRasterPos3d (10, (rectPort.bottom - rectPort.top) - 3, 0); 
                DrawCStringGL ((char*) glGetString (GL_RENDERER), pWindowInfo->fontList);
            glPopMatrix(); // GL_MODELVIEW
            glMatrixMode (GL_PROJECTION);
        glPopMatrix();
        glMatrixMode (matrixMode);
    }
    aglSwapBuffers(pWindowInfo->aglContext);                                        // send swap command
}