TweetFollow Us on Twitter

Graf3D
Volume Number:4
Issue Number:6
Column Tag:Forth Forum

Graf3D Library Access

By Jörg Langowski, MacTutor Editorial Board

Graf3D and Mach2 - accessing external libraries

The subject of this month has been initiated by one of our readers, Paul Thomas, who in a desperate mood sent me both a paper letter and GEnie mail, because he needed to know whether it would be possible at all to access the Graf3D routines from Mach2.

A little background for those who weren’t with the Mac (or with us, for that matter) from the beginning: Graf3D is a set of routines on top of QuickDraw, which enable to create a 3-d GrafPort with all necessary support to do 3-dimensional perspective drawing. The routines aren’t explained in Inside Macintosh, but in several other different documents, one of them being the MPW Pascal manual (Appendix J).

Graf3D was also part of the Lisa Workshop, and one of the first Macintosh demo programs, Boxes, used those routines. The Boxes program - many of you might have seen it - draws at random fifteen rectangular boxes on a plane and displays them in a 3-d perspective view. The program is written originally in Lisa Pascal, and also contained on the TML Pascal disk as an example. Listing 4 shows the original program.

Glancing through the code, you might notice that this example certainly wouldn’t please the User Interface Thought Police today. Using the whole screen as a GrafPort without regard to anything else on there is a definite no-no in the days of Multifinder, and if you run the example under Multifinder, you won’t find your windows back on the screen afterwards because they are all covered by little boxes. Nevertheless, it is a nice example for the use of Graf3D, and we’ll show you this month how to translate it into Mach2 (We’ll also correct the garbled screen problem under Multifinder).

First and most difficult question: How can we access routines from Forth that are clearly labeled (Not in ROM) in the documentation? This remark tells us, of course, that they are part of some object library, no source code available and inaccessible to the Forth user. Just like the printing manager was before it was implemented in the Mach2 and MacForth systems.

There may be other libraries to come, also not in ROM, and waiting for updates takes a long time. So I’ll give you two general strategies to get access to object library code from Forth, making you independent of those updates.

The first scheme I thought up was simply to write a short Pascal program that calls all the routines at least once - so that they will be loaded -, compile that program, create a linker map if possible, and pass the final application through Nosy. That will get you a more or less annotated assembly listing from which you can extract the source code of the not in ROM routines that you are interested in.

Well, that works for you and me on our respective desks, but we certainly cannot publish reverse-engineered Apple source code in MacTutor, at least if we want to stay in business. Also, it is a lot of work (i.e. translating to a different assembler dialect, writing the glue code, etc.), and all in all qualifies as a master example of a dirty hack.

There is an easier way to go, and much more general, too: write some sort of a linker for Pascal library code. We write an assembly main program (Listing 2), which is just a table of JMP instructions to the routines that we want to call, and let the MPW linker do its job (listing 3).

The assembly/link script will create a new resource, gr3D, which contains the jump instructions at the beginning, followed by the linked Graf3D code. All we have to do now is to provide a block of memory in our Forth code where this resource can be copied to.

In order to assign Forth words to the JMP instructions, we simply make a table of CREATEs, which will allocate 4 bytes to each name (the length of a JMP d(PC) instruction), and create a dictionary entry so that we know the routine’s address in the jump table. After the block of CREATEs, we allocate sufficient memory so that the gr3D resource can be loaded (see listing 1).

We write a word, Init3D, that gets the gr3D resource and copies it into the table, starting with the address of the first Graf3d word, gInitGrf3D. Now the Graf3D routines are all set up for use by Mach2. As simple as that.

Well, not quite. We still need to write glue code to move the parameters from the Forth stack (A6) to the Pascal stack (A7). That glue code is rather simple and is just the same as is used for calling toolbox ROM routines. Like the traps, the Graf3D code preserves all registers that are vital to Mach2 (A2-A7, D4-D7). Like in the case of traps, we have to make A7 point to the lowest stack (EXG D4,A7) in order to avoid overwriting of Mach2 space by the intermediate Quickdraw record that is put between the stack and the heap. The glue code for the different Graf3D routines is given at the beginning of listing 1.

The Boxes examples should be self-explanatory when you compare it with the Pascal code; in fact, it might help some of you Pascal programmers and casual Forth readers appreciate that there is really no big difference between Forth and Pascal code...

I should point out some more things. First, the ‘access words’ for fields in a record, .x, .y, .pt1, and so on, defined at the beginning of the Forth code. Second, the word restore.screen, which cleans up the display after the example has run; very important when running under Multifinder. It basically does a PaintBehind(FrontWindow, grayRgn), the same mechanism by which many screen savers restore a blacked-out screen. Third, we define a terminal task that runs the Boxes example; that way, we can simply check for ?terminal after each drawing loop to see whether we’re done. Again, we have to make sure (like always in Mach2 multitasking) that the correct GrafPort is set by calling myPort3D SetPort3D before each passage through the loop. This is because any PAUSE-containing word, such as ?terminal, may change the active GrafPort.

For using the example, you will first have to create the Graf3Dglue resource file with the gr3D resource in it, then move that resource into the MACH.RSRC file before starting your Mach2 system. In case you don’t have access to MPW, the source code disk contains the Graf3Dglue and MACH.RSRC files. The complete program, of course, is also on the disk.

That’s it for this month; next month I plan to discuss various projects of object-oriented extensions to Mach2 that have recently appeared on the networks. Some of you might also appreciate that NEON hasn’t died altogether, but that there is at least one person trying to extend it in a very interesting way.

Listing 1: The Boxes example in Mach2
\ Graf3d / Mach2 glue code
\ An example for calling MPW routines from Forth
\ J. Langowski April 1988
\ __________________________________________
Only Forth Also Mac Also Assembler

\ some general definitions first
16 CONSTANT portRect

GLOBAL
 CODE SCALE
    MOVE.L   (A6)+,D0
    BMI.S    @1
    MOVE.L   (A6),D1
    ASL.L    D0,D1
    MOVE.L   D1,(A6)
    RTS
@1  MOVE.L   (A6),D1
    NEG.L    D0
    ASR.L    D0,D1
    MOVE.L   D1,(A6)
    RTS
END-CODE

global
CODE white
 MOVE.L (A5),-(A6)
 SUBQ.L #8,(A6)
 RTS
END-CODE MACH

global
CODE black
 MOVE.L (A5),-(A6)
 SUBI.L #16,(A6)
 RTS
END-CODE MACH

global
CODE gray
 MOVE.L (A5),-(A6)
 SUBI.L #24,(A6)
 RTS
END-CODE MACH

: 4ASCII 
 0
4 0 DO
  8 SCALE 0 WORD 1+ C@ + 
LOOP
;

4ASCII gr3D CONSTANT “gr3D \ resource ID

\ Graf3D jump table

CREATE  gInitGrf3D
CREATE  gOpen3DPort
CREATE  gSetPort3D 
CREATE  gGetPort3D 
CREATE  gMoveTo2D
CREATE  gMoveTo3D
CREATE  gLineTo2D
CREATE  gLineTo3D
CREATE  gMove2D
CREATE  gMove3D
CREATE  gLine2D
CREATE  gLine3D
CREATE  gViewPort
CREATE  gLookAt
CREATE  gViewAngle
CREATE  gIdentity
CREATE  gScale
CREATE  gTranslate
CREATE  gPitch
CREATE  gYaw
CREATE  gRoll
CREATE  gSkew
CREATE  gTransform
CREATE  gClip3D
CREATE  gSetPt3D
CREATE  gSetPt2D

\ The glue code is 2636 bytes long, so we allocate
\ sufficient additional buffer space to put it into
2600 ALLOT

: Init3D \ gets Graf3D code from gr3D=1 resource 
  \ and copies it into buffer
 “gr3D 1 call GetResource
 dup @ swap call SizeRsrc
 [‘] gInitGrf3D swap cmove
;

CODE InitGrf3d ( globalPtr -- )
 EXG  D4,A7
 MOVE.L (A6)+,-(A7)
 JSR  gInitGrf3d
 EXG  D4,A7
 RTS
END-CODE

CODE Open3DPort  ( port -- )
 EXG  D4,A7
 MOVE.L (A6)+,-(A7)
 JSR  gOpen3DPort
 EXG  D4,A7
 RTS
END-CODE

CODE SetPort3d ( port -- )
 EXG  D4,A7
 MOVE.L (A6)+,-(A7)
 JSR  gSetPort3d
 EXG  D4,A7
 RTS
END-CODE

CODE GetPort3d ( VAR port -- )
 EXG  D4,A7
 MOVE.L (A6)+,-(A7)
 JSR  gGetPort3d
 EXG  D4,A7
 RTS
END-CODE

CODE MoveTo2d  ( x y -- )
 EXG  D4,A7
 MOVE.L 4(A6),-(A7)
 MOVE.L (A6),-(A7)
 ADDA.W #8,A6
 JSR  gMoveTo2d
 EXG  D4,A7
 RTS
END-CODE

CODE MoveTo3d  ( x y z -- )
 EXG  D4,A7
 MOVE.L 8(A6),-(A7)
 MOVE.L 4(A6),-(A7)
 MOVE.L (A6),-(A7)
 ADDA.W #12,A6
 JSR  gMoveTo3d
 EXG  D4,A7
 RTS
END-CODE

CODE LineTo2d  ( x y -- )
 EXG  D4,A7
 MOVE.L 4(A6),-(A7)
 MOVE.L (A6),-(A7)
 ADDA.W #8,A6
 JSR  gLineTo2d
 EXG  D4,A7
 RTS
END-CODE

CODE LineTo3d  ( x y z -- )
 EXG  D4,A7
 MOVE.L 8(A6),-(A7)
 MOVE.L 4(A6),-(A7)
 MOVE.L (A6),-(A7)
 ADDA.W #12,A6
 JSR  gLineTo3d
 EXG  D4,A7
 RTS
END-CODE

CODE Move2d ( dx dy -- )
 EXG  D4,A7
 MOVE.L 4(A6),-(A7)
 MOVE.L (A6),-(A7)
 ADDA.W #8,A6
 JSR  gMove2d
 EXG  D4,A7
 RTS
END-CODE

CODE Move3d ( dx dy dz -- )
 EXG  D4,A7
 MOVE.L 8(A6),-(A7)
 MOVE.L 4(A6),-(A7)
 MOVE.L (A6),-(A7)
 ADDA.W #12,A6
 JSR  gMove3d
 EXG  D4,A7
 RTS
END-CODE

CODE Line2d ( x y -- )
 EXG  D4,A7
 MOVE.L 4(A6),-(A7)
 MOVE.L (A6),-(A7)
 ADDA.W #8,A6
 JSR  gLine2d
 EXG  D4,A7
 RTS
END-CODE

CODE Line3d ( x y z -- )
 EXG  D4,A7
 MOVE.L 8(A6),-(A7)
 MOVE.L 4(A6),-(A7)
 MOVE.L (A6),-(A7)
 ADDA.W #12,A6
 JSR  gLine3d
 EXG  D4,A7
 RTS
END-CODE

CODE ViewPort  ( r -- )
 EXG  D4,A7
 MOVE.L (A6)+,-(A7)
 JSR  gViewPort
 EXG  D4,A7
 RTS
END-CODE

CODE LookAt ( left top right bottom -- )
 EXG  D4,A7
 MOVE.L 12(A6),-(A7)
 MOVE.L 8(A6),-(A7)
 MOVE.L 4(A6),-(A7)
 MOVE.L (A6),-(A7)
 ADDA.W #16,A6
 JSR  gLookAt
 EXG  D4,A7
 RTS
END-CODE

CODE ViewAngle ( angle -- )
 EXG  D4,A7
 MOVE.L (A6)+,-(A7)
 JSR  gViewAngle
 EXG  D4,A7
 RTS
END-CODE

CODE Identity
 EXG  D4,A7
 JSR  gIdentity
 EXG  D4,A7
 RTS
END-CODE

CODE Scal ( xfactor yfactor zfactor -- )
 EXG  D4,A7
 MOVE.L 8(A6),-(A7)
 MOVE.L 4(A6),-(A7)
 MOVE.L (A6),-(A7)
 ADDA.W #12,A6
 JSR  gScale
 EXG  D4,A7
 RTS
END-CODE

CODE Translate ( dx dy dz -- )
 EXG  D4,A7
 MOVE.L 8(A6),-(A7)
 MOVE.L 4(A6),-(A7)
 MOVE.L (A6),-(A7)
 ADDA.W #12,A6
 JSR  gTranslate
 EXG  D4,A7
 RTS
END-CODE

CODE Pitch( xangle -- )
 EXG  D4,A7
 MOVE.L (A6)+,-(A7)
 JSR  gPitch
 EXG  D4,A7
 RTS
END-CODE

CODE Yaw( yangle -- )
 EXG  D4,A7
 MOVE.L (A6)+,-(A7)
 JSR  gYaw
 EXG  D4,A7
 RTS
END-CODE

CODE Rol( zangle -- )
 EXG  D4,A7
 MOVE.L (A6)+,-(A7)
 JSR  gRoll
 EXG  D4,A7
 RTS
END-CODE

CODE Skew ( zangle -- )
 EXG  D4,A7
 MOVE.L (A6)+,-(A7)
 JSR  gSkew
 EXG  D4,A7
 RTS
END-CODE

CODE Transform ( src dst -- )
 EXG  D4,A7
 MOVE.L 4(A6),-(A7)
 MOVE.L (A6),-(A7)
 ADDA.W #8,A6
 JSR  gTransform
 EXG  D4,A7
 RTS
END-CODE

CODE Clip3D ( src1 src2 dst1 dst2 -- flag )
 EXG  D4,A7
 CLR.W  -(A7)
 MOVE.L 12(A6),-(A7)
 MOVE.L 8(A6),-(A7)
 MOVE.L 4(A6),-(A7)
 MOVE.L (A6),-(A7)
 ADDA.W #16,A6
 JSR  gClip3D
 MOVE.W (A7)+,D0
 EXT.L  D0
 MOVE.L D0,-(A6)
 EXG  D4,A7
 RTS
END-CODE

CODE SetPt3d( pt3D x y z -- )
 EXG  D4,A7
 MOVE.L 12(A6),-(A7)
 MOVE.L 8(A6),-(A7)
 MOVE.L 4(A6),-(A7)
 MOVE.L (A6),-(A7)
 ADDA.W #16,A6
 JSR  gSetPt3D
 EXG  D4,A7
 RTS
END-CODE

CODE SetPt2d( pt2D x y -- )
 EXG  D4,A7
 MOVE.L 8(A6),-(A7)
 MOVE.L 4(A6),-(A7)
 MOVE.L (A6),-(A7)
 ADDA.W #12,A6
 JSR  gSetPt2D
 EXG  D4,A7
 RTS
END-CODE

\ Translation of Boxes.pas example into Forth follows
\ _________________________________________

: .x ; mach
: .y 4 + ; mach
: .z 8 + ; mach

: .pt1 ; mach
: .pt2 12 + ; mach

15 CONSTANT BoxCount
Variable MyPort  104 vallot 
 \ grafPort is 108 bytes long
Variable MyPort3D  150 vallot 
 \ graf3DPort is 154 bytes long
Variable boxArray   24 BoxCount * vallot 
 \ BoxCount * 2* point3D @ 3 long words
Variable nboxes     \ # of boxes made
Variable MyBox   20 vallot \ 24 bytes for 2* point3d
Variable p1   8 vallot \ point3d
Variable p2   8 vallot \ point3d
Variable myRect    4 vallot \ Rect
Variable testRect   4 vallot \ Rect

: DrawBrick { pt1 pt2 | tempRgn -- }
 call NewRgn -> tempRgn

 call OpenRgn  
 pt1 .x @ pt1 .y @ pt1 .z @ MoveTo3D
 pt1 .x @ pt1 .y @ pt2 .z @ LineTo3D
 pt2 .x @ pt1 .y @ pt2 .z @ LineTo3D
 pt2 .x @ pt1 .y @ pt1 .z @ LineTo3D
 pt1 .x @ pt1 .y @ pt1 .z @ LineTo3D
 tempRgn call CloseRgn
 tempRgn white call FillRgn

 call OpenRgn
 pt1 .x @ pt1 .y @ pt2 .z @ MoveTo3D
 pt1 .x @ pt2 .y @ pt2 .z @ LineTo3D
 pt2 .x @ pt2 .y @ pt2 .z @ LineTo3D
 pt2 .x @ pt1 .y @ pt2 .z @ LineTo3D
 pt1 .x @ pt1 .y @ pt2 .z @ LineTo3D
 tempRgn call CloseRgn
 tempRgn gray call FillRgn

 call OpenRgn  
 pt2 .x @ pt1 .y @ pt1 .z @ MoveTo3D
 pt2 .x @ pt1 .y @ pt2 .z @ LineTo3D
 pt2 .x @ pt2 .y @ pt2 .z @ LineTo3D
 pt2 .x @ pt2 .y @ pt1 .z @ LineTo3D
 pt2 .x @ pt1 .y @ pt1 .z @ LineTo3D
 tempRgn call CloseRgn
 tempRgn black call FillRgn

 white call penpat
 pt2 .x @ pt2 .y @ pt2 .z @ MoveTo3D
 pt2 .x @ pt2 .y @ pt1 .z @ LineTo3D
 pt2 .x @ pt1 .y @ pt1 .z @ LineTo3D
 call pennormal

 tempRgn call DisposRgn
;

: hi -16 scale ;

: chkBox { | box -- }
 1 ( flag )
 nBoxes @ 0 DO
 boxArray i 24 * + -> box
 testRect  
 box .pt1 .x @ hi   
 box .pt1 .y @ hi 
 box .pt2 .x @ hi 
 box .pt2 .y @ hi  call SetRect
 testRect -1 -1 call InSetRect
 myRect testRect testRect call SectRect
 IF drop 0 leave THEN
 LOOP
;

: MakeBox { | p1x p1y p1z p2x p2y p2z box ii -- }
 call random 70 mod 15 - 1 call FixRatio -> p1x
 call random 70 mod 10 - 1 call FixRatio -> p1y
 0 -> p1z

 call random 30 mod abs 10 + 1 call FixRatio p1x + 
 -> p2x
 call random 45 mod abs 10 + 1 call FixRatio p1y + 
 -> p2y
 call random 30 mod abs 10 + 1 call FixRatio p1z + 
 -> p2z

 myRect p1x hi p1y hi p2x hi p2y hi call SetRect

 chkBox IF
 p1x myBox .pt1 .x !
 p1y myBox .pt1 .y !
 p1z myBox .pt1 .z !
 p2x myBox .pt2 .x !
 p2y myBox .pt2 .y !
 p2z myBox .pt2 .z !

 0 -> ii
 myBox boxArray nBoxes @ 24 * + 24 cmove

 BEGIN
 myBox .pt1 .y @  boxArray ii + .pt2 .y @ >
 myBox .pt2 .y @  boxArray ii + .pt1 .y @ > and
 myBox .pt1 .x @  boxArray ii + .pt2 .x @ <
 myBox .pt2 .x @  boxArray ii + .pt1 .x @ < and or
 WHILE
 24 +> ii
 REPEAT
 ii 24 / -> ii

 ii 1+ nBoxes @ DO
 boxArray i 1- 24 * +
 boxArray i 24 * + 
 24 cmove
 -1 +loop
 myBox boxArray ii 24 * + 24 cmove
 
 1 nBoxes +!
 THEN
;

: drawGrid
 11 -10 DO
 i 10 * 1 call FixRatio -100 1 call FixRatio 0
 MoveTo3D
 i 10 * 1 call FixRatio  100 1 call FixRatio 0
 LineTo3D
 LOOP

 11 -10 DO
 -100 1 call FixRatio i 10 * 1 call FixRatio 0
 MoveTo3D
  100 1 call FixRatio i 10 * 1 call FixRatio 0
 LineTo3D
 LOOP
;

: restore.screen
 call drawmenubar
 call frontwindow 
 grayrgn @ call paintbehind
 call showcursor
;

: main
 init3d
 call hidecursor
 myPort call OpenPort
 myPort3D Open3DPort
 myPort portRect + ViewPort
 -100 1 call FixRatio  75 1 call FixRatio
  100 1 call FixRatio -75 1 call FixRatio
 LookAt
 30 1 call FixRatio ViewAngle
 Identity
 20 1 call FixRatio Rol
 70 1 call FixRatio Pitch 

 BEGIN
 myPort3D SetPort3D
 0 nBoxes !
 BEGIN makeBox nBoxes @ boxCount = UNTIL

 white call penPat
 black call backPat
 myPort portRect + call EraseRect

 drawGrid

 0 nBoxes @ 1- DO
 boxArray i 24 * + 
 dup .pt1 swap .pt2 DrawBrick
 -1 +LOOP 
 
 ?terminal UNTIL
 restore.screen
 bye
;

NEW.WINDOW Boxes
“ Boxes” Boxes TITLE
0 0 20 20 Boxes BOUNDS
Plain Visible NoCloseBox NoGrowBox Boxes ITEMS

600 5000 terminal Box

: go.box activate main ;

: start
 Boxes add
 Boxes Box build
 Box go.Box
; 

.( To create a turkey application ) cr
.( type TURNKEY START BOXES )
Listing 2: MPW Assembly glue code for accessing the Graf3D Pascal library
 TITLE  ‘Graf3D glue code for Mach2’
 BLANKS OFF 
 PRINT  OFF
 INCLUDE  ‘Traps.a’
 INCLUDE  ‘ToolEqu.a’
 INCLUDE  ‘QuickEqu.a’
 INCLUDE  ‘SysEqu.a’
 INCLUDE  ‘Graf3DEqu.a’
 PRINT  ON

GrafGlueMAIN
 JMP   InitGrf3D
 JMP   Open3DPort
 JMP   SetPort3D
 JMP   GetPort3D
 JMP   MoveTo2D
 JMP   MoveTo3D
 JMP   LineTo2D
 JMP   LineTo3D
 JMP   Move2D
 JMP   Move3D
 JMP   Line2D
 JMP   Line3D
 JMP   ViewPort
 JMP   LookAt
 JMP   ViewAngle
 JMP   Identity
 JMP   Scale
 JMP   Translate
 JMP   Pitch
 JMP   Yaw
 JMP   Roll
 JMP   Skew
 JMP   Transform
 JMP   Clip3D
 JMP   SetPt3D
 JMP   SetPt2D
 END  
Listing 3: MPW assembly / link script for generating the gr3D resource 
(to be put into the MACH.RSRC file)
 Asm Graf3dglue.a -l
 Link Graf3dglue.a.o 
 {Libraries}Interface.o 
 -rt gr3D=1 -o Graf3dglue -l > Graf3dglue.map
Listing 4: The original Boxes example (from TML Pascal)
 PROGRAM Boxes;

{ Boxes demonstrates the use of the Three Dimensional
Quickdraw package Graf3D.

  Pascal source:  Boxes.Pas
  Resources:      *none*
  
  This program is from Apple’s Lisa Software Supplement,
modified for TML Systems Pascal compiler.
}

USES MacIntf, FixMath, Graf3D;

CONST boxCount = 15;
 keyOrMouse = 10;

TYPE  Box3D = 
     RECORD
 pt1: Point3D;
 pt2: Point3D;
     END;

VARmyPort:   GrafPort;
 myPort3D: Port3D;
 boxArray: ARRAY [0..boxCount] OF Box3D;
 nBoxes:   INTEGER;
 i:        INTEGER;
 dummy:    EventRecord;
      
PROCEDURE DrawBrick(pt1, pt2: Point3D);
{ draws a 3D brick with shaded faces.  
  only shades correctly in one direction.
}
VARtempRgn: RgnHandle;
BEGIN
   tempRgn := NewRgn;
   OpenRgn;
   MoveTo3D(pt1.X, pt1.Y, pt1.Z); { front face, y=y1 }
   LineTo3D(pt1.X, pt1.Y, pt2.Z);
   LineTo3D(pt2.X, pt1.Y, pt2.Z);
   LineTo3D(pt2.X, pt1.Y, pt1.Z);
   LineTo3D(pt1.X, pt1.Y, pt1.Z);
   CloseRgn(tempRgn);
   FillRgn(tempRgn, white);

   OpenRgn;
   MoveTo3D(pt1.X, pt1.Y, pt2.Z); { top face, z=z2 }
   LineTo3D(pt1.X, pt2.Y, pt2.Z);
   LineTo3D(pt2.X, pt2.Y, pt2.Z);
   LineTo3D(pt2.X, pt1.Y, pt2.Z);
   LineTo3D(pt1.X, pt1.Y, pt2.Z);
   CloseRgn(tempRgn);
   FillRgn(tempRgn, gray);

   OpenRgn;
   MoveTo3D(pt2.X, pt1.Y, pt1.Z); { right face, x=x2 }
   LineTo3D(pt2.X, pt1.Y, pt2.Z);
   LineTo3D(pt2.X, pt2.Y, pt2.Z);
   LineTo3D(pt2.X, pt2.Y, pt1.Z);
   LineTo3D(pt2.X, pt1.Y, pt1.Z);
   CloseRgn(tempRgn);
   FillRgn(tempRgn, black);

   PenPat(white);
   MoveTo3D(pt2.X, pt2.Y, pt2.Z); { outline right }
   LineTo3D(pt2.X, pt2.Y, pt1.Z);
   LineTo3D(pt2.X, pt1.Y, pt1.Z);
   PenNormal;

   DisposeRgn(tempRgn);
END;

PROCEDURE MakeBox;
LABEL 1;
VARmyBox: Box3D;
 i, j, h, v: INTEGER;
 p1, p2: Point3D;
 myRect: Rect;
 testRect: Rect;
BEGIN
   p1.x := FixRatio((Random mod 70 - 15), 1);
   p1.y := FixRatio((Random mod 70 - 10), 1);
   p1.z := 0;

   p2.x := p1.x + FixRatio((10 + ABS(Random) MOD 30), 1);
   p2.y := p1.y + FixRatio((10 + ABS(Random) MOD 45), 1);

   p2.z := p1.z + FixRatio((10 + ABS(Random) MOD 35), 1);

   { reject box if it intersects one already in list }
   SetRect(myRect, HiWord(p1.x), HiWord(p1.y), HiWord(p2.x), HiWord(p2.y));

   FOR i := 0 TO nBoxes - 1 DO BEGIN
      WITH boxArray[i] DO
  SetRect(testRect, 
          HiWord(pt1.x), 
  HiWord(pt1.y), 
  HiWord(pt2.x),
          HiWord(pt2.y));
      InSetRect(testRect, -1, -1);
      IF SectRect(myRect, testRect, testRect) THEN goto 1
      END;

   myBox.pt1 := p1;
   myBox.pt2 := p2;

   { calc midpoint of box and its distance from the eye }
   i := 0;
   boxArray[nBoxes].pt1 := myBox.pt1; { sentinel }
   boxArray[nBoxes].pt2 := myBox.pt2;

   WHILE
   ((myBox.pt1.y > boxArray[i].pt2.y) AND (myBox.pt2.y > boxArray[i].pt1.y)) 
OR
   ((myBox.pt1.x < boxArray[i].pt2.x) AND (myBox.pt2.x < boxArray[i].pt1.x)) 
DO
      inc(i); { insert in order of dist }
   FOR j := nBoxes DOWNTO i + 1 DO boxArray[j] := boxArray[j - 1];
   boxArray[i] := myBox;
   inc(nBoxes);
1: 
END;

BEGIN { main program }
   FlushEvents(everyEvent, 0);
   InitGraf(@thePort);
   InitCursor;
   HideCursor;
   OpenPort(@myPort);
   Open3DPort(@myPort3D);

   { put the image in this rect }
   ViewPort(myPort.portRect);
   
   { aim the camera into 3D space }   
   LookAt(FixRatio(-100, 1), 
          FixRatio(75, 1), 
   FixRatio(100, 1),
          FixRatio(-75, 1)); 

   { choose lens focal length }
   ViewAngle(FixRatio(30, 1)); 
   Identity;
   Roll(FixRatio(20, 1));
   Pitch(FixRatio(70, 1)); { roll and pitch the plane }

   REPEAT
      nBoxes := 0;
      REPEAT
         MakeBox
      UNTIL nBoxes=boxCount;

      PenPat(white);
      BackPat(black);
      EraseRect(myPort.portRect);

      FOR i := -10 TO 10 DO BEGIN
         MoveTo3D(FixRatio(i*10, 1), FixRatio(-100, 1), 0);
         LineTo3D(FixRatio(i*10, 1), FixRatio(100, 1), 0);
         END;

      FOR i := -10 TO 10 DO BEGIN
         MoveTo3D(FixRatio(-100, 1), FixRatio(i*10, 1), 0);
         LineTo3D(FixRatio(100, 1), FixRatio(i*10, 1), 0);
         END;

      FOR i := nBoxes-1 DOWNTO 0 DO 
         DrawBrick(boxArray[i].pt1,boxArray[i].pt2);

   UNTIL OSEventAvail(keyOrMouse, dummy);
END.
 
AAPL
$99.26
Apple Inc.
+0.08
MSFT
$45.91
Microsoft Corpora
+0.01
GOOG
$569.90
Google Inc.
+1.63

MacTech Search:
Community Search:

Software Updates via MacUpdate

Dropbox 2.10.30 - Cloud synchronization...
Dropbox is an application that creates a special Finder folder that automatically syncs online and between your computers. It allows you to both backup files and keep them up-to-date between systems... Read more
Twitter 3.1 - Official Twitter client fo...
Twitter (was Tweetie) is a Twitter client with a variety of features. Important Note: As of January 2011, AteBit's Tweetie application has been acquired and renamed by Twitter. Version 1.2.8 of the... Read more
Cocktail Family License (5 Macs) 7.6.1 -...
Cocktail is a general purpose utility for OS X that lets you clean, repair and optimize your Mac. It is a powerful digital toolset that helps hundreds of thousands of Mac users around the world get... Read more
Cocktail 8.0 Beta 2 - General maintenanc...
Cocktail is a general purpose utility for OS X that lets you clean, repair and optimize your Mac. It is a powerful digital toolset that helps hundreds of thousands of Mac users around the world get... Read more
QuickBooks 2015 16.0.0.1352 R1 - Financi...
QuickBooks 2015 helps you manage your business easily and efficiently. Organize your finances all in one place, track money going in and out of your business, and spot areas where you can save.... Read more
Mac DVDRipper Pro 5.0.1 - Copy, backup,...
Mac DVDRipper Pro is the DVD backup solution that lets you protect your DVDs from scratches, save your batteries by reading your movies from your hard disk, manage your collection with just a few... Read more
Apple OS X bash Update 1.0 - Fix for sec...
The OS X bash Update fixes a security flaw in the bash UNIX shell on OS X 10.9.5 (also on OS X 10.8 and 10.7 [see Related Links below]). OS X 10.9.5 or later Downloads for OS X 10.8 and OS X 10.7 in... Read more
SyncTwoFolders 2.0.5 - Syncs two user-sp...
SyncTwoFolders simply synchronizes two folders. It supports synchronization across mounted network drives and it is a possibility to run a simulation showing in a log what will be done. Please visit... Read more
FinderPop 2.5.7 - Classic Mac utility, n...
FinderPop is a Universal preference pane that extends OS X's contextual menus using a FinderPop Items folder much as the Apple Menu Items folder used to do for the Apple menu. It has other features... Read more
VueScan 9.4.45 - Scanner software with a...
VueScan is a scanning program that works with most high-quality flatbed and film scanners to produce scans that have excellent color fidelity and color balance. VueScan is easy to use, and has... Read more

Latest Forum Discussions

See All

Ms.Pac-Man Goes Pink for National Breast...
Ms.Pac-Man Goes Pink for National Breast Cancer Foundation Campaign Posted by Ellis Spice on October 2nd, 2014 [ permalink ] | Read more »
The Maze Runner Review
The Maze Runner Review By Lee Hamlet on October 2nd, 2014 Our Rating: :: A NICE CHANGE OF PACEUniversal App - Designed for iPhone and iPad The Maze Runner is a surprisingly enjoyable movie tie-in that will succeed in keeping... | Read more »
RPG Soul of Deva (Games)
RPG Soul of Deva 1.0.0 Device: iOS Universal Category: Games Price: $3.99, Version: 1.0.0 (iTunes) Description: SPECIAL PRICE56% OFF(USD 8.99 -> USD 3.99)!!! Demons attack humans, and humans live in fear of them...Set off on a... | Read more »
Banner Saga (Games)
Banner Saga 1.0.17 Device: iOS Universal Category: Games Price: $9.99, Version: 1.0.17 (iTunes) Description: NOTE: The Banner Saga does NOT run on iPhone 4. iPhone 4S and more modern devices recommended. | Read more »
Beatbuddy HD (Games)
Beatbuddy HD 1.0.2 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0.2 (iTunes) Description: **IMPORTANT** Beatbuddy runs only on iPhone 6, 6 Plus, 5, 5c, 5s, iPad 4, iPad Mini Retina and iPad Air. | Read more »
Spirits of Spring (Games)
Spirits of Spring 1.0.1 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0.1 (iTunes) Description: From the creators of the award-winning empathy game, Papo & Yo, comes a tale about finding strength. | Read more »
I am a brave knight (Games)
I am a brave knight 1.0 Device: iOS Universal Category: Games Price: $.99, Version: 1.0 (iTunes) Description: Do you have ten minutes to live a life? | Read more »
iKeywi - Customizable 5-Row Keyboard (U...
iKeywi - Customizable 5-Row Keyboard 1.0 Device: iOS Universal Category: Utilities Price: $.99, Version: 1.0 (iTunes) Description: Want to add an extra row to your iPhone/iPad? One of the most popular keyboard extension in iOS... | Read more »
Manage Your Cloud – Wunderlist Now Suppo...
Manage Your Cloud – Wunderlist Now Supports Dropbox Posted by Jessica Fisher on October 1st, 2014 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
Nexticy Review
Nexticy Review By Jennifer Allen on October 1st, 2014 Our Rating: :: IDEAL FORM CREATIONiPad Only App - Designed for the iPad Nexticy allows you to make your own forms for research purposes or to organize your business better. It’s... | Read more »

Price Scanner via MacPrices.net

Apple drops prices on refurbished 27-inch iMa...
The Apple Store has dropped prices on Apple Certified Refurbished 27″ iMacs, now available for up to $340 off the cost of new models. Apple’s one-year warranty is standard, and shipping is free: - 27... Read more
Logitech Type+ iPad Air Keyboard Case: Laptop...
If you want to make your iPad Air look and feel more like a laptop for productivity use, as well as protect it from impacts, spills, and scratches while on the move, the new Logitech Type+, a... Read more
ASUS, Lenovo, and Amazon Slug It Out For Tabl...
According to market intelligence firm ABI Research, Apple and Samsung have led the touchscreen tablet market by a substantial margin since Apple energized the category back in 2010. However, ABI says... Read more
Branded Tablet Growth Expected to Disappoint...
ABI Research says the 200 million annual shipments milestone for branded tablets continues to elude OEM vendors, and overall growth for 2014 is set to come in at a disappointing 2.5 percent. Apple... Read more
Amazon offers 13-inch MacBook Air for $899, $...
Amazon.com has the 13″ 1.4GHz 128GB MacBook Air on sale for $100 off MSRP including free shipping: - 13″ 1.4GHz 128GB MacBook Air: $899.99 Read more
Apple resting On Its iPhone Laurels? – The ‘B...
Apple calls its new iPhone 6 and 6 Plus “The Biggest Advancements in iPhone History,” but does reality live up to the hype? “Seldom have so many waited so breathlessly for so little,” tweeted veteran... Read more
Roundup of Apple Mac and iPad Education disco...
Purchase a new Mac or iPad at The Apple Store for Education and take up to $300 off MSRP. All teachers, students, and staff of any educational institution qualify for the discount. Shipping is free,... Read more
Apple Boycotts German Magazine Computer Bild...
Apple has revoked its PR accreditation of Germany’s Computer Bild, Europe’s best-selling PC magazine, in reaction to Bild’s posting of a “#Bentgate” YouTube video. Axel Telzerow, editor in chief of... Read more
iPhone 6 & iPhone 6 Plus Available in Chi...
Apple has announced that iPhone 6 and iPhone 6 Plus will be available in China beginning Friday, October 17 from the Apple Online Store (http://www.apple.com), Apple’s retail stores, and an expansive... Read more
MacBook Airs on sale for $100 off MSRP, start...
Best Buy has the new 2014 MacBook Airs on sale for $100 off MSRP on their online store. Choose free home shipping or free local store pickup (if available). Prices valid for online orders only, in-... Read more

Jobs Board

*Apple* Retail - Multiple Positions (US) - A...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
*Apple* Retail - Multiple Positions (US) - A...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
Senior Event Manager, *Apple* Retail Market...
…This senior level position is responsible for leading and imagining the Apple Retail Team's global event strategy. Delivering an overarching brand story; in-store, Read more
*Apple* Solutions Consultant (ASC) - Apple (...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
Project Manager / Business Analyst, WW *Appl...
…a senior project manager / business analyst to work within our Worldwide Apple Fulfillment Operations and the Business Process Re-engineering team. This role will work Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.