/*---------------------------------------------------------------------------- * m.c * * This file starts the program and opens the screen and window. *---------------------------------------------------------------------------- */ #include #include #include #include #include "defs.h" #include "ds.h" extern BOOL OpenWorkBench(), CloseWorkBench() ; extern struct Menu *first_menu ; extern struct View *ViewAddress() ; /* pointers to op sys libraries */ struct IntuitionBase *IntuitionBase = NULL ; struct GfxBase *GfxBase = NULL ; int MathBase = NULL ; int MathTransBase = NULL ; /* pointers to custom screen and window opened and used by the program */ struct Screen *screen = NULL, *OpenScreen() ; struct Window *window = NULL, *OpenWindow() ; /* text font in use */ struct TextAttr prog_font = { "topaz.font", /* font name */ 8, /* height of font */ FS_NORMAL, /* font style */ FPF_ROMFONT /* font is in ROM */ } ; /* Information used to set up a work area for the ROM graphic routines. */ /* These structures are shared by the window temporary drawing area */ /* and the the 2 screen (double buffered) rastports and bitmaps */ PLANEPTR rastptr = NULL ; UWORD areabuffer [500] ; struct TmpRas tmpras ; struct AreaInfo areainfo ; /* information needed to set up double buffering in the screen */ struct View *v = NULL ; struct ViewPort *vp = NULL ; struct RasInfo *ri = NULL ; struct RastPort rp, rp2 ; struct BitMap b, b2 ; /* color information used to load the color registers */ COLORTABLE colortable = /* default colors */ { {GREY, RED, WHITE, BLUE, ORANGE, GREEN, PURPLE, DARK_BLUE}, /* set1 colors */ {GREY1, RED1, WHITE1, BLUE1, ORANGE1, GREEN1, PURPLE1, DARK_BLUE1}, /* set2 colors */ {GREY2, RED2, WHITE2, BLUE2, ORANGE2, GREEN2, PURPLE2, DARK_BLUE2}, /* set3 colors */ {GREY3, RED3, WHITE3, BLUE3, ORANGE3, GREEN3, PURPLE3, DARK_BLUE3}, /* colors to clear the screen to background */ {BACKGROUND_COLOR, BACKGROUND_COLOR, BACKGROUND_COLOR, BACKGROUND_COLOR, BACKGROUND_COLOR, BACKGROUND_COLOR, BACKGROUND_COLOR, BACKGROUND_COLOR} } ; /* declaration of the arm data structure */ ARM arm ; /* FFP constants */ FFP_CONSTANTS ffp ; /* viewing transformations available - precalculated at start of program */ /* - based on a viewpoint specified as a point in world space */ VIEW_TRANS view_trans ; /* store rotation information for each link */ ROTATION_INFO rot_info ; /* reference axes coordinate positions */ REF_AXES ref_axes [NUM_LINKS] ; /* record of current user selected menu items */ /* initialized to default values */ MENU_CHOICES menu_choices = { WIRE_FRAME, /* type of rendering */ ANGLE1_VIEW, /* default viewpoint */ PARALLEL, /* persective type */ ROTATE, /* type of animation */ START, /* color setting */ OFF /* ref axes setting */ } ; main () { /*-------------------------------------------------------------------------- * Open the required system libraries. Open a custom screen and a window * on the screen. Initialize a graphics work area, viewing transformations, * and rotation information. The input float vertex coordinates are * transferred to FFP format for the duration of the program. * Call "get_input()" to await user input. *-------------------------------------------------------------------------- */ open_libraries () ; allocate_double_buffer_bitmaps () ; make_screen () ; make_window () ; CloseWorkBench () ; initialize_requesters () ; setup_screen_temporary_draw_areas () ; setup_window_temporary_draw_area () ; init_FFP_constants () ; init_arm_data () ; convert_arm_data_to_FFP () ; initialize_link_rotation_info () ; initialize_viewing_transformations () ; init_flypast_trans () ; get_input () ; } open_libraries () { /*--------------------------------------------------------------------------- * Open required system libraries. *--------------------------------------------------------------------------- */ IntuitionBase = (struct IntuitionBase *) OpenLibrary ("intuition.library", INTUITION_REV) ; if (IntuitionBase == NULL) close_down ("Error: Could not open intuition library\n") ; GfxBase = (struct GfxBase *) OpenLibrary ("graphics.library", GRAPHICS_REV) ; if (GfxBase == NULL) close_down ("Error: Could not open graphics library\n") ; MathBase = OpenLibrary ("mathffp.library", MATH_REV) ; if (MathBase == NULL) close_down ("Error: Could not open mathffp library\n") ; MathTransBase = OpenLibrary ("mathtrans.library", MATHTRANS_REV) ; if (MathTransBase == NULL) close_down ("Error: Could not open mathtrans library\n") ; } make_screen () { /*--------------------------------------------------------------------------- * Setup a screen data structure and call OpenScreen() to open a custom * screen. The NewScreen data structure is not required once the screen is * open, ie. it disappears on the program stack. * Since double buffering is being used, a custom bitmap is connected to the * screen. * Load "background" colors into all relevant color registers to ease the * transition from custom screen to window. *--------------------------------------------------------------------------- */ struct NewScreen NewScreen ; NewScreen.LeftEdge = 0 ; NewScreen.TopEdge = 0 ; NewScreen.Width = WIDTH ; NewScreen.Height = HEIGHT ; NewScreen.Depth = DEPTH ; NewScreen.DetailPen = COLOR2 ; NewScreen.BlockPen = COLOR1 ; NewScreen.ViewModes = HIRES ; /* 640 x 200 pixel screen */ NewScreen.Type = CUSTOMSCREEN | CUSTOMBITMAP ; NewScreen.Font = &prog_font ; NewScreen.DefaultTitle = " Double Buffered Animation Screen" ; NewScreen.Gadgets = NULL ; NewScreen.CustomBitMap = &b ; if ((screen = OpenScreen (&NewScreen)) == NULL) close_down ("Error: Could not open Custom Screen - memory shortage?\n") ; LoadRGB4 (&screen->ViewPort, colortable.clr_screen, NUM_COLORS) ; SetRast (&screen->RastPort, COLOR0) ; SetRast (&rp2, COLOR0) ; ShowTitle (screen, FALSE) ; /* info used later to swap screen bitmaps for double buffering */ v = ViewAddress () ; vp = &screen->ViewPort ; ri = vp->RasInfo ; } make_window () { /*--------------------------------------------------------------------------- * Open a window on the screen. Set up the window menus and load the * color registers with the values to be used by the program. *--------------------------------------------------------------------------- */ struct NewWindow NewWindow ; NewWindow.LeftEdge = 0 ; NewWindow.TopEdge = 0 ; NewWindow.Width = WIDTH ; NewWindow.Height = HEIGHT ; NewWindow.DetailPen = COLOR1 ; NewWindow.BlockPen = COLOR2 ; NewWindow.Title = " Animation Setup Window" ; NewWindow.Flags = ACTIVATE | SMART_REFRESH | NOCAREREFRESH | GIMMEZEROZERO ; NewWindow.IDCMPFlags = MENUPICK | GADGETUP ; NewWindow.Type = CUSTOMSCREEN ; NewWindow.FirstGadget = NULL ; NewWindow.CheckMark = NULL ; NewWindow.Screen = screen ; NewWindow.BitMap = NULL ; NewWindow.MinWidth = 0 ; NewWindow.MinHeight = 0 ; NewWindow.MaxWidth = 0 ; NewWindow.MaxHeight = 0 ; if ((window = OpenWindow (&NewWindow)) == NULL) close_down ("Error: Could not open Window - memory shortage?\n") ; fill_in_menu_item_text () ; SetMenuStrip (window, first_menu) ; switch (menu_choices.colors) { case START: LoadRGB4 (&screen->ViewPort, colortable.start, NUM_COLORS) ; break ; case SET1: LoadRGB4 (&screen->ViewPort, colortable.set1, NUM_COLORS) ; break ; case SET2: LoadRGB4 (&screen->ViewPort, colortable.set2, NUM_COLORS) ; break ; case SET3: LoadRGB4 (&screen->ViewPort, colortable.set3, NUM_COLORS) ; break ; default: close_down ("Error: \"make_window\" - bad color menu choice\n"); break ; } } close_down (message) char *message ; { int i ; /*--------------------------------------------------------------------------- * Close down the program. Free all dynamically allocated memory, and * close all opened libraries etc. If the shut down is due to a system * problem print a message to this effect on the standard error output. *--------------------------------------------------------------------------- */ if (rastptr) FreeRaster (rastptr, WIDTH, HEIGHT) ; if (window) ClearMenuStrip (window) ; if (window) CloseWindow (window) ; if (screen) CloseScreen (screen) ; for ( i = 0; i < DEPTH; ++i) { if (b2.Planes [i]) FreeRaster (b2.Planes[i], WIDTH, HEIGHT) ; if (b.Planes [i]) FreeRaster (b.Planes[i], WIDTH, HEIGHT) ; } if (IntuitionBase) CloseLibrary (IntuitionBase) ; if (GfxBase) CloseLibrary (GfxBase) ; if (MathBase) CloseLibrary (MathBase) ; if (MathTransBase) CloseLibrary (MathTransBase) ; if (message) fprintf (stderr, message) ; OpenWorkBench () ; exit (!!message) ; } allocate_double_buffer_bitmaps () { int i ; /*--------------------------------------------------------------------------- * Allocate memory for 2 sets of bitplanes for a double buffered Intuition * screen. Set up a rastport for each bitplane set. Rastports coordinate * drawing information for the bitplane sets. *--------------------------------------------------------------------------- */ InitBitMap (&b, DEPTH, WIDTH, HEIGHT) ; InitBitMap (&b2, DEPTH, WIDTH, HEIGHT) ; for (i = 0; i < DEPTH; ++i) { b.Planes [i] = (PLANEPTR) AllocRaster (WIDTH, HEIGHT) ; if (b.Planes [i] == NULL) close_down ("Error: Not enough memory for double buffered screen\n") ; b2.Planes [i] = (PLANEPTR) AllocRaster (WIDTH, HEIGHT) ; if (b2.Planes [i] == NULL) close_down ("Error: Not enough memory for double buffered screen\n") ; } /* set up a rastport for each set of bitmaps */ InitRastPort (&rp) ; rp.BitMap = &b ; InitRastPort (&rp2) ; rp2.BitMap = &b2 ; } setup_screen_temporary_draw_areas () { /*--------------------------------------------------------------------------- * The area fill draw routines require a temporary workspace. * Allocate memory for one and allow both screen rastports to use it, since * they will never both require access to it at the same time. *--------------------------------------------------------------------------- */ SetDrMd (&rp, JAM1) ; SetOPen (&rp, COLOR7) ; SetDrMd (&rp2, JAM1) ; SetOPen (&rp2, COLOR7) ; InitArea (&areainfo, areabuffer, 200) ; rastptr = (PLANEPTR) AllocRaster (WIDTH, HEIGHT) ; if (rastptr == NULL) close_down ("Error: Not enough memory for db temp drawing area\n") ; InitTmpRas (&tmpras, rastptr, RASSIZE (WIDTH, HEIGHT)) ; rp.AreaInfo = rp2.AreaInfo = &areainfo ; rp.TmpRas = rp2.TmpRas = &tmpras ; } setup_window_temporary_draw_area () { /*--------------------------------------------------------------------------- * As above. The window rastport shares the same temporoary work area. *--------------------------------------------------------------------------- */ SetDrMd (window->RPort, JAM1) ; SetOPen (window->RPort, COLOR7) ; window->RPort->AreaInfo = &areainfo ; window->RPort->TmpRas = &tmpras ; } draw_image (rp) struct RastPort *rp ; { /*--------------------------------------------------------------------------- * Decide whether to draw a wire frame or solid view, and whether to * display the reference axes. *--------------------------------------------------------------------------- */ SetRast (rp, COLOR0) ; switch (menu_choices.render) { case WIRE_FRAME: draw_wire_frame_arm (rp) ; break ; case SOLID_VIEW: draw_solid_arm (rp) ; break ; } if (menu_choices.ref_axes == ON) draw_ref_axes (rp) ; } draw_ref_axes (rp) struct RastPort *rp ; { int i ; /*--------------------------------------------------------------------------- * Draw the current reference axes on the screen. The endpoints of axes * AXES_LENGTH away from a joint origin are transformed (along with the * origin) so that perspective joint axes positions are always available. *--------------------------------------------------------------------------- */ SetDrMd (rp, JAM2) ; SetAPen (rp, COLOR1) ; SetBPen (rp, COLOR2) ; for (i = 0; i < NUM_LINKS; ++i) { Move (rp, ref_axes [i].scrn_x [ORIGIN], ref_axes [i].scrn_y [ORIGIN]) ; Draw (rp, ref_axes [i].scrn_x [X], ref_axes [i].scrn_y [X]) ; Text (rp, "x", 1) ; Move (rp, ref_axes [i].scrn_x [ORIGIN], ref_axes [i].scrn_y [ORIGIN]) ; Draw (rp, ref_axes [i].scrn_x [Y], ref_axes [i].scrn_y [Y]) ; Text (rp, "y", 1) ; Move (rp, ref_axes [i].scrn_x [ORIGIN], ref_axes [i].scrn_y [ORIGIN]) ; Draw (rp, ref_axes [i].scrn_x [Z], ref_axes [i].scrn_y [Z]) ; Text (rp, "z", 1) ; } SetDrMd (rp, JAM1) ; } start_over () { /*--------------------------------------------------------------------------- * Called when the user selects "new" on the Project menu. * Reset all original parameters and redraw the initial display. *--------------------------------------------------------------------------- */ SetRast (window->RPort, COLOR0) ; ClearMenuStrip (window) ; reinitialize_menus () ; SetMenuStrip (window, first_menu) ; menu_choices.render = WIRE_FRAME ; menu_choices.viewpoint = ANGLE1_VIEW ; menu_choices.viewtype = PARALLEL ; menu_choices.goaltype = ROTATE ; menu_choices.colors = START ; menu_choices.ref_axes = OFF ; LoadRGB4 (&screen->ViewPort, colortable.start, NUM_COLORS) ; reinitialize_angle_pots () ; initialize_link_rotation_info () ; rot_info.curr_view_trans = (int *) &view_trans.angle1 ; transform_links () ; set_screen_coords () ; draw_image (window->RPort) ; } init_FFP_constants () { /*--------------------------------------------------------------------------- * Store frequently used float constants in a form that can be used by the * much faster Motorola FFP routines. *--------------------------------------------------------------------------- */ ffp.zero.f = 0.0 ; ffp.zero.i = SPFieee (ffp.zero.i) ; ffp.one.f = 1.0 ; ffp.one.i = SPFieee (ffp.one.i) ; ffp.neg_one.f = -1.0 ; ffp.neg_one.i = SPFieee (ffp.neg_one.i) ; ffp.two.f = 2.0 ; ffp.two.i = SPFieee (ffp.two.i) ; ffp.screen_scale_x.f = SCREEN_SCALE_X ; ffp.screen_scale_x.i = SPFieee (ffp.screen_scale_x.i) ; ffp.incr_z [0].f = 0.0 ; ffp.incr_z [0].i = SPFieee (ffp.incr_z [0].i) ; ffp.incr_z [1].f = 72.0 ; ffp.incr_z [1].i = SPFieee (ffp.incr_z [1].i) ; ffp.incr_z [2].f = 124.0 ; ffp.incr_z [2].i = SPFieee (ffp.incr_z [2].i) ; ffp.test_pt [0].f = 0.0 ; ffp.test_pt [0].i = SPFieee (ffp.test_pt [0].i) ; ffp.test_pt [1].f = 0.0 ; ffp.test_pt [1].i = SPFieee (ffp.test_pt [1].i) ; ffp.test_pt [2].f = -1.0 ; ffp.test_pt [2].i = SPFieee (ffp.test_pt [2].i) ; ffp.test_pt [3].f = 0.0 ; ffp.test_pt [3].i = SPFieee (ffp.test_pt [3].i) ; ffp.telephoto_aperture.f = TELEPHOTO_APERTURE ; ffp.telephoto_aperture.i = SPFieee ( ffp.telephoto_aperture.i ) ; ffp.wide_angle_aperture.f = WIDE_ANGLE_APERTURE ; ffp.wide_angle_aperture.i = SPFieee ( ffp.wide_angle_aperture.i ) ; ffp.large_num.f = 1000000.0 ; ffp.large_num.i = SPFieee (ffp.large_num.i) ; ffp.small_num.f = -1000000.0 ; ffp.small_num.i = SPFieee (ffp.small_num.i) ; ffp.screen_fill_x.f = SCREEN_FILL_X ; ffp.screen_fill_x.i = SPFieee (ffp.screen_fill_x.i) ; ffp.screen_fill_y.f = SCREEN_FILL_Y ; ffp.screen_fill_y.i = SPFieee (ffp.screen_fill_y.i) ; ffp.pi.f = 3.1415926 ; ffp.pi.i = SPFieee (ffp.pi.i) ; ffp.one_eighty.f = 180.0 ; ffp.one_eighty.i = SPFieee (ffp.one_eighty.i) ; ffp.radians = SPDiv (ffp.one_eighty.i, ffp.pi.i) ; ffp.min_angle_change.f = MIN_ANGLE_CHANGE ; ffp.min_angle_change.i = SPFieee (ffp.min_angle_change.i) ; ffp.axes_length.f = AXES_LENGTH ; ffp.axes_length.i = SPFieee (ffp.axes_length.i) ; } convert_arm_data_to_FFP () { LINK_PTR l ; FACE_PTR f ; POINT_PTR p ; FFP_POINT_PTR fp ; FFP temp ; float *c ; int *c1, i, j, k, n ; /*--------------------------------------------------------------------------- * Store the input float arm vertices in FFP format. These will be used * throughout the program instead of the original float values. *--------------------------------------------------------------------------- */ l = &arm.link [UPPER] ; for (k = 0; k < NUM_LINKS; ++k) { init_ref_coords (k) ; f = &l->face[0] ; for (i = 0; i < l->num_faces; ++i) { p = &f->vertex [0] ; fp = &f->ffp_orig_vertex [0] ; for (j = 0; j < f->num_vertices; ++j) { c = (float *) p++ ; c1 = (int *) fp++ ; for (n = X; n <= W; ++n) { temp.f = *(c+n) ; temp.i = SPFieee (temp.i) ; if (n == Z) *(c1+n) = SPAdd (temp.i, ffp.incr_z [k].i) ; else *(c1+n) = temp.i ; } } ++f ; } ++l ; } } init_ref_coords (link) int link ; { int i ; /*--------------------------------------------------------------------------- * Initialize the reference axes coordinates. Each "unit" axis vector is * AXES_LENGTH long. These axes will be transformed along with the arm * vertex points and can be displayed on request. *--------------------------------------------------------------------------- */ for (i = X; i <= ORIGIN; ++i) ref_axes [link].orig_coord [i][W] = ffp.one.i ; ref_axes [link].orig_coord [ORIGIN][X] = ffp.zero.i ; ref_axes [link].orig_coord [ORIGIN][Y] = ffp.zero.i ; ref_axes [link].orig_coord [ORIGIN][Z] = ffp.incr_z [link].i ; ref_axes [link].orig_coord [X][X] = ffp.axes_length.i ; ref_axes [link].orig_coord [X][Y] = ffp.zero.i ; ref_axes [link].orig_coord [X][Z] = ffp.incr_z [link].i ; ref_axes [link].orig_coord [Y][X] = ffp.zero.i ; ref_axes [link].orig_coord [Y][Y] = ffp.axes_length.i ; ref_axes [link].orig_coord [Y][Z] = ffp.incr_z [link].i ; ref_axes [link].orig_coord [Z][X] = ffp.zero.i ; ref_axes [link].orig_coord [Z][Y] = ffp.zero.i ; ref_axes [link].orig_coord [Z][Z] = SPAdd (ffp.incr_z [link].i, ffp.axes_length.i) ; }