-- File: Draw3dImpl.mesa
-- Last edited by Bier on December 18, 1982 1:32 am
-- Author: Eric Bier on July 3, 1983 1:34 pm
-- Contents: Some useful combinations of Graphics operations

DIRECTORY
 CoordSys,
CSG,
 CSGGraphics,
 DisplayList3d,
 Draw3d,
 Graphics,
 Matrix3d,
 RealFns,
 SVBoundBox,
 SVPolygon3d,
 SVVector2d,
 SVVector3d;

Draw3dImpl: PROGRAM
IMPORTS CSGGraphics, Graphics, Matrix3d, RealFns, SVBoundBox, SVPolygon3d, SVVector2d, SVVector3d
EXPORTS Draw3d =
BEGIN

Camera: TYPE = CSGGraphics.Camera;
CoordSystem: TYPE = REF CoordSysObj;
CoordSysObj: TYPE = CoordSys.CoordSysObj;
CSGTree: TYPE = REF CSGTreeObj;
CSGTreeObj: TYPE = CSG.CSGTreeObj;
MasterObject: TYPE = DisplayList3d.MasterObject;
Matrix4by4: TYPE = Matrix3d.Matrix4by4;
Point2d: TYPE = Matrix3d.Point2d;
Point3d: TYPE = Matrix3d.Point3d;
Poly3d: TYPE = SVPolygon3d.Poly3d;
Primitive: TYPE = CSG.Primitive;
Composite: TYPE = CSG.Composite;
Vector: TYPE = SVVector3d.Vector;
Vector2d: TYPE = SVVector2d.Vector2d;

DrawCoordSys: PUBLIC PROC [dc: Graphics.Context, mat: Matrix4by4, camera: Camera] = {
 origin: Point3d;
 XAxis, YAxis, ZAxis: Vector;
-- assume that mat is a CAMERA to LOCAL transform matrix
-- The last column of a homogenous transform, is the origin of the coordinate system it represents in terms of the world coord system.
 origin[1] ← mat[1][4]; origin[2] ← mat[2][4]; origin[3] ← mat[3][4];
-- The columns correspond to the directional vectors of the mat coord system.
 XAxis ← [mat[1][1],mat[2][1],mat[3][1]];
 YAxis ← [mat[1][2],mat[2][2],mat[3][2]];
 ZAxis ← [mat[1][3],mat[2][3],mat[3][3]];
 DrawVector[dc, XAxis, origin, camera];
  Graphics.DrawChar[dc,'x];
 DrawVector[dc, YAxis, origin, camera];
  Graphics.DrawChar[dc,'y];
 DrawVector[dc, ZAxis, origin, camera];
  Graphics.DrawChar[dc,'z];
 }; -- Could be faster if I expand out the Draw Vectors internally.

DrawVector: PUBLIC PROC [dc: Graphics.Context, v: Vector, origin: Point3d, camera: Camera] = {
-- assumes vector is in camera coordinates
 VectorEnd: Point3d;
 leftBarb, rightBarb, v50, v90: Vector;
 leftBarb2d, rightBarb2d, v2d: Vector2d;
 v ← SVVector3d.Normalize[v];
 v50 ← SVVector3d.Scale[v, 50];
 VectorEnd ← SVVector3d.Add[origin,v50];
-- the barbs on the arrow head are of length 10 and shoot off at 45 degrees from the vector, parallel to the xy plane. To find them, we project v onto the xy plane and rotate 45 degrees.
 v2d ← SVVector3d.ProjectOntoXYPlane[v50];
 rightBarb2d ← SVVector2d.VectorPlusAngle[v2d, 135];
 leftBarb2d ← SVVector2d.VectorPlusAngle[v2d, -135];
 rightBarb ← SVVector3d.Vector2DAsXYVector[rightBarb2d];
 rightBarb ← SVVector3d.Scale[rightBarb, 10];
 leftBarb ← SVVector3d.Vector2DAsXYVector[leftBarb2d];
 leftBarb ← SVVector3d.Scale[leftBarb, 10];
-- rear facing vectors are shown with barbs
IF v[3] < 0 THEN {
  CSGGraphics.SetCPAbsolute[dc, origin, camera];
  CSGGraphics.DrawToAbsolute[dc, VectorEnd, camera];
  CSGGraphics.DrawToAbsolute[dc, SVVector3d.Add[VectorEnd, rightBarb], camera];
  CSGGraphics.SetCPAbsolute[dc, VectorEnd, camera];
  CSGGraphics.DrawToAbsolute[dc, SVVector3d.Add[VectorEnd, leftBarb], camera];
  }
-- forward facing vectors have filled-in tips.
ELSE {
   headPoly: Poly3d ← SVPolygon3d.CreatePoly[3];
   CSGGraphics.SetCPAbsolute[dc, origin, camera];
   CSGGraphics.DrawToAbsolute[dc, VectorEnd, camera];
   headPoly ← SVPolygon3d.AddPolyPoint[headPoly, VectorEnd];
   headPoly ← SVPolygon3d.AddPolyPoint[headPoly,
    SVVector3d.Add[VectorEnd, rightBarb]];
   headPoly ← SVPolygon3d.AddPolyPoint[headPoly,
    SVVector3d.Add[VectorEnd, leftBarb]];
   CSGGraphics.DrawAreaAbsolute[dc, headPoly, camera];
   };
   
  v90 ← SVVector3d.Scale[v, 90];
  CSGGraphics.SetCPAbsolute[dc, SVVector3d.Add[origin, v90], camera];
   -- prepare to draw a character after this vector
   
 };

DrawForwardVector
: PUBLIC PROC [dc: Graphics.Context, v: Vector, origin: Point3d, camera: Camera] = {
-- assumes vector is in camera coordinates
 VectorEnd: Point3d;
 leftBarb, rightBarb: Vector;
 leftBarb2d, rightBarb2d, v2d: Vector2d;
 v ← SVVector3d.Normalize[v];
 v ← SVVector3d.Scale[v, 50];
 VectorEnd ← SVVector3d.Add[origin,v];
-- the barbs on the arrow head are of length 10 and shoot off at 45 degrees from the vector, parallel to the xy plane. To find them, we project v onto the xy plane and rotate 45 degrees.
 v2d ← SVVector3d.ProjectOntoXYPlane[v];
 rightBarb2d ← SVVector2d.VectorPlusAngle[v2d, 135];
 leftBarb2d ← SVVector2d.VectorPlusAngle[v2d, -135];
 rightBarb ← SVVector3d.Vector2DAsXYVector[rightBarb2d];
 rightBarb ← SVVector3d.Scale[rightBarb, 10];
 leftBarb ← SVVector3d.Vector2DAsXYVector[leftBarb2d];
 leftBarb ← SVVector3d.Scale[leftBarb, 10];
-- rear facing vectors are shown with barbs
IF v[3] < 0 THEN {
  --CSGGraphics.MoveToAbsolute[dc, origin, camera];
  --CSGGraphics.DrawToAbsolute[dc, VectorEnd, camera];
  --CSGGraphics.DrawToAbsolute[dc, SVVector3d.Add[VectorEnd, rightBarb], camera];
  --CSGGraphics.MoveToAbsolute[dc, VectorEnd, camera];
  --CSGGraphics.DrawToAbsolute[dc, SVVector3d.Add[VectorEnd, leftBarb], camera];
  }
-- forward facing vectors have filled-in tips.
ELSE {
   headPoly: Poly3d ← SVPolygon3d.CreatePoly[3];
   CSGGraphics.SetCPAbsolute[dc, origin, camera];
   CSGGraphics.DrawToAbsolute[dc, VectorEnd, camera];
   headPoly ← SVPolygon3d.AddPolyPoint[headPoly, VectorEnd];
   headPoly ← SVPolygon3d.AddPolyPoint[headPoly,
    SVVector3d.Add[VectorEnd, rightBarb]];
   headPoly ← SVPolygon3d.AddPolyPoint[headPoly,
    SVVector3d.Add[VectorEnd, leftBarb]];
   CSGGraphics.DrawAreaAbsolute[dc, headPoly, camera];
   };
   
 };

DrawLocalVector: PUBLIC PROC [dc: Graphics.Context, v: Vector, origin: Point3d, camera: Camera, localCS: CoordSystem] = { -- assumes v and origin are in localCS coords. 
 vCamera: Vector ← Matrix3d.UpdateVectorWithInverse[localCS.cameraWRTlocal, v];
 originCamera: Point3d ← Matrix3d.Update[localCS.wrtCamera, origin];
 vCamera ← SVVector3d.Normalize[vCamera];
 vCamera ← SVVector3d.Scale[vCamera, 50];
 DrawVector[dc, vCamera, originCamera, camera];
 };

Draw2dVector: PUBLIC PROC [dc: Graphics.Context, vec: Vector2d, at: Point2d] = {
 unitVec, vec50: Vector2d;
 mag: REAL;
 mag ← RealFns.SqRt[vec[1]*vec[1] + vec[2]*vec[2]];
 unitVec[1] ← vec[1]/mag;
 unitVec[2] ← vec[2]/mag;
 vec50[1] ← unitVec[1]*50;
 vec50[2] ← unitVec[2]*50;
 Graphics.SetCP[dc, at[1], at[2]];
 Graphics.DrawTo[dc, at[1]+vec50[1], at[2]+vec50[2]];
 }; -- end of Draw2dVector

Draw2dCoordSys: PUBLIC PROC [dc: Graphics.Context, origin: Point2d, camera: Camera] = {
 CSGGraphics.SetCPAbsolute[dc, [-1000, origin[2],0], camera];
 CSGGraphics.DrawToAbsolute[dc, [1000, origin[2],0], camera];
 CSGGraphics.SetCPAbsolute[dc, [origin[1], -1000,0], camera];
 CSGGraphics.DrawToAbsolute[dc, [origin[1], 1000,0], camera];
 }; -- assumes Point2d in CAMERA coords

DrawX: PUBLIC PROC [dc: Graphics.Context, point: Point2d, camera: Camera] = {
 halfWidthOfX, halfHeightOfX: REAL;
 halfWidthOfX ← 10; halfHeightOfX ← 10;
 CSGGraphics.SetCPAbsolute[dc, [point[1]-halfWidthOfX, point[2]+halfHeightOfX, 0], camera];
 CSGGraphics.DrawToAbsolute[dc, [point[1]+halfWidthOfX, point[2]-halfHeightOfX, 0], camera];
 CSGGraphics.SetCPAbsolute[dc, [point[1]+halfWidthOfX, point[2]+halfHeightOfX, 0],camera];
 CSGGraphics.DrawToAbsolute[dc, [point[1]-halfWidthOfX, point[2]-halfHeightOfX, 0], camera];
 }; -- assumes point in CAMERA coords

DrawBoundBoxes: PUBLIC PROC [dc: Graphics.Context, tree: CSGTree, camera: Camera] = {
 DrawNode[dc, tree.son, camera];
 };

DrawNode: PRIVATE PROC [dc: Graphics.Context, node: REF ANY, camera: Camera] = {
WITH node SELECT FROM
 prim: Primitive => {mo: MasterObject;
   SVBoundBox.DrawBoundBox[dc, prim.boundBox, camera.screenCS];
   mo ← NARROW[prim.mo];
   mo.class.drawSubBoxes[dc, prim, camera.screenCS];
   };  
 comp: Composite =>
  {DrawNode[dc, comp.leftSolid, camera];
   DrawNode[dc, comp.rightSolid, camera];
   SVBoundBox.DrawBoundBox[dc, comp.boundBox, camera.screenCS];
   };
ENDCASE => ERROR;
 }; -- end of DrawNode

END.