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

CrossOver 14.1.6 - Run Windows apps on y...
CrossOver can get your Windows productivity applications and PC games up and running on your Mac quickly and easily. CrossOver runs the Windows software that you need on Mac at home, in the office,... Read more
Printopia 2.1.14 - Share Mac printers wi...
Run Printopia on your Mac to share its printers to any capable iPhone, iPad or iPod Touch. Printopia will also add virtual printers, allowing you to save print-outs to your Mac and send to apps.... Read more
Google Drive 1.24 - File backup and shar...
Google Drive is a place where you can create, share, collaborate, and keep all of your stuff. Whether you're working with a friend on a joint research project, planning a wedding with your fiancé, or... Read more
Chromium 45.0.2454.85 - Fast and stable...
Chromium is an open-source browser project that aims to build a safer, faster, and more stable way for all Internet users to experience the web. Version 45.0.2454.85: Note: Does not contain the "... Read more
OmniFocus 2.2.5 - GTD task manager with...
OmniFocus helps you manage your tasks the way that you want, freeing you to focus your attention on the things that matter to you most. Capturing tasks and ideas is always a keyboard shortcut away in... Read more
iFFmpeg 5.7.1 - Convert multimedia files...
iFFmpeg is a graphical front-end for FFmpeg, a command-line tool used to convert multimedia files between formats. The command line instructions can be very hard to master/understand, so iFFmpeg does... Read more
VOX 2.6 - Music player that supports man...
VOX is a beautiful music player that supports many filetypes. The beauty is in its simplicity, yet behind the minimal exterior lies a powerful music player with a ton of features and support for all... Read more
Box Sync 4.0.6567 - Online synchronizati...
Box Sync gives you a hard-drive in the Cloud for online storage. Note: You must first sign up to use Box. What if the files you need are on your laptop -- but you're on the road with your iPhone? No... Read more
Carbon Copy Cloner 4.1.4 - Easy-to-use b...
Carbon Copy Cloner backups are better than ordinary backups. Suppose the unthinkable happens while you're under deadline to finish a project: your Mac is unresponsive and all you hear is an ominous,... Read more
OmniGraffle Pro 6.3.1 - 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

You Can Play Madfinger Games' Unkil...
Madfinger Games - probably best known for the Dead Trigger series - has officially launched their newest zombie shooter (that isn't called Dead Trigger), named Unkilled. [Read more] | Read more »
Rock(s) Rider - HD Edition (Games)
Rock(s) Rider - HD Edition 1.0.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0.0 (iTunes) Description: *** PLEASE NOTE: Compatible with iPhone 4s, iPad 2, iPad mini, iPod touch (5th generation) or newer *** Do you... | Read more »
Rebuild 3: Gangs of Deadsville (Games)
Rebuild 3: Gangs of Deadsville 1.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0 (iTunes) Description: It's been a few years since the zombpocalypse turned the world's cities into graveyards and sent the few... | Read more »
Power Ping Pong (Games)
Power Ping Pong 1.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0 (iTunes) Description: Do you wield your bat with zen-like focus or do your balls of fury give you a killer spin? Table tennis goes mobile with a... | Read more »
Z.O.N.A Project X (Games)
Z.O.N.A Project X 1.00 Device: iOS Universal Category: Games Price: $1.99, Version: 1.00 (iTunes) Description: Z.O.N.A Project X - shooter in the post-apocalyptic world. | Read more »
Trick Shot (Games)
Trick Shot 1.0.6 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0.6 (iTunes) Description: A game where all you have to do is throw a ball into a box, simple? Trick Shot is a minimalist physics puzzler with 90 levels... | Read more »
Goat Simulator MMO Simulator (Games)
Goat Simulator MMO Simulator 1.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0 (iTunes) Description: ** IMPORTANT - SUPPORTED DEVICESiPhone 4S, iPad 2, iPod Touch 5 or better.** Coffee Stain Studios brings next-gen... | Read more »
Worms™ 4 (Games)
Worms™ 4 1.02 Device: iOS Universal Category: Games Price: $4.99, Version: 1.02 (iTunes) Description: The latest instalment in the worldwide mega hit franchise! Coming soon to iPhone, iPad and iPod touch. When the guys and girls at... | Read more »
The Deer God (Games)
The Deer God 1.0 Device: iOS Universal Category: Games Price: $6.99, Version: 1.0 (iTunes) Description: 30% off launch sale!!! “It can be a struggle, but it's all worth it when you're shooting fire out your antlers.” Kotaku “The... | Read more »
AppSpy's Patreon campaign kicks off
Occasionally you'll see us use AppSpy's videos here on 148Apps to support an article we've written. That's because we're part of Steel Media, and AppSpy is Steel's video arm, so we're all part of one happy family. [Read more] | Read more »

Price Scanner via MacPrices.net

Near-Office Input Functionality Virtually Any...
Today Logitech introduced the Logitech K380 Multi-Device Bluetooth Keyboard and the Logitech M535 Bluetooth Mouse, giving users the freedom to work on any device, most anywhere. According to... Read more
College Student Deals: Additional $100 off Ma...
Take an additional $100 off all MacBooks and iMacs at Best Buy Online with their College Students Deals Savings, valid through September 4, 2015. Anyone with a valid .EDU email address can take... Read more
Will You Buy An iPad Pro? – The ‘Book Mystiqu...
It looks like we may not have to wait much longer to see what finally materializes as a new, larger-panel iPad (Pro/Plus?) Usually reliable Apple product prognosticator KGI Securities analyst Ming-... Read more
eFileCabinet Announces SMB Document Managemen...
Electronic document management (EDM) eFileCabinet, Inc., a hosted solutions provider for small to medium businesses, has announced that its SecureDrawer and eFileCabinet Online services will be... Read more
WaterField Designs Unveils American-Made, All...
San Francisco’s WaterField Designs today unveiled their all-leather Cozmo 2.0 — an elegant attach laptop bag with carefully-designed features to suit any business environment. The Cozmo 2.0 is... Read more
Apple’s 2015 Back to School promotion: Free B...
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
128GB MacBook Airs on sale for $100 off MSRP,...
B&H Photo has 11″ & 13″ MacBook Airs with 128GB SSDs on sale for $100 off MSRP. Shipping is free, and B&H charges NY sales tax only: - 11″ 1.6GHz/128GB MacBook Air: $799.99, $100 off MSRP... Read more
13-inch 2.5GHz MacBook Pro (refurbished) avai...
The Apple Store has Apple Certified Refurbished 13″ 2.5GHz MacBook Pros available for $829, or $270 off the cost of new models. Apple’s one-year warranty is standard, and shipping is free: - 13″ 2.... Read more
27-inch 3.2GHz iMac on sale for $1679, save $...
B&H Photo has the 27″ 3.2GHz iMac on sale for $1679.99 including free shipping plus NY sales tax only. Their price is $120 off MSRP. Read more
Apple and Cisco Partner to Deliver Fast-Lane...
Apple and Cisco have announced a partnership to create a “fast lane” for iOS business users by optimizing Cisco networks for iOS devices and apps. The alliance integrates iPhone with Cisco enterprise... Read more

Jobs Board

*Apple* Desktop Analyst - KDS Staffing (Unit...
…field and consistent professional recruiting achievement. Job Description: Title: Apple Desktop AnalystPosition Type: Full-time PermanentLocation: White Plains, NYHot Read more
Simply Mac *Apple* Specialist- Repair Techn...
Simply Mac is the greatest premier retailer of Apple products expertise in North America. We're looking for dedicated individuals to provide personalized service and Read more
Simply Mac *Apple* Specialist- Service Repa...
Simply Mac is the greatest premier retailer of Apple products expertise in North America. We're looking for dedicated individuals to provide personalized service and Read more
*Apple* Desktop Analyst - KDS Staffing (Unit...
…field and consistent professional recruiting achievement. Job Description: Title: Apple Desktop AnalystPosition Type: Full-time PermanentLocation: White Plains, NYHot Read more
Simply Mac- *Apple* Specialist- Store Manag...
Simply Mac is the largest premier retailer for Apple products and solutions. We're looking for dedicated individuals with a passion to simplify and enhance the Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.