COM1370, Computer Graphics, Summer 1998, Professor Futrelle The first part of this file is the PA2 assignment description, as emailed. This is followed by all the source files concatenated together. This assignment for smooth animation, PA2, is due Monday, August 10. Since a lot of your sources will be identical to mine, please hand in only the sources of the files you changed, as well as a Mac floppy with your project which runs under Code Warrior for the Mac. I handed out hardcopy in class on Thursday of all the sources for the "smoothy" project. I have also put the project, all the sources, etc. on Ambassador. The project, which I was unable to demo in class (cart Mac problems) shows a moving read circle in the left window and a non-flickering version in the right window. This is because the window pixels are all moved rapidly to the right window after the update is finished in the left window (using bitblt == bit block transfer). In addition, the demo rotates a line using a 3x3 matrix (homogeneous coordinates), and draws a triangle to demonstrate polygon drawing. Your programming assignment 2, PA2, has two requirements. You should use all of my Smoothy code you can, don't display any of the things currently in it, and make changes as necessary to meet the two requirements below. 1. Display two or more rotating star-shaped or gear-shaped polygons in the left window whose "teeth" interdigitate like the teeth of a gear, as the rotate around their centers. Bitblt the image to the right-hand window after each update, to give a smooth animation. As I explained, to rotate a polygon, you rotate each point on the polygon and then create a new polygon and display it, just as I did for the static triangle. You just do it repeatedly with slightly different coordinates each time. 2. Draw your objects with the smallest number of integer parameter values you can use and still have an interesting image. That is, re-use a few basic parameters as much as possible. For example, you could take a basic length parameter L, say 100. Your windows could each be 2L by 3L. Your two stars could each have diameter L and then could overlap by a fraction F, so that there centers are (2 - F)L apart. The diameter of the "hub" of the stars could be L/2, and so forth. The number of "teeth" T could be 4. The centers would be horizontally aligned across the window and centered between the top can bottom of the window. The entire static part of the image would require only three parameters. Changing those would change your entire image in a coordinated way. Then you'd need to have a few parameters for the angle between rotational steps and the total angle of number of steps taken. To demonstrate that your parameterized formulation works. Show two runs with different values of your parameters, e.g., of L and F. You may want to choose a different set of parameters, but the goal is to avoid hardcoding in many, many integers, because the slightest change could force you to go back in and change many values, in coordinated ways. /* File: ALL-SMOOTHY-SOURCES.doc Author: R. P. Futrelle Date: 7/29/98 Notice: Copyright 1998 by R. P. Futrelle and the College of Computer Science, Northeastern University Proj: Code Warrior Mac project, smoothy.µ Description: This is not a file that's compiled. It simply concatenates together all the source files from the working/commented project smoothy.µ. These demonstrate smooth animation, bitblt-ing, polygons, sized text, pauses and mouse clicks, and 2D rotations using vectors and matrices in homogeneous coordinates. This project also demonstrates how to organize a large number of files including declarations, definitions, globals, and main() in a consistent way that can grow easily and safely, or be adapted to other projects (see more notes below). Modification history: 1/25/98: New. 7/29/98: Project is now smoothy.µ -- modest changes made. */ // The descriptions of the files just below is also included at the // beginning of main.cp /* The dependency chain has various branches, but is basically as follows (illustrated for the graphics classes): Forward references (bare declares) in: graphics_classes_declares.h Definitions of classes in: graphics_classes.h Definitions of member functions in: graphics.cp Ditto for other classes: windows, linear_alg All the headers are included in: declarations.h except globals.h and lobs.h Globals includes declarations: globals.h and defines global vars. all .cp files include globals.h General items with no other home: utils.h and utils.cp Functions in main() declared in: main.h Definitions of the main() functions: smoothy_fns.pc main() itself in: main.cp The files below are each clearly labeled and commented (the commenting took about as long as the coding -- that's about right -- 50/50). They are roughly in build order with the declarations first, then definitions and finally main() at the end. This may have a few typos, since I proofread my individual files and may find typos later and won't update both. The copy of the machine (Ambassador) will be updated from time-to-time. */ /* File: graphics_classes_declares.h Author: R. P. Futrelle Date: 7/29/98 Notice: Copyright 1998 by R. P. Futrelle and the College of Computer Science, Northeastern University Proj: Code Warrior Mac project, smoothy.µ Description: Declarations for the graphics classes, both abstract and concrete. Further details in other graphics files. Modification history: 1/12/98: RPF. Started as console1 to use SIOUX 1/20/98: RPF. Put in bitblt for simple circle motion and saved as "one smooth circle 1-98". 1/21/98: lobs.µ project initiated. 7/29/98: Project is now smoothy.µ -- modest changes made. */ class G_Obj; // Abstract superclasss class Rect_Based; // rectangles, ovals, circles class Circle; class Poly; class Line_; /* File: graphics_classes.h Author: R. P. Futrelle Date: 7/29/98 Notice: Copyright 1998 by R. P. Futrelle and the College of Computer Science, Northeastern University Proj: Code Warrior Mac project, smoothy.µ Description: Class declarations for graphics objects. There are two abstract classes, G_Obj and Rect_Based (the latter for rectangles and ovals/circles). Concrete classes are Circle, Line_, and Poly (polygon). The member functions are in graphics.cp. Modification history: 1/12/98: RPF. Started as console1 to use SIOUX 1/20/98: RPF. Put in bitblt for simple circle motion and saved as "one smooth circle 1-98". 1/21/98: lobs.µ project initiated. 1/24/98: Line_ and Poly added. 7/29/98: Project is now smoothy.µ -- modest changes made. */ // It's traditional to put "define" protection around these files, since they // can end up be loaded twice, through various include paths, and that would create // illegal duplicate definitions. #ifndef GRAPHICS_CLASSES_ #define GRAPHICS_CLASSES_ #include "graphics_classes_declares.h" // Abstract class root of drawable things (lines, rectangles, polygons, text) // All have Draw() and Erase(), always specialized. class G_Obj{ public: Point origin; void Draw(); void Erase(); }; // Has both a constructor and a setter for existing lines. // [missing a color slot] class Line_ : public G_Obj { public: int h1, v1, h2, v2; void Set_Line(int h1, int v1, int h2, int v2); void Draw(); void Erase(); Line_(int h1, int v1, int h2, int v2); }; // Abstract class for all Rect-based objects // [Color not specific for fill or frame -- needs work.] class Rect_Based: public G_Obj { public: int horz, vert; Rect my_rect; RGBColor color; void Set_Origin_Rect(Point origin); }; /* not used at the moment class Rectangle: public Rect_Based { public: Rectangle(Point loc, int height, int width); ~Rectangle(); }; */ class Circle: public Rect_Based { public: int radius; void Set_Origin_Rect(Point origin); void Draw(); void Erase(); Circle(int radius); }; class Poly: public G_Obj { public: PolyHandle my_poly_handle; void Open_Poly(); void Close_Poly(); void Draw(); void Erase(); void Dispose_Poly(); Poly(); }; #endif /* File: window_classes_declares.h Author: R. P. Futrelle Date: 7/29/98 Notice: Copyright 1998 by R. P. Futrelle and the College of Computer Science, Northeastern University Proj: Code Warrior Mac project, smoothy.µ Description: This has the declaration for my window class. See other windows files for details. Modification history: 1/12/98: RPF. Started as console1 to use SIOUX 1/20/98: RPF. Put in bitblt for simple circle motion and saved as "one smooth circle 1-98". 1/21/98: lobs.µ project initiated. 7/29/98: Project is now smoothy.µ -- modest changes made. */ class Window_C; /* File: linear_alg_classes_declares.h Author: R. P. Futrelle Date: 7/29/98 Notice: Copyright 1998 by R. P. Futrelle and the College of Computer Science, Northeastern University Proj: Code Warrior Mac project, smoothy.µ Description: Contains declarations for linear algebra classes. See other linear_alg files for details. Modification history: 1/24/98: Created for line rotation. 7/29/98: Project is now smoothy.µ -- modest changes made. */ class Vector_s; class Matrix_s; void Matrix_x_Vector(Matrix_s*, Vector_s*); // matrix * vector, product /* File: graphics_classes.h Author: R. P. Futrelle Date: 7/29/98 Notice: Copyright 1998 by R. P. Futrelle and the College of Computer Science, Northeastern University Proj: Code Warrior Mac project, smoothy.µ Description: Class declarations for graphics objects. There are two abstract classes, G_Obj and Rect_Based (the latter for rectangles and ovals/circles). Concrete classes are Circle, Line_, and Poly (polygon). The member functions are in graphics.cp. Modification history: 1/12/98: RPF. Started as console1 to use SIOUX 1/20/98: RPF. Put in bitblt for simple circle motion and saved as "one smooth circle 1-98". 1/21/98: lobs.µ project initiated. 1/24/98: Line_ and Poly added. 7/29/98: Project is now smoothy.µ -- modest changes made. */ // It's traditional to put "define" protection around these files, since they // can end up be loaded twice, through various include paths, and that would create // illegal duplicate definitions. #ifndef GRAPHICS_CLASSES_ #define GRAPHICS_CLASSES_ #include "graphics_classes_declares.h" // Abstract class root of drawable things (lines, rectangles, polygons, text) // All have Draw() and Erase(), always specialized. class G_Obj{ public: Point origin; void Draw(); void Erase(); }; // Has both a constructor and a setter for existing lines. // [missing a color slot] class Line_ : public G_Obj { public: int h1, v1, h2, v2; void Set_Line(int h1, int v1, int h2, int v2); void Draw(); void Erase(); Line_(int h1, int v1, int h2, int v2); }; // Abstract class for all Rect-based objects // [Color not specific for fill or frame -- needs work.] class Rect_Based: public G_Obj { public: int horz, vert; Rect my_rect; RGBColor color; void Set_Origin_Rect(Point origin); }; /* not used at the moment class Rectangle: public Rect_Based { public: Rectangle(Point loc, int height, int width); ~Rectangle(); }; */ class Circle: public Rect_Based { public: int radius; void Set_Origin_Rect(Point origin); void Draw(); void Erase(); Circle(int radius); }; class Poly: public G_Obj { public: PolyHandle my_poly_handle; void Open_Poly(); void Close_Poly(); void Draw(); void Erase(); void Dispose_Poly(); Poly(); }; #endif /* File: window_classes.h Author: R. P. Futrelle Date: 7/29/98 Notice: Copyright 1998 by R. P. Futrelle and the College of Computer Science, Northeastern University Proj: Code Warrior Mac project, smoothy.µ Description: Class declarations for windows. Each has a Mac window in it, as well as redundant vars for its Rect and origin. In_Window sets up for drawing in a particular window (setting Mac grafport). The member functions are in windows.cp. Modification history: 1/12/98: RPF. Started as console1 to use SIOUX 1/20/98: RPF. Put in bitblt for simple circle motion and saved as "one smooth circle 1-98". 1/21/98: lobs.µ project initiated. 7/29/98: Project is now smoothy.µ -- modest changes made. */ // It's traditional to put "define" protection around these files, since they // can end up be loaded twice, through various include paths, and that would create // illegal duplicate definitions. #ifndef WINDOW_CLASSES_ #define WINDOW_CLASSES_ #include "window_classes_declares.h" // Encapsulate a Mac window to abstract it. class Window_C { public: WindowPtr win_ptr; Rect win_rect; Point win_origin; Window_C(Point loc, int height, int width); ~Window_C(); void In_Window(); // sets grafport to this window }; #endif /* File: linear_alg_classes.h Author: R. P. Futrelle Date: 7/29/98 Notice: Copyright 1998 by R. P. Futrelle and the College of Computer Science, Northeastern University Proj: Code Warrior Mac project, smoothy.µ Description: Contains simple definitions to create a matrix to rotate around a point, and a vector type to work with it. This handles 2D vectors and transforms using 3-element vectors and 3x3-element matrices in homogeneous coordinates. The member functions are in linear_alg.cp. Modification history: 1/24/98: Created for line rotation. 1/25/98: Constructor restricted to rotator 7/29/98: Project is now smoothy.µ -- modest changes made. */ // It's traditional to put "define" protection around these files, since they // can end up be loaded twice, through various include paths, and that would create // illegal duplicate definitions. #ifndef LINEAR_ALG_CLASSES_ #define LINEAR_ALG_CLASSES_ // names "..._s" mean "simple", the versions for now #include "linear_alg_classes_declares.h" class Vector_s { public: float vec[3]; // vec[2] always = 1.0, for homogeneous coordinates Vector_s(float x, float y); }; class Matrix_s { public: float matrix[3][3]; // constructor only makes special matrix rotating around xc, yc. Matrix_s(float theta, float xc, float yc); }; #endif /* File: utils.h Author: R. P. Futrelle Date: 7/29/98 Notice: Copyright 1998 by R. P. Futrelle and the College of Computer Science, Northeastern University Proj: Code Warrior Mac project, smoothy.µ Description: The declarations for functions defined in utils.cp. Modification history: 1/12/98: RPF. Started as console1 to use SIOUX 1/20/98: RPF. Put in bitblt for simple circle motion and saved as "one smooth circle 1-98". 1/21/98: lobs.µ project initiated. 1/22/98: Added Time_Is_Up, fixed ran_pos_int. 1/24/98: Pause_Ticks and Mouse_Event added. 7/29/98: Project is now smoothy.µ -- modest changes made. */ // Note that the utils.h is loaded after many others, so classes such as // Window_C are defined at that point. void Pause_Ticks(int nticks); bool Mouse_Event(int pause = 0); // default can appear only once, traditionally here int ran_pos_int(int low, int high); int ran_pos_float(float low, float high); bool Time_Is_Up(unsigned long end_time); void Copy_Win_Bits(Window_C *w1, Window_C *w2); void Clear_Window(Window_C *w); /* File: declarations.h Author: R. P. Futrelle Date: 7/29/98 Notice: Copyright 1998 by R. P. Futrelle and the College of Computer Science, Northeastern University Proj: Code Warrior Mac project, smoothy.µ Description: Gathers together all important smoothy.µ project includes. Only globals.h is not here, but it includes _this_ file and is included by all the .cp files. Modification history: 1/12/98: RPF. Started as console1 to use SIOUX 1/20/98: RPF. Put in bitblt for simple circle motion and saved as "one smooth circle 1-98". 1/21/98: lobs.µ project initiated. 7/29/98: Project is now smoothy.µ -- modest changes made. */ #include#include "window_classes_declares.h" #include "graphics_classes_declares.h" #include "linear_alg_classes_declares.h" #include "window_classes.h" #include "graphics_classes.h" #include "linear_alg_classes.h" #include "utils.h" /* File: globals.h Author: R. P. Futrelle Date: 7/29/98 Notice: Copyright 1998 by R. P. Futrelle and the College of Computer Science, Northeastern University Proj: Code Warrior Mac project, smoothy.µ Description: This file contains external declarations for globals. It gets the type definitions from the headers loaded by including declarations.h. Since this includes declarations.h, various .cp files include this as their _only_ include. Note that we access three system globals that must be accessed in the following way, in Code Warrior: qd.thePort, qd.screenBits, qd.randSeed Modification history: 1/12/98: RPF. Started as console1 to use SIOUX 1/20/98: RPF. Put in bitblt for simple circle motion and saved as "one smooth circle 1-98". 1/21/98: lobs.µ project initiated. 7/29/98: Project is now smoothy.µ -- modest changes made. */ #include "declarations.h" extern bool mouse_was_down; extern int screen_w, screen_h, screen_mid, top_win; extern Window_C *win_left, *win_right, *banner_win; extern float x_min, x_max, y_min, y_max, vel_min, vel_max; extern unsigned long startup_delay_max, run_time_max; extern int ob_size; /* File: main.h Author: R. P. Futrelle Date: 7/29/98 Notice: Copyright 1998 by R. P. Futrelle and the College of Computer Science, Northeastern University Proj: Code Warrior Mac project, smoothy.µ Description: Declares the basic calls in main(). These functions are the ones defined in smoothy_fns.cp and called in main.cp. Modification history: 1/12/98: RPF. Started as console1 to use SIOUX 1/20/98: RPF. Put in bitblt for simple circle motion and saved as "one smooth circle 1-98". 1/21/98: lobs.µ project initiated. 1/25/98: Various declares added over the last two days. 7/29/98: Project is now smoothy.µ -- modest changes made. */ #include "declarations.h" void init_managers(); void init_globals(); void init_windows(); void Banner_(); void All_Done(); void Move_circle_simple(); void Draw_One_Poly(); void Spin_Line(); // **************************************************** // END OF INCLUDES (.h), BEGINNING OF DEFINITION (.cp) FILES // **************************************************** /* File: graphics.cp Author: R. P. Futrelle Date: 7/29/98 Notice: Copyright 1998 by R. P. Futrelle and the College of Computer Science, Northeastern University Proj: Code Warrior Mac project, smoothy.µ Description: Member function definitions for the graphics classes. Only tricky/messy thing here is erasing a line by saving and restoring the foreground color while I set it to background to redraw the line in background. (The save/restore needs to worked on for similar drawing of other objects.) Modification history: 1/12/98: RPF. Started as console1 to use SIOUX 1/20/98: RPF. Put in bitblt for simple circle motion and saved as "one smooth circle 1-98". 1/21/98: lobs.µ project initiated. 1/24/98: Line and polygon functionality added. 7/29/98: Project is now smoothy.µ -- modest changes made. */ #include "globals.h" //SetRect(r, left, top, right, bottom); // template from TBA // Lines // Create a line, putting the origin at the first endpoint Line_::Line_(int H1, int V1, int H2, int V2) { h1 = H1; v1 = V1; h2 = H2; v2 = V2; origin.h = h1; origin.v = v1; } // Virtually identical to the creation setup for a line void Line_::Set_Line(int H1, int V1, int H2, int V2) { h1 = H1; v1 = V1; h2 = H2; v2 = V2; origin.h = h1; origin.v = v1; } void Line_::Draw() { MoveTo(h1, v1); LineTo(h2, v2); } // Strategy is to redraw in the current background color. // Note how RGB colors are manipulated using built-ins. void Line_::Erase() { RGBColor fore; GetForeColor(&fore); RGBColor back; GetBackColor(&back); RGBForeColor(&back); // draw in background color MoveTo(h1, v1); LineTo(h2, v2); RGBForeColor(&fore); // restore to previous foreground color } // Circles: Circle::Circle(int the_radius) {radius = the_radius;}; // This is to reset center position to translate circle, // with no change in the radius. my_rect has its values // changed by this. void Circle::Set_Origin_Rect(Point center) { origin = center; int center_h = origin.h; int center_v = origin.v; SetRect(&my_rect, center_h - radius, center_v - radius, center_h + radius, center_v + radius); }; void Circle::Draw() {PaintOval(&my_rect);}; void Circle::Erase() {EraseOval(&my_rect);}; // Polygons: // These are a bit tricky. The creation is not done in a member function, // since that would require a vector of points. Instead we use the standard // QD paradigm of opening, drawing lines, and closing the polygon. // The poly structure can get big, so its a good idea to dispose of it after // its last use, with Dispose_Poly which reclaims the memory. Poly::Poly() {}; void Poly::Open_Poly() {my_poly_handle = OpenPoly();} void Poly::Close_Poly() {ClosePoly();} void Poly::Draw() {PaintPoly(my_poly_handle);} void Poly::Erase() {ErasePoly(my_poly_handle);} void Poly::Dispose_Poly() {KillPoly(my_poly_handle);} /* File: windows.cp Author: R. P. Futrelle Date: 7/29/98 Notice: Copyright 1998 by R. P. Futrelle and the College of Computer Science, Northeastern University Proj: Code Warrior Mac project, smoothy.µ Description: The constructor makes a simple color window with no title bar or scroll bars, initially displayed. In_Window() makes subsequent drawing appear in the window (instance). Modification history: 1/12/98: RPF. Started as console1 to use SIOUX 1/20/98: RPF. Put in bitblt for simple circle motion and saved as "one smooth circle 1-98". 1/21/98: lobs.µ project initiated. 7/29/98: Project is now smoothy.µ -- modest changes made. */ #include "globals.h" /* Here are the arguments for the new window call, from the Toolbox Assistant (set in C mode): WindowPtr NewCWindow(void *wStorage, const Rect *boundsRect, ConstStr255Param title, Boolean visible, short procID, WindowPtr behind, Boolean goAwayFlag, long refCon); Note the correspondence between the argument specs and the actual arguments used below, for non-nil entries: Argument spec Actual arg ------------- ---------- const Rect* &win_rect Boolean visible true short procID plainDBox (a system global - see TBA or IM) WindowPtr (WindowPtr)-1L (a long integer cast to a pointer) */ Window_C::Window_C(Point loc, int width, int height) { SetRect(&win_rect, loc.h, loc.v, loc.h + width, loc.v + height); win_origin = loc; win_ptr = NewCWindow(nil, &win_rect, nil, true, plainDBox, (WindowPtr)-1L, nil, nil); } void Window_C::In_Window() { SetPort(win_ptr); } /* File: linear_alg.cp Author: R. P. Futrelle Date: 7/29/98 Notice: Copyright 1998 by R. P. Futrelle and the College of Computer Science, Northeastern University Proj: Code Warrior Mac project, smoothy.µ Description: Implementation of linear algebra member functions and auxiliary functions. Modification history: 1/24/98: Created for line rotation. 1/25/98: Finished details of rotation matrix and matrix-vec product 7/29/98: Project is now smoothy.µ -- modest changes made. */ #include "linear_alg_classes.h" #include Vector_s::Vector_s(float x, float y) { vec[0] = x; vec[1] = y; vec[2] = 1.0; // 1.0 because of homogeneous coords. } // Constructor only makes special matrix rotating around xc, yc. // See Hearn and Baker, eq. 5-31, pg. 193. Matrix_s::Matrix_s(float theta, float xc, float yc) { float sn = sin(theta), cs = cos(theta); // remember, theta is in radians matrix[0][0] = cs; matrix[0][1] = -sn; matrix[0][2] = xc * (1.0 - cs) + yc * sn; matrix[1][0] = sn; matrix[1][1] = cs; matrix[1][2] = yc * (1.0 - cs) - xc * sn; matrix[2][0] = 0.0; matrix[2][1] = 0.0; matrix[2][2] = 1.0; } // The auxiliary function for product of matrix * vector // Not a member function of either. // NOTE: THIS OVERWRITES THE VECTOR WITH THE NEW ONE void Matrix_x_Vector(Matrix_s* m, Vector_s* v) { float vtemp[3] = {0.0, 0.0, 0.0}; // temp to avoid overwriting during sums for(int r = 0; r < 3; r++) { // do rows for(int c =0; c < 3; c++) // do columns { vtemp[r] = vtemp[r] + m->matrix[r][c] * v->vec[c]; }; // end columns }; // end rows for(int r = 0; r < 3; r++) v->vec[r] = vtemp[r]; // xfer vtemp vals to v } /* The following was used to test the functions above, values checked in dbg // rotate 50, 0 by 0.1 radians around 50, 100. 0.1 * 100 = +10, // so should move to about 60, epsilon (y rises just a bit) // that's about what is seen in debug, so it looks fine. // But I was wrong. theta = 0.0 gave 1, -1, 1, on the diagonal, woops! // Fixed sign error for [1][1] element. OK now. Matrix_s *m1 = new Matrix_s(0.1, 50.0, 100.0); Vector_s *v1 = new Vector_s(50.0, 0.0); Matrix_x_Vector(m1, v1); */ /* File: utils.cp Author: R. P. Futrelle Date: 7/29/98 Notice: Copyright 1998 by R. P. Futrelle and the College of Computer Science, Northeastern University Proj: Code Warrior Mac project, smoothy.µ Description: Contains definitions of miscellaneous functions. The various time delay and wait-on-mouse functions all use event loops so that other things can run in the gaps, e.g., Flash-It to grab screen images of even animated things, e.g., to get an image of one "frame" of a rotating line. The use of CopyBits to aid smooth animation should be noted. Modification history (by RPF == Futrelle, unless noted) 1/12/98: Started as console1 to use SIOUX 1/20/98: Put in bitblt for simple circle motion and saved as "one smooth circle 1-98". 1/21/98: lobs.µ project initiated. 1/22/98: Added Time_Is_Up, fixed ran_pos_int. 1/24/98: Pause_Ticks and Mouse_Event added. 7/29/98: Project is now smoothy.µ -- modest changes made. */ #include "globals.h" // Note: random() generates from -32767 to 32767 // From it we make two generators, one for positive ints // The other for positive floats. There is also a C function, // that could have been used. // Generate random positive int in a range: int ran_pos_int(int low, int high) {return (low + (32767 + rand()) % (high - low + 1));} // Generate random positive float in range (inclusive). int ran_pos_float(float low, float high) {return(low + (32767 + rand())/float(65534) * (high - low));} // Is true the moment TickCount() equals or exceeds end_time // Since TickCount() counts real time intervals (1/60's of a second) some absolute // pace can be set, which won't vary from one machine to the next. bool Time_Is_Up(unsigned long end_time) {return(TickCount() >= end_time);} // Safe wait function fires the moment TickCount() equals or exceeds the time. // It also notes mouse-down event -> mouse_was_down (global) void Pause_Ticks(int nticks) { EventRecord theEvent; unsigned long end_time = TickCount() + nticks; while(TRUE) { WaitNextEvent(everyEvent, &theEvent, 6, nil); if(theEvent.what == mouseDown) mouse_was_down = TRUE; if (Time_Is_Up(end_time)) break; } } // This resets the mouse_was_down flag and then waits for a click // (it doesn't "save" earlier clicks). bool Mouse_Event(int pause) { mouse_was_down = FALSE; while(TRUE) {Pause_Ticks(1); if(mouse_was_down) return(TRUE);}} /* This function Copy_Win_Bits copies all the pixels from one window to another. Thus an object can be drawn in the left window and copied to the right, then erased and redrawn and then copied again. No erased screen is ever seen in the right window, so animation can be smooth -- the updates from copying are so fast that no glitches are seen. This function is messy because of the complexity of its arguments. Here's the declaration from the TBA: void CopyBits (const BitMap *srcBits, const BitMap *dstBits, const Rect *srcRect, const Rect *dstRect, short mode, RgnHandle maskRgn); The primary task of building the arguments is to dig out the references from the various structures and to cast them to the right type, if necessary. CopyBits is explained functionally in IM Imaging, and the considerations for casting the args are best explained in the TBA (Toolbox Assistant). The major cast is to change the grafport from a color one to a basic QD grafport from which the bitmap is extracted. The strong typing of C++ forces such casting. */ void Copy_Win_Bits(Window_C *w1, Window_C *w2) { CopyBits(&GrafPtr(w1->win_ptr)->portBits, &GrafPtr(w2->win_ptr)->portBits, &w1->win_ptr->portRect, &w2->win_ptr->portRect, srcCopy, NULL); } // Not clear that the cast here is required. void Clear_Window(Window_C *w) {EraseRect(&CGrafPtr(qd.thePort)->portRect);} // ********************************************************* // END OF DEFINITIONS. NOW DEFINE FUNCTIONS TO RUN IN main() // ********************************************************* /* File: smoothy_fns.cp Author: R. P. Futrelle Date: 7/29/98 Notice: Copyright 1998 by R. P. Futrelle and the College of Computer Science, Northeastern University Proj: Code Warrior Mac project, smoothy.µ Description: This defines globals (allocates and initializes), declared in globals.h. It also defines the functions that run in main(). These are the messiest functions in this project, since they have to deal with many details, both small and large. Has both initialization routines and the routines that run/draw the examples, both geometrical objects and text. Modification history: 1/12/98: RPF. Started as console1 to use SIOUX 1/20/98: RPF. Put in bitblt for simple circle motion and saved as "one smooth circle 1-98". 1/21/98: lobs.µ project initiated. A lot of "Lob" data structures were put in here initially but not subsequently. used. 7/29/98: Project is now smoothy.µ -- modest changes made. */ #include "globals.h" #include "main.h" bool mouse_was_down = FALSE; int screen_w; int screen_h; int screen_mid; int top_win; Window_C *win_left; Window_C *win_right; Window_C *banner_win; float x_min, x_max, y_min, y_max, vel_min, vel_max; unsigned long startup_delay_max, run_time_max; int ob_size; void init_managers() { InitGraf(&qd.thePort); InitFonts(); InitWindows(); InitCursor(); TEInit(); } void init_globals() { mouse_was_down = FALSE; screen_w = qd.screenBits.bounds.right; screen_h = qd.screenBits.bounds.bottom; screen_mid = screen_w/2; top_win = screen_h/2; ob_size = 30; x_min = 2*ob_size; x_max = 0.8*screen_mid; y_min = 2*ob_size; y_max = 0.8*top_win; vel_min = 1.0; vel_max = 10.0; startup_delay_max = 30; run_time_max = 100; qd.randSeed = TickCount(); } void init_windows() { Point p; // create the left window (it flickers, bitblt *from* it) p.h = 3; p.v = top_win; win_left = new Window_C(p, screen_mid - 6, top_win - 3); // And the right one (it's smooth, bitblt *to* it) p.h = screen_mid; p.v = top_win; win_right = new Window_C(p, screen_mid - 6, top_win - 3); } // Puts initial Banner in left window: void Banner_() { win_left->In_Window(); // set to draw in left window MoveTo(20,40); TextSize(24); DrawString("\pClick your way through this demo"); Mouse_Event(); } // Ditto for another text piece, but 36pt type. Window is cleared first. void All_Done() { win_left->In_Window(); // set to draw in left window Clear_Window(win_left); MoveTo(20,60); TextSize(36); DrawString("\pAll Done!"); } // Moves circle across left window and bitblts to right window void Move_circle_simple() { Circle *circ = new Circle(100); Point pc; pc.h = 100; pc.v = 200; RGBColor c; c.red = 0xFFFF; c.green = 0; c.blue = 0; // a red win_left->In_Window(); // set to draw in left window RGBForeColor(&c); // now that we're there, set forecolor // This loops, incrementing the horizontal position, via pc.h += 1. // For each position it sets the rectangle (square) describing the circle, // draws it, copies left window to right, pauses (0 for now), erases the // circle and then loops. The erased screen is never copied over == no flicker. for(int j = 0; j < 50; j++) { pc.h += 4; circ->Set_Origin_Rect(pc); circ->Draw(); Copy_Win_Bits(win_left, win_right); // Pause_Ticks(0); circ->Erase(); }; } // Draw a stationary polygon (and copybits). This shows one way of drawing a polygon, // not completely hidden inside the object as a member function. This is the close to // the underlying method used in QD: Open a polygon data structure, move to a point, // draw a series of lines and close the data structure. We could easily implement an // alernative form in which an array of points or x,y coordinates was created and passed. // The Polygon data structure on the Mac allocates an array of exactly the right size, // once it knows how many vertices there are, on closing the drawing sequence. void Draw_One_Poly() { Poly *poly = NULL; RGBColor c; c.red = 0; c.green = 0xFFFF; c.blue = 0x7FFF; // light green win_left->In_Window(); // set to draw in left window RGBForeColor(&c); // now that we're there, set forecolor // Construct a triangle. This is the poly->Open_Poly(); MoveTo(100,100); LineTo(175, 135); LineTo(125, 250); poly->Close_Poly(); // Draw it poly->Draw(); Copy_Win_Bits(win_left, win_right); Pause_Ticks(60); poly->Erase(); // erase left but right remains Pause_Ticks(60); poly->Dispose_Poly(); // dispose/return the low-level data structure } // Spin a line using 2D matrix transforms. This involves concepts that come fairly // early in our graphics course. This uses rather simple vector and matrix classes // and operations for now. Remember that angles are in radians, about 6 radians around // a circle (2*pi to be exact). A radian is about 57 degrees. But radians are especially // good for describing small rotations, since rotating by 1/100 of a radian moves the end // of a line about 1/100 of its length. The move/copy/pause/erase/update strategy is // explained below. void Spin_Line() { RGBColor c; c.red = 0xFFFF; c.green = 0x1000; c.blue = 0x1000; // light red // xc,yc are the non-moving center points or the rotation, one end of the line. // xs,ys define the other end, which is constantly changed to "spin" the line. float xc = 150.0, yc= 150.0, xs = 200.0, ys = 200.0; Matrix_s *m1 = new Matrix_s(-0.05, xc, yc); // 1/20 radian each step Vector_s *v1 = new Vector_s(xs, ys); // holds the moving endpoint. win_left->In_Window(); // set to draw in left window RGBForeColor(&c); // now that we're there, set forecolor PenSize(1,30); // make the pen really odd-shaped, giving "3D" effect. Line_ *line = new Line_(xc, yc, xs, ys); // Loop strategy is: xfer the vec values to the line, draw, bitblt, erase, loop. for(int i = 0; i < 100; i++) { line->Set_Line(xc, yc, // xfer vec to line int(v1->vec[0]), int(v1->vec[1])); line->Draw(); // draw the line Copy_Win_Bits(win_left, win_right); // copy to right window // Pause_Ticks(1); // pause 1/60 sec line->Erase(); // erase on the left Matrix_x_Vector(m1, v1); // update v1 by slight rotation } } // ******************************************************* // BELOW IS main.cp CONTAINING THE MAIN PROGRAM main() // ******************************************************* /* File: main.cp Author: R. P. Futrelle Date: 7/29/98 Notice: Copyright 1998 by R. P. Futrelle and the College of Computer Science, Northeastern University Proj: Code Warrior Mac project, smoothy.µ Description: This contains main() which consists of a handful of calls to routines defined in smoothy_fns.cp. Modification history: 1/12/98: RPF. Started as console1 to use SIOUX 1/20/98: RPF. Put in bitblt for simple circle motion and saved as "one smooth circle 1-98". 1/21/98: lobs.µ project initiated. 1/25/98: Many slight changes yesterday and today as things were tested. As of today the following things work, all bitblt'd from left window to right to give smooth motion: moving circle, fixed triangle, line rotating around one end. It also has various timed delays as well as mouse clicks between "scenes". (The triangle is an example that shows how to create and render polygons.) 7/29/98: Project is now smoothy.µ -- modest changes made. ` Prepared for COM1370 class, summer 1998. There are occasional references to the "TBA" which is the Toolbox Assistant, a hyperlinked utility giving you call arguments for all the Toolbox calls in easy-to-use cut-and-paste form (C code). "IM" is Inside Macintosh, with some references to the Toolbox volume and some to the Imaging volume. This project also demonstrates how to organize a large number of files including declarations, definitions, globals, and main() in a consistent way that can grow easily and safely, or be adapted to other projects. The dependency chain has various branches, but is basically as follows (illustrated for the graphics classes): Forward references (bare declares) in: graphics_classes_declares.h Definitions of classes in: graphics_classes.h Definitions of member functions in: graphics.cp Ditto for other classes: windows, linear_alg All the headers are included in: declarations.h except globals.h and main.h Globals includes declarations: globals.h and defines global vars. all .cp files include globals.h General items with no other home: utils.h and utils.cp Functions in main() declared in: main.h Definitions of the main() functions: smoothy_fns.pc main() itself in: main.cp */ #include "globals.h" #include "main.h" void main() { init_managers(); init_globals(); init_windows(); Banner_(); // Tells user to click through the demo. // Moves circle across left window and bitblts to right Move_circle_simple(); // Requires a click (mouse down) after this begins to execute, // before it will return and allow things to proceed. Mouse_Event(); // Draw a simple polygon Draw_One_Poly(); // ditto Mouse_Event(); // Spin a line using 2D (3x3) rotation matrix Spin_Line(); // Announce all done All_Done(); // This returns when the mouse event occurs -- another way to use it. if(Mouse_Event(1)) return; // to quit entire run, when done }