/* 
File: ALL_3D_SOURCES.doc
Author: R. P. Futrelle
Date: 8/16/98
Notice: Copyright 1998 by R. P. Futrelle and the College of Computer Science,
  Northeastern University
Proj: Code Warrior Mac project, 3D.µ (in the Documents project group)
Description: Single file containing all source code for the 3D.µ project. 
       Strategy is to list simple includes, then forward declarations,
       then declarations, then definitions, and finally the files for
       main itself. The Web document, "COM1370 Summer 98, 3D animation, 
       PA3, instructions" contains the assignment in which the pendulum
       in this example is replaced by two rotating clock hands. 
Modification history:
2/9/98: RPF. Started. 
8/16/98: RPF.  Checked over for handout, Summer 98 class.
     Most of the individual files have not been altered from 
     the Winter 98 version of the code.
    
*/
/* 
File: declarations.h
Author: R. P. Futrelle
Date: 2/9/98
Notice: Copyright 1998 by R. P. Futrelle and the College of Computer Science,
  Northeastern University
Proj: Code Warrior Mac project, 3D.µ
Description: This bundles together various includes for the 3D project.
       This means the forward declarations and regular declarations
       of the graphics and linear algebra classes and their members.  
Modification history:
2/9/98: RPF. Started. 
8/16/98: RPF.  Checked over for handout, Summer 98 class.
    
*/
//  hmmmmm....whatever happened to pi?
#ifndef CONST_PI
#define CONST_PI
 const float pi = 3.1415926535;
 const float pi2 = pi/2.0;
#endif
#include #include #include #include "graphics_classes_declares.h"
#include "linear_alg_classes_declares.h"
#include "graphics_classes.h"
#include "linear_alg_classes.h"
#include "utils.h"
/* 
File: utils.h
Author: R. P. Futrelle
Date: 2/9/98
Notice: Copyright 1998 by R. P. Futrelle and the College of Computer Science,
  Northeastern University
Proj: Code Warrior Mac project, 3D.µ
Description: Some globals and general functions.  
Modification history:
2/9/98: RPF. Started. 
8/16/98: RPF.  Checked over for handout, Summer 98 class.
    
*/
#include #ifndef UTILS_GLOBALS_
#define UTILS_GLOBALS_
// GLOBALS
// These are externs, because they are allocated in 3D.h
// Can't be allocated in two places.
extern WindowPtr fullScreenWin;
extern bool mouse_was_down;
extern EventRecord theEvent;
void wait_for_click();
#endif 
/* 
File: linear_alg_classes_declares.h
Author: R. P. Futrelle
Date: 2/9/98
Notice: Copyright 1998 by R. P. Futrelle and the College of Computer Science,
  Northeastern University
Proj: Code Warrior Mac project, 3D.µ
Description: Declares for 3D linear transforms (4x4 matrices).  
Modification history:
2/9/98: RPF. Started. 
8/16/98: RPF.  Checked over for handout, Summer 98 class.
    
*/
// CLASSES
class Transform; // contains 4x4 matrix for 3D transforms
// PROCEDURES
// Compose two transforms
void Compose(Transform *result, Transform *t1, Transform *t2); // all must exist
void CopyTrans(Transform *t1, Transform *t2); // from t2 to t1
void SetTranslationToFrom(GPt *pTo, GPt *pFrom);
Transform *MakeIdent();
// MISCELLANEOUS
enum ChangeMode {replace, compose}; // for the master transform.  Used?
/* 
File: linear_alg_classes.h
Author: R. P. Futrelle
Date: 2/9/98
Notice: Copyright 1998 by R. P. Futrelle and the College of Computer Science,
  Northeastern University
Proj: Code Warrior Mac project, 3D.µ
Description: Class definitions for Transform (in 3D, using 4x4 matrices)  
Modification history:
2/9/98: RPF. Started. 
8/16/98: RPF.  Checked over for handout, Summer 98 class.
    
*/
#ifndef LINEAR_ALG_CLASSES_
#define LINEAR_ALG_CLASSES_
#include "graphics_classes_declares.h"
#include "linear_alg_classes_declares.h"
class Transform {
 public:
  float matrix[4][4]; // uses homogeneous coordinates in 3D
  
  Transform() {};
  void SetIdent();   // sets transform to the identity matrix
  void SetTranslation(GPt *gPt); // sets transform to translation by gPt
  void SetTranslationToFrom(GPt *pTo, GPt *pFrom);
  
  // note for rotations: "pi" is a built-in constant  
   void SetRotX(float theta); // X rotation by theta radians
   void SetRotY(float theta); // Y rotation by theta radians
   void SetRotZ(float theta); // Z rotation by theta radians
     
  };
  
#endif
/* 
File: linear_alg.cp
Author: R. P. Futrelle
Date: 2/9/98
Notice: Copyright 1998 by R. P. Futrelle and the College of Computer Science,
  Northeastern University
Proj: Code Warrior Mac project, 3D.µ
Description: Class member definitions for Transform. A transform is an object whose
       internal values can be set and which can be composed with other transforms
       and applied to points (vectors) to move them through space.  In our
       case only rigid translations and rotations are used.  
Modification history:
2/9/98: RPF. Started. 
8/16/98: RPF.  Checked over for handout, Summer 98 class.
    
*/
#include #include "declarations.h"
Transform *MakeIdent() {
 Transform *tnew;
 tnew = new Transform;
 tnew->SetIdent();
 return(tnew);
 }
 void Transform::SetIdent() {
   // Sets matrix to the identity matrix
   for(int i = 0; i < 4; i++)
    for(int j = 0; j < 4; j++)
     matrix[i][j] = 0.0;
   for(int i = 0; i < 4; i++)
    matrix[i][i] = 1.0;}
  
 void Transform::SetTranslation(GPt *gPt) {
   // Sets to translation by vec amount
   this->SetIdent(); // first, set to identity (note use of "this")
   // then set last column to the translation vector
   for(int i = 0; i < 4; i++)
    matrix[i][3] = gPt->ptCoords[i];}
    
 void Transform::SetRotX(float theta) {
  // Sets to rotation by theta radians, CCW (counterclockwise)
  SetIdent();
  float sine = sin(theta);
  // Set appropriate sine and cosine elements
  matrix[1][1] = matrix[2][2] = cos(theta);
  matrix[1][2] = -sine;
  matrix[2][1] =  sine;
  }
 void Transform::SetRotY(float theta) {
  // Sets to rotation by theta radians, CCW (counterclockwise)
  SetIdent();
  float sine = sin(theta);
  // Set appropriate sine and cosine elements
  matrix[0][0] = matrix[2][2] = cos(theta);
  matrix[2][0] =  sine;
  matrix[0][2] = -sine;
  }
 void Transform::SetRotZ(float theta) {
  // Sets to rotation by theta radians, CCW (counterclockwise)
  SetIdent();
  float sine = sin(theta);
  // Set appropriate sine and cosine elements
  matrix[0][0] = matrix[1][1] = cos(theta);
  matrix[0][1] = -sine;
  matrix[1][0] =  sine;
  }
void Transform::SetTranslationToFrom(GPt *pTo, GPt *pFrom) {
 GPt *ptmp = new GPt(0.0, 0.0, 0.0);
 DiffGPoints(ptmp, pTo, pFrom); 
 SetTranslation(ptmp);
 }
// Two basic transform functions
// Results are included as arguments to avoid reallocation.
// That is, the result matrix must already exist and the functions set
// the values in it.
// Compose two transforms.  result is changed by this fn.
void Compose(Transform *result, Transform *t1, Transform *t2){
 for(int i = 0; i < 4; i++)
  for(int j = 0; j < 4; j++)
   {result->matrix[i][j] = 0.0; // init the i,j element
    for(int k = 0; k < 4; k++)
     result->matrix[i][j] += t1->matrix[i][k] * t2->matrix[k][j];}
 }
void CopyTrans(Transform *t1, Transform *t2) {
 for(int i = 0; i < 4; i++)
  for(int j = 0; j < 4; j++)
   t1->matrix[i][j] = t2->matrix[i][j];
 }
/* 
File: graphics_classes_declares.h
Author: R. P. Futrelle
Date: 2/9/98
Notice: Copyright 1998 by R. P. Futrelle and the College of Computer Science,
  Northeastern University
Proj: Code Warrior Mac project, 3D.µ
Description: Declarations for 3D graphics objects.  
Modification history:
2/9/98: RPF. Started. 
8/16/98: RPF.  Checked over for handout, Summer 98 class.
    
*/
// GRAPHICS CLASSES, ALL 3D OBJECTS (except for text)
class GObj;  // abstract class, graphical object
class GComp; // composite objects
class GPoly; // polygon
class GRectangle; // polygon so can be transformed, e.g., rotated.
class GTriangle; // specialized polygon
class GText; // text (non-rotatable)
class GPt; // low-level, a 4D float vector, 3D point in homogeneous coords.
// PROCEDURES
GPt *P(float x, float y, float z); // Only the constructor used?
void SumGPoints(GPt *sum, GPt *p1, GPt *p2); // result in sum
void DiffGPoints(GPt *diff, GPt *pPlus, GPt *pMinus); // result in diff
// GLOBAL CONSTANT
const int MAXCHILDREN = 20;
const int MAXVERTICES = 20;
/* 
File: graphics_classes.h
Author: R. P. Futrelle
Date: 2/9/98
Notice: Copyright 1998 by R. P. Futrelle and the College of Computer Science,
  Northeastern University
Proj: Code Warrior Mac project, 3D.µ
Description: Class definitions for 3D graphics objects.  GObj is an abstract class.
       GComp is a composite class that can contain children.  The other
       classes are instantiable geometric objects.  The most important for
       us are points (GPt) and polygons (GPoly).  
Modification history:
2/9/98: RPF. Started. 
8/16/98: RPF.  Checked over for handout, Summer 98 class.
    
*/
#ifndef GRAPHICS_CLASSES_
#define GRAPHICS_CLASSES_
#include "graphics_classes_declares.h"
#include "linear_alg_classes_declares.h"
class GObj{ 
 public:
  Transform *masterTrans;
  Transform *propagatedTrans;
  
  GObj();
  virtual void ChangeMasterTransform(Transform *tr, ChangeMode replace_compose) ;
  virtual void PropagateTrans(Transform *tr);
  void Translate(GPt *gPt);
  virtual  void Draw() {};
 };
 
class GComp : public GObj {
 public:
  GObj *children[MAXCHILDREN];
  int nChildren;
  
  GComp();
  void PropagateTrans(Transform *tr);
  void Draw();
  void InsertChild(GObj *child); // no deletes for now
  void InsertRect(GRectangle *child); // workaround bug?
  };
class GPt{
 public:
  float ptCoords[4]; // for 3D
  float tmpCoords[4]; // avoid overwriting ptCoords during matrix multiply
  
  GPt();
  GPt(float x, float y, float z);
  void zeroGPt();
  void SumGPoints(GPt *sum, GPt *p1, GPt *p2);
  void DiffGPoints(GPt *diff, GPt *pPlus, GPt *pMinus);
  int intX(){return((int)ptCoords[0]);}
  int intY(){return((int)ptCoords[1]);}
  
  };
 
class GPoly : public GObj{
 public:
  
  GPt *polyPts[MAXVERTICES];
  GPt *masterPts[MAXVERTICES]; // fixed
  Point *QDPts[MAXVERTICES];
  int nPts;
  PolyHandle polyH;
  float A, B, C, D;
  GPt *normalVec;
  int visible;
  RGBColor rgbColor;
  GPt *center;
  
  GPoly();
  void PropPoly();
  void MakeQDPoly();
  void PropagateTrans(Transform *tr);
  void PolyAddPt(GPt *ptPtr);
  GPt *FindMasterCenter();
  void MoveCenterTo(GPt *destGpt);  
  void SetVisibility();
  void MakeNormalVec();
  //bool PointInFront(GPt *ptPtr); // we're not doing tricky visible surface calcs.
  void Draw(); 
  };
// The following two are specialized subclasses of the more general polygon class.
class GTriangle : public GPoly {
 public:
  GTriangle(GPt *gPt1, GPt *gPt2);
 };
 
class GRectangle : public GPoly {
 public:
  GPt *centerRect;
  
  GRectangle(GPt *gPt);
  void FlipRect();
  void FoldBackX();
  void FoldBackY();
 };
class Text : public GObj{
  public:
   GPt *textLocation;
   char *string; // null-terminated
 };
  
#endif
/* 
File: graphics_classes.cp
Author: R. P. Futrelle
Date: 2/15/98
Notice: Copyright 1998 by R. P. Futrelle and the College of Computer Science,
  Northeastern University
Proj: Code Warrior Mac project, 3D.µ
Description: Class definitions for 3D graphics objects.  Includes methods for
       propagating transforms down containment hierarchies.  
Modification history:
2/15/98: RPF. Started. 
     Hadn't moved definitions into this file;
     others in pretty good shape.
8/16/98: RPF.  Checked over for handout, Summer 98 class.
*/
#include "declarations.h"
extern Transform *tFoldBackX, *tFoldBackY, *tSlide, *tRotYPi;
// DETAILED DEFINITIONS   ********************************
// GENERAL OBJECTS   ********************************
GObj::GObj() {
 masterTrans = new Transform;
 masterTrans->SetIdent();
 propagatedTrans = new Transform;
 }
void GObj::PropagateTrans(Transform *tr) {
   Compose(propagatedTrans, tr, masterTrans);
   }
// This allows the internal transform of an object or a containing node to either
// be composed with a matrix passed to it or to be replaced by the transform.
// This is needed if an object is to have its own behavior in its model space, yet
// still function in the containment hierarchy.
   
 void GObj::ChangeMasterTransform(Transform *tr, ChangeMode replace_compose) {
 Transform tmpTrans;
 switch (replace_compose) {
  case replace:
   CopyTrans(masterTrans, tr);
  break;
  case compose:
   Compose(&tmpTrans, tr, masterTrans);
   CopyTrans(masterTrans, &tmpTrans);
  }
 }
void GObj::Translate(GPt *gPt) {
 Transform ttmp;
 ttmp.SetTranslation(gPt);
 ChangeMasterTransform(&ttmp, compose);
}
// COMPOSITE OBJECTS   ********************************
GComp::GComp() : nChildren (0) {}
// To draw a composite object, draw all its children:
 void GComp::Draw() {
 for(int i = 0; i < nChildren ; i++)
  children[i]->Draw();
 }
// Insert a child into a composite object
void GComp::InsertChild(GObj *child) {
 if (nChildren < (MAXCHILDREN -1))
  children[nChildren++] = child; // postincrement
 }
 
void GComp::InsertRect(GRectangle *child) { // workaround bug?
 if (nChildren < (MAXCHILDREN -1))
  children[nChildren++] = child; // postincrement
 }
// Propagate transform to children
// Quite simple -- just propagates to each child.
void GComp::PropagateTrans(Transform *tr) {
 for(int i = 0; i < nChildren ; i++)
  children[i]->PropagateTrans(tr);
 }
// POINTS   ********************************
// create an all-zero point
GPt::GPt() {
 zeroGPt();
 }
 
// Create a point, 4 els. for 3D
 GPt::GPt(float x, float y, float z){
 ptCoords[0] = x;
  ptCoords[1] = y;
  ptCoords[2] = z; 
 ptCoords[3] = 1.0;
 } 
// Useful for compact representations -- not sure why we need both.
GPt *P(float x, float y, float z) {
 return(new GPt(x, y, z));}
 
// zero an existing point
void GPt::zeroGPt() {
 for(int i = 0; i < 4; i++)
  ptCoords[i] = 0.0;
 }
  
// add two points, putting result into an existing one
void SumGPoints(GPt *sum, GPt *p1, GPt *p2) {
 for(int i = 0; i < 3; i++)
 sum->ptCoords[i] = p1->ptCoords[i] + p2->ptCoords[i];
 // 3rd coord remains 1.0;
 }
// form difference of two points, putting result into an existing one
void DiffGPoints(GPt *diff, GPt *pPlus, GPt *pMinus) {
 for(int i = 0; i < 3; i++)
 diff->ptCoords[i] = pPlus->ptCoords[i] - pMinus->ptCoords[i];
 }
// POLYGONS   ********************************
GPoly::GPoly() : nPts (0), visible (1) {}
 void GPoly::PropPoly() {
 for(int i_thPt = 0; i_thPt < nPts; i_thPt++) {
  polyPts[i_thPt]->zeroGPt();
   for(int j_thCoord = 0; j_thCoord < 4; j_thCoord++)
    for(int k_thCoord = 0; k_thCoord < 4; k_thCoord++)
     polyPts[i_thPt]->ptCoords[j_thCoord] += 
      propagatedTrans->matrix[j_thCoord][k_thCoord] 
      * masterPts[i_thPt]->ptCoords[k_thCoord];
  }
 // now calcute if front face is visible.
 SetVisibility();
 }
void GPoly::PropagateTrans(Transform *tr) {
   GObj::PropagateTrans(tr); // updates matrix  
    PropPoly(); // updates poly points
    MakeQDPoly(); // creates QD poly
    }
// This finds the Z component of the normal vector and sets the visible flag so
// that the draw routine will know whether or not to display it
void GPoly::SetVisibility() {
 float x0 = polyPts[0]->ptCoords[0];
 float y0 = polyPts[0]->ptCoords[1];
 float x1 = polyPts[1]->ptCoords[0];
 float y1 = polyPts[1]->ptCoords[1];
 float x2 = polyPts[2]->ptCoords[0];
 float y2 = polyPts[2]->ptCoords[1];
 float dx0 = x1 - x0;
 float dy0 = y1 - y0;
 float dx1 = x2 - x1;
 float dy1 = y2 - y1;
 visible = (dx0 * dy1 - dx1 * dy0) > 0.0 ? 1 : 0;
 }
 void GPoly::PolyAddPt(GPt *gPtPtr) {
 if (nPts < (MAXVERTICES -1))
  polyPts[nPts++] = gPtPtr; // postincrement
 }
// This actually makes the QuickDraw poly corresponding to our polygon object.
// Of course z-coordinates are ignored here, since the QD poly is 2D.
void GPoly::MakeQDPoly() {
 polyH = OpenPoly();
 MoveTo(polyPts[0]->intX(),polyPts[0]->intY());
 for(int ptNum = 1; ptNum < nPts; ptNum++)
  LineTo(polyPts[ptNum]->intX(),polyPts[ptNum]->intY());
 LineTo(polyPts[0]->intX(),polyPts[0]->intY());
 ClosePoly();
 }
GPt* GPoly::FindMasterCenter() {
 GPt *gp = new GPt(0.0, 0.0, 0.0);
 for(int i = 0; i < 3; i++) {
  for(int nth = 0; nth < nPts; nth++)
   gp->ptCoords[i] +=
    masterPts[nth]->ptCoords[i];
  gp->ptCoords[i] /= 3.0; // why 3.0?
  }
 return(gp);
 }
void GPoly::MoveCenterTo(GPt *destGPt) {
 GPt *center = FindMasterCenter();
 tSlide->SetTranslationToFrom(destGPt, center);
 ChangeMasterTransform(tSlide, compose);
 }
// Draws the QD poly that's stored in the object.
 void GPoly::Draw() {
  if (visible) {
   RGBColor save; 
   GetForeColor(&save);
   RGBForeColor(&rgbColor);
  PaintPoly(polyH);
  RGBForeColor(&save);
  }
 }
 // void GPoly::MakeNormalVec() {} // do later
 // bool GPoly::PointInFront(GPt *ptPtr) {} // do later
// TRIANGLES   ********************************
// Define triangle with one point at origin, x,y plane.
// Sense (CW vs. CCW) not controlled.
GTriangle::GTriangle(GPt *gPt1, GPt *gPt2) {
 masterPts[0] = P(0.0, 0.0, 0.0);
 masterPts[1] = P(gPt1->ptCoords[0], gPt1->ptCoords[1], 0.0);
 masterPts[2] = P(gPt2->ptCoords[0], gPt2->ptCoords[1], 0.0);
 }
// RECTANGLES   ********************************
// Define CCW rectangle with lower left at origin in x,y plane.
GRectangle::GRectangle(GPt *gPt) {
 float x = gPt->ptCoords[0];
 float y = gPt->ptCoords[1];
 
 masterPts[0] = P(0.0, 0.0, 0.0);
 masterPts[1] = P(x, 0.0, 0.0);
 masterPts[2] = P(x, y, 0.0);
 masterPts[3] = P(0.0, y, 0.0);
 
 nPts = 4;
 // put placeholders here for later transformations
 for(int i = 0; i < 4; i++)
  polyPts[i] = new GPt();
 }
// Three transforms useful for building a model:
void GRectangle::FlipRect() {
 float width = masterPts[1]->ptCoords[0];
 tSlide->SetTranslation(P(width, 0.0, 0.0));
 ChangeMasterTransform(tRotYPi, compose); 
 ChangeMasterTransform(tSlide, compose);
  }
 
void GRectangle::FoldBackX() {
 ChangeMasterTransform(tFoldBackX, compose);
 }
 
void GRectangle::FoldBackY(){
 ChangeMasterTransform(tFoldBackY, compose);
 }
/* 
File: 3D.h
Author: R. P. Futrelle
Date: 2/15/98
Notice: Copyright 1998 by R. P. Futrelle and the College of Computer Science,
  Northeastern University
Proj: Code Warrior Mac project, 3D.µ
Description: Has definitions of all variables used in 3D.cp, as well as a simple
       function def.  
Modification history:
2/15/98: RPF. Started. 
     Added at late date to separate items from main.
8/16/98: RPF.  Checked over for handout, Summer 98 class.
    
*/
#include "declarations.h"
Rect rc;
PenState ps;
 
void do_it_all();
void wait_for_click(); 
 
void Init_Toolbox_Stuff();
WindowPtr NewWin(Rect &R);
void InitTransforms();
int ran_num_in_range(int low, int high);
float ran_float_in_range(float low, float high);
int Max3int(int i, int j, int k);
int Max3int(int i, int j, int k) {
 return (i > j ? (i > k ? i : k) : (j > k ? j : k));
 }
WindowPtr fullScreenWin;
bool mouse_was_down;
EventRecord theEvent;
RGBColor *MakeRGB(float, int, int, int);
Transform *tFoldBackX, *tFoldBackY, *tSlide, *tRotYPi;
Transform *tIdent, *tTemp1, *tTemp2;
GRectangle *rectTemp1, *rectTemp2;
GPt *g1, *g2, *g3, *g4;
 
Transform *tFront, *tBack, *tLeft, *tRight, *tTop, *tBottom;
Transform *tDepth,*tRotPlusX, *tRotMinusX, *tRotPlusY, *tRotMinusY; // all pi/2
Transform *tXWidth, *tYHeight;
Transform *tToOrigin, *tToScreenCenter;
Transform *tRotX, *tRotY, *tRotZ; 
 
float height = 100.0, width = 2 * height, depth = height/2;
float centerX = width/2, centerY = height/2, centerZ = depth/2;
float decLength = height/10, decWidth = decLength/2;
float handWidth = decWidth, minHandLength = height/3, hourHandLength = height/5;
  
GComp *Clock;
GComp *decFront;
GRectangle *clkFront, *clkBack, *clkTop, *clkBottom, *clkLeft, *clkRight;
GRectangle *clkDec12, *clkDec3,* clkDec6, *clkDec9;
GRectangle *rectTemp1, *rectTemp2;
GTriangle *clkHHand, *clkMHand;
 
RGBColor clkFrontColor, clkSidesColor, clkBackColor, clkDecColor, clkHandsColor;
/* 
File: 3D.cp
Author: R. P. Futrelle
Date: 2/9/98
Notice: Copyright 1998 by R. P. Futrelle and the College of Computer Science,
  Northeastern University
Proj: Code Warrior Mac project, 3D.µ
Description: Has definitions for the few functions used in 3D_main.cp, as well
       as a few used here.  Far and away the most important is do_it_all()
       that constructs a 6-sided rectangular solid plus a small decorative
       rectangle, and then tumbles it in space, redrawing after each step. 
Modification history:
2/9/98: RPF. Started. 
8/16/98: RPF.  Checked over for handout, Summer 98 class.
    
*/
#include "3D.h"
  
 Rect rc;
 PenState ps;
 
 void wait_for_click() 
 {
 
 FlushEvents(everyEvent,0); // Start with a clean slate.
 
 // and wait for one
 while(true)
  {WaitNextEvent(everyEvent, &theEvent, 6, nil);
   if(theEvent.what == mouseDown)
     {
     {DisposeWindow(fullScreenWin);
     mouse_was_down = true;
     break;}
   }
 return;
 
  }
 }
// Example, pink RGBColor produced with MakeRGB(1.0, 5, 4, 4):
RGBColor *MakeRGB(float brightness, int red, int green, int blue) {
 RGBColor rgb;
 float scale = 0xFFFF * brightness / Max3int(red, green, blue);
 rgb.red  =  scale * red;
 rgb.blue  =  scale * blue;
 rgb.green  =  scale * green;
 return (&rgb);
 }
 /* Modeling of a solid, a rectangular box built from polygons 
 at the origin which are then moved to their master coordinates 
 in the model. 
 */
void Init_Toolbox_Stuff()
 {
  InitGraf(&qd.thePort);  
  InitFonts();
  InitWindows();
  InitCursor();
  TEInit();
 }
void InitTransforms() {
 tIdent = MakeIdent();
 tTemp1 = MakeIdent(); 
 tTemp2 = MakeIdent();
 tFoldBackX = MakeIdent();
  tFoldBackX->SetRotX(-pi2);
 tFoldBackY = MakeIdent();
   tFoldBackY->SetRotY(-pi2); // final bug, had + sign, now fixed
 tSlide = MakeIdent();
 tRotYPi = MakeIdent();
  tRotYPi->SetRotY(pi);
 }
WindowPtr NewWin(Rect &R)
 { return (
 NewCWindow(nil, 
      &R, 
               nil,
               true,
               plainDBox,
               (WindowPtr)-1L,
               nil, 
               nil));  
  };
// Note that ansi library rand() returns 0 to RAND_MAX = 32767
// Generate random number in a range:
int ran_num_in_range(int low, int high)
 {return (low + rand() % (high - low + 1));}
// Simple approach to float RNG
float ran_float_in_range(float low, float high) {
 // scale floats to the 0 to 32767 range of rand() in stdlib.
 return(low + (high - low) * rand() / 32767.0);
 }
void do_it_all() { 
// SOLID VARIABLES AND VALUES   ********************************
 
 tToOrigin = new Transform; tToScreenCenter = new Transform;
 tRotX = new Transform;  tRotY = new Transform; tRotZ = new Transform; 
   
 Clock = new GComp;
 decFront = new GComp;
 
 // RGB COLORS   ********************************
 RGBColor Gblack = *MakeRGB(0.0, 0, 0, 0);
 RGBColor Gwhite = *MakeRGB(1.0, 1, 1, 1);
 RGBColor Ggrey = *MakeRGB(0.5, 1, 1, 1);
 RGBColor Gdarkgrey = *MakeRGB(0.25, 1, 1, 1);
 RGBColor Gred = *MakeRGB(1.0, 1, 0, 0);
 RGBColor Gpink = *MakeRGB(1.0, 5, 4, 4);
 RGBColor Gdarkred = *MakeRGB(0.7, 1, 0, 0);
 RGBColor Ggreen = *MakeRGB(1.0, 0, 1, 0);
 RGBColor Gblue = *MakeRGB(1.0, 0, 0, 1);
 RGBColor Gcyan = *MakeRGB(1.0, 0, 1, 1); // no red
 RGBColor Gmagenta = *MakeRGB(1.0, 1, 0, 1); // no green
 RGBColor Gyellow = *MakeRGB(1.0, 1, 1, 0); // no blue
 // Get the screen size.
 int screenW = qd.screenBits.bounds.right;
 int screenH = qd.screenBits.bounds.bottom;
// BUILD MODEL   ********************************
// AND ANIMATE IT   ********************************
// (but prepare screen first)
 // Blank full screen for background:
 fullScreenWin = NewWin(qd.screenBits.bounds);
 
 SetPort(fullScreenWin); // we can draw anywhere on huge screen
 
 RGBForeColor(&Gblack);
 PaintRect(&(fullScreenWin->portRect)); // note dereferencing required
 // Delay(60, 0L); // Toolbox delay fn uses ticks, 1/60th sec and ignored long int
 // Create the six sides so they all fit together.  Insert each into the overall
 // "clock" object -- let's get some hands spinning on this thing!
 
 // The setting up of faces has repetitive code that could be telescoped with
 // some decent functions.
 
 // Front
 rectTemp1 = new GRectangle(P(width, height, 0.0));
 rectTemp1->rgbColor = Gwhite;
 Clock->InsertRect(rectTemp1);
 
 // Back
 rectTemp1 = new GRectangle(P(width, height, 0.0));
 rectTemp1->FlipRect();
 rectTemp1->Translate(P(0.0, 0.0, -depth));
 rectTemp1->rgbColor = Ggrey;
 Clock->InsertRect(rectTemp1);
 rectTemp2 = (GRectangle*) (Clock->children[1]);
 
 // Left
 rectTemp1 = new GRectangle(P(depth, height, 0.0));
 rectTemp1->FlipRect();
 rectTemp1->FoldBackY();
 rectTemp1->rgbColor = Gred;
 Clock->InsertRect(rectTemp1);
 // Right
 rectTemp1 = new GRectangle(P(depth, height, 0.0));
 rectTemp1->FoldBackY();
 rectTemp1->Translate(P(width, 0.0, 0.0));
 rectTemp1->rgbColor = Gred;
 Clock->InsertChild(rectTemp1);
 
 // Top
 rectTemp1 = new GRectangle(P(width, depth, 0.0));
 rectTemp1->FoldBackX();
 rectTemp1->Translate(P(0.0, height, 0.0));
 rectTemp1->rgbColor = Gpink;
 Clock->InsertChild(rectTemp1);
 
 // Bottom
 rectTemp1 = new GRectangle(P(width, depth, 0.0));
 rectTemp1->FlipRect();
 rectTemp1->FoldBackX();
 rectTemp1->rgbColor = Gdarkred;
 Clock->InsertChild(rectTemp1);
 
 // Green decoration on front
 // Like front but smaller, and centered on front
 // Insert last so it's rendered last and appears on outside.
 // Prevents this solid from being 100% boring.
 
 rectTemp1 = new GRectangle(P(width/4, height/4, 0.0));
 rectTemp1->Translate(P(3*width/8, 3*height/8, 0.0));
 rectTemp1->rgbColor = Ggreen;
 Clock->InsertRect(rectTemp1);
 // All sides done, now set translations (rotate around origin)
 tToOrigin = new Transform;
 tToOrigin->SetTranslation(P(-centerX, -centerY, -centerZ));
 tToScreenCenter = new Transform;
 tToScreenCenter->SetTranslation(P(screenW/2, screenH/2, 0.0));
// Now make a composite rotation matrix each time, with the angles 
// increasing steadily.  We never alter the model, just apply larger rotations
// from scratch each time.
 for(int i = 0; i < 120; i++) {
  tRotX->SetRotX(0.05 * i);
  tRotY->SetRotY(0.08 * i);
  tRotZ->SetRotZ(0.10 * i);
  Compose(tTemp1, tRotY, tRotX);
  Compose(tTemp2, tRotZ, tTemp1);
  Compose(tTemp1, tTemp2, tToOrigin);
  Compose(tTemp2, tToScreenCenter, tTemp1);
  
  Clock->PropagateTrans(tTemp2);
  
  Clock->Draw();
  
  Delay(5, 0L);
  RGBForeColor(&Gyellow);
  
  PaintRect(&(fullScreenWin->portRect)); // note dereferencing required
  } // end of for loop for rotations and rendering
  
 Clock->Draw(); // finish up with one final draw so it will be visible.
 
 // Should add a wait for click here.
 
 } // end of do_it_all()
 
 /* 
File: 3D_main.cp
Author: R. P. Futrelle
Date: 2/9/98
Notice: Copyright 1998 by R. P. Futrelle and the College of Computer Science,
  Northeastern University
Proj: Code Warrior Mac project, 3D.µ
Description: This contains main() which consists of a handful of calls to routines
       defined in 3D.cp.   Could hardly be simpler.  
Modification history:
2/9/98: RPF. Started.  Derived from tr1 project of Jan-Feb 96.
    Primarily a splitting up of the monolithic earlier project.
8/16/98: RPF.  Checked over for handout, Summer 98 class.
    
*/
void Init_Toolbox_Stuff();
void InitTransforms();
void do_it_all();
void wait_for_click();
void main() 
 {
 Init_Toolbox_Stuff();
 InitTransforms();
 do_it_all();
 
 wait_for_click(); // needs fixing
 
 }