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.
 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Dragon Dictate 6.0 - Premium voice-recog...
With Dragon Dictate speech recognition software, you can use your voice to create and edit text or interact with your favorite Mac applications. Far more than just speech-to-text, Dragon Dictate lets... Read more
OmniFocus 3.11.7 - GTD task manager with...
OmniFocus is an organizer app. It uses projects to organize tasks naturally, and then add tags to organize across projects. Easily enter tasks when you’re on the go, and process them when you have... Read more
rekordbox 6.5.1.0009 - Professional DJ m...
rekordbox is the best way of preparing and managing your tracks, be it at home, in the studio, or even on the plane! It allows you to import music from other music-management software using the... Read more
1Password 7.8.1 - Powerful password mana...
1Password is a password manager that uniquely brings you both security and convenience. It is the only program that provides anti-phishing protection and goes beyond password management by adding Web... Read more
Ableton Live 10.1.35 - Record music usin...
Ableton Live lets you create and record music on your Mac. Use digital instruments, pre-recorded sounds, and sampled loops to arrange, produce, and perform your music like never before. Ableton Live... Read more
Microsoft Office 365, 2019 16.48 - Popul...
Microsoft Office 365. The essentials to get it all done. Unmistakably Office, designed for Mac Get started quickly with new, modern versions of Word, Excel, PowerPoint, Outlook and OneNote-... Read more
Adobe After Effects 18.1 - Create profes...
After Effects is available as part of Adobe Creative Cloud for $52.99/month (or $20.99/month for a single app license). The new, more connected After Effects can make the impossible possible. Get... Read more
Adobe Audition 14.1 - Professional post-...
Audition is available as part of Adobe Creative Cloud for as little as $20.99/month (or $9.99/month if you're a previous Audition customer). Adobe Audition empowers you to create and deliver... Read more
Adobe Animate 21.0.5 - Animation authori...
Animate is available as part of Adobe Creative Cloud for as little as $20.99/month (or $9.99/month if you're a previous Flash Professional customer). Animate (was Flash CC) lets you share work... Read more
Adobe Photoshop 22.3.1 - Professional im...
You can download Photoshop for Mac as a part of Creative Cloud for only $20.99/month (or $9.99/month if you have purchased an earlier software version). Adobe Photoshop is a recognized classic of... Read more

Latest Forum Discussions

See All

Moonlight Sculptor is an upcoming MMORPG...
Kakao Games and XL Games – who you might be familiar with from their previous game ArcheAge – have announced that their MMORPG Moonlight Sculptor is now available to pre-order for iOS and Android devices. Moonlight Sculptor has previously launched... | Read more »
MU Archangel is now open for pre-registr...
MU Archangel is now open for pre-registration in Southeast Asia following its massive success in other territories. Players from Singapore, Thailand, Malaysia, Indonesia, and the Philippines (except Vietnam) can now join in on the fun by applying... | Read more »
Compete, a new social media app you can...
Whoever told you you can’t get rich making videos has obviously never heard of Compete, Competitive Media Technologies Limited’s hot new social media app where you can rake in all the dough just by doing what you love. Video monetization that... | Read more »
Bethesda has released a new DOOM mobile...
Bethesda Softworks has released a new DOOM game out of the blue exclusively for mobile devices. It’s called Mighty DOOM and is currently only available as an early access title on Android but will be expanding to more users in the future. [Read... | Read more »
Anagraphs is a word puzzle game with a t...
Cinq-Mars Media has released its word puzzle game Anagraphs for iOS and Android devices. The game released last week after a short delay in getting it onto the appropriate platforms. [Read more] | Read more »
These are the top 5 best iPhone games li...
Fortnite has been the big hitter in mobile gaming this year, and it's not hard to see why. Thanks to some excellent marketing, and a polished experience that almost anyone can enjoy, it's really taken the App Store by storm. But there are other... | Read more »
The top 5 best iPhone games like Pokemon...
Pokemon GO is still the, if you'll excuse the pun, go-to game if you want some AR action on your phone. But it's not the only choice out there, and if you've got a hankering for something a bit different, then your eyes might already have started... | Read more »
The top 5 best iPhone games like Starcra...
Starcraft sits at the top of the RTS tree for a number of very good reasons. It also isn't on mobile, again, for a number of very good reasons. But that doesn't mean you can't find a way to indulge your sci-fi, competitive, massive, or engaging RTS... | Read more »
Apple Arcade: Ranked - Top 25 [Updated 4...
In case you missed it, I am on a quest to rank every Apple Arcade game there is. [Read more] | Read more »
The top 5 best iPhone games like The Roo...
The Room has had a massive impact on the world of mobile gaming. Not only is it a brilliant adventure, it also shows how the touchscreen controls on your iPhone can be turned into something far more elegant and tactile than just a bunch of buttons... | Read more »

Price Scanner via MacPrices.net

B&H is offering clearance prices on lefto...
Apple reseller B&H Photo has clearance 2020 13″ 1.4GHz Intel-based MacBook Pros on sale today for $200-$300 off Apple’s original MSRP with prices starting at only $1099. Expedited shipping is... Read more
Roundup of Today’s Best MacBook Deals: M1 Mac...
Apple resellers are offering sale prices on Apple’s M1-powered 13″ MacBook Airs ranging up to $190 off MSRP. Here’s where to pick one up today, and as always, keep an eye on our 13″ MacBook Air Price... Read more
Apple AirPods Pro drop to new low price of on...
Amazon has Apple’s AirPods Pro on sale today for a new low price of only $197 shipped. That’s $52 off MSRP and the lowest price currently available for a set of AirPods Pro from any Apple reseller.... Read more
Apple restocks clearance 13″ Intel-based MacB...
Apple has clearance, Certified Refurbished, 2020 13″ Intel-based MacBook Airs available starting at only $809 and up to $280 off original MSRP. Each MacBook features a new outer case, comes with a... Read more
OWC drops prices on 2020 Intel multi-core Mac...
Other World Computing has clearance 2020 Intel-based Mac minis on sale starting at only $499. Both 4-core and 6-core models are in stock today. These are new, unopened, factory-sealed minis: – 3.6GHz... Read more
Save $50 off Apple’s 10.9″ iPad Air today at...
B&H Photo has new 10.9″ Apple iPad Airs in stock and on sale today for up to $50 off MSRP. Expedited shipping is free to most addresses in the US. Note that some sale prices may be restricted to... Read more
Rare Apple sale: Get a HomePod mini for $10 o...
Apple reseller Expercom has the Space Gray HomePod mini on sale today for $89 shipped. Their price is $10 off Apple’s MSRP, and it’s currently the only sale price available for a HomePod mini among... Read more
Apple has M1 Mac minis available starting at...
Apple has a full line of standard configuration M1 Mac minis available in their Certified Refurbished section starting at only $589 and up to $140 off MSRP. Each mini comes with Apple’s one-year... Read more
New sale at Amazon: $55-$70 discounts on Appl...
Amazon has 7.9″ iPad minis on sale today for up to $70 off Apple’s MSRP, each including free shipping. Prices start at $344. These are the same iPad minis sold by Apple in their retail and online... Read more
Apple offering 13″ M1 MacBook Airs for as lit...
Apple has a full line of 2020 13″ M1 MacBook Airs available, Certified Refurbished, starting at only $849 and up to $190 off original MSRP. These are the cheapest M1 MacBook Airs for sale today at... Read more

Jobs Board

*Apple* Valley 20hr Teller - Wells Fargo (Un...
…or scheduled + Ability to stand for extended periods of time **Street Address** **MN- Apple Valley:** 14325 Cedar Ave - Apple Valley, MN **Disclaimer** All offers Read more
*Apple* Valley 20hr Teller - Wells Fargo (Un...
…or scheduled + Ability to stand for extended periods of time **Street Address** **MN- Apple Valley:** 14325 Cedar Ave - Apple Valley, MN **Disclaimer** All offers Read more
Desktop Support Technician - *Apple* / Mac...
…infrastructure and internal desktop systems. Must have an IT background that includes Apple / Mac support. **Overview:** + Responds to routine technical questions or Read more
Geek Squad *Apple* Consultation Professiona...
**801042BR** **Job Title:** Geek Squad Apple Consultation Professional **Job Category:** Store Associates **Store Number or Department:** 000214-Willowbrook-Store Read more
*Apple* Mobility Specialist - Best Buy (Unit...
**800879BR** **Job Title:** Apple Mobility Specialist **Job Category:** Store Associates **Store Number or Department:** 000803-Lansing-Store **Job Description:** Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.