GTFile.c

// GTFile.c, file and metafile routines
 
 
// system headers
#include <Devices.h>
#include <Dialogs.h>
#include <DiskInit.h>
#include <Fonts.h>
#include <Menus.h>
#include <PictUtils.h>
#include <QDOffScreen.h>
#include <QuickDraw.h>
#include <Resources.h>
#include <SegLoad.h>
#include <StandardFile.h>
#include <TextEdit.h>
#include <ToolUtils.h>
 
#include "GTSupport.h"
#include "GTFile.h"
 
#include "QD3D.h"
#include "QD3DDrawContext.h"
#include "QD3DRenderer.h"
#include "QD3DShader.h"
#include "QD3DCamera.h"
#include "QD3DLight.h"
#include "QD3DGeometry.h"
#include "QD3DTransform.h"
#include "QD3DGroup.h"
#include "QD3DMath.h"
 
#include "QD3DStorage.h"
#include "QD3DIO.h"
 
 
//-------------------------------------------------------------------------------------------
//
 
static void InitDocumentData( DocumentHdl theDocument ) 
{
    TQ3Point3D      myOrigin = { 0, 0, 0 } ;
    
    // sanity check
    if( theDocument == nil || (**theDocument).fWindow == nil )
        return ;
        
    // Lock and load
    HLock( (Handle)theDocument ) ;
    
    // sets up the 3d data for the scene
    //  Create view for QuickDraw 3D.
    (**theDocument).fView = MyNewView( (**theDocument).fWindow );
 
    // the main display group:
    (**theDocument).fModel = NULL ; 
    
    // the drawing styles:
    (**theDocument).fInterpolation = Q3InterpolationStyle_New(kQ3InterpolationStyleNone) ;
    (**theDocument).fBackFacing = Q3BackfacingStyle_New(kQ3BackfacingStyleBoth ) ;
    (**theDocument).fFillStyle = Q3FillStyle_New(kQ3FillStyleFilled ) ;
 
 
    (**theDocument).fGroupScale = 1;                
    (**theDocument).fGroupCenter = myOrigin ;   
    
    // set up an illumination shder for this document
    (**theDocument).fShader = Q3PhongIllumination_New();        
 
    // set the rotation matrix the identity matrix
    Q3Matrix4x4_SetIdentity(&(**theDocument).fRotation);    
                    
    // unlock the handle            
    HUnlock((Handle) theDocument ) ;
    
    return ;
    
bail:
    // either we failed getting the model or the view
    // so we want to quit here
    ExitToShell() ;
    
}
 
//-------------------------------------------------------------------------------------------
//
 
static void DisposeDocumentData( DocumentHdl theDocument )
{
    // Lock and load
    HLock( (Handle)theDocument ) ;
    
    if( (**theDocument).fView ) 
        Q3Object_Dispose((**theDocument).fView) ;               // the view for the scene
 
    if( (**theDocument).fModel )  
        Q3Object_Dispose((**theDocument).fModel) ;              // object in the scene being modelled
 
    if( (**theDocument).fInterpolation )  
        Q3Object_Dispose((**theDocument).fInterpolation) ;      // interpolation style used when rendering
 
    if( (**theDocument).fBackFacing )  
        Q3Object_Dispose((**theDocument).fBackFacing) ;         // whether to draw shapes that face away from the camera
 
    if( (**theDocument).fFillStyle )  
        Q3Object_Dispose((**theDocument).fFillStyle) ;          // whether drawn as solid filled object or decomposed to components
 
    if( (**theDocument).fShader )  
        Q3Object_Dispose((**theDocument).fShader) ;
 
    HUnlock((Handle) theDocument ) ;
    
    // And free the storage used by the document handle
    DisposHandle((Handle) theDocument);
}
 
//-------------------------------------------------------------------------------------------
//
void HandleCloseWindow( WindowPtr theWindow )
{
    DocumentHdl  theDocument ;
    
    if( theWindow ) {
        theDocument = (DocumentHdl) GetWRefCon( theWindow ) ;
        DisposeWindow ( theWindow );
        if( theDocument )
            DisposeDocumentData( theDocument ) ;
    }
 
}
 
 
//-------------------------------------------------------------------------------------------
// Create and init a document with the 3d stuff - gets called by both open and new
 
static DocumentHdl  CreateDocument( void ) 
{
    DocumentHdl     theDocument;
    WindowPtr       theWindow = nil ;
    OSErr           theErr = noErr ;
    
    if(( theDocument = (DocumentHdl)NewHandleClear( sizeof(DocumentRec))) != nil )
    {
        theWindow = GetNewCWindow(128,nil,(WindowPtr)-1);
        if( theWindow == nil ) 
            return nil ;
        
        SetWRefCon( theWindow, (long)theDocument );
        (**theDocument).fWindow = theWindow ;
        
        // initialise our document structure
        InitDocumentData( theDocument ) ;
    
    }
    else // handle the error
        theErr = MemError() ;
    
    return theDocument ;        
}
 
OSErr   HandleNewCommand( void )
{
    DocumentHdl theDocument ;
    OSErr       theErr = noErr ;
    theDocument = CreateDocument() ;
    if(theDocument == nil )
    {
        theErr = MemError() ;
        if( theErr == noErr )
        {
            theErr = ResError() ;
        }
    
    }
    return theErr ;
}
 
//-------------------------------------------------------------------------------------------
//
static Boolean MetafileFileSpecify( FSSpec *theFile )
{
    StandardFileReply   theSFReply ;
    SFTypeList          myTypes = { 'TEXT', '3DMF' } ;
    const short         numTypes = 2 ;
        
    // Get the file name to open
    StandardGetFile( nil, numTypes, myTypes, &theSFReply ) ;
    
    if( theSFReply.sfGood )
        *theFile = theSFReply.sfFile ;
    
    // did the user cancel?
    return theSFReply.sfGood ;
    
}
 
//-----------------------------------------------------------------------------------------------
//
OSErr   HandleOpenCommand( void )
{
    DocumentHdl theDocument ;
    OSErr       theErr = noErr ;
    FSSpec      theFileSpec ;
    
    
    theDocument = CreateDocument() ;
    if(theDocument == nil )
    {
        theErr = MemError() ;
        if( theErr == noErr )
        {
            theErr = ResError() ;
        }
        return theErr ;
    }
 
    if(MetafileFileSpecify( &theFileSpec )) {
    
        WindowPtr       myWindow = (**theDocument).fWindow ;
    
        SetCursor(*(GetCursor(watchCursor)));
        HLock((Handle)theDocument) ;
        
        // try to read the file into the main display group
        if(((**theDocument).fModel = MyNewModelFromFile(&theFileSpec)) != NULL ) {      
 
            AdjustCamera(   theDocument,
                            (myWindow->portRect.right - myWindow->portRect.left),
                            (myWindow->portRect.bottom - myWindow->portRect.top) ) ;
 
            SetWTitle( myWindow, theFileSpec.name );
            ShowWindow( myWindow ) ;
            SetPort( myWindow ) ;
    
            SetCursor(&qd.arrow) ;
            
        }
        
        HUnlock((Handle)theDocument) ;
    }
 
    return theErr ;
}   
 
 
//-----------------------------------------------------------------------------------------------
// cleaned up from IM QuickDraw 3D pp 15-5
static TQ3FileObject MyGetNewFile( FSSpec *myFSSpec, TQ3Boolean *isText )
{
    TQ3FileObject       myFileObj;
    TQ3StorageObject        myStorageObj;
    OSType              myFileType;
    
    FInfo               fndrInfo ;
 
    // we assume the FSSpec passed in was valid, get the file information
    // we need to know the file type, this routine may get called by an appleEvent
    // handler, so we can't assume a type, we need to get it from the fsspec.
    
    FSpGetFInfo( myFSSpec, &fndrInfo ) ;
    
    // pull out the file type
    
    myFileType = fndrInfo.fdType ;
    
    // Create new storage object and new file object 
    if(((myStorageObj = Q3FSSpecStorage_New( myFSSpec )) == NULL) 
        || ((myFileObj = Q3File_New()) == NULL)) 
    {
        if (myStorageObj != NULL) 
            Q3Object_Dispose(myStorageObj);
        return(NULL);
    }
 
    // Set the storage for the file object
    Q3File_SetStorage(myFileObj, myStorageObj);
    Q3Object_Dispose(myStorageObj);
 
    if ((myFileType == '3DMF') || (myFileType == 'EO3D'))
        *isText = kQ3False ;
    else if (myFileType == 'TEXT')
        *isText = kQ3True ;
 
    return (myFileObj);
}
 
 
//----------------------------------------------------------------------------------
// read model from file object into the supplied group
 
static TQ3Status MyReadModelFromFile( TQ3FileObject theFile,TQ3GroupObject myGroup)
{   
    if(theFile != NULL) {
    
        TQ3Object           myTempObj ;
        TQ3Boolean          isEOF ;
                
    
        // read objects from the file
        do {
        
            myTempObj = Q3File_ReadObject( theFile );
            
            if( myTempObj != NULL ) {
                // we only want the object in our main group if we can draw it
                if ( Q3Object_IsDrawable( myTempObj) ) 
                    Q3Group_AddObject( myGroup, myTempObj ) ;
                
                // we either added the object to the main group, or we don't care
                // so we can safely dispose of the object
                Q3Object_Dispose( myTempObj ) ;
            }
            
            // check to see if we reached the end of file yet
            isEOF = Q3File_IsEndOfFile( theFile );
            
        } while (isEOF == kQ3False);    
    }
    
    if( myGroup != NULL )
        return kQ3Success ;
    else
        return kQ3Failure ;
}
 
//----------------------------------------------------------------------------------
// attach a shader to the group
 
static TQ3Status MyAddShaderToGroup( TQ3GroupObject group )
{
    TQ3ShaderObject illuminationShader = Q3PhongIllumination_New();
 
    Q3Group_AddObject(group, illuminationShader);
    Q3Object_Dispose(illuminationShader);
    return(kQ3Success);
}
 
//----------------------------------------------------------------------------------
 
static TQ3GroupObject MyNewModelFromFile(FSSpec *theFileSpec)
{
    TQ3GroupObject      myGroup = NULL ;
    TQ3Boolean          isText = kQ3False ;
    TQ3FileMode         myFileMode = 0;
    TQ3FileObject       theFile;
    
    //  Create a ordered group for the complete model.
    if ((myGroup = Q3DisplayGroup_New()) == NULL )
        return NULL;
        
    MyAddShaderToGroup( myGroup ) ;
 
    theFile = MyGetNewFile( theFileSpec, &isText ) ;
    
    if( isText == kQ3True )
        myFileMode |= kQ3FileModeText;  // is it a text metafile??  
 
    // Open the file object
    if( Q3File_OpenRead( theFile, &myFileMode ) != kQ3Success)
        return  NULL ;
 
    if( MyReadModelFromFile( theFile, myGroup ) == NULL)
        DebugStr("\pMetafile data read is null") ;
    
    Q3File_Close(theFile);          // close and dispose of the file object
    Q3Object_Dispose(theFile);
    
    return myGroup ;
}