Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
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 |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14