3DMF2PICTShell.c

// Quickdraw 3D sample code
//
// Nick Thompson, AppleLink: DEVSUPPORT (devsupport@applelink.apple.com)
//
// ©1994-5 Apple Computer Inc., All Rights Reserved
 
 
// 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 <SegLoad.h>
#include <StandardFile.h>
#include <TextEdit.h>
#include <ToolUtils.h>
 
// for QuickDraw 3D
#include "QD3D.h"
#include "QD3DMath.h"
#include "QD3DDrawContext.h"
#include "QD3DShader.h"
#include "QD3DTransform.h"
#include "QD3DGroup.h"
#include "QD3DCamera.h"
 
 
#include "3DMF2PICTShell.h"
#include "3DMF2PICTSupport.h"
 
// get the interface to my error handler routines
#include "MyErrorHandler.h"
 
 
//-------------------------------------------------------------------------------------------
// function prototypes
 
static void         InitToolbox( void ) ;
static void         MainEventLoop( void ) ;
static void         HandleKeyPress(EventRecord *event) ;
static void         HandleOSEvent(EventRecord *event) ;
void InitDocumentData( DocumentPtr theDocument ) ;
TQ3Status DocumentDraw3DData( DocumentPtr theDocument ) ;
void DisposeDocumentData( DocumentPtr theDocument) ;
void DocumentDrawOnscreen(DocumentPtr theDocument, Rect *clipRect) ;
 
OSErr WritePict( PicHandle myPic, short  dstPictFRef ) ;
OSErr GetOutputFileRef(short    *dstPictFRef ) ;
PicHandle ImageToPict( DocumentPtr theDocument, WindowPtr theWindow ) ;
void DoSaveAs(DocumentPtr theDocument)  ;
 
//-------------------------------------------------------------------------------------------
//
 
Boolean         gQuitFlag       = false ;
WindowPtr       gMainWindow     = nil ;
DocumentRec     gDocument ;
 
//-------------------------------------------------------------------------------------------
// main()
// entry point for the application, initialize the toolbox, initialize QuickDraw 3D
// and enter the main event loop.  On exit from the main event loop, we want to call
// the QuickDraw 3D exit function to clean up QuickDraw 3d.
 
void main(void)
{
    TQ3Status   myStatus;
    Rect        rBounds = { 50, 50, 350, 350 } ;
    Str255      title = "\pSpinning Box" ;
    FSSpec      theFileSpec ;               // the file we are opening
 
    InitToolbox() ;
 
    if(MetafileFileSpecify( &theFileSpec )) {
    
        SetCursor(*(GetCursor(watchCursor)));
        
        //  Initialize QuickDraw 3D, open a connection to the QuickDraw 3D library
        myStatus = Q3Initialize();
        if ( myStatus == kQ3Failure )
            DebugStr("\pErInitialize returned failure.");           
    
        // install the error & warning handler - these get called whenever
        // errors or warnings occur, which means we don't have to check so 
        // much
        Q3Error_Register( MyErrorHandler, 0L );     
        Q3Warning_Register( MyWarningHandler, 0L );     
    
        // set up our globals
        gQuitFlag = false ;
        gMainWindow = NewCWindow(nil,&rBounds,title,false,noGrowDocProc,(WindowPtr)-1,true,0) ;
 
        // initialise our document structure
        InitDocumentData( &gDocument ) ;
        
        // try to read the file into the main display group
        if((gDocument.fModel = MyNewModelFromFile(&theFileSpec)) != NULL ) {        
 
            AdjustCamera(   &gDocument,
                            (gMainWindow->portRect.right - gMainWindow->portRect.left),
                            (gMainWindow->portRect.bottom - gMainWindow->portRect.top) ) ;
 
            SetWTitle( gMainWindow, theFileSpec.name );
            ShowWindow( gMainWindow ) ;
            SetPort( gMainWindow ) ;
    
            SetCursor(&qd.arrow) ;
            MainEventLoop();
            
        }
                
        DisposeDocumentData( &gDocument ) ;
        
        //  Close our connection to the QuickDraw 3D library
        myStatus = Q3Exit();
        if ( myStatus == kQ3Failure )
            DebugStr("\pErExit returned failure.");
    }   
}
 
//-------------------------------------------------------------------------------------------
//
 
void InitDocumentData( DocumentPtr theDocument ) 
{
    GWorldPtr       theOffscreen ;
    GDHandle        theDevice ;
    TQ3Point3D      myOrigin = { 0, 0, 0 } ;
    
    // create a GWorld the size of the window area
    OSErr myErr = NewGWorld(    &theDocument->fGWorld,
                                32,
                                &gMainWindow->portRect,
                                nil,
                                nil,
                                0L );
    
    if(myErr != noErr )
        goto bail ;
        
    GetGWorld( &theOffscreen, &theDevice ) ;
    SetGWorld( theDocument->fGWorld, nil ) ;
    EraseRect( &gMainWindow->portRect ) ;
    SetGWorld( theOffscreen, theDevice ) ;
    
    // sets up the 3d data for the scene
    //  Create view for QuickDraw 3D.
    theDocument->fView = MyNewView( theDocument->fGWorld );
 
    // the main display group:
    theDocument->fModel = NULL ;
    
    // scale and group center
    theDocument->fGroupScale = 1;               
    theDocument->fGroupCenter = myOrigin ;  
    
    // the drawing styles:
    theDocument->fInterpolation = Q3InterpolationStyle_New(kQ3InterpolationStyleNone) ;
    theDocument->fBackFacing = Q3BackfacingStyle_New( kQ3BackfacingStyleBoth ) ;
    theDocument->fFillStyle = Q3FillStyle_New(kQ3FillStyleFilled ) ;
 
    // set the rotation matrix the identity matrix
    Q3Matrix4x4_SetIdentity(&theDocument->fRotation);   
                    
    return ;
    
bail:
    // we failed setting up the GWorld
    // so we want to quit here
    ExitToShell() ;
    
}
 
void DisposeDocumentData( DocumentPtr theDocument)
{
    Q3Object_Dispose(theDocument->fView) ;              // the view for the scene
    Q3Object_Dispose(theDocument->fModel) ;             // object in the scene being modelled
    Q3Object_Dispose(theDocument->fInterpolation) ;     // interpolation style used when rendering
    Q3Object_Dispose(theDocument->fBackFacing) ;        // whether to draw shapes that face away from the camera
    Q3Object_Dispose(theDocument->fFillStyle) ;         // whether drawn as solid filled object or decomposed to components
}
//-----------------------------------------------------------------------------
// assumes the port is set up before being called
 
TQ3Status DocumentDraw3DData( DocumentPtr theDocument )
{   
    TQ3Status theStatus ;   
//{
//  TQ3CameraData       theCameraData ;
//  TQ3CameraObject     theCameraObject;
//  
//  Q3View_GetCamera(theDocument->fView, &theCameraObject);
//  Q3Camera_GetData(theCameraObject, &theCameraData);
//Debugger() ;
//
//}
 
    //  Start rendering.
    Q3View_StartRendering(theDocument->fView) ;
    do {
        theStatus = SubmitScene( theDocument ) ;
    } while (Q3View_EndRendering(theDocument->fView) == kQ3ViewStatusRetraverse );
 
    return theStatus ;  
}
 
//-------------------------------------------------------------------------------------------
//
 
void DocumentDrawOnscreen(DocumentPtr theDocument, Rect *clipRect)
{
    if (theDocument->fGWorld) {
    
        CGrafPtr            savedPort;
        GDHandle            savedDevice;
 
        GetGWorld( &savedPort, &savedDevice);
        SetGWorld( (CGrafPtr)gMainWindow,  nil);
        
        ClipRect( clipRect ) ;
        
        // don't need to lockPixels on the GWorld as the 
        // offscreen remains locked (see IM: QD3D), the
        // pixmap for a pixmap draw context must remain locked
        
        CopyBits ((BitMapPtr) &theDocument->fGWorld->portPixMap,
                  &gMainWindow->portBits,
                  &theDocument->fGWorld->portRect, 
                  &gMainWindow->portRect,
                  srcCopy, 
                  0L);
                  
        SetGWorld( savedPort, savedDevice);
    }
}
 
//--------------------------------------------------------------------------------------
 
OSErr WritePict( PicHandle myPic, short  dstPictFRef )
{
    long                    length ;
    long                    dummy ;
    int                     index ;
    OSErr                   result ;
 
    // ok, myPic now contains a handle to the compressed picture
                    
    HLock( (Handle)(Handle)myPic);
 
   // set up the 512 byte header for a PICT file 
    dummy = 0;
    
    for( index = 0; index < ( 512 / 4 ); index ++ ){
        length = 4 ;
        
        if( (result = FSWrite(dstPictFRef, &length, &dummy)) != noErr ) {
            // ErrorAlert( rErrorStrs, eCantWriteFile );
            return result ;     
        }
    }               
    
    length = GetHandleSize( (Handle)myPic);
    
    if( (result = FSWrite(dstPictFRef, &length, *myPic)) != noErr ) {
        //ErrorAlert( rErrorStrs, eCantWriteFile );
        return result ;     
    }
 
    // now get rid of the picture handle 
    HUnlock( (Handle) (Handle)myPic ) ;
    KillPicture(myPic);
 
    return noErr ;
}
 
//--------------------------------------------------------------------------------------
 
 
OSErr GetOutputFileRef(short    *dstPictFRef ) // GetOutputFileRefNum
{
    StandardFileReply   aPictSFR;   // new style Standard file record 
    OSErr               result ;
    SFTypeList  types = { 'PICT',0 };       // we are only interested in PICT files
        
    // check to see if we have the new style standard file package
 
    StandardPutFile( "\pSave PICT as:", "\pNew PICT", &aPictSFR);
    if ( aPictSFR.sfGood  ) {
        
        // Delete the file of the same name, if one exits, 
        // and create a new PICT file.
        
        FSpDelete(&aPictSFR.sfFile);
        
        result = FSpCreate( &aPictSFR.sfFile,'ttxt','PICT', aPictSFR.sfScript);
        if (result != noErr) {
            return result;
        }
        
        // open the data fork for writing
        // ??? need to change the permissions here ???
        
        result = FSpOpenDF( &aPictSFR.sfFile, fsCurPerm, dstPictFRef);
        if (result != noErr) {
            return result;
        }
    }
    else 
        return userCanceledErr ;
        
    return noErr ;
}
//--------------------------------------------------------------------------------------
PicHandle ImageToPict( DocumentPtr theDocument, WindowPtr theWindow )
{
    PicHandle thePicture = OpenPicture(&theDocument->fGWorld->portRect) ;
    DocumentDrawOnscreen( theDocument, &theWindow->portRect) ;
    ClosePicture() ;
    return thePicture ;
}
 
//--------------------------------------------------------------------------------------
 
void DoSaveAs(DocumentPtr theDocument) 
{
    short               dstPictFRef = 0;
    PicHandle           myPic = nil;
    OSErr               theErr;
    extern gxShape      gthePicture;        // defined in BitmAp Shape with Clip.c
    
    // get an open a file for writing
    if( (theErr = GetOutputFileRef( &dstPictFRef )) != noErr ) {
        return ;
    } 
    else {
        if(( myPic = ImageToPict ( theDocument, gMainWindow )) != nil ) {
            if(WritePict( myPic, dstPictFRef ) != noErr ) {
                FSClose(dstPictFRef);
                return ;
            }
        }
    }
    
    FSClose(dstPictFRef);
 
    return ;
 
}
//-------------------------------------------------------------------------------------------
//
 
short HiWrd(long aLong)
{
    return  (((aLong) >> 16) & 0xFFFF) ;
}
 
//-------------------------------------------------------------------------------------------
//
 
short LoWrd(long aLong)
{
    return  ((aLong) & 0xFFFF) ;
 
}
 
//-------------------------------------------------------------------------------------------
//
 
void InitToolbox()
{
    Handle      menuBar = nil;
 
    MaxApplZone() ;
    MoreMasters() ; MoreMasters() ; MoreMasters() ; 
    
    InitGraf( &qd.thePort );
    InitFonts();
    InitWindows();
 
    FlushEvents( everyEvent, 0 ) ;
    // initialize application globals
    
    gQuitFlag = false;
    InitCursor();
    
}
 
//-------------------------------------------------------------------------------------------
//
void MainEventLoop()
{
    EventRecord     event;
    WindowPtr       window;
    short           thePart;
    Rect            screenRect, updateRect;
    Point           aPoint = {100, 100};
    
 
    while( !gQuitFlag )
    {
        if (WaitNextEvent( everyEvent, &event, 0, nil ))
        {
 
            switch (event.what) {
                case mouseDown:
                
                    thePart = FindWindow( event.where, &window );
                    
                    switch( thePart ) {
                        case inMenuBar: 
                            break;
                        
                        case inDrag:
                    
                            screenRect = (**GetGrayRgn()).rgnBBox;
                            DragWindow( window, event.where, &screenRect );
                            break ;
                    
                        case inContent:
                    
                            if (window != FrontWindow())
                                SelectWindow( window );
                            break ;
                    
                        case inGoAway:
                            if (TrackGoAway( window, event.where )) {
                                DoSaveAs(&gDocument) ;
                                DisposeWindow ( window );
                                gQuitFlag = true;
 
                            }
                            break ;
                            
                        default:
                            break ;
                    }
                    break ;
                            
                        
                case updateEvt:
                
                    window = (WindowPtr)event.message;
                    updateRect = (**(window->visRgn)).rgnBBox;
                    SetPort( window ) ;
                    BeginUpdate( window );
                    DocumentDraw3DData( &gDocument ) ;
                    DocumentDrawOnscreen( &gDocument, &updateRect ) ;
                    EndUpdate( window );
 
                    break ;
                    
                case keyDown:
                case autoKey:
                    HandleKeyPress(&event);
                    break;
                    
                case diskEvt:
                    if ( HiWrd(event.message) != noErr ) 
                        (void) DIBadMount(aPoint, event.message);
                    break;
                    
                case osEvt:
                case activateEvt:
                    break;
 
 
            }
        }
        else {
            // we received a null event, rotate the cube
            TQ3Matrix4x4    tmp;
            Rect        theRect = ((GrafPtr)gMainWindow)->portRect ;
            
            SetPort((GrafPtr)gMainWindow) ;
            Q3Matrix4x4_SetRotate_XYZ(&tmp, 0.1, 0.12, 0.08);
            Q3Matrix4x4_Multiply(&gDocument.fRotation, &tmp, &gDocument.fRotation);
 
            InvalRect( &theRect ) ;
        }
    }
}
 
 
//-------------------------------------------------------------------------------------------
//
void HandleKeyPress(EventRecord *event)
{}
 
//-------------------------------------------------------------------------------------------
//