From: wysocki@husc.harvard.edu (Chris Wysocki)
Newsgroups: comp.sys.mac.programmer
Subject: Re: Think C 5.0, Apple libs and Graf3D
Date: 4 Dec 91 03:20:41 GMT
Organization: Harvard University, Cambridge, MA

In article <1991Dec4.005525.13637@ux1.cso.uiuc.edu>, databoy@mrcnext.cso.uiuc.edu
(John Snook) writes:

> Ok, I've got the 5.0 vers, new libs. I'm looking in :Mac Libraries: and I find
> "Graf3D". I'm thinking "oh boy oh boy". I look at the header file in headers:
> apple headers:, Graf3D.h, and I'm thinking "oh shit".
> Any Docs, Suggestions or recomendations would be greatly appreciated.

Here's some pseudo-documentation for Graf3D, as well as a couple of sample
programs.  I believe that the Graf3D routines are also documented in one of the
MPW manuals.

Chris Wysocki
wysocki@husc.harvard.edu

--------
Graf3D: The Three-dimensional Graphics Library

Graf3D draws three dimensional graphics in the two-dimensional environment 
provided by Quickdraw.

Graf3D presents a "camera-eye view" of the objects drawn.  With Graf3D 
procedures, the programmer sets the camera's location and field-of-view, 
as well as the location and orientation of the object being viewed.  Graf3D 
manages a "viewing pyramid" whose apex is at the camera's eye and whose base is 
Graf3D's "ViewPort".  The Graf3D package will clip objects being viewed to this 
pyramid.

The Graf3D package makes extensive use of the "fixed point" data type.  "Fixed" 
is defined as:
   type 
      fixed = longint;
The high order word of a fixed variable is the integer part;  the low order 
word is the fraction part.  Values are represented in units of 1/65536ths.  For 
example, the number 2.5 would be represented by a "2" in the high word and a 
32768 in the low order word (32768/65536 = .5), which would yield the longint 
value 163840.  Another way to think of it is that the value of a "fixed" 
variable is the value of the longint divided by 65536.  For more detail see 
Inside Macintosh in the "Introduction to Memory Management" chapter.  


Graf3D Types

Point3D
A Point3D is a record containing three "fixed" coordinates.

   Point3D = record
            x : fixed;
            y : fixed;
            z : fixed;
         end;

Point2D
A Point2D is a record containing two "fixed" coordinates.

   Point2D = record
            x : fixed;
            y : fixed;
         end;


XfMatrix
An XfMatrix is a 4x4 matrix of "fixed" values that holds the transformation 
equation for points to be viewed.

      XfMatrix = array [0..3, 0..3] of fixed;

Port3D
The Port3D contains all of the state variables necessary to map the three 
dimensional coordinates of the image into the two dimensional screen coordinates.  
"GrPort" is the pointer to the QuickDraw grafPort associated with this Port3D.  
"viewRect" is the viewing rectangle within the Port3D.  "xLeft, yTop, xRight, 
yBottom" are the coordinates of the viewRect in the three-dimensional "world".  
"pen" is the three dimensional pen location.  "penPrime" is the pen location 
transformed by the "xForm" matrix.  "eye" is the position of the camera in 
three-dimensional coordinates.  "hSize, vSize" are the half-width and half-
height of the viewPort in screen coordinates.  "hCenter, vCenter" are the 
coordinates of the center of the viewPort in screen coordinates.  "xCotan, 
yCotan" are the cotangents of the horizontal and vertical viewing angles.  
"ident" is a boolean which is true when "xForm" is equal to the identity 
transformation.  "xForm" is the transformation matrix.

   Port3DPtr = ^Port3D;
   Port3D = record
            GrPort : GrafPtr;
            viewRect : Rect;
            xLeft, yTop, xRight, yBottom : fixed;
            pen, penPrime, eye : Point3D;
            hSize, vSize : fixed;
            hCenter, vCenter : fixed;
            xCotan, yCotan : fixed;
            ident : BOOLEAN;
            xForm : XfMatrix;
         end;




Graf3D Procedures and Functions

Graf3D is a three dimensional Quickdraw package.  Its types, variable and 
routines mimic Quickdraw in many ways.  The following procedures and functions 
are provided in the Graf3D package:

Graf3DPort port initialization routines:

var thePort3D : Port3DPtr;
procedure InitGrf3D (globalPtr : Ptr);

InitGrf3D initializes the Graf3D drawing environment.  This procedure should be 
called once and only once per program execution, after Quickdraw is initialized.  
"globalPtr" is a pointer to the storage you wish to use for the Graf3D global 
variables.  Lightspeed Pascal programmers should always pass "@thePort3D" in 
this parameter.

procedure Open3DPort (port : Port3DPtr);
Open3DPort opens and initializes a 3D GrafPort whose space is pointed to by the 
parameter "port".  It also sets "thePort3D" (the current Graf3DPort) to "port".

procedure SetPort3D (port : Port3DPtr);
SetPort3D sets the current Graf3DPort ("thePort3D") to "port" and calls SetPort 
for "port"'s associated grafPort.

procedure GetPort3D (var port : Port3DPtr);
GetPort3D returns a pointer to the current graf3DPort in "port".  This is useful 
when the programmer wishes to change ports for drawing something and then 
restore the port before proceeding with the rest of the program.  For example:

var
   myPort, savePort: Port3DPtr;
..
   GetPort3D( savePort );     { save the current port }
   SetPort3D( myPort );    { set the port to my own }
   { I can do my drawing nowI }
   SetPort3D( savePort );     { restore the port to the one saved }


Pen movement and drawing

The following routines are used to move the pen in the 3D space and draw lines 
in the space.  NOTE:  The coordinates in these routines are specified in "fixed 
point" notation (NOT INTEGERS as in Quickdraw).

procedure MoveTo2D (x, y : fixed);
procedure MoveTo3D (x, y, z : fixed);
These procedures move the pen to the designated coordinates.  (MoveTo2D moves 
without changing the Z-coordinate.)

procedure LineTo2D (x, y : fixed);
procedure LineTo3D (x, y, z : fixed);
These procedures draw lines from the current pen position to the given 
coordinates (LineTo2D draws without changing the z-coordinate, i.e. the line is 
drawn in the same z-plane.)

procedure Move2D (dx, dy : fixed);
procedure Move3D (dx, dy, dz : fixed);
These procedures move the pen by the specified amounts relative to the current 
pen position.  (Move2D moves without changing the Z-coordinate.)

procedure Line2D (dx, dy : fixed);
procedure Line3D (dx, dy, dz : fixed);
These procedures draw lines from the current pen position to the given offsets 
relative to the current pen position (Line2D draws without changing the 
z-coordinate, i.e. the line is drawn in the same z-plane.)

function Clip3D (src1, src2 : Point3D;  var dst1, dst2 : POINT): boolean;
Clip3D clips a three-dimensional line segment to the viewing pyramid and returns 
the clipped line projected onto screen coordinates.  Clip3D returns true if any 
part of the line is visible.

procedure SetPt3D ( var pt3D : Point3D;  x, y, z : fixed);
SetPt3D assigns the 3 fixed numbers "x,y,z" to the point pt3D.

procedure SetPt2D ( var pt2D : Point2D;  x, y : fixed);
SetPt3D assigns the 2 fixed numbers "x,y" to the point pt2D.


Setting up the point of view

The following three procedures set the position and field-of-view of the "point 
of view".

procedure LookAt (left, top, right, bottom : fixed);
LookAt specifies the real number x,y coordinates of the viewing rectangle.

procedure ViewPort (r : Rect);
ViewPort specifies where to put the image in the grafPort.  The ViewPort 
rectangle is specified in integer coordinates and tells where to map the LookAt 
coordinates.

procedure ViewAngle (angle : fixed);
ViewAngle controls the amount of perspective by specifying the horizontal angle 
subtended by the viewing rectangle.  Typical ViewAngles are 0! (no perspective), 
10! (telephoto lens), 25! (normal human eye), and 80! (wide angle lens).


Transformation matrix procedures

The following procedures modify the transformation matrix that is used to plot 
the points in the viewing coordinates.

procedure Identity;
Identity sets the transformation matrix to the identity matrix.

procedure Scale (xFactor, yFactor, zFactor : fixed);
Scale modifies the transformation matrix so as to shrink or expand the image by 
the factors specified.

procedure Translate (dx, dy, dz : fixed);
Transform modifies the transformation matrix so as to displace the image by the 
specified amounts in the three coordinates.

procedure Pitch (xAngle : fixed);
Pitch modifies the transformation matrix so as to rotate "xangle" degrees around 
the x axis.  Positive values cause a clockwise rotation when looking at the 
origin from positive x.

procedure Yaw (yAngle : fixed);
Yaw modifies the transformation matrix so as to rotate "yAngle" degrees around 
the y axis.  Positive values cause a clockwise rotation when looking at the 
origin from positive y.

procedure Roll (zAngle : fixed);
Roll modifies the transformation matrix so as to rotate "zAngle" degrees around 
the z axis.  Positive values cause a clockwise rotation when looking at the 
origin from positive z.

procedure Skew (zAngle : fixed);
Skew modifies the transformation matrix so as to skew the image by "zAngle" 
degrees around the z axis.  Skew only changes the x axis.  Positive values cause 
a clockwise rotation when looking at the origin from positive z.

procedure TransForm (src : Point3D;  var dst : Point3D);
Transform applies the transformation matrix to the "src" point, and returns the 
result in "dst".



program boxes;
   uses
      Graf3D;

   const
      boxcount = 10;

   type
      box3d = record
            pt1 : Point3D;
            pt2 : point3D;
            dist : real;
         end;

   var
      GPort1 : GrafPort;
      GPort2 : Port3D;
      myPort : GrafPtr;
      myPort3D : Port3DPtr;
      boxArray : array[0..boxCount] of Box3D;
      nBoxes : integer;
      i : integer;
      ph : picHandle;
      r : rect;

   function HeapError (hz : QDPtr;
            bytesNeeded : integer) : integer;
   begin
      writeln('The heap is full!!!');
   end;

   function Distance (pt1, pt2 : Point3D) : real;
      var
         dx, dy, dz : real;
   begin
      dx := pt2.x - pt1.x;
      dy := pt2.y - pt1.y;
      dz := pt2.z - pt1.z;
      Distance := sqrt(dx * dx + dy * dy + dz * dz);
   end;

   procedure  MakeBox;
      label
         99;
      var
         myBox : Box3D;
         i, j, k, v : integer;
         p1, p2 : point3D;
         myRect : Rect;
         testRect : Rect;
   begin
      p1.x := (Random mod 140 - 85) * 65536;
      p1.y := (Random mod 140 - 80) * 65536;
      p1.z := 0;
      p2.x := p1.x + (10 + abs(Random) mod 30) * 65536;
      p2.y := p1.y + (10 + abs(Random) mod 45) * 65536;
      p2.z := p1.z + (10 + abs(Random) mod 35) * 65536;
      SetRect(myRect, round(p1.x div 65536), round(p1.y div 65536), round(p2.x div 65536),            round(p2.y div 65536));
      for i := 1 to nBoxes - 1 do
         begin
            with boxArray[i] do
               SetRect(testRect, round(pt1.x DIV 65536), round(pt1.y DIV 65536),                      round(pt2.x DIV 65536), round(pt2.y DIV 65536));
            if sectrect(myRect, testRect, testRect) then
               goto 99;
         end;
      myBox.pt1 := p1;
      myBox.pt2 := p2;
      p1.x := (p1.x + p2.x) DIV 2;
      p1.y := (p1.y + p2.y) DIV 2;
      p1.z := (p1.z + p2.z) DIV 2;
      Transform(p1, p2);
      myBox.dist := Distance(p2, myPort3D^.eye);
      i := 0;
      boxArray[nBoxes].dist := myBox.dist;
      while myBox.dist > boxArray[i].dist do
         i := i + 1;
      for j := nBoxes downto i + 1 do
         boxArray[j] := boxArray[j - 1];
      boxArray[i] := myBox;
      nBoxes := nBoxes + 1;
99 :
   end;

   procedure drawBox (pt1, pt2 : Point3D);
      var
         tempRgn : RgnHandle;
   begin
      tempRgn := NewRgn;
      OpenRgn;
      MoveTo3D(pt1.x, pt1.y, pt1.z);
      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);
      FrameRgn(tempRgn);
      OpenRgn;
      MoveTo3D(pt1.x, pt1.y, pt2.z);
      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);
      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);
      LineTo3D(pt2.x, pt2.y, pt1.z);
      LineTo3D(pt2.x, pt1.y, pt1.z);
      PenNormal;
      DisposeRgn(tempRgn);
   end;

begin
   setrect(r, 0, 40, 512, 342);
   SetDrawingRect(r);
   InitGrf3D(@thePort3D);
   showdrawing;
   GetPort(myPort);
   ph := OpenPicture(myPort^.portRect);
   showpen;
   myPort3D := @GPort2;
   Open3DPort(myPort3D);
   ViewPort(myPort^.portRect);
   LookAt($FF9C0000, $4B0000, $640000, $FFB50000);
   ViewAngle($200000);
   Identity;
   Roll($140000);
   Pitch($460000);
   PenPat(white);
   BackPat(black);
   EraseRect(myPort^.portRect);
   for i := -10 to 10 do
      begin
         MoveTo3D(i * 10 * 65536, -100 * 65536, 0);
         LineTo3D(i * 10 * 65536, 100 * 65536, 0);
      end;
   for i := -10 to 10 do
      begin
         MoveTo3D(-100 * 65536, i * 10 * 65536, 0);
         LineTo3D(100 * 65536, i * 10 * 65536, 0);
      end;
   nBoxes := 0;
   repeat
      MakeBox
   until nBoxes = boxCount;
   for i := nBoxes - 1 downto 0 do
      DrawBox(boxArray[i].pt1, boxArray[i].pt2);
   HidePen;
   ClosePicture;
   readln
end.
--------



I can't think of anything more politically correct than assasination...:)
Segmentation Fault (core dumped)
Newsgroups: comp.sys.mac.programmer