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

SpamSieve 2.9.37 - Robust spam filter fo...
SpamSieve is a robust spam filter for major email clients that uses powerful Bayesian spam filtering. SpamSieve understands what your spam looks like in order to block it all, but also learns what... Read more
Viber 11.3.1 - Send messages and make fr...
Viber lets you send free messages and make free calls to other Viber users, on any device and network, in any country! Viber syncs your contacts, messages and call history with your mobile device, so... Read more
Monosnap 3.6.1 - Versatile screenshot ut...
Monosnap lets you capture screenshots, share files, and record video and .gifs. Features Capture Capture full screen, just part of the screen, or a selected window Make your crop area pixel... Read more
WhatRoute 2.2.6 - Geographically trace o...
WhatRoute is designed to find the names of all the routers an IP packet passes through on its way from your Mac to a destination host. It also measures the round-trip time from your Mac to the router... Read more
MacFamilyTree 9.0.5 - Create and explore...
MacFamilyTree gives genealogy a facelift: modern, interactive, convenient and fast. Explore your family tree and your family history in a way generations of chroniclers before you would have loved.... Read more
WhatsApp 0.3.4375 - Desktop client for W...
WhatsApp is the desktop client for WhatsApp Messenger, a cross-platform mobile messaging app which allows you to exchange messages without having to pay for SMS. WhatsApp Messenger is available for... Read more
Mactracker 7.8.1 - Database of all Mac m...
Mactracker provides detailed information on every Mac computer ever made, including items such as processor speed, memory, optical drives, graphic cards, supported OS X versions, and expansion... Read more
Boom 3D 1.3.1 - 3D surround sound and ph...
Boom 3D is a revolutionary app with 3D Surround Sound and phenomenally rich and intense audio that is realistic and works on any headphones. Features 3D surround sound Built-in audio player... Read more
OmniGraffle 7.11.2 - Create diagrams, fl...
OmniGraffle helps you draw beautiful diagrams, family trees, flow charts, org charts, layouts, and (mathematically speaking) any other directed or non-directed graphs. We've had people use Graffle to... Read more
OmniGraffle Pro 7.11.2 - Create diagrams...
OmniGraffle Pro helps you draw beautiful diagrams, family trees, flow charts, org charts, layouts, and (mathematically speaking) any other directed or non-directed graphs. We've had people use... Read more

Latest Forum Discussions

See All

Steam Link Spotlight - Dicey Dungeons
Steam Link Spotlight is a new feature where we take a look at PC games that play exceptionally well with the Steam Link app. In case you missed it, our last entry focused on Faeria, a collectible card game that used to be available on the App Store... | Read more »
I can't believe Sky came out after...
I play games almost exclusively on mobile, and I’ve been doing so since around the time I started writing for 148Apps. This is why I’m late to the party on Journey. It wasn’t until last week that the game was playable on mobile, and it wasn’t until... | Read more »
Gigantic X guide - What you need to know...
Gigantic X continues to inspire loot lust over here at 148Apps, particularly because the game has already been updated just in its second week of release. Unfortunately, this 1.1.0 patch doesn’t bring a whole ton of new goodies with it, but it does... | Read more »
Steam Link Spotlight - Faeria
If you’ve been following 148Apps.com for a while, chances are you’ve seen me talk about Faeria. I reviewed it when it initially came out on iOS, and again when The Adventure Pouch: Oversky came out. I also put the game on my best games of 2017 list... | Read more »
Gigantic X guide - Tips and tricks for b...
Gigantic X has only been out for a little over a week, but it’s shaping up to be the mobile loot shooter of our dreams. That said, it’s not exactly the most friendly game out there. We noted in our review that you need to invest some time in the... | Read more »
Do Not Feed The Monkeys is one of the mo...
I’ve done a lot of messed up stuff in video games. I’ve beat people to death, slaghtered innocent animals, and even committed genocide. In doing all of that though, I’m not sure I’ve felt as uncomfortable as I have while playing Do Not Feed The... | Read more »
Civilization VI - What you need to know...
Last week, the mobile version of Civilization VI got updated to include the huge Rise and Fall expansion. Where previous updates to the game provided one or two new civilizations and maybe a few scenarios, Rise and Fall makes sweeping changes to... | Read more »
Combo Quest (Games)
Combo Quest 1.0 Device: iOS Universal Category: Games Price: $.99, Version: 1.0 (iTunes) Description: Combo Quest is an epic, time tap role-playing adventure. In this unique masterpiece, you are a knight on a heroic quest to retrieve... | Read more »
Hero Emblems (Games)
Hero Emblems 1.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0 (iTunes) Description: ** 25% OFF for a limited time to celebrate the release ** ** Note for iPhone 6 user: If it doesn't run fullscreen on your device... | Read more »
Puzzle Blitz (Games)
Puzzle Blitz 1.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0 (iTunes) Description: Puzzle Blitz is a frantic puzzle solving race against the clock! Solve as many puzzles as you can, before time runs out! You have... | Read more »

Price Scanner via MacPrices.net

Price drop! B&H now has new 4-Core Mac mi...
B&H Photo has dropped prices on 2018 4-Core Mac minis to $100 off MSRP, only $699. They’re also offering a $100 discount on the 6-Core Mac mini. Shipping is free: – 3.6GHz Quad-Core mini: $699 $... Read more
Amazon is offering a 37% discount on Apple Sm...
Amazon has Apple Smart Keyboards for current-generation 10″ iPad Airs and previous-generation 10″ iPad Pros on sale today for $99.99 shipped. That’s a 37% discount over Apple’s regular MSRP of $159... Read more
12″ iPad Pros on sale today for up to $400 of...
Amazon has new 2018 Apple 12″ iPad Pros in stock today and on sale for up to $400 off Apple’s MSRP. These are the same iPad Pros sold by Apple in its retail and online stores. Be sure to select... Read more
Apple has 2019 iMacs, Certified Refurbished,...
Apple has Certified Refurbished 2019 21″ & 27″ iMacs now available starting at $929 and up to $350 off the cost of new models. Apple’s one-year warranty is standard, shipping is free, and each... Read more
Sale! New 11″ WiFi iPad Pros for up to $400 o...
Walmart has new 2018 Apple 11″ WiFi iPad Pros in stock today and on sale for up to $400 off Apple’s MSRP. These are the same iPad Pros sold by Apple in its retail and online stores. Choose free local... Read more
New 2019 15″ 2.3GHz 8-Core MacBook Pro on sal...
Apple resellers B&H Photo and Amazon are offering the new 2019 15″ 2.3GHz Silver 8-Core MacBook Pro for $2449. That’s $350 off Apple’s MSRP and the lowest price available for an 8-Core MacBook... Read more
B&H has new 4-Core and 6-Core Mac minis o...
B&H Photo has the new 2018 4-Core and 6-Core Mac minis on sale for $80-$100 off Apple’s standard MSRP. Shipping is free: – 3.6GHz Quad-Core mini: $719 $80 off MSRP – 3.0GHz 6-Core mini: $999 $... Read more
10″ iPad Airs on sale for up to $50 off Apple...
B&H Photo has new 10.5″ iPad Airs on sale today for $30-$50 off Apple’s standard MSRP including free overnight shipping to many address in the US: – 10.5″ 64GB WiFi iPad Air: $469 $30 off MSRP –... Read more
Apple has clearance 2018 13″ 2.3GHz Quad-Core...
Apple has Certified Refurbished 2018 13″ 2.3GHz 4-Core Touch Bar MacBook Pros available starting at $1489. Apple’s one-year warranty is included, shipping is free, and each MacBook has a new outer... Read more
Clearance 2018 13″ MacBook Airs drop to an al...
B&H Photo has clearance 2018 13″ MacBook Airs available for $300 off Apple’s original MSRP with prices starting at only $899. Overnight shipping, or expedited shipping, is free depending on your... Read more

Jobs Board

*Apple* Mobility Pro - Best Buy (United Stat...
**719892BR** **Job Title:** Apple Mobility Pro **Job Category:** Store Associates **Location Number:** 001096-Grove City-Store **Job Description:** At Best Buy, our Read more
Best Buy *Apple* Computing Master - Best Bu...
**719975BR** **Job Title:** Best Buy Apple Computing Master **Job Category:** Store Associates **Location Number:** 001198-East Orange-Store **Job Description:** The Read more
*Apple* Mobile Master - Best Buy (United Sta...
**721421BR** **Job Title:** Apple Mobile Master **Job Category:** Store Associates **Location Number:** 000878-Dubuque-Store **Job Description:** **What does a Best Read more
Best Buy *Apple* Computing Master - Best Bu...
**716411BR** **Job Title:** Best Buy Apple Computing Master **Job Category:** Sales **Location Number:** 001089-Watertown-Store **Job Description:** **What does a Read more
*Apple* Mobility Pro - Best Buy (United Stat...
**721359BR** **Job Title:** Apple Mobility Pro **Job Category:** Store Associates **Location Number:** 000952-Baytown-Store **Job Description:** At Best Buy, our Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.