Source/Process.c

/****************************/
/*      PROCESS.C           */
/* By Brian Greenstone      */
/****************************/
 
 
/****************************/
/*    EXTERNALS             */
/****************************/
#include <Resources.h>
#include <NumberFormatting.h>
 
#include <QuickTimeComponents.h>
#include <QD3D.h>
#include <QD3DGeometry.h>
#include <QD3DMath.h>
#include <QD3DView.h>
#include <QD3DGroup.h>
#include <QD3DTransform.h>
#include <QD3DStorage.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  TQ3SurfaceShaderObject  QD3D_GetTextureMap(long textureRezID);
static  TQ3SurfaceShaderObject  QD3D_PICTToTexture(PicHandle picture);
 
 
/****************************/
/*    CONSTANTS             */
/****************************/
 
#define MODEL_WIND_ID           400
 
#define TEXTURE_ORIGINAL_DEPTH  32
 
/*********************/
/*    VARIABLES      */
/*********************/
 
WindowPtr               gModelWindow = nil;
QD3DSetupOutputType     gModelViewInfo;
TQ3Object               gModelGroup = nil;
TQ3GroupObject          gBaseGroup = nil;
 
CodecQ          gCodecQuality   = codecNormalQuality;
CodecType       gCodecType      = kRawCodecType;
CodecComponent  gCodecComponent = anyCodec;
short           gCodecDepth     = TEXTURE_ORIGINAL_DEPTH;
short           gCodecDepth2    = TEXTURE_ORIGINAL_DEPTH;
 
TQ3AttributeSet     gTextureAttr;
 
TQ3Matrix4x4    gTransformMatrix;
TQ3Object       gTransformObject = nil;
 
Str255          gCompressionRatio,gCompressionSize;
 
 
 
#pragma mark ========INITIALIZATION STUFF=========
 
/******************** INIT TEST ************************/
 
void InitTest(void)
{
 
            /* INIT THE WINDOW */
            
    InitModelWindow();
 
 
            /* CREATE THE TEST MODEL */
            
    BuildTestModel();
 
 
            /* CREATE DISPLAY GROUP */
            
    gBaseGroup = Q3DisplayGroup_New();                                      // make display group   
    Q3Matrix4x4_SetIdentity(&gTransformMatrix);
    gTransformObject = Q3MatrixTransform_New(&gTransformMatrix);            // make transform object
    
    Q3Group_AddObject(gBaseGroup, gTransformObject);                        // add to group     
    Q3Group_AddObject(gBaseGroup, gModelGroup);                             // add geometry to group 
 
 
            /* DRAW THE WINDOW */
                        
    DrawModelWindow();
}
 
 
 
/************** INIT MODEL WINDOW *******************/
 
static void InitModelWindow(void)
{
QD3DSetupInputType  viewDef;
TQ3Point3D          cameraFrom = { 0,0, 100 };
TQ3Point3D          cameraTo = { 0, 0, 0 };
TQ3Vector3D         cameraUp = { 0.0, 1.0, 0 };
TQ3ColorARGB        clearColor = {1,0,0,.5};
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);
 
 
            /***********************/
            /* SET QD3D PARAMETERS */
            /***********************/
 
    viewDef.view.displayWindow      = gModelWindow;
    viewDef.view.rendererType       = kQ3RendererTypeInteractive;
    viewDef.view.clearColor         = clearColor;
    viewDef.view.paneClip.left      = 0;
    viewDef.view.paneClip.right     = 0;
    viewDef.view.paneClip.top       = 16;
    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           = 5;
    viewDef.camera.yon              = 3000;
    viewDef.camera.fov              = 1.0;
 
    viewDef.lights.ambientBrightness = 1.0;
    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);
}
 
 
 
/********************* 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);
        
    gTextureAttr = Q3AttributeSet_New();
    Q3AttributeSet_Add(gTextureAttr, kQ3AttributeTypeSurfaceShader, &texture);      
 
            /* 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;
 
            /* ROTATE THE GEOMETRY */
            
    QD3D_CalcFramesPerSecond();
    Q3Matrix4x4_SetRotate_XYZ(&m,0.4/gFramesPerSecond,0.5/gFramesPerSecond,0);
    Q3Matrix4x4_Multiply(&m,&gTransformMatrix,&gTransformMatrix);   
 
 
            /* UPDATE THE MATRIX */
            
    Q3MatrixTransform_Set(gTransformObject,&gTransformMatrix);
 
 
            /* 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)
{
    QD3D_DrawScene(&gModelViewInfo,(void *)DrawTheGeometry);
}
 
 
/*************** DRAW THE GEOMETRY ******************/
 
void DrawTheGeometry(QD3DSetupOutputType *viewInfo)
{
    Q3Object_Submit(gBaseGroup,viewInfo->viewObject);
}
 
 
#pragma mark ======= COMPRESSION STUFF ========
 
 
/****************** SELECT COMPRESSOR ************************/
 
void SelectCompressor(void)
{
ComponentInstance   aComponent;
OSErr               iErr;
PicHandle           picture;
ComponentResult     aCompRes;
Boolean             cancel = false;
SCSpatialSettings   spatialInfo;
TQ3Object           texture;
 
            /* CREATE COMPONENT */
            
    aComponent = OpenDefaultComponent('scdi', 'imag');
    if (aComponent == nil)
        DoFatalAlert("\pSelectCompressor: OpenDefaultComponent failed!");
 
            /* SET TEST PICT */
            
    picture = GetPicture(128);  
    aCompRes = SCSetTestImagePictHandle(aComponent, picture, nil, 0);
 
 
            /* DO THE DIALOG */
                        
    aCompRes = SCRequestImageSettings(aComponent);
    if (aCompRes == scUserCancelled)
    {
        cancel = true;
        goto cleanup;
    }
    if (aCompRes < 0)
        DoFatalAlert("\pSelectCompressor: SCRequestSequenceSettings failed!");
    
    
            /* EXTRACT INFO */
    
    aCompRes = SCGetInfo(aComponent, scSpatialSettingsType, &spatialInfo);      
    if (aCompRes < 0)
        DoFatalAlert("\pSelectCompressor: SCGetInfo failed!");
 
    gCodecType      = spatialInfo.codecType;                            // get codec type
    gCodecComponent = spatialInfo.codec;                                // get codec component
    gCodecQuality   = spatialInfo.spatialQuality;                       // get quality
    gCodecDepth     = spatialInfo.depth;                                // get depth
    
    if (gCodecDepth & (1<<5))                                           // see if using greyscale
        gCodecDepth2 = gCodecDepth & 0x1f;                              // mask out bit depth from encoded value
    else
        gCodecDepth2 = gCodecDepth;
        
 
            /* CHANGE TEXTURE */
            
    Q3AttributeSet_Clear(gTextureAttr, kQ3AttributeTypeSurfaceShader);
    texture = QD3D_GetTextureMap(128);                                  // get original texture (and knock to gCodecDepth)
    Q3AttributeSet_Add(gTextureAttr, kQ3AttributeTypeSurfaceShader, &texture);      
    Q3Object_Dispose(texture);
 
 
            /* CLEANUP */
            
cleanup:            
    ReleaseResource((Handle)picture);                                       // nuke pict
    iErr = CloseComponent(aComponent);                                      // nuke component
    if (iErr)
        DoFatalAlert("\pSelectCompressor: CloseComponent failed!");
}
 
 
 
/**************** QD3D GET TEXTURE MAP ***********************/
//
// Loads a PICT resource and returns a shader object which is
// based on the PICT converted to a texture map.
//
// INPUT: textureRezID = resource ID of texture PICT to get.
//          myFSSpec != nil if want to load PICT from file instead
//
// OUTPUT: TQ3ShaderObject = shader object for texture map.
//
 
static TQ3SurfaceShaderObject   QD3D_GetTextureMap(long textureRezID)
{
PicHandle                   picture;
TQ3SurfaceShaderObject      shader;
 
            /* LOAD PICT REZ */
        
    picture = GetPicture (textureRezID);
    if (picture == nil)
        DoFatalAlert("\pUnable to load texture PICT resource");
 
 
            /* CONVERT PICT TO TEXTURE OBJECT */
            
    shader = QD3D_PICTToTexture(picture);
        
    ReleaseResource ((Handle) picture);
    return(shader); 
}
 
 
/**************** QD3D PICT TO TEXTURE ***********************/
//
//
// INPUT: picture = handle to PICT.
//
// OUTPUT: TQ3ShaderObject = shader object for texture map.
//
 
static TQ3SurfaceShaderObject   QD3D_PICTToTexture(PicHandle picture)
{
TQ3CompressedPixmap     pixmap;
TQ3TextureObject        texture;
TQ3SurfaceShaderObject  shader;
long                    width, height,numBytesPerPixel;
Rect                    rectGW;
GWorldPtr               pGWorld;
PixMapHandle            hPixMap;
OSErr                   myErr;
GDHandle                oldGD;
GWorldPtr               oldGW;
unsigned long           pictMapAddr;
unsigned long           pictRowBytes;
TQ3Status               status;
 
                /* CALC DIMENSIONS OF TEXTURE */
                
    width = (**picture).picFrame.right  - (**picture).picFrame.left;
    height = (**picture).picFrame.bottom - (**picture).picFrame.top;
 
 
                /* CREATE A GWORLD TO DRAW PICT INTO */
 
    GetGWorld(&oldGW, &oldGD);                                      // save current port
    SetRect(&rectGW, 0, 0, width, height);                          // set dimensions
    myErr = NewGWorld(&pGWorld, gCodecDepth2, &rectGW, 0, 0, 0L);   // make gworld
    if (myErr)
        DoFatalAlert("\pQD3D_PICTToTexture: NewGWorld failed!");
 
                /* DRAW PICTURE INTO GWORLD */
            
    hPixMap = GetGWorldPixMap(pGWorld);                             // get gworld's pixmap
    numBytesPerPixel = ((int)(**hPixMap).pixelSize/8);              // need this for ratio calculation below
    SetGWorld(pGWorld, nil);    
    LockPixels(hPixMap);
    EraseRect(&rectGW);
    DrawPicture(picture, &rectGW);
 
 
            /****************************************/
            /* MAKE A COMPRESSED PIXMAP FROM GWORLD */
            /****************************************/
            
                /* GET TEXTURE ADDR & ROWBYTES */
                    
    pictMapAddr = (unsigned long )GetPixBaseAddr(hPixMap);
    pictRowBytes = (unsigned long)(**hPixMap).rowBytes & 0x3fff;
 
 
            /* FILL OUT COMPRESSED PIXMAP STRUCTURE */
 
    pixmap.compressedImage = nil;
    pixmap.imageDesc    = nil;
    pixmap.makeMipmaps  = kQ3True;  
    pixmap.width        = width;
    pixmap.height       = height;
    if (gCodecDepth == 32)
    {
        pixmap.pixelSize = 32;
        pixmap.pixelType = kQ3PixelTypeRGB32;
    }
    else
    {
        pixmap.pixelSize = 16;
        pixmap.pixelType = kQ3PixelTypeRGB16;
    }
 
 
 
            /* COMPRESS IMAGE AND FILL OUT REMAINING RECORDS IN STRUCTURE */
            //
            // pass in compression quality, codec type, etc.
            //
            
    status = Q3CompressedPixmapTexture_CompressImage(&pixmap, hPixMap, gCodecType, gCodecComponent,
                                                    gCodecDepth, gCodecQuality);
    SetGWorld (oldGW, oldGD);
    DisposeGWorld (pGWorld);
 
    if (status == kQ3Failure)
        DoFatalAlert("\pQ3CompressedPixmapTexture_CompressImage Failed!");  
 
    
                /* CALC COMPRESSION RATIO FOR DISPLAYING */
                
    {
        unsigned char *buffer;
        unsigned long   compSize;
        float           unCompSize;
        
        Q3MemoryStorage_GetBuffer(pixmap.compressedImage, &buffer, &compSize, &compSize);   // get compressed size          
 
//      unCompSize = width * height * numBytesPerPixel;                     // calc uncompressed size
        unCompSize = width * height * (TEXTURE_ORIGINAL_DEPTH/8);           // calc uncompressed size (based on original depth)
        
        FloatToString((float)compSize/unCompSize,gCompressionRatio);        // calc compression ratio and convert to string
 
        NumToString(compSize, gCompressionSize);                            // also calc string for compressed size
    }
 
 
            /***************************/
            /* MAKE NEW PIXMAP TEXTURE */
            /***************************/
            
        /* MAKE NEW COMPRESSED PIXMAP TEXTUE OBJECT */
                
    texture = Q3CompressedPixmapTexture_New (&pixmap);
    if (texture == nil)
        DoFatalAlert("\pError calling Q3CompressedPixmapTexture_New!");
        
        
        /* MAKE NEW SHADER FROM TEXTURE */
        
    shader = Q3TextureShader_New (texture);
    if (shader == nil)
        DoFatalAlert("\pError calling Q3TextureShader_New!");
 
    Q3Object_Dispose(texture);
    Q3Object_Dispose(pixmap.compressedImage);           // disposes of extra reference to storage objs
    Q3Object_Dispose(pixmap.imageDesc);
 
    return(shader); 
}