If you really want a retro MacPlus experience and would like to learn Pascal instead of C, Turbo or LightSpeed Pascal might work (but different from C, of course). Alternately, MacSEs are relatively cheap ($50-150) and go to 4Mb. Otherwise, don't worry about the Mac and just install SheepShaver and run it virtually on a new PC or Mac -- definitely faster compile times.
Also, for drawing stuff in windows, it is usually best to save and restore the drawing port. Below is some very minimal example code that may involve some foreign concepts (like pointers, defines, data types, prototypes, digital vampirism, rodent dietary habits, etc.). The main thing to note is how to save and restore the port. Otherwise, maybe some of the other C stuff will help. Here is some example code below that may be slightly ahead of where you guys are right now, but maybe it will help. I am not at all trying to bust the lesson plan. So, if you find anything below confusing, just ignore it. You will get to it eventually.
Code:
GrafPtr oldPort;
GetPort(&oldPort); // save the current port
SetPort(myPort); // set the target port (where GrafPtr = WindowPtr)
[call a bunch of QuickDraw functions to draw text and pixelated anime woodland creatures trying not to get bitten by vampires]
SetPort(oldPort); // restore the port
OR...in terms of scope, if you are delegating to dedicated graphic subroutines that expect the caller to manage the port and are only concerned about pixel manipulation, then you wouldn't need to call GetPort or SetPort in those subroutines. But, be careful and make sure you are not drawing somewhere you don't expect. Problems can and do occur -- like calling a subroutine that expects the port to be managed, then calling that same code from somewhere else when you forget you are supposed to manage the port and aren't doing it. In C++, this kind of problem might be less likely, depending on how you define your objects in terms of public/private routines. In C, it is easier to be naughty.
Here is a short example of delegating to a dedicated drawing routine that does not save/restore the port, plus some other tidbits:
Code:
// prototypes -- a prototype is a definition or specification of a procedure or function and terminates with a ";"
void BuffyTheBoxSlayer(Rect *r1, Rect *r2);
void BoxMagic(GrafPtr myPort);
// defines
#define kFatChipmunkWidth 512 // someone has been eating a few too many acorns!
// routines
// dedicated graphics subroutine that assumes it owns the port, so no port saving
void BuffyTheBoxSlayer(Rect *r1, Rect *r2) // note that routines have no ";" at the end, "void" just means it returns nothing
{
[some cool rectangle drawing stuff that can go wild without any port saving or restoring]
// here is how to dereference a pointer to a rectangle passed from another function to get to its members (top, left, bottom, right)
r1->top = 0; // or (*r1).top
r1->left = 0; // or (*r1).left..etc.
r1->bottom = (*r2).bottom; // like this
r1->right = kFatChipmunkWidth; // or set a value with a constant
FrameRect(r1); // draw the new rectangle -- in this case, passing 'r1' passes the address of (a pointer to) your Rect storage in BoxMagic,
// or just passing along what was passed to you in this routine, like forwarding a phone call.
// So, r1 passed in above is the pointer to the Rect r1 in BoxMagic, and when you want to see a field it points to,
// you have to use either an * and . [(*r1).top] or a -> [r1->top].
}
// the graphics calling routine that does all the port management
void BoxMagic(GrafPtr myPort)
{
GrafPtr oldPort;
Rect r1,r2; // define local storage for the rectangles
GetPort(&oldPort);
SetPort(myPort); // where WindowPtr = GrafPtr
// assume you initialize the Rects to something useful like myPort->portRect, etc.
BuffyTheBoxSlayer(&r1,&r2); // call Buffy to slay the boxes -- delegating to a dedicated drawing routine that assumes it owns the port
SetPort(oldPort); // restore the port
n.b. The Rect is a very important variable type to learn. It consists of 4 integer fields -- top, left, bottom, right -- the coordinates of the corners of the rectangle. So, in your routines (and the above example), you use the type "Rect" which allocates the local storage for the Rect(s). Then, when you want to pass a Rect to a subroutine, you use an '&' which means that you are taking the
effective address or location of that Rect in memory and telling the subroutine (...or pointing to the Rect...aka a "pointer") where it is. C has certain limits on parameter passing -- you will learn about them later...but that's why it's necesssary to use & and pass it as an address. More to learn for later.
Also, because you defined a "prototype" for BuffyTheBoxSlayer, the compiler has no trouble understanding the exact specification for the interface to that routine and will do the right thing when it compiles your code. Defining prototypes also helps ensure that your compiler will (almost always) be able to spit out type-checking errors when programmers screw up, which happens frequently.
I say "
almost always" because there are sometimes compiler bugs or exotic typing issues that do not throw errors -- or there may be no errors because some careless programmer has explicity told the compiler something is the expected type, even though doing that may cause another error later on. Using prototypes and header files are good habits to develop and necessary to define the calling interface to your code -- they will also help you create portable/reusable code and prevent a multitude of sins.
Again -- sorry -- not trying to skip ahead or cause confusion. Hope the above info is more helpful than not!