1 line
4.3 KiB
C
1 line
4.3 KiB
C
#include <math.h>
|
|
#include "common.h"
|
|
#include "pendulum.h"
|
|
#include "pendMenu.h"
|
|
#include "pendDialog.h"
|
|
|
|
#define SET_RECT(R,t,l,b,r) \
|
|
do { (R).top = (t); (R).left = (l); (R).bottom = (b); (R).right = (r); } while(0)
|
|
|
|
#define THETA (M_PI / 3)
|
|
#define D_THETA (0)
|
|
#define MU 0.1
|
|
#define LEN 2
|
|
#define GRAV 9.8
|
|
|
|
extern Boolean running = true;
|
|
extern Boolean resetting = true;
|
|
extern Boolean paused = false;
|
|
extern Boolean forceRedraw = false;
|
|
extern struct dialog_prefs_t pendPrefs = {
|
|
THETA, D_THETA, MU, LEN, GRAV
|
|
};
|
|
|
|
Rect WINDOW_RECT = {50, 50, 250, 250};
|
|
char WINDOW_NAME[] = "\pPendulum";
|
|
WindowPtr pendWindow;
|
|
struct pendulum_t thePend;
|
|
static Rect dragRect; /* const */
|
|
|
|
static void InitMacintosh(void);
|
|
static void ExitError(void);
|
|
static long HandleEvent(int eventMask);
|
|
static void HandleMouseDown(EventRecord *theEvent);
|
|
static void WaitTicks(unsigned qty);
|
|
static void WindowCreate(void);
|
|
static void WindowDrawContent(WindowPtr theWin, double angle, Boolean force);
|
|
|
|
static int iround(double n) {
|
|
double ipart, fpart;
|
|
int sign;
|
|
|
|
fpart = modf(n, &ipart);
|
|
sign = (n >= 0 ? 1 : -1);
|
|
if(fabs(fpart) >= 0.5) return (int)(ipart) + sign;
|
|
return (int) ipart;
|
|
}
|
|
|
|
void InitMacintosh(void) {
|
|
MaxApplZone();
|
|
|
|
InitGraf(&thePort);
|
|
InitFonts();
|
|
InitWindows();
|
|
InitMenus();
|
|
TEInit();
|
|
InitDialogs(0L);
|
|
|
|
FlushEvents(everyEvent, 0);
|
|
InitCursor();
|
|
}
|
|
|
|
void ExitError(void) {
|
|
SysBeep(1);
|
|
ExitToShell();
|
|
}
|
|
|
|
void WaitTicks(unsigned qty) {
|
|
static long lastTick = 0;
|
|
|
|
if(qty == 0) return;
|
|
while(--qty) {
|
|
while(lastTick == Ticks) {
|
|
HandleEvent(updateMask);
|
|
HandleEvent(everyEvent);
|
|
}
|
|
}
|
|
|
|
lastTick = Ticks;
|
|
}
|
|
|
|
long HandleEvent(int eventMask) {
|
|
int res;
|
|
EventRecord theEvent;
|
|
|
|
HiliteMenu(0);
|
|
SystemTask(); /* Handle desk accessories */
|
|
|
|
if (!GetNextEvent(eventMask, &theEvent)) return;
|
|
switch (theEvent.what) {
|
|
case mouseDown:
|
|
HandleMouseDown(&theEvent);
|
|
break;
|
|
|
|
case keyDown:
|
|
if(theEvent.modifiers & cmdKey) {
|
|
MenuEvent(MenuKey(theEvent.message & 0xFF));
|
|
}
|
|
|
|
/* FALLTHROUGH */
|
|
case autoKey:
|
|
break;
|
|
|
|
case activateEvt:
|
|
if(theEvent.modifiers & activeFlag) {
|
|
MenuEditMode(false);
|
|
paused = 0;
|
|
} else {
|
|
MenuEditMode(true);
|
|
paused = 1;
|
|
}
|
|
break;
|
|
|
|
case updateEvt:
|
|
WindowDrawContent((WindowPtr) theEvent.message,
|
|
thePend.theta, paused || forceRedraw);
|
|
forceRedraw = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void HandleMouseDown(EventRecord *theEvent) {
|
|
WindowPtr theWindow;
|
|
int windowCode = FindWindow(theEvent->where, &theWindow);
|
|
|
|
switch (windowCode) {
|
|
case inSysWindow:
|
|
SystemClick (theEvent, theWindow);
|
|
break;
|
|
|
|
case inDrag:
|
|
DragWindow(theWindow, theEvent->where, &dragRect);
|
|
break;
|
|
|
|
case inMenuBar:
|
|
MenuEvent(MenuSelect(theEvent->where));
|
|
break;
|
|
|
|
case inContent:
|
|
if(theWindow != FrontWindow()) {
|
|
SelectWindow(theWindow);
|
|
}
|
|
break;
|
|
|
|
case inGoAway:
|
|
if(TrackGoAway(theWindow, theEvent->where)) {
|
|
HideWindow(theWindow);
|
|
running = false;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void WindowCreate(void) {
|
|
pendWindow = NewWindow(0L, &WINDOW_RECT, WINDOW_NAME,
|
|
true, noGrowDocProc, (WindowPtr) -1L, true, 0);
|
|
|
|
if(!pendWindow) ExitError();
|
|
}
|
|
|
|
void WindowDrawContent(WindowPtr theWin, double angle, Boolean force) {
|
|
static Point lastPoint = {0, 0};
|
|
Rect BallRect = {0, 0, 25, 25};
|
|
Point lineEnd;
|
|
|
|
lineEnd.h = 100 + iround(75.0 * sin(angle));
|
|
lineEnd.v = 100 + iround(75.0 * cos(angle));
|
|
if(!force &&
|
|
lastPoint.h == lineEnd.h && lastPoint.v == lineEnd.v) {
|
|
return;
|
|
}
|
|
|
|
/*HideCursor();*/
|
|
BeginUpdate(theWin);
|
|
|
|
EraseRect(&theWin->portRect);
|
|
MoveTo(100, 100);
|
|
LineTo(lineEnd.h, lineEnd.v);
|
|
|
|
OffsetRect(&BallRect, lineEnd.h - 12, lineEnd.v - 12);
|
|
PaintRoundRect(&BallRect, 25, 25);
|
|
|
|
EndUpdate(theWin);
|
|
/*ShowCursor();*/
|
|
|
|
lastPoint.h = lineEnd.h;
|
|
lastPoint.v = lineEnd.v;
|
|
}
|
|
|
|
int main(void) {
|
|
InitMacintosh();
|
|
WindowCreate();
|
|
MenuCreate();
|
|
SetPort(pendWindow);
|
|
|
|
SET_RECT(dragRect, 4, 24, screenBits.bounds.right-4,
|
|
screenBits.bounds.bottom-4);
|
|
|
|
thePend.timestep = 1.0/20.0;
|
|
|
|
while(running) {
|
|
if(resetting) {
|
|
thePend.theta = pendPrefs.theta;
|
|
thePend.d_theta = pendPrefs.d_theta;
|
|
thePend.mu = pendPrefs.mu;
|
|
thePend.gl = pendPrefs.grav / pendPrefs.len;
|
|
resetting = false;
|
|
}
|
|
|
|
if(!paused) {
|
|
InvalRect(&pendWindow->portRect);
|
|
WaitTicks(4);
|
|
pendulum_iter(&thePend);
|
|
} else {
|
|
HandleEvent(everyEvent);
|
|
}
|
|
}
|
|
} |