home *** CD-ROM | disk | FTP | other *** search
- /* Title: Teapot.c
- * Author: David Phillip Oster
- * Synopsis: The Macintosh interface for teapot.
- * Teapot is an example of 3-D graphics on the Mac. Useless
- * in itself, it is meant to inspire others.
- * History:
- * February 19, 1987 - dpo - added this note
- * Note: this program was designed to compile using a C compiler that
- * supports ANSI prototypes, such as LightSpeed C Version 2, by Think
- * Technologies, Inc. (Lexington, Ma.) To compile this program with some
- * other C compiler, extern declarations of the form:
- pascal void MoveTo2D(Fixed x, Fixed y);
- * need to be changed to:
- pascal void MoveTo2D();
- * i.e.: the argument list needs to be removed.
- * November 17, 1995 - dpo converted to THINK C 7
- */
- #include <setjmp.h>
- #include "Graf3D.h"
- #include "teapot.h"
- #include "TeapotRes.h"
-
- #define NIL 0L
- #define SKIPGRAYLINE 2
-
- enum{ ABOUTI = 1 }; /* Apple menu items */
-
- enum{ DRAWI = 1,
- QUITI = DRAWI + SKIPGRAYLINE }; /* File Menu items */
-
- #define LASTMENU kScaleMenu /* change this if add a new menu */
-
- typedef EventRecord *EventPtr;
- typedef long int LongInt;
- typedef short int Integer;
-
- /* ********* the forward declarations ********* */
-
- static void GoMouseDown(EventPtr); /* handle mouse down */
- static void GoKey(EventPtr); /* handle key down */
- static void GoMenuBar(EventPtr); /* handle click in menu bar */
- static void GoCommand(LongInt); /* handle menu command, click or key */
- static void DoAppleMenu(Integer);
- static void DoDeskAcc(Integer);
- static void DoDrawing(void); /* redo a new drawing */
- static void DoFileMenu(Integer);
- static void DoEditMenu(Integer);
- static void GoActiveEvent(EventPtr);
- static void GoUpdateEvent(EventPtr);
- static PicHandle PicContents(WindowPtr); /* turn window contents to picture */
- static void GoGoAway(EventPtr, WindowPtr);
- static void DoQuit(void); /* procedure so can pass pointer to InitDialog */
- static void DoParamMenu(Integer, Integer, int *); /* parameter menus */
- static Boolean UserFrontWindow(void);
- static void DoDecompile(void);
-
- /* order of these is important. pass address in DoParamMenu
- */
- typedef struct{
- int pitch;
- int yaw;
- int roll;
- int view;
- int smooth;
- int scale;
- } UserParams;
-
- UserParams val = {
- /* pitch(x) yaw (y) roll(z) view smooth scale*/
- 70, 0, 20, 10, 6, 6
- };
-
- /* synonym for above structure as an integer array */
- int *valInt = (int *) &val;
-
- jmp_buf drawBuf; /* hold continuation for setjmp/longjmp */
-
- Integer ourResFile; /* initialize this early (DAs may play with */
- /* our resFile) */
-
- /* OneEvent - dispatch on events, do idle processing
- */
-
- void OneEvent(void){
- EventRecord myEvent;
-
- do{
- if(GetNextEvent(everyEvent, &myEvent)){
- switch(myEvent.what){
- case updateEvt: GoUpdateEvent( &myEvent);
- break;
- case activateEvt : GoActiveEvent( &myEvent);
- break;
- case mouseDown: GoMouseDown( &myEvent);
- break;
- case keyDown: GoKey( &myEvent);
- break;
- default : ;
- }
- }
- SystemTask();
- }while( ! UserFrontWindow());
- }
-
-
- /* GoMouseDown - handle mouse down from event manager
- *
- * Note: we forbid the user to drag the window (we don't implement dragging)
- * because we aren't prepared to handle the update event that would occur when
- * the user dragged back onto the screen a partially offscreen window. We
- * do handle redrawing after a desk accessory is closed though.
- *
- * Note: we forbid the user to resize the window (we don't implement growing)
- * just out of laziness.
- */
- static void GoMouseDown(EventPtr theEvent){
- WindowPtr whichWindow;
-
- switch(FindWindow(theEvent->where, &whichWindow)){
- case inMenuBar : GoMenuBar(theEvent); break;
- case inGoAway : GoGoAway(theEvent, whichWindow); break;
- case inSysWindow :
- SystemClick(theEvent, whichWindow);
- SetPort(FrontWindow());
- break;
- }
- }
-
- /* GoKey - handle key down from event manager
- * <command>- . is a special case.
- */
- static void GoKey(EventPtr theEvent){
- if((theEvent->modifiers & cmdKey) && ((theEvent->message & charCodeMask) != '.')){
- GoCommand(MenuKey( (Integer) (theEvent->message & charCodeMask) ));
- }
- }
-
-
- /* GoMenuBar - handle mousedown in menu bar
- */
- static void GoMenuBar(EventPtr theEvent){
- GoCommand(MenuSelect(theEvent->where));
- }
-
- /* GoCommand - dispatches on the menu.
- * It guarantees that the item in the menubar is
- * hilighted long enough to be able to see it.
- */
- static void GoCommand(LongInt theCom){
- LongInt endTime, newTime;
- Integer theLow;
-
- theLow = LoWord(theCom);
- endTime = 5 + TickCount();
- switch(HiWord(theCom)){
- case kAppleMenu : DoAppleMenu(theLow);
- break;
- case kFileMenu : DoFileMenu(theLow);
- break;
- case kEditMenu : DoEditMenu(theLow);
- break;
- case kPitchMenu:
- case kYawMenu:
- case kRollMenu:
- case kViewMenu:
- case kSmoothMenu:
- case kScaleMenu:
- DoParamMenu(HiWord(theCom),theLow, &valInt[HiWord(theCom)-kPitchMenu]);
- break;
- }
- newTime = TickCount();
- if(newTime < endTime){ /* let's see that command */
- Delay(endTime - newTime, &newTime);
- }
- HiliteMenu(0);
- }
-
- /* PreserveContents - save our drawing window if something will cover
- * it.
- */
- void PreserveContents(void){
- if(qd.thePort != NIL &&
- ((WindowPeek) qd.thePort)->windowKind == userKind &&
- NIL == GetWindowPic(qd.thePort)){
-
- SetWindowPic(qd.thePort, PicContents(qd.thePort));
- }
- }
-
- /* DoAppleMenu - handle mouse down in apple menu
- */
-
- void DoAppleMenu(Integer theItem){
- GrafPtr savePort;
-
- switch(theItem){
- case ABOUTI:
- GetPort(&savePort);
- PreserveContents();
- Alert(rAbout, NIL);
- SetPort(savePort);
- break;
- default : DoDeskAcc(theItem); break;
- }
- }
-
- /* DoDeskAcc - run a desk accessory
- */
- static void DoDeskAcc(Integer theItem){
- Str255 accessory;
-
- PreserveContents();
- GetItem(GetMHandle(kAppleMenu), theItem, accessory);
- theItem = OpenDeskAcc(accessory); /* don't care about return value */
- }
-
- /* DoFileMenu -
- */
- static void DoFileMenu(Integer theItem){
- switch(theItem){
- case DRAWI : DoDrawing();
- break;
- case QUITI : DoQuit();
- break;
- }
- }
-
- /* DoEditMenu - _should_ put the teapot on the clipboard if cut or copy
- * actually just passes event to desk accessory.
- */
- static void DoEditMenu(Integer theItem){
- if( ! SystemEdit(theItem -1)){
- switch(theItem){
- case cutCmd:
- case copyCmd:
- break;
- }
- }
- }
-
- /* DoQuit - a proc so we can pass it in InitDialog
- */
- static void DoQuit(){
- ExitToShell();
- }
-
- /* TrimToDigits - truncate the string to remove non-digit chars.
- * except: null characters get turned into okay spaces.
- */
- static void TrimToDigits(Str255 s){
- int i;
- for(i=1;i<=s[0];i++){
- if( s[i] == '\0'){
- s[i] = ' ';
- } else if( s[i] < '-' || s[i] > '9'){
- break;
- }
- }
- s[0] = i-1;
- }
-
- /* DoParamMenu - do a click on menu m, item i.
- * put resultant value in v.
- */
- static void DoParamMenu(Integer m, Integer i, int *v){
- Str255 s;
- int j, jMax;
- LongInt n;
- MenuHandle theMenu;
-
- theMenu = GetMHandle(m);
- GetItem(theMenu, i, s);
- jMax = CountMItems(theMenu);
- for(j=1 ; j<= jMax ; j++){
- CheckItem(theMenu, j, j==i);
- }
- TrimToDigits(s);
- StringToNum(s, &n);
- *v = n;
- }
-
- /* IsNumSame - return true if sPre is a numeric prefix of s. ignore nulls in s
- */
- static Boolean IsNumSame(unsigned char *sPre, unsigned char *s){
- int pLen, sLen;
-
- pLen = *sPre++;
- sLen = *s++;
- if(*s == '\0'){ /* skip leading null char, if any */
- s++;
- sLen--;
- }
- if(pLen > sLen){ /* prefix too big to match */
- return FALSE;
- }
- while(pLen > 0){
- if(*sPre++ != *s++)
- return FALSE;
- sLen--;
- pLen--;
- }
- return sLen == 0 || ! ('0' <= *s && *s <= '9'); /* true if s out of digits */
- }
-
- /* CheckInitial - if i is in the menu, checkmark it.
- */
- static void CheckInitial(MenuHandle m, int i){
- Str255 sVal, sItem;
-
- NumToString( (LongInt) i, sVal);
-
- for(i=1;i<= CountMItems(m);i++){
- GetItem(m, i, sItem);
-
- if(IsNumSame(sVal, sItem)){
- CheckItem(m, i, TRUE);
- return;
- }
- }
- }
-
- /* FindInitials - draw the initial checkmarks.
- */
- static void FindInitials(void){
- Integer i;
-
- for(i = kPitchMenu ; i <= LASTMENU ; i++){
- CheckInitial(GetMHandle(i), valInt[i - kPitchMenu]);
- }
- }
-
- /* PicContents - make pic of window's contents
- */
- static PicHandle PicContents(WindowPtr w){
- PicHandle p;
- GrafPtr savePort;
-
- GetPort(&savePort);
- SetPort(w);
- p = OpenPicture(&qd.thePort->portRect);
- CopyBits(&qd.thePort->portBits,&qd.thePort->portBits,
- &qd.thePort->portRect,&qd.thePort->portRect,srcCopy, NIL);
- ClosePicture();
- SetPort(savePort);
- if(MemError() != noErr){
- KillPicture(p);
- return NIL;
- }
- return p;
- }
-
- /* GoActiveEvent - handle activate/deactivate events.
- */
- static void GoActiveEvent(EventPtr theEvent){
- WindowPtr w, savePort;
- PicHandle p;
-
- w = (WindowPtr) theEvent->message;
- if( ((WindowPeek) w)->windowKind == userKind){
- if(theEvent->modifiers & activeFlag){
- SetPort(w);
- if(NIL != (p = GetWindowPic(w))){
- DrawPicture(p, &qd.thePort->portRect);
- KillPicture(p);
- SetWindowPic(w, NIL);
- }
- }else{
- GetPort(&savePort);
- SetPort(w);
- PreserveContents();
- SetPort(savePort);
- }
- }
- }
-
- /* GoUpdateEvent - clean these out of the event queue.
- */
- static void GoUpdateEvent(EventPtr theEvent){
- BeginUpdate((WindowPtr) theEvent->message);
- EndUpdate((WindowPtr) theEvent->message);
- }
-
- /* GoGoAway - handles mouse in GoAway
- */
- static void GoGoAway(EventPtr theEvent, WindowPtr w){
- if(TrackGoAway(w, theEvent->where) &&
- ((WindowPeek) w)->windowKind == userKind){
-
- DoQuit();
- }
- }
-
- /* DoDrawing - start drawing again
- */
- static void DoDrawing(void){
- if(UserFrontWindow()){
- HiliteMenu(0); /* since we never return, do it heer */
- longjmp(drawBuf, 0);
- }
- }
-
- /* UserFrontWindow - true if drawing window on top
- */
- static Boolean UserFrontWindow(void){
- if(FrontWindow() == NIL){
- return FALSE;
- }
- return ((WindowPeek) FrontWindow())->windowKind == userKind;
- }
-
- /* Int2Fix - do this faster than FixRatio(i,1)
- */
- static Fixed Int2Fix(Integer i){
- union {
- Fixed f;
- struct { Integer whole, frac; } i;
- } iAndF;
-
- iAndF.i.whole = i;
- iAndF.i.frac = 0;
- return iAndF.f;
- }
-
- /* SetDrawTransform - set up the viewing transform:
- * world coordinates are roughly from 4 to -0.5 vertically,
- * and the appropriate horizontally to correct for the aspect
- * ratio of the picture. mutiply by user's scale factor
- *
- * 1.) re-initialize the matrix with Identity()
- * 2.) set scale factor for world coordinates, preserving x, y ratio of window
- * 3.) set wide-angleness of lens (24° is human eye standard)
- * 4.) tip about the x, y, and z axes. these values are in degrees, expressed
- * as fixed point numbers.
- */
- static void SetDrawTransform(void){
- int width,height; /* set in main */
-
- width = qd.thePort->portRect.right - qd.thePort->portRect.left;
- height = qd.thePort->portRect.bottom - qd.thePort->portRect.top;
- Identity(); /* order of next few lines is important */
- if(val.scale)LookAt(FixRatio(-50,2*val.scale), /* left */
- FixRatio(40*height,width*val.scale), /* top */
- FixRatio(50,2*val.scale), /* right */
- FixRatio(-10*height,width*val.scale)); /* bottom */
-
- ViewAngle(Int2Fix(val.view));
-
- if(val.roll)Roll( Int2Fix(val.roll));
- if(val.yaw)Yaw( Int2Fix(val.yaw));
- if(val.pitch)Pitch( Int2Fix(val.pitch));
- }
-
- Port3DPtr thePort3D;
-
- StringPtr binName = "\pTeapot.binData";
- main(){
- Port3D my3Port;
- GrafPtr myPort;
- LongInt len;
- Integer f;
- OSErr eCode;
-
- FlushEvents(everyEvent, 0);
- InitGraf(&qd.thePort);
- InitGrf3d(&thePort3D);
- InitFonts();
- InitWindows();
- InitCursor();
- InitDialogs( 0 );
- InitMenus();
- TEInit();
- SetMenuBar(GetNewMBar(kMBAR));
- AddResMenu(GetMHandle(kAppleMenu), 'DRVR');
- DrawMenuBar();
- ourResFile = CurResFile(); /* get it before DAs change it */
-
- myPort = GetNewWindow(rWin, NIL, (WindowPtr) -1L);
- SetPort(myPort);
- Open3DPort(&my3Port);
-
- SetCursor( *GetCursor(watchCursor));
- DisableItem(GetMHandle(kFileMenu), DRAWI);
-
- len = sizeof(Point3D)*(1+DUCKCOUNT);
- f = 0;
- /* use the binary data file if we can, else try to make it */
- if( ! (noErr == FSOpen(binName, 0, &f) && noErr == FSRead(f, &len, &Pt3ds))){
-
- FloatsToFixeds( (float *) &ducks, (Fixed *) &Pt3ds, (DUCKCOUNT+1)*3);
- FSClose(f);
- if(Create(binName, 0, '????', '????') == noErr){
- if(FSOpen(binName, 0, &f) == noErr){
- len = sizeof(Point3D)*(1+DUCKCOUNT);
- eCode = FSWrite(f, &len, &Pt3ds);
- FSClose(f);
- if(eCode != noErr)
- FSDelete(binName, 0);
- FlushVol(NIL, 0);
- f = 0;
- }
- }
- }
- if(0 != f){
- FSClose(f);
- }
- InitCursor();
- EnableItem(GetMHandle(kFileMenu), DRAWI);
- FindInitials();
- ShowWindow(qd.thePort);
-
- if(setjmp(drawBuf)){ /* come here when user selects "draw" */
- }
- SetPort(myPort);
- BackPat(&qd.black);
- EraseRect(&myPort->portRect);
-
- SetDrawTransform();
-
- PenPat(&qd.white);
-
- BaseGrid();
- DisplayPatches(val.smooth);
- SysBeep(1);
- while(TRUE){
- OneEvent();
- }
- }
-
-