Source/Process.c

/****************************/
/*      PROCESS.C           */
/* By Brian Greenstone      */
/****************************/
 
 
/****************************/
/*    EXTERNALS             */
/****************************/
#include <Resources.h>
#include <Sound.h>
 
#include <Rave.h>
#include <QD3D.h>
#include <QD3DGeometry.h>
#include <QD3DMath.h>
#include <QD3DGroup.h>
#include <QD3DTransform.h>
 
#include "myglobals.h"
#include "misc.h"
#include "process.h"
#include "qd3d_support.h"
 
extern  float               gFramesPerSecond;
 
 
/****************************/
/*    PROTOTYPES            */
/****************************/
 
static void InitModelWindow(void);
static void BuildTestModel(void);
static void SubmitMyStuff(QD3DSetupOutputType *viewInfo);
static void GetMyRAVEInfo(void);
static void MyRaveInvalidateCallback(TQ3RendererObject rendererRef);
static void DoMyRAVECalls(void);
 
 
/****************************/
/*    CONSTANTS             */
/****************************/
 
#define MODEL_WIND_ID           400
 
#define MY_HITHER               10
#define MY_YON                  500
 
#define NUM_OBJECTS             12
 
#define MAX_CONTEXTS            4                           // assume no sane person will have more than 4 monitors on their system
 
#define BACKGROUND_WIDTH        400
#define BACKGROUND_HEIGHT       400
 
 
/*********************/
/*    VARIABLES      */
/*********************/
 
 
WindowPtr               gModelWindow = nil;
QD3DSetupOutputType     gModelViewInfo;
TQ3Object               gModelGroup = nil;
TQ3GroupObject          gBaseGroup[NUM_OBJECTS];
 
TQ3AttributeSet     gTextureAttr;
 
TQ3Matrix4x4    gRotMatrix[NUM_OBJECTS];
TQ3Matrix4x4    gMoveMatrix[NUM_OBJECTS];
TQ3Object       gTransformObject[NUM_OBJECTS];
TQ3ColorARGB    gClearColor = {1,0,0,0};
 
unsigned long   gNumContexts = 0;
TQADrawContext  *gContexts[MAX_CONTEXTS];                       // pointer to array of (TQADrawContext *)
 
unsigned long   gNumEngines = 0;
TQAEngine       *gEngines[MAX_CONTEXTS];                        // pointer to array of (TQAEngine *)
 
TQABitmap       *gBitmap[MAX_CONTEXTS];
 
#pragma mark ========INITIALIZATION STUFF=========
 
/******************** INIT TEST ************************/
 
void InitTest(void)
{
int     i;
TQ3Matrix4x4    m;
 
            /* INIT THE WINDOW */
            
    InitModelWindow();
 
 
            /* CREATE THE TEST MODEL */
            
    BuildTestModel();
 
 
            /* CREATE DISPLAY GROUPS */
            
    for (i = 0; i < NUM_OBJECTS; i++)
    {
        gBaseGroup[i] = Q3DisplayGroup_New();                               // make display group   
    
        Q3Matrix4x4_SetRotate_XYZ(&gRotMatrix[i], RandomFloat() * kQ3Pi,    // start @ random rotation
                                                        RandomFloat() * kQ3Pi,
                                                        RandomFloat() * kQ3Pi);
 
        Q3Matrix4x4_SetTranslate(&gMoveMatrix[i], RandomFloat() * 100 - 50, // start @ random location
                                                        RandomFloat() * 100 - 50,
                                                        -20);
    
        Q3Matrix4x4_Multiply(&gRotMatrix[i], &gMoveMatrix[i], &m);          // accumulate matrices
    
        gTransformObject[i] = Q3MatrixTransform_New(&m);                    // make transform object
        
        Q3Group_AddObject(gBaseGroup[i], gTransformObject[i]);              // add transform to group       
        Q3Group_AddObject(gBaseGroup[i], gModelGroup);                      // add geometry to group 
    }
 
            /* DRAW THE WINDOW */
                        
    DrawModelWindow();
}
 
/**************** CLEANUP TEST *********************/
//
// Called at quit
// 
 
void CleanupTest(void)
{
int i;
 
    for (i = 0; i < NUM_OBJECTS; i++)
    {
        if (gBaseGroup[i])
            Q3Object_Dispose(gBaseGroup[i]);
        if (gTransformObject[i])
            Q3Object_Dispose(gTransformObject[i]);
    }
    
    if (gModelGroup)
        Q3Object_Dispose(gModelGroup);
        
        /* UNLOAD BITMAPS */
        
    for (i = 0; i < gNumEngines; i++)   
    {
        if (gBitmap[i])
            QABitmapDelete(gEngines[i], gBitmap[i]);
    }
}
 
 
/************** INIT MODEL WINDOW *******************/
//
// Create window & setup QuickDraw 3D View and Draw Context stuff.
//
 
static void InitModelWindow(void)
{
QD3DSetupInputType  viewDef;
TQ3Point3D          cameraFrom = { 0,0, 100 };
TQ3Point3D          cameraTo = { 0, 0, 0 };
TQ3Vector3D         cameraUp = { 0.0, 1.0, 0 };
TQ3ColorRGB         ambientColor = { 1.0, 1.0, 1.0 };
TQ3Vector3D         fillDirection1 = {1, -.3, -.8 };
TQ3Vector3D         fillDirection2 = { -1, -.1, -.2 };
 
 
            /* CREATE THE WINDOW */
            
    gModelWindow = GetNewCWindow(MODEL_WIND_ID, nil,MOVE_TO_FRONT);
    if (gModelWindow == nil)
        DoFatalAlert("\pWhere did the GameWindow window go?");                  
    SetPort((GrafPtr)gModelWindow);
    SizeWindow(gModelWindow, BACKGROUND_WIDTH, BACKGROUND_HEIGHT, true);
 
 
            /* CREATE QD3D VIEW */
 
    viewDef.view.displayWindow      = gModelWindow;
    viewDef.view.rendererType       = kQ3RendererTypeInteractive;
    viewDef.view.clearColor         = gClearColor;
    viewDef.view.paneClip.left      = 0;
    viewDef.view.paneClip.right     = 0;
    viewDef.view.paneClip.top       = 0;
    viewDef.view.paneClip.bottom    = 0; 
 
    viewDef.styles.interpolation    = kQ3InterpolationStyleVertex; 
    viewDef.styles.backfacing       = kQ3BackfacingStyleBoth;
    viewDef.styles.fill             = kQ3FillStyleFilled; 
    viewDef.styles.illuminationType = kQ3IlluminationTypePhong; 
 
    viewDef.camera.from             = cameraFrom;
    viewDef.camera.to               = cameraTo;
    viewDef.camera.up               = cameraUp;
    viewDef.camera.hither           = MY_HITHER;
    viewDef.camera.yon              = MY_YON;
    viewDef.camera.fov              = 1.0;
 
    viewDef.lights.ambientBrightness = 0.5;
    viewDef.lights.ambientColor     = ambientColor;
    viewDef.lights.numFillLights    = 2;
    viewDef.lights.fillDirection[0] = fillDirection1;
    viewDef.lights.fillDirection[1] = fillDirection2;
    viewDef.lights.fillColor[0]     = ambientColor;
    viewDef.lights.fillColor[1]     = ambientColor;
    viewDef.lights.fillBrightness[0] = 1.1;
    viewDef.lights.fillBrightness[1] = 0.4;
 
    QD3D_SetupWindow(&viewDef, &gModelViewInfo);    
 
 
            /* GET RAVE DRAW CONTEXTS */
    
    GetMyRAVEInfo();
    
        
            /* SET SOME RAVE INFO */
            
    DoMyRAVECalls();
}
 
 
 
 
 
 
/********************* BUILD TEST MODEL **************************/
 
static void BuildTestModel(void)
{
TQ3TriMeshData                  myTriMeshData;
TQ3TriMeshAttributeData         vertexAttribs[3],faceAttribs;
 
TQ3Point3D points[3] = 
{
    0,35,0,
    -35,-35,0,
    35,-35,0
};
 
TQ3Vector3D vertexNormals[3] = 
{
    0,0,1,
    0,0,1,
    0,0,1
};
 
TQ3Vector3D faceNormals[1] =
{
    0,0,1
};
 
TQ3Param2D uvArray[3] =
{
    .5,1,
    0,0,
    1,0
};
 
 
TQ3TriMeshTriangleData  triangles[1] =
{
    0,1,2
};
        
 
TQ3SurfaceShaderObject  texture;
 
 
            /* FIRST LOAD THE TEXTUREMAP */
                    
    texture = QD3D_GetTextureMap(128,nil);
        
    gTextureAttr = Q3AttributeSet_New();
    Q3AttributeSet_Add(gTextureAttr, kQ3AttributeTypeSurfaceShader, &texture);      
    
    
            /* ASSIGN TRANSPARENCY ATTRIBUTE */
                
//  transColor.r = transColor.g = transColor.b = 1.0;
//  Q3AttributeSet_Add(gTextureAttr, kQ3AttributeTypeTransparencyColor, &transColor);
 
 
            /* BUILD MAIN TRIMESH DATA STRUCTURE */
 
    myTriMeshData.triMeshAttributeSet = gTextureAttr;
 
    myTriMeshData.numTriangles = 1;
    myTriMeshData.triangles = &triangles[0];
 
    myTriMeshData.numTriangleAttributeTypes = 1;
    myTriMeshData.triangleAttributeTypes = &faceAttribs;
 
    myTriMeshData.numEdges = 0;
    myTriMeshData.edges = nil;
    myTriMeshData.numEdgeAttributeTypes = 0;
    myTriMeshData.edgeAttributeTypes = nil;
 
    myTriMeshData.numPoints = 3;
    myTriMeshData.points = &points[0];
 
    myTriMeshData.numVertexAttributeTypes = 1;
    myTriMeshData.vertexAttributeTypes = &vertexAttribs[0];
 
 
            /* CALCULATE BOUNDING BOX */
 
    Q3BoundingBox_SetFromPoints3D(&myTriMeshData.bBox, &points[0],  3, sizeof(TQ3Point3D));
 
 
            /* CREATE FACE ATTRIBUTES */ 
 
    faceAttribs.attributeType = kQ3AttributeTypeNormal;
    faceAttribs.data = &faceNormals[0];
    faceAttribs.attributeUseArray = nil;
 
 
            /* CREATE VERTEX ATTRIBUTES */ 
 
    vertexAttribs[0].attributeType = kQ3AttributeTypeSurfaceUV;
    vertexAttribs[0].data = &uvArray[0];
    vertexAttribs[0].attributeUseArray = nil;
 
 
        /* MAKE THE TRIMESH GEOMETRY OBJECT */
 
    gModelGroup = Q3TriMesh_New(&myTriMeshData);
    if (gModelGroup == nil)
        DoFatalAlert("\pQ3TriMesh_New failed!");
 
 
}
 
 
#pragma mark =========UPDATING============
 
 
/*************** DO MODEL WINDOW NULL EVENT **********************/
 
void DoModelWindowNullEvent(void)
{
TQ3Matrix4x4    m,m2;
int             i;
 
            /* ROTATE THE GEOMETRY */
            
    QD3D_CalcFramesPerSecond();
    Q3Matrix4x4_SetRotate_XYZ(&m,0.4/gFramesPerSecond,0.5/gFramesPerSecond,0);
    
    for (i = 0; i < NUM_OBJECTS; i++)
    {
        Q3Matrix4x4_Multiply(&m,&gRotMatrix[i],&gRotMatrix[i]);         // rotate it
        Q3Matrix4x4_Multiply(&gRotMatrix[i], &gMoveMatrix[i], &m2);     // accumulate matrices
            
        Q3MatrixTransform_Set(gTransformObject[i],&m2);                 // update transform object
    }
 
            /* REDRAW IT */
                
    DrawModelWindow();
}
 
 
/******************* DRAW MODEL WINDOW *********************/
//
// Calls the support function QD3D_DrawScene.
// It passes the view info and a pointer to the game draw callback.
//
 
void DrawModelWindow(void)
{
            /* DRAW STUFF */
            
    QD3D_DrawScene(&gModelViewInfo,(void *)SubmitMyStuff);
}
 
 
/*************** SUBMIT MY STUFF ******************/
 
static void SubmitMyStuff(QD3DSetupOutputType *viewInfo)
{
int i;
static TQAVGouraud  vertex;
 
    vertex.x = 0;
    vertex.y = 0;
    vertex.z = .9999;
    vertex.invW = 1.0;
    vertex.r = .5;
    vertex.g = .5;
    vertex.b = .5;
    vertex.a = 1.0;
 
    for (i = 0; i < gNumContexts; i++)                                          // draw bitmaps in background
    {
        if (gBitmap[i] != nil)
            QADrawBitmap(gContexts[i], &vertex, gBitmap[i]);
    }
 
    for (i = 0; i < NUM_OBJECTS; i++)
    {
        Q3Object_Submit(gBaseGroup[i],viewInfo->viewObject);                    // submit the geometry
    }
}
 
 
 
#pragma mark =========== RAVE CONTEXT STUFF ====================
 
 
 
/********************** GET MY RAVE INFO ***********************/
//
// Gets pointers to the RAVE Draw Contexts uses by our view and renderer.
//
 
static void GetMyRAVEInfo(void)
{
TQ3ViewObject       theView;
TQ3RendererObject   theRenderer;
TQ3Status           status, viewStatus;
TQAEngine           *engines[MAX_CONTEXTS];
int                 i,j;
 
            /* GET RENDERER FROM VIEW */
 
    theView = gModelViewInfo.viewObject;
    status = Q3View_GetRenderer(theView,&theRenderer);
    if (status == kQ3Failure)
        DoFatalAlert("\pGetMyRAVEInfo: Q3View_GetRenderer failed!");
        
    
            /*************************/
            /* GET THE RAVE CONTEXTS */
            /*************************/
            //
            // 1.   Call _StartRendering to make sure RAVE contexts have been created.
            // 2.   Call _GetRAVEDrawContexts to retrieve the RAVE contexts & setup a callback.
            // 3.   Call _Cancel & _EndRendering to finish it.
            //          
 
    viewStatus = Q3View_StartRendering(theView);                                // enter render loop
    
    status = Q3InteractiveRenderer_GetRAVEDrawContexts(theRenderer,             // pass in renderer
                                                     gContexts,                 // fill this array with pointers to Draw Contexts
                                                     engines,                   // fill this array with pointers to Draw Engines
                                                     &gNumContexts,             // recieves # draw contexts gotten
                                                     MyRaveInvalidateCallback); // callback function to use when Contexts change
    if (status == kQ3Failure)
        DoFatalAlert("\pGetMyRAVEInfo: Q3InteractiveRenderer_GetRAVEDrawContexts failed!");
    
    if (viewStatus == kQ3Success)                                               // if we're in a render loop, we need to cancel it
    {
        status = Q3View_Cancel(theView);                                        // exit render loop
        if (status == kQ3Failure)
            DoFatalAlert("\pGetMyRAVEInfo: Q3View_Cancel failed!");
        Q3View_EndRendering(theView);                                           // *must* call EndRendering after a Cancel
    }
 
            /* VERIFY IF WE GOT ANYTHING */
            //
            // NOTE: if the user window shades a window, then we might
            //      get zero here.  An app should handle this gracefully,
            //      but we are not really doing so here.  Here we just bail out
            //      but we never attempt to get the draw contexts again.
            //
            
            
    if (gNumContexts == 0)
    {
        DoAlert("\pNo RAVE Contexts exist");
        return;
    }
        
        
        /* REMOVE DUPLICATES FROM ENGINES LIST */
        //
        // _GetRAVEDrawContexts returns a list of Draw Contexts and a parallel list of Drawing Engines for each Draw Context.
        // The Engines list may contain multiple copies of the same engine since different Draw Contexts can use the
        // same drawing engine (ie. multiple 3D windows on the same monitor).  Here, we scan thru the list and remove
        // the duplicates since we only want one copy of each engine for this test app.
        //
 
    gNumEngines = 0;
    
    for (i = 0; i < gNumContexts; i++)
    {
        for (j = 0; j < gNumEngines; j++)               // see if this engine is already in the global list
        {       
            if (engines[i] == gEngines[j])
                goto skip_me;
        }
        gEngines[gNumEngines++] = engines[i];           // this engine is unique, so put into global list       
skip_me:;       
    }   
        
        
        
                /* CLEAN UP */
                
    Q3Object_Dispose(theRenderer);                      
}
 
 
/******************* DO MY RAVE CALLS ************************/
//
// Uses the RAVE Draw Contexts to set up some fun stuff.
//
 
static void DoMyRAVECalls(void)
{
int         i;
TQAImage    image;
TQAError    err;
PicHandle   pict;
GWorldPtr   gworld;
Rect        r;
GDHandle                oldGD;
GWorldPtr               oldGW;
PixMapHandle            hPixMap;
 
 
    for (i = 0; i < gNumContexts; i++)                      // set the RAVE info on *all* of the contexts
    {
                /* LET'S CHANGE THE BLENDING MODE */
    
        QASetInt(gContexts[i], kQATag_Blend, kQABlend_OpenGL);
        QASetInt(gContexts[i], kQATagGL_BlendSrc, 1);
        QASetInt(gContexts[i], kQATagGL_BlendDst, 1);
    
                
                /* TURN OFF PERSPECTIVE Z */
                
        QASetInt(gContexts[i], kQATag_PerspectiveZ, kQAPerspectiveZ_Off);
    }
    
            /* LOAD A BITMAP TO USE FOR BACKGROUND */
            //
            // Must load it into all of the Engines being used.
            //
            
                /* DRAW PICT INTO GWORLD */
                        
    pict = GetPicture(129);                                     // load the PICT rez        
    SetRect(&r, 0,0, BACKGROUND_WIDTH, BACKGROUND_HEIGHT);
    NewGWorld(&gworld, 16, &r, 0, 0, 0L);                       // make gworld
    GetGWorld(&oldGW, &oldGD);                                  // save current port
    SetGWorld(gworld, nil); 
    hPixMap = GetGWorldPixMap(gworld);                          // calc addr & rowbytes
    LockPixels(hPixMap);                                        // lock gworld's pixels
    DrawPicture(pict, &r);                                      // draw it
    SetGWorld (oldGW, oldGD);
    ReleaseResource((Handle)pict);                              // nuke the PICT rez
            
            /* SETUP RAVE IMAGE STURCTURE */
            
    image.width = r.right;
    image.height = r.bottom;
    image.rowBytes = (**hPixMap).rowBytes & 0x3fff;
    image.pixmap = GetPixBaseAddr(hPixMap);
            
            
            /* UPLOAD THE IMAGE TO ALL DRAWING ENGINES */
                
    for (i = 0; i < gNumEngines; i++)   
    {
        err = QABitmapNew(gEngines[i], kQABitmap_NoCompression, kQAPixel_RGB16, &image, &gBitmap[i]);
        if (err)
            gBitmap[i] = nil;
        else
            QABitmapDetach (gEngines[i], gBitmap[i]);           // detach so I can nuke the gworld
            
    }
 
    DisposeGWorld(gworld);
 
}
 
 
/****************** MY RAVE INVALIDATE CALLBACK ***********************/
//
//  INPUT:  rendererRef = reference to the renderer calling the callback.
//                      You must not dispose of this reference in the callback!
//
 
static void MyRaveInvalidateCallback(TQ3RendererObject rendererRef)
{
short   i;
 
    rendererRef;                                        // unused
 
    SysBeep(0);                                         // play beep when Draw Contexts get invalidated
 
    gNumContexts = 0;                                   // we aint got no contexts no more
        
            /* UNLOAD BITMAPS */
            //
            // since the context got nuked, I should probably unload the bitmaps I've loaded as well.
            // These will be reloaded by function above.
            //
        
    for (i = 0; i < gNumEngines; i++)   
    {
        if (gBitmap[i])
        {
            QABitmapDelete(gEngines[i], gBitmap[i]);
            gBitmap[i] = nil;
        }
    }
 
 
            /* GET NEW RAVE CONTEXTS & RESET THE RAVE TAGS */
 
    GetMyRAVEInfo();                                // get the contexts & engines
    DoMyRAVECalls();                                // make my RAVE calls again to keep things setup the way I like
}