DumpGroup.c

/*
 * DumpGroup.c
 *
 * This code lets you select a QuickDraw 3D 3DMF file (via
 * the Standard Get File dialog) which is parsed to find all
 * objects in the metafile.  The object class names of these
 * objects are printed in a SIOUX window indented according
 * to their nested level in the group hierarchy. When an
 * attribute set is encountered all contained attributes
 * are printed after this object type.
 *
 * Change History:
 * 
 *  12/01/96    Nick Thompson - Created initial version.
 *  01/21/97    Robert Dierkes - Added nesting level at beginning of each
 *              printed line and the parsing of attribute sets.
 * 
 * ©1997 Apple computer Inc., All Rights Reserved
 */
 
#include <stdio.h>
#include <stdlib.h>
 
#include <CodeFragments.h>
#include <Dialogs.h>
#include <Fonts.h>
#include <Memory.h>
#include <QuickDraw.h>
#include <StandardFile.h>
#include <Windows.h>
 
#include "QD3D.h"
#include "QD3DGroup.h"
#include "QD3DIO.h"
#include "QD3DStorage.h"
 
 
/* Local prototypes */
static void InitToolbox(void) ;
void PrintGroupElementsAndRecurse( TQ3GroupObject theGroup, unsigned long depth );
TQ3Status PrintAttributeSetType(TQ3AttributeSet objectType);
 
 
 
/* initialize the Mac toolbox */
static void InitToolbox(void)
{
 
    MaxApplZone() ;
    MoreMasters() ; MoreMasters() ; MoreMasters() ; 
    
    InitGraf( &qd.thePort );
    InitFonts();
    InitWindows();
 
    FlushEvents( everyEvent, 0 ) ;
 
    InitCursor();
}
 
static TQ3FileObject MyNewFileObject( FSSpec *myFSSpec )
{
    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);
 
    return (myFileObj);
}
 
 
static TQ3Status MyReadObjectsFromFileIntoGroup( TQ3FileObject theFile,TQ3GroupObject myGroup)
{   
    if(theFile != NULL) {
    
        TQ3Object           myTempObj ;
        TQ3Boolean          isEOF ;
                
    
        /* read all objects from the file into the group */
        do {
        
            myTempObj = Q3File_ReadObject( theFile );
            
            if( myTempObj != NULL ) {
            
                if( !Q3Object_IsType( myTempObj, kQ3SharedTypeViewHints ) )
                {
                    Q3Group_AddObject( myGroup, myTempObj ) ;
                }
                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 ;
}
 
 
static TQ3GroupObject MyNewModelFromFile(FSSpec *theFileSpec)
{
    TQ3GroupObject      myGroup = NULL ;
    TQ3Boolean          isText = kQ3False ;
    TQ3FileMode         myFileMode = 0;
    TQ3FileObject       theFile;
    
    /*  Create a group for the complete model. */
    if ((myGroup = Q3Group_New()) == NULL )
        return NULL;
 
    theFile = MyNewFileObject( theFileSpec ) ;
    
    // Open the file object
    if( Q3File_OpenRead( theFile, &myFileMode ) != kQ3Success)
        return  NULL ;
 
    if( MyReadObjectsFromFileIntoGroup( theFile, myGroup ) == 0)
        DebugStr("\pMetafile data read is null") ;
    
    Q3File_Close(theFile);          // close and dispose of the file object
    Q3Object_Dispose(theFile);
    
    return myGroup ;
}
 
/* get an FSSpec for a metafile */
static Boolean MetafileFileSpecify( FSSpec *theFile )
{
    StandardFileReply   theSFReply ;
    SFTypeList          myTypes = { '3DMF' } ;
    const short         numTypes = 1 ;
        
    /* Get the file name to open */
    StandardGetFile( nil, numTypes, myTypes, &theSFReply ) ;
    
    if( theSFReply.sfGood )
        *theFile = theSFReply.sfFile ;
    
    /* did the user cancel? */
    return theSFReply.sfGood ;
    
}
 
/* the guts... :) */
void PrintGroupElementsAndRecurse( TQ3GroupObject theGroup, unsigned long depth )
{
 
    TQ3GroupPosition            thePosition ;
    TQ3Object                   theObjectAtPosition ;
    TQ3Status                   theStatus ;
 
    TQ3Object                   thisObject ;
    TQ3ObjectType               thisObjectType ;
    TQ3ObjectClassNameString    objectClassString ;
    
    unsigned long               i ;
    unsigned long               numberOfObjects ;
    
    /* sanity checks, and totals... */
    if( depth < 1 ) 
        depth = 1 ; /* we must always be called with a depth of at least 1 */
    
    if ( Q3Object_IsType( theGroup, kQ3ShapeTypeGroup) )
    {
        /* print the group name here */
        thisObjectType = Q3Object_GetLeafType ( theGroup ) ;
        
        Q3ObjectHierarchy_GetStringFromType( thisObjectType,  objectClassString) ;
        Q3Group_CountObjects( theGroup, &numberOfObjects ) ;
        
        /* really this group is at the level before this, so subtract 1 from the total */
        printf("%4u  ", (depth - 1)) ;
        for( i = 0; i < (depth - 1); i++ )
            printf("  ") ;
            
        printf( "%s (contains %u objects)\n",   objectClassString,  numberOfObjects) ;  
    }
    else
    {
        printf( "PrintGroupElementsAndRecurse called in error, theGroup ain't a group") ;
        return ;
    }
        
 
    /* get the first object from the group and iterate through */
    theStatus = Q3Group_GetFirstPosition ( theGroup, &thePosition ) ;
    
    
    while( thePosition != NULL && theStatus == kQ3Success )
    {
    
        theStatus = Q3Group_GetPositionObject ( theGroup, thePosition, &thisObject ) ;
        
        if(theStatus == kQ3Failure )
        {
            printf("GetPositionObject failed, Aborting") ;
            return ;
        }
        
        
        if ( Q3Object_IsType( thisObject, kQ3ShapeTypeGroup) )
        {
            PrintGroupElementsAndRecurse( thisObject, depth + 1 ) ;
        }
        else
        {
            thisObjectType = Q3Object_GetLeafType ( thisObject ) ;
            
            Q3ObjectHierarchy_GetStringFromType( thisObjectType,  objectClassString) ;
            
            printf("%4u  ", depth) ;
            for( i = 0; i < depth; i++ )
                printf("  ") ;
                
            printf( "%s",   objectClassString ) ;   
 
            if (thisObjectType == kQ3SetTypeAttribute) {
                PrintAttributeSetType(thisObject);
            }
                
            printf( "\n" ) ;    
        }
            
        Q3Object_Dispose( thisObject ) ;
        
        /* finally get the next object in the group */
        theStatus = Q3Group_GetNextPosition(theGroup, &thePosition) ;
    }
    
}
 
TQ3Status PrintAttributeSetType(TQ3Object object)
{
    TQ3AttributeType    attrType;
    TQ3AttributeType    attributeTypes[] = {
                            kQ3AttributeTypeNone,
                            kQ3AttributeTypeSurfaceUV,
                            kQ3AttributeTypeShadingUV,
                            kQ3AttributeTypeNormal,
                            kQ3AttributeTypeAmbientCoefficient,
                            kQ3AttributeTypeDiffuseColor,
                            kQ3AttributeTypeSpecularColor,
                            kQ3AttributeTypeSpecularControl,
                            kQ3AttributeTypeTransparencyColor,
                            kQ3AttributeTypeSurfaceTangent,
                            kQ3AttributeTypeHighlightState,
                            kQ3AttributeTypeSurfaceShader
                        };
    char                *attributeTypeNames[] = {
                            "None",
                            "SurfaceUV",
                            "ShadingUV",
                            "Normal",
                            "AmbientCoefficient",
                            "DiffuseColor",
                            "SpecularColor",
                            "SpecularControl",
                            "TransparencyColor",
                            "SurfaceTangent",
                            "HighlightState",
                            "SurfaceShader"
                        };
    unsigned long       i, total, count;
    TQ3Status           status;
 
    if (Q3Object_IsType(object, kQ3SetTypeAttribute) == kQ3False) {
        return kQ3Failure;
    }
 
    count = 0;
    total = sizeof(attributeTypes) / sizeof(TQ3AttributeType);
    attrType = kQ3AttributeTypeNone;
 
    while (1) {
        status = Q3AttributeSet_GetNextAttributeType(object, &attrType);
        if (status == kQ3Failure) {
            break;
        }
 
        if (attrType == kQ3AttributeTypeNone) {
            break;
        }
 
        printf((count == 0) ? "  [" : ", ");
 
        for (i = 0; i < total; i++) {
            if (attrType == attributeTypes[i]) {
                break;
            }
        }
 
        if (i < total) {
            printf("%s", attributeTypeNames[i]);
        }
        else {
            printf("Custom(%u)", attrType);
        }
 
        count++;
    }
 
    if (count) {
        printf("]");
    }
    else {
        printf("  [None]", attrType);
    }
 
    return status;
}
 
 
#ifdef STADALONE_PROGRAM_TO_DUMP_A_GROUP
/* entry point */
void main(void)
{
    TQ3Status   myStatus ;
    
    InitToolbox() ;
    if( (long)Q3Initialize != kUnresolvedCFragSymbolAddress )
    {
        if((myStatus = Q3Initialize()) == kQ3Success)
        {
            FSSpec      theFileSpec ;
            
            /* get a metafile */
            if( MetafileFileSpecify( &theFileSpec ))
            {
                TQ3GroupObject      theGroup ;
                
                if((theGroup = MyNewModelFromFile(&theFileSpec )) != NULL )
                    PrintGroupElementsAndRecurse( theGroup, 0L );
                    
                Q3Object_Dispose( theGroup ) ;
            }
            Q3Exit() ;
        } 
    }
}
#endif