Source/3DMF.c

/****************************/
/*      3DMF.C              */
/* By Brian Greenstone      */
/****************************/
 
 
/****************************/
/*    EXTERNALS             */
/****************************/
#include <Script.h>
 
#include <QD3D.h>
#include <QD3DGroup.h>
#include <QD3DStorage.h>
#include <QD3DIO.h>
#include <QD3DErrors.h>
#include <QD3DGeometry.h>
#include "myglobals.h"
#include "misc.h"
#include "3dmf.h"
#include "mywindows.h"
#include "process.h"
 
extern  WindowPtr   gBreakdownWindow;
extern  Boolean     gShowContentStructure,gSaveTextToFile;
 
 
/****************************/
/*    PROTOTYPES            */
/****************************/
 
static TQ3Status MyRead3DMFModel(TQ3FileObject file, TQ3Object *model, TQ3Object *viewHints);
static Boolean Get3DMFInputFileName(FSSpec *myFSSpec);
static TQ3FileObject    Create3DMFFileObject(FSSpec *myFSSpec);
static Boolean Get3DMFOutputFileName(FSSpec *myFSSpec);
 
 
 
/****************************/
/*    CONSTANTS             */
/****************************/
 
 
/*********************/
/*    VARIABLES      */
/*********************/
 
FSSpec  gLast3DMF_FSSpec;
 
 
/*************** LOAD 3DMF MODEL **************/
//
// INPUT: inFile = nil if use Standard File Dialog, else FSSpec of file to load
//
// OUTPUT: nil = didnt happen
//
 
TQ3Object   Load3DMFModel(FSSpec *inFile)
{
TQ3FileObject       fileObj;
TQ3Object           theModel,viewHints;
FSSpec              myFSSpec;
 
 
    if (inFile == nil)                                      // see if need to let user choose file
    {
            /* SELECT FILE TO OPEN */
            
        if (!Get3DMFInputFileName(&myFSSpec))
            return(nil);
    }
    else
        myFSSpec = *inFile;                                 // use input FSSpec
        
    gLast3DMF_FSSpec = myFSSpec;                            // also keep a global copy
 
            /* CREATE A FILE OBJECT */
                
    fileObj = Create3DMFFileObject(&myFSSpec);
    if (fileObj == nil)
        theModel = nil;
    else
    {
 
            /* READ THE 3DMF FILE */
            
        if (MyRead3DMFModel(fileObj, &theModel, &viewHints) == kQ3Failure)
            theModel = nil;
    }
    
    Q3Object_Dispose(fileObj);
 
 
    return(theModel);
}
 
 
/*************** CREATE 3DMF FILE OBJECT ****************/
//
// Creates and returns a File Object which contains the 3DMF file.
//
// INPUT: myFSSpec = file to create object for
//
 
static TQ3FileObject    Create3DMFFileObject(FSSpec *myFSSpec)
{
TQ3FileObject       myFileObj;
TQ3StorageObject    myStorageObj;
        
        /* CREATE NEW STORAGE OBJECT WHICH IS THE 3DMF FILE */
            
    myStorageObj = Q3FSSpecStorage_New(myFSSpec);
    if (myStorageObj == nil)
    {
        DoFatalAlert("\pError calling Q3FSSpecStorage_New");
        return(nil);
    }
    
    
            /* CREATE NEW FILE OBJECT */
            
    myFileObj = Q3File_New();
    if (myFileObj == nil)
    {
        DoFatalAlert("\pError calling Q3File_New");
        Q3Object_Dispose(myStorageObj);
        return(nil);
    }
    
            /* SET THE STORAGE FOR THE FILE OBJECT */
            
    if (Q3File_SetStorage(myFileObj, myStorageObj) != kQ3Success)
    {
        DoAlert("\pError Q3File_SetStorage");
        return(nil);
    }
    Q3Object_Dispose(myStorageObj);
            
    return(myFileObj);
}
 
 
/******************* GET 3DMF INPUT FILE NAME ********************/
//
// Does Standard File IO and returns a filled in FSSpec record for selected 3DMF file.
//
// OUTPUT: false = error occurred
//          FSSpec = file info
//
 
static Boolean Get3DMFInputFileName(FSSpec *myFSSpec)
{
StandardFileReply   reply;
SFTypeList  typeList;
short       numTypes;
 
    typeList[0] = '3DMF';
    typeList[1] = 'TEXT';
    numTypes = 2;
        
    StandardGetFile(nil,numTypes,typeList,&reply);
    if (!reply.sfGood)                              // see if cancelled 
        return(false);
 
    *myFSSpec = reply.sfFile;                       // copy FSSpec back
    return(true);
}
 
 
 
/***************** READ 3DMF MODEL ************************/
//
// Reads the 3DMF file and saves into new TQ3Object.
//
// INPUT:  file = File Object containing reference to 3DMF file
//
// OUTPUT: model =object containing all the important data in the 3DMF file
//         viewHints = object containing all viewHints objects???
//
//
 
static TQ3Status MyRead3DMFModel(TQ3FileObject file, TQ3Object *model, TQ3Object *viewHints)
{
TQ3GroupObject  myGroup;
TQ3Object       myObject;
 
        /* INIT VIEW HINTS & MODEL TO BE RETURNED */
        
    *viewHints = *model = nil;                                          // assume return nothing
    myGroup = myObject = nil;
    
        /* OPEN THE FILE OBJECT & EXIT GRACEFULLY IF UNSUCCESSFUL */
 
    if (Q3File_OpenRead(file,nil) != kQ3Success)                            // open the file
    {
        DoFatalAlert("\pReading 3DMF file failed!");
        return  kQ3Failure;
    }
    
    do
    {
        myObject = nil;
        
            /* READ A METAFILE OBJECT FROM THE FILE OBJECT */
 
        myObject = Q3File_ReadObject(file);
        if (myObject == nil)
        {
        
            if (myGroup)
                Q3Object_Dispose(myGroup);
 
            QD3D_ShowError("\pReading returned NULL object!", true);
            break;
        }
                        
        /* SAVE A VIEW HINTS OBJECT & ADD ANY DRAWABLE OBJECTS TO A GROUP */
        
        if (Q3Object_IsType(myObject, kQ3SharedTypeViewHints))          // see if is a View Hint object
        {
            if (*viewHints == nil)
            {
                *viewHints = myObject;
                myObject = NULL;
            }
        }
        else
        if (Q3Object_IsDrawable(myObject))                              // see if is a drawable object
        {
            if (myGroup)                                                // if group exists
            {
                Q3Group_AddObject(myGroup,myObject);                    // add object to group
            }
            else
            if (*model == nil)                                          // if no model data yet
            {
                *model = myObject;                                      // set model to this object
                myObject = nil;                                         // clear this object
            }
            else
            {
                myGroup = Q3DisplayGroup_New();                         // make new group
                Q3Group_AddObject(myGroup,*model);                      // add existing model to group
                Q3Group_AddObject(myGroup,myObject);                    // add object to group
                Q3Object_Dispose(*model);                               // dispose model
                *model = myGroup;                                       // set return value to the new group
            }
        }
        
        if (myObject != nil)
            Q3Object_Dispose(myObject);
    } while(!Q3File_IsEndOfFile(file));
    
    if (Q3Error_Get(nil) != kQ3ErrorNone)
    {
        if (*model != nil)
        {
            Q3Object_Dispose(*model);
            *model = nil;
        }
        
        if (*viewHints != nil)
        {
            Q3Object_Dispose(*viewHints);
            *viewHints = nil;
        }
        return(kQ3Failure);
    }
    return(kQ3Success);
}
    
 
/*************** SAVE 3DMF MODEL **************/
//
// INPUT: outFile = nil if use Standard File Dialog, else FSSpec of file to load
//
//
 
void Save3DMFModel(QD3DSetupOutputType *setupInfo,FSSpec *outFile, void (*callBack)(QD3DSetupOutputType *))
{
TQ3FileObject       fileObj;
TQ3Object           theModel;
FSSpec              myFSSpec;
TQ3Status               myStatus;
TQ3ViewStatus           myViewStatus;
TQ3FileMode         fileMode;
 
#if DEMO_VERSION
    DoAlert("\pSorry, the demo version of 3DMF Optimizer cannot save files, but the optimized model will now be displayed in the Model Window.");
#else
 
    if (outFile == nil)                                     // see if need to let user choose file
    {
            /* SELECT FILE TO OPEN */
            
        if (!Get3DMFOutputFileName(&myFSSpec))
            return;
    }
    else
    {
        myFSSpec = *outFile;                                // use input FSSpec 
        FSpDelete(&myFSSpec);                               // delete any old one
        FSpCreate(&myFSSpec, 'OP20', '3DMF', smSystemScript);       // create new file
    }
    
    gLast3DMF_FSSpec = myFSSpec;                            // also keep a global copy
 
            /* CREATE A FILE OBJECT */
                
    fileObj = Create3DMFFileObject(&myFSSpec);
    if (fileObj == nil)
        theModel = nil;
    else
    {
                                            // set binary or text output
//      fileMode = kQ3FileModeNormal;
        fileMode = kQ3FileModeText;
            
        myStatus = Q3File_OpenWrite(fileObj, fileMode);
        if ( myStatus != kQ3Success )
            DoFatalAlert("\pQ3File_OpenWrite Failed!");
    
            /* WRITE THE 3DMF FILE */
            
                
        myStatus = Q3View_StartWriting(setupInfo->viewObject,fileObj);          
        if ( myStatus != kQ3Success )
            DoFatalAlert("\pQ3View_StartWriting Failed!");
        
                /***************/
                /* SUBMIT LOOP */
                /***************/
        do
        {
    
                /* CALL INPUT WRITE FUNCTION */
    
            callBack(setupInfo);
    
            myViewStatus = Q3View_EndWriting(setupInfo->viewObject);
        } while ( myViewStatus == kQ3ViewStatusRetraverse );            
    }
    
    myStatus = Q3File_Close(fileObj);
    if ( myStatus == kQ3Failure )
        DoFatalAlert("\pQ3File_Close Failed!");
 
    Q3Object_Dispose(fileObj);
 
#endif
}
    
    
    
/******************* GET 3DMF OUTPUT FILE NAME ********************/
//
// Does Standard File IO and returns a filled in FSSpec record for selected 3DMF file & creates the file!
//
// OUTPUT: false = error occurred
//          FSSpec = file info
//
 
static Boolean Get3DMFOutputFileName(FSSpec *myFSSpec)
{
StandardFileReply   reply;
    
        
    StandardPutFile("\pSave 3DMF file",gLast3DMF_FSSpec.name,&reply);
    if (!reply.sfGood)                              // see if cancelled 
        return(false);
 
    *myFSSpec = reply.sfFile;                       // copy FSSpec back
    
    if (reply.sfReplacing)
        FSpDelete(myFSSpec);                                    // delete any old one
    FSpCreate(myFSSpec, 'OP20', '3DMF', smSystemScript);        // create new file
    
    return(true);
}