/* Polyhedra */ /* A simple 3-D demo for the USRobotics Palm Pilot. */ /* Copyright 1997 by Ka-Ping Yee. All rights reserved. */ #include #include #include #include #include "fixed.h" /* numbering convention: forms/alerts 1000+, menus 2000+, (menu)items 3000+, controls 4000+, strings 5000+ */ #define APPID 0x506f6c79 /* 'Poly' */ #define APPVER 1 #define fidMain 1000 #define aidAbout 1001 #define iidTetra 3000 #define iidCube 3001 #define iidOcta 3002 #define iidTrunc 3003 #define iidWire 3100 #define iidDotted 3101 #define iidHidden 3102 #define iidAbout 3200 #define iidReset 3201 enum { modeWire, modeDotted, modeHidden }; enum { shapeTetra=0, shapeCube, shapeOcta, shapeTrunc }; typedef struct { SByte x, y, z; } Vert; typedef struct { Short a, b; } Edge; typedef struct { SByte e[4]; } Gon; typedef struct { Byte nverts, nedges, ngons; Vert* verts; Edge* edges; Gon* gons; } Shape; /* The octahedron. */ Vert overts[6] = { {35, 0, 0}, {0, 35, 0}, {0, 0, 35}, {-35, 0, 0}, {0, -35, 0}, {0, 0, -35} }; Edge oedges[12] = { {1, 2}, {2, 4}, {4, 5}, {5, 1}, {0, 1}, {0, 2}, {0, 4}, {0, 5}, {3, 1}, {3, 2}, {3, 4}, {3, 5} }; Gon ogons[8] = { {{4, 0, 5, -1}}, {{7, 3, 4, -1}}, {{5, 1, 6, -1}}, {{6, 2, 7, -1}}, {{0, 8, 9, -1}}, {{3,11, 8, -1}}, {{1, 9,10, -1}}, {{2,10,11, -1}} }; /* The cube. */ Vert cverts[8] = { {20, 20, 20}, {20, 20,-20}, {20,-20, 20}, {20,-20,-20}, {-20, 20, 20}, {-20, 20,-20}, {-20,-20, 20}, {-20,-20,-20} }; Edge cedges[12] = { {0, 1}, {1, 3}, {3, 2}, {2, 0}, {4, 5}, {5, 7}, {7, 6}, {6, 4}, {0, 4}, {1, 5}, {2, 6}, {3, 7}}; Gon cgons[6] = { {{3, 2, 1, 0}}, {{4, 5, 6, 7}}, {{0, 9, 4, 8}}, {{2,10, 6,11}}, {{3, 8, 7,10}}, {{1,11, 5, 9}} }; /* The tetrahedron. */ Vert tverts[4] = { {0, 0, 36}, {34, 0, -12}, {-17, 29,-12}, {-17,-29,-12} }; Edge tedges[6] = { {0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3} }; Gon tgons[4] = { {{0, 3, 1,-1}}, {{4, 0, 2,-1}}, {{1, 5, 2,-1}}, {{5, 3, 4,-1}} }; /* The truncated cube. */ Vert uverts[12] = { {20, 20, 0}, {20, 0, 20}, {20,-20, 0}, {20, 0,-20}, {0,-20,-20}, {-20,0,-20}, {0, 20,-20}, {-20,20, 0}, {0, 20, 20}, {-20,0, 20}, {0,-20, 20}, {-20,-20,0} }; Edge uedges[24] = { {0, 1}, {1, 2}, {2, 3}, {3, 0}, {3, 4}, {4, 5}, {5, 6}, {6, 3}, {6, 7}, {7, 8}, {8, 0}, {0, 6}, {8, 9}, {9,10},{10, 1}, {1, 8}, {10,11},{11, 4}, {4, 2}, {2,10}, {11, 9}, {9, 7}, {7, 5}, {5,11} }; Gon ugons[14] = { {{ 0, 1, 2, 3}}, {{ 4, 5, 6, 7}}, {{ 8, 9, 10, 11}}, {{12, 13, 14, 15}}, {{16, 17, 18, 19}}, {{20, 21, 22, 23}}, {{ 0, 10, 15, -1}}, {{16, 13, 20, -1}}, {{ 4, 2, 18, -1}}, {{19, 1, 14, -1}}, {{17, 23, 5, -1}}, {{ 3, 7, 11, -1}}, {{12, 9, 21, -1}}, {{ 6, 22, 8, -1}} }; /* Scale and 3-D rotate an array of vertices. */ void transform(Shape* shape, Fixed rx, Fixed ry, Fixed sc, Vert* xformed) { Short vi; Fixed sx = fsin(rx), sy = fsin(ry); Fixed cx = fcos(rx), cy = fcos(ry); Fixed x, y, z, nx, ny, nz; for (vi = 0; vi < shape->nverts; vi++) { /* Apply the scaling factor. */ x = fmul(intf(shape->verts[vi].x), sc); y = fmul(intf(shape->verts[vi].y), sc); z = fmul(intf(shape->verts[vi].z), sc); /* Do the rotation. */ nx = fmul(x, cx) - fmul(z, sx); ny = y; nz = fmul(z, cx) + fmul(x, sx); xformed[vi].x = fint(nx); xformed[vi].y = fint(fmul(ny, cy) + fmul(nz, sy)); xformed[vi].z = fint(fmul(nz, cy) - fmul(ny, sy)); } } /* Draw a shape, given its transformed vertices. */ void draw(Shape* shape, Vert* xformed, Short mode) { Short gi, ei, a, b, p, q, r, s; Fixed ax, ay, bx, by; RectangleType rect = { { 0, 12 }, { 156, 146 } }; Byte draw[25]; if (mode != modeWire) { /* Check for hidden edges. */ for (ei = 0; ei < shape->nedges; ei++) draw[ei+1] = 0; for (gi = 0; gi < shape->ngons; gi++) { a = shape->gons[gi].e[0]; b = shape->gons[gi].e[1]; p = shape->edges[a].a; q = shape->edges[a].b; r = shape->edges[b].a; s = shape->edges[b].b; /* The first edge vector for this polygon. */ ax = xformed[q].x - xformed[p].x; ay = xformed[q].y - xformed[p].y; /* The second edge vector for this polygon. */ bx = xformed[s].x - xformed[r].x; by = xformed[s].y - xformed[r].y; /* Their cross product is the normal vector. */ if (ax * by - bx * ay > 0) for (ei = 0; ei < 4; ei++) draw[shape->gons[gi].e[ei]+1] = 1; } } /* Clear the drawing area. */ WinEraseRectangle(&rect, 0); /* Draw the edges. */ WinSetClip(&rect); for (ei = 0; ei < shape->nedges; ei++) { a = shape->edges[ei].a; b = shape->edges[ei].b; p = 78 + xformed[a].x; q = 84 - xformed[a].y; r = 78 + xformed[b].x; s = 84 - xformed[b].y; if (draw[ei+1] || mode == modeWire) WinDrawLine(p, q, r, s); else if (mode == modeDotted) WinDrawGrayLine(p, q, r, s); } WinResetClip(); } /* Remember the drawing mode, shape, and its position between invocations. */ typedef struct { Fixed dx, dy, rx, ry, sc; Short si, mode; } PrefType; DWord PilotMain(Word cmd, Ptr cmdPBP, Word launchflags) { Word err; EventType evt; PrefType prefs; Fixed dx = 0, dy = 0, ds = 0, rx = 0, ry = 0, sc = intf(1); Byte redraw, si = shapeOcta, mode = modeWire; Short lastx, lasty; DWord keystate; WinHandle mainwindow = 0; Vert xformed[12]; Shape tetra = { 4, 6, 4, tverts, tedges, tgons }; Shape cube = { 8, 12, 6, cverts, cedges, cgons }; Shape octa = { 6, 12, 8, overts, oedges, ogons }; Shape trunc = { 12, 24, 14, uverts, uedges, ugons }; Shape* shape[4] = { &tetra, &cube, &octa, &trunc }; if (cmd != sysAppLaunchCmdNormalLaunch) return 0; /* Get saved preferences. */ if (PrefGetAppPreferences(APPID, APPVER, &prefs, sizeof(prefs))) { dx = prefs.dx; dy = prefs.dy; rx = prefs.rx; ry = prefs.ry; sc = prefs.sc; mode = prefs.mode; si = prefs.si; } FrmGotoForm(fidMain); while (1) { EvtGetEvent(&evt, 2); if (SysHandleEvent(&evt)) continue; if (MenuHandleEvent(NULL, &evt, &err)) continue; if (evt.eType == frmLoadEvent) FrmSetActiveForm(FrmInitForm(evt.data.frmLoad.formID)); if (evt.eType == frmOpenEvent) { FrmDrawForm(FrmGetActiveForm()); mainwindow = WinGetDrawWindow(); redraw = 1; } /* Handle the up/down keys. */ keystate = KeyCurrentState(); if (keystate & keyBitPageUp) ds = 5; else if (keystate & keyBitPageDown) ds = -5; else ds = 0; /* Handle menu selections or Graffiti strokes. */ if (evt.eType == menuEvent || evt.eType == keyDownEvent) { switch (evt.data.menu.itemID) /* same as evt.data.keyDown.chr */ { case 'a': case 'A': case iidAbout: FrmAlert(aidAbout); break; case 'r': case 'R': case iidReset: dx = dy = rx = ry = 0; sc = 256; redraw = 1; break; case 't': case 'T': case iidTetra: si = shapeTetra; redraw = 1; break; case 'c': case 'C': case iidCube: si = shapeCube; redraw = 1; break; case 'o': case 'O': case iidOcta: si = shapeOcta; redraw = 1; break; case 'u': case 'U': case iidTrunc: si = shapeTrunc; redraw = 1; break; case 'w': case 'W': case iidWire: mode = modeWire; redraw = 1; break; case 'd': case 'D': case iidDotted: mode = modeDotted; redraw = 1; break; case 'h': case 'H': case iidHidden: mode = modeHidden; redraw = 1; break; } } if (evt.eType == appStopEvent) break; if (FrmHandleEvent(FrmGetActiveForm(), &evt)) continue; if (evt.eType == penDownEvent) { lastx = evt.screenX; lasty = evt.screenY; } if (evt.eType == penMoveEvent) { /* Ignore small jitters in the digitizer. */ if (evt.screenX < lastx-1 || evt.screenX > lastx+1 || evt.screenY < lasty-1 || evt.screenY > lasty+1) { dx = (lastx - evt.screenX) << 2; dy = (lasty - evt.screenY) << 2; lastx = evt.screenX; lasty = evt.screenY; } else dx = dy = 0; } if ((dx || dy || ds || redraw) && (WinGetDrawWindow() == mainwindow)) { /* Compute the new rotation and scale values. */ rx += dx; if (rx < -804) rx += 1608; if (rx > 804) rx -= 1608; ry += dy; if (ry < -804) ry += 1608; if (ry > 804) ry -= 1608; sc += ds; if (sc < 1) sc = 1; if (sc > 500) sc = 500; transform(shape[si], rx, ry, sc, xformed); draw(shape[si], xformed, mode); redraw = 0; } } /* Save preferences on exit. */ prefs.dx = dx; prefs.dy = dy; prefs.rx = rx; prefs.ry = ry; prefs.sc = sc; prefs.mode = mode; prefs.si = si; PrefSetAppPreferences(APPID, APPVER, &prefs, sizeof(prefs)); }