| /* |
| * Easygl Version 2.0.1 |
| * Written by Vaughn Betz at the University of Toronto, Department of * |
| * Electrical and Computer Engineering, with additions by Paul Leventis * |
| * and William Chow of Altera, and Guy Lemieux of the University of * |
| * Brish Columbia. * |
| * All rights reserved by U of T, etc. * |
| * * |
| * You may freely use this graphics interface for non-commercial purposes * |
| * as long as you leave the author info above in it. |
| * * |
| * Revision History: * |
| * * |
| * V2.0.1 Sept. 2012 (Vaughn Betz) |
| * - Fixed a bug in Win32 where postscript output would make the graphics |
| * crash when you redrew. |
| * - Made a cleaner makefile to simplify platform selection. |
| * - Commented and reorganized some of the code. Started cleaning up some of the |
| * win32 code. Win32 looks inefficient; it is saving and updating graphics contexts |
| * all the time even though we know when the context is valid vs. not-valid. |
| * TODO: make win32 work more like X11 (minimize gc updates). |
| * |
| * V2.0: Nov. 21, 2011 (Vaughn Betz) |
| * - Updated example code, and some cleanup and bug fixes to win32 code. |
| * - Removed some win32 code that had no X11 equivalent or wasn't well |
| * documented. |
| * - Used const char * where appropriate to get rid of g++ warnings. |
| * - Made interface to things like xor drawing more consistent, and added to |
| * example program. |
| * - Made a simpler (easygl.cpp) interface to the graphics library for |
| * use by undergraduate students. |
| * |
| * V1.06 : July 23, 2003 : (Guy Lemieux) |
| * - added some typecasts to cleanly compile with g++ and MS c++ tools |
| * - if WIN32 not defined, it defines X11 automatically |
| * - fixed X11 compilation; WIN32 broke some things |
| * |
| * V1.05 : July 26, 2001 : (William) * |
| * - changed keyboard detect function to accept an int (virtual key) * |
| * * |
| * V1.04 : June 29, 2001 : (William) * |
| * - added drawcurve(), fillcurve() using Bezier curves * |
| * (support WIN32 screen / ps) * |
| * - added pt on object capability : using a memory buffer to draw an * |
| * graphics objects, then query if a point fall on the object (bear the * |
| * object's colour) : object_start(), object_end(), pt_on_object() * |
| * - added drawellipticarc(), fillellipticarc() * |
| * - added findfontsize() to help find a pointsize of a given height * |
| * - extended t_report to keep xleft, xright, ytop, ybot * |
| * - added update_window() to set the window bb * |
| * * |
| * V1.03 : June 18, 2001 : (William) * |
| * - added change_button_text() * |
| * * |
| * V1.02 : June 13, 2001 : (William) * |
| * - extension to mouse click function : can tell if ctrl/shift keys are * |
| * pressed * |
| * * |
| * V1.01 : June 1, 2001 : (William) * |
| * - add tooltip support * |
| * * |
| * V1.0 : May 14, 2001 : (William) * |
| * - fixed a problem with line styles, initial release on the internet * |
| * * |
| * March 27, 2001 : (William) * |
| * - added setcolor_by_colorref to make more colors available (in Win32) * |
| * * |
| * February 16, 2001 : (William) * |
| * - added quick zoom using right mouse clicks * |
| * * |
| * February 11, 2001 : (William) * |
| * - can define cleanup(), passed in when calling init_graphics(), and * |
| * called when shutting down * |
| * * |
| * February 1, 2001 : (William) * |
| * - fix xor mode redraw problem * |
| * * |
| * September 19, 2000 : (William) * |
| * - can define mouse_move callback function * |
| * - can add separators in between buttons * |
| * * |
| * September 8, 2000 : (William) * |
| * - added result_structure(), * |
| * - can define background color in init_graphics * |
| * * |
| * August 10, 2000 : (William Chow, choww@eecg.utoronto.ca) * |
| * - Finished all Win32 support functions * |
| * - use XOR mode for window zooming box * |
| * - added double buffering feature * |
| * * |
| * January 12, 1999: (Paul) * |
| * - Fixed a bunch of stuff with the Win32 support (memory leaks, etc) * |
| * - Made the clipping function using the update rectangle for Win32 * |
| * * |
| * January 9, 1999: (Paul Leventis, leventi@eecg.utoronto.ca) * |
| * - Added Win32 support. Should work under Windows98/95/NT 4.0/NT 5.0. * |
| * - Added a check to deselect_all to determine whether the screen needs to * |
| * be updated or not. Should elminate flicker from mouse clicks * |
| * - Added invalidate_screen() call to graphics.c that in turn calls * |
| * update_screen, so this function was made non-static and added to the * |
| * header file. This is due to differences in the structure of Win32 * |
| * windowing apps. * |
| * - Win32 needs clipping (though done automatically, could be faster) * |
| * * |
| * Sept. 19, 1997: Incorporated Zoom Fit code of Haneef Mohammed at * |
| * Cypress. Makes it easy to zoom to a full view of the graphics. * |
| * * |
| * Sept. 11, 1997: Added the create_and destroy_button interface to * |
| * make it easy to add and destroy buttons from user code. Removed the * |
| * bnum parameter to the button functions, since it wasn't really needed. * |
| * * |
| * June 28, 1997: Added filled arc drawing primitive. Minor modifications * |
| * to PostScript driver to make the PostScript output slightly smaller. * |
| * * |
| * April 15, 1997: Added code to init_graphics so it waits for a window * |
| * to be exposed before returning. This ensures that users of non- * |
| * interactive graphics can never draw to a window before it is available. * |
| * * |
| * Feb. 24, 1997: Added code so the package will allocate a private * |
| * colormap if the default colormap doesn't have enough free colours. * |
| * * |
| * June 28, 1996: Converted all internal functions in graphics.c to have * |
| * internal (static) linkage to avoid any conflicts with user routines in * |
| * the rest of the program. * |
| * * |
| * June 12, 1996: Added setfontsize and setlinewidth attributes. Added * |
| * pre-clipping of objects for speed (and compactness of PS output) when * |
| * graphics are zoomed in. Rewrote PostScript engine to shrink the output * |
| * and make it easier to read. Made drawscreen a callback function passed * |
| * in rather than a global. Graphics attribute calls are more efficient -- * |
| * they check if they have to change anything before doing it. * |
| * * |
| * October 27, 1995: Added the message area, a callback function for * |
| * interacting with user button clicks, and implemented a workaround for a * |
| * Sun X Server bug that misdisplays extremely highly zoomed graphics. * |
| * * |
| * Jan. 13, 1995: Modified to incorporate PostScript Support. */ |
| |
| #ifndef NO_GRAPHICS // Strip everything out and just put in stubs if NO_GRAPHICS defined |
| |
| /********************************** |
| * Common Preprocessor Directives * |
| **********************************/ |
| |
| #define TRUE 1 |
| #define FALSE 0 |
| |
| #include <math.h> |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <string.h> |
| #include <string> |
| #include <iostream> |
| #include "graphics.h" |
| using namespace std; |
| |
| |
| #if defined(X11) || defined(WIN32) |
| |
| /* Macros for translation from world to PostScript coordinates */ |
| #define XPOST(worldx) (((worldx)-xleft)*ps_xmult + ps_left) |
| #define YPOST(worldy) (((worldy)-ybot)*ps_ymult + ps_bot) |
| |
| /* Macros to convert from X Windows Internal Coordinates to my * |
| * World Coordinates. (This macro is used only rarely, so * |
| * the divides don't hurt speed). */ |
| #define XTOWORLD(x) (((float) x)*xdiv + xleft) |
| #define YTOWORLD(y) (((float) y)*ydiv + ytop) |
| |
| #ifndef max |
| #define max(a,b) (((a) > (b))? (a) : (b)) |
| #endif |
| #ifndef min |
| #define min(a,b) ((a) > (b)? (b) : (a)) |
| #endif |
| |
| #define MWIDTH 104 /* width of menu window */ |
| #define T_AREA_HEIGHT 24 /* Height of text window */ |
| #define MAX_FONT_SIZE 24 /* Largest point size of text. */ |
| // Some computers only have up to 24 point |
| #define PI 3.141592654 |
| |
| #define BUTTON_TEXT_LEN 100 |
| #define BUFSIZE 1000 |
| #endif |
| |
| /********************************************* |
| * X-Windows Specific Preprocessor Directives * |
| *********************************************/ |
| #ifdef X11 |
| |
| #include <X11/Xlib.h> |
| #include <X11/Xutil.h> |
| #include <X11/Xos.h> |
| #include <X11/Xatom.h> |
| |
| /* Uncomment the line below if your X11 header files don't define XPointer */ |
| /* typedef char *XPointer; */ |
| |
| // Really large pixel values cna make some X11 implementations draw crazy things |
| // (internal overflow in the X11 library). Use these constants to clip. |
| #define MAXPIXEL 15000 |
| #define MINPIXEL -15000 |
| |
| #endif /* X11 Preprocessor Directives */ |
| |
| |
| /************************************************************* |
| * Microsoft Windows (WIN32) Specific Preprocessor Directives * |
| *************************************************************/ |
| #ifdef WIN32 |
| #pragma warning(disable : 4996) // Turn off annoying warnings about strcmp. |
| |
| #include <windows.h> |
| |
| // Lines below are for displaying errors in a message box on windows. |
| #define SELECT_ERROR() { char msg[BUFSIZE]; sprintf (msg, "Error %i: Couldn't select graphics object on line %d of graphics.c\n", GetLastError(), __LINE__); MessageBox(NULL, msg, NULL, MB_OK); exit(-1); } |
| #define DELETE_ERROR() { char msg[BUFSIZE]; sprintf (msg, "Error %i: Couldn't delete graphics object on line %d of graphics.c\n", GetLastError(), __LINE__); MessageBox(NULL, msg, NULL, MB_OK); exit(-1); } |
| #define CREATE_ERROR() { char msg[BUFSIZE]; sprintf (msg, "Error %i: Couldn't create graphics object on line %d of graphics.c\n", GetLastError(), __LINE__); MessageBox(NULL, msg, NULL, MB_OK); exit(-1); } |
| #define DRAW_ERROR() { char msg[BUFSIZE]; sprintf (msg, "Error %i: Couldn't draw graphics object on line %d of graphics.c\n", GetLastError(), __LINE__); MessageBox(NULL, msg, NULL, MB_OK); exit(-1); } |
| |
| /* Avoid funny clipping problems under windows that I suspect are caused by round-off |
| * in the Win32 libraries. |
| */ |
| #define MAXPIXEL 3000 |
| #define MINPIXEL -3000 |
| |
| #define DEGTORAD(x) ((x)/180.*PI) |
| #define FONTMAG 1.3 |
| #endif /* Win32 preprocessor Directives */ |
| |
| |
| /************************************************************* |
| * Common Type Definitions * |
| *************************************************************/ |
| |
| /* Used to define where the output of drawscreen (graphics primitives in the user-controlled |
| * area) currently goes to: the screen or a postscript file. |
| */ |
| typedef enum { |
| SCREEN = 0, |
| POSTSCRIPT = 1 |
| } t_display_type; |
| |
| |
| /* Indicates if this button displays text, a polygon or is just a separator. |
| */ |
| typedef enum { |
| BUTTON_TEXT = 0, |
| BUTTON_POLY, |
| BUTTON_SEPARATOR |
| } t_button_type; |
| |
| |
| /* Structure used to define the buttons on the right hand side of the main window (menu region). |
| * width, height: button size, in pixels. |
| * xleft, ytop: coordinates, in pixels, of the top-left corner of the button relative to its |
| * containing (menu) window. |
| * fcn: a callback function that is called when the button is pressed. This function takes one |
| * argument, a function pointer to the routine that can draw the graphics area (user routine). |
| * win, hwnd: X11 and Win32 data pointer to the window, respectively. |
| * button_type: indicates if this button displays text, a polygon or is just a separator. |
| * text: the text to display if this is a text button. |
| * poly: the polygon (up to 3 points right now) to display if this is a polygon button |
| * is_pressed: has the button been pressed, and is currently executing its callback? |
| * is_enabled: can you press this button right now? Visually will look "pushed in" when |
| * not enabled, and won't respond to clicks. |
| */ |
| typedef struct { |
| int width; |
| int height; |
| int xleft; |
| int ytop; |
| void (*fcn) (void (*drawscreen) (void)); |
| #ifdef X11 |
| Window win; |
| #else |
| HWND hwnd; |
| #endif |
| t_button_type type; |
| char text[BUTTON_TEXT_LEN]; |
| int poly[3][2]; |
| bool ispressed; |
| bool enabled; |
| } t_button; |
| |
| |
| /* Structure used to store overall graphics state variables. |
| * TODO: Gradually move more file scope variables in here. |
| * initialized: true if the graphics window & state have been |
| * created and initialized, false otherwise. |
| * disp_type: Selects SCREEN or POSTSCRIPT |
| * background_cindex: index of the window (or page for PS) background colour |
| */ |
| typedef struct { |
| bool initialized; |
| int disp_type; |
| int background_cindex; |
| } t_gl_state; |
| |
| |
| /********************************************************************* |
| * File scope variables. TODO: group in structs * |
| *********************************************************************/ |
| |
| // Need to initialize graphics_loaded to false, since checking it is |
| // how we avoid multiple construction or destruction of the graphics |
| // window. |
| static t_gl_state gl_state = {false, SCREEN, 0}; |
| |
| static const int menu_font_size = 12; /* Font for menus and dialog boxes. */ |
| |
| static t_button *button = NULL; /* [0..num_buttons-1] */ |
| static int num_buttons = 0; /* Number of menu buttons */ |
| |
| static int display_width, display_height; /* screen size */ |
| static int top_width, top_height; /* window size */ |
| static float xleft, xright, ytop, ybot; /* world coordinates */ |
| static float saved_xleft, saved_xright, saved_ytop, saved_ybot; |
| |
| static float ps_left, ps_right, ps_top, ps_bot; /* Figure boundaries for * |
| * PostScript output, in PostScript coordinates. */ |
| static float ps_xmult, ps_ymult; /* Transformation for PostScript. */ |
| static float xmult, ymult; /* Transformation factors */ |
| static float xdiv, ydiv; |
| |
| static int currentcolor; |
| static int currentlinestyle; |
| static int currentlinewidth; |
| static int currentfontsize; |
| static e_draw_mode current_draw_mode; |
| |
| /* For PostScript output */ |
| static FILE *ps; |
| |
| static int ProceedPressed; |
| |
| static char statusMessage[BUFSIZE] = ""; /* User message to display */ |
| |
| static bool font_is_loaded[MAX_FONT_SIZE + 1]; |
| static bool get_keypress_input, get_mouse_move_input; |
| static const char *ps_cnames[NUM_COLOR] = {"white", "black", "grey55", "grey75", |
| "blue", "green", "yellow", "cyan", "red", "darkgreen", "magenta", |
| "bisque", "lightblue", "thistle", "plum", "khaki", "coral", |
| "turquoise", "mediumpurple", "darkslateblue", "darkkhaki"}; |
| |
| |
| /********************************************* |
| * Common Subroutine Declarations * |
| *********************************************/ |
| |
| static void *my_malloc(int ibytes); |
| static void *my_realloc(void *memblk, int ibytes); |
| static int xcoord (float worldx); |
| static int ycoord (float worldy); |
| static void force_setcolor(int cindex); |
| static void force_setlinestyle(int linestyle); |
| static void force_setlinewidth(int linewidth); |
| static void force_setfontsize (int pointsize); |
| static void load_font(int pointsize); |
| |
| static void reset_common_state (); |
| static void build_default_menu (void); |
| |
| /* Function declarations for button responses */ |
| static void translate_up (void (*drawscreen) (void)); |
| static void translate_left (void (*drawscreen) (void)); |
| static void translate_right (void (*drawscreen) (void)); |
| static void translate_down (void (*drawscreen) (void)); |
| static void zoom_in (void (*drawscreen) (void)); |
| static void zoom_out (void (*drawscreen) (void)); |
| static void zoom_fit (void (*drawscreen) (void)); |
| static void adjustwin (void (*drawscreen) (void)); |
| static void postscript (void (*drawscreen) (void)); |
| static void proceed (void (*drawscreen) (void)); |
| static void quit (void (*drawscreen) (void)); |
| static void map_button (int bnum); |
| static void unmap_button (int bnum); |
| |
| #ifdef X11 |
| |
| /************************************************* |
| * X-Windows Specific File-scope Variables * |
| **************************************************/ |
| static Display *display; |
| static int screen_num; |
| static GC gc, gcxor, gc_menus, current_gc; |
| static XFontStruct *font_info[MAX_FONT_SIZE+1]; /* Data for each size */ |
| static Window toplevel, menu, textarea; /* various windows */ |
| static Colormap private_cmap; /* "None" unless a private cmap was allocated. */ |
| |
| /* Color indices passed back from X Windows. */ |
| static int colors[NUM_COLOR]; |
| |
| |
| /**************************************************** |
| * X-Windows Specific Subroutine Declarations * |
| *****************************************************/ |
| |
| static Bool test_if_exposed (Display *disp, XEvent *event_ptr, |
| XPointer dummy); |
| static void build_textarea (void); |
| static void drawbut (int bnum); |
| static int which_button (Window win); |
| |
| static void turn_on_off (int pressed); |
| static void drawmenu(void); |
| |
| #endif /* X11 Declarations */ |
| |
| |
| |
| #ifdef WIN32 |
| |
| /***************************************************** |
| * Microsoft Windows (Win32) File Scope Variables * |
| *****************************************************/ |
| static const int win32_line_styles[2] = { PS_SOLID, PS_DASH }; |
| |
| static const COLORREF win32_colors[NUM_COLOR] = { RGB(255, 255, 255), |
| RGB(0, 0, 0), RGB(128, 128, 128), RGB(192, 192, 192), RGB(0, 0, 255), |
| RGB(0, 255, 0), RGB(255, 255, 0), RGB(0, 255, 255), RGB(255, 0, 0), RGB(0, 128, 0), |
| RGB(255, 0, 255), RGB(255, 228, 196), RGB(173, 216, 230), RGB(216, 191, 216), RGB(221, 160, 221), |
| RGB(240, 230, 140), RGB(255, 127, 80), RGB(64, 224, 208), RGB(147, 112, 219), RGB(72, 61, 139), |
| RGB(189, 183, 107)}; |
| |
| static TCHAR szAppName[256], |
| szGraphicsName[] = TEXT("VPR Graphics"), |
| szStatusName[] = TEXT("VPR Status"), |
| szButtonsName[] = TEXT("VPR Buttons"); |
| static HPEN hGraphicsPen; |
| static HBRUSH hGraphicsBrush, hGrayBrush; |
| static HDC hGraphicsDC, hForegroundDC, hBackgroundDC, |
| hCurrentDC, /* WC : double-buffer */ |
| hObjtestDC, hAllObjtestDC; /* object test */ |
| |
| /* WC */ |
| static HFONT hGraphicsFont; |
| static LOGFONT *font_info[MAX_FONT_SIZE+1]; /* Data for each size */ |
| |
| /* Handles to the top level window and 3 subwindows. */ |
| static HWND hMainWnd, hGraphicsWnd, hButtonsWnd, hStatusWnd; |
| |
| static int cxClient, cyClient; |
| |
| /* These are used for the "Window" graphics button. They keep track of whether we're entering |
| * the window rectangle to zoom to, etc. |
| */ |
| static int windowAdjustFlag = 0, adjustButton = -1; |
| static RECT adjustRect, updateRect; |
| |
| static boolean InEventLoop = FALSE; |
| |
| //static HBITMAP buttonImages[4]; |
| |
| |
| /******************************************************************* |
| * Win32-specific subroutine declarations * |
| *******************************************************************/ |
| |
| /* Callback functions for the top-level window and 3 sub-windows. |
| * Windows uses an odd mix of events and callbacks, so it needs these. |
| */ |
| static LRESULT CALLBACK GraphicsWND(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); |
| static LRESULT CALLBACK StatusWND(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); |
| static LRESULT CALLBACK ButtonsWND(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); |
| static LRESULT CALLBACK MainWND(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); |
| |
| |
| // For Win32, need to save pointers to these callback functions at file |
| // scope, since windows has a bizarre event loop structure where you poll |
| // for events, but then dispatch the event and get called via a callback |
| // from windows (GraphicsWND, below). I can't figure out why windows |
| // does things this way, but it is what makes saving these function pointers |
| // necessary. VB. |
| |
| static void (*mouseclick_ptr)(float x, float y); |
| static void (*mousemove_ptr)(float x, float y); |
| static void (*keypress_ptr)(char entered_char); |
| static void (*drawscreen_ptr)(void); |
| |
| static void invalidate_screen(); |
| |
| static void reset_win32_state (); |
| static void win32_drain_message_queue (); |
| |
| void drawtoscreen(); |
| void displaybuffer(); |
| |
| |
| #endif /* Win32 Declarations */ |
| |
| /********************************************************* |
| * Common Subroutine Definitions * |
| *********************************************************/ |
| |
| |
| /* safer malloc */ |
| static void *my_malloc(int ibytes) { |
| void *mem; |
| |
| mem = (void*)malloc(ibytes); |
| if (mem == NULL) { |
| printf("memory allocation failed!"); |
| exit(-1); |
| } |
| |
| return mem; |
| } |
| |
| /* safer realloc */ |
| static void *my_realloc(void *memblk, int ibytes) { |
| void *mem; |
| |
| mem = (void*)realloc(memblk, ibytes); |
| if (mem == NULL) { |
| printf("memory allocation failed!"); |
| exit(-1); |
| } |
| |
| return mem; |
| } |
| |
| |
| /* Translates from my internal coordinates to real-world coordinates * |
| * in the x direction. Add 0.5 at end for extra half-pixel accuracy. */ |
| static int xcoord (float worldx) |
| { |
| int winx; |
| |
| winx = (int) ((worldx-xleft)*xmult + 0.5); |
| |
| /* Avoids overflow in the Window routines. This will allow horizontal * |
| * and vertical lines to be drawn correctly regardless of zooming, but * |
| * will cause diagonal lines that go way off screen to change their * |
| * slope as you zoom in. The only way I can think of to completely fix * |
| * this problem is to do all the clipping in advance in floating point, * |
| * then convert to integers and call Windows. This is a lot of extra * |
| * coding, and means that coordinates will be clipped twice, even though * |
| * this "Super Zoom" problem won't occur unless users zoom way in on * |
| * the graphics. */ |
| |
| winx = max (winx, MINPIXEL); |
| winx = min (winx, MAXPIXEL); |
| |
| return (winx); |
| } |
| |
| |
| /* Translates from my internal coordinates to real-world coordinates * |
| * in the y direction. Add 0.5 at end for extra half-pixel accuracy. */ |
| static int ycoord (float worldy) |
| { |
| int winy; |
| |
| winy = (int) ((worldy-ytop)*ymult + 0.5); |
| |
| /* Avoid overflow in the X/Win32 Window routines. */ |
| winy = max (winy, MINPIXEL); |
| winy = min (winy, MAXPIXEL); |
| |
| return (winy); |
| } |
| |
| |
| #ifdef WIN32 |
| static void invalidate_screen(void) |
| { |
| /* Tells the graphics engine to redraw the graphics display since information has changed */ |
| |
| if(!InvalidateRect(hGraphicsWnd, NULL, FALSE)) |
| DRAW_ERROR(); |
| if(!UpdateWindow(hGraphicsWnd)) |
| DRAW_ERROR(); |
| } |
| #endif |
| |
| /* Sets the current graphics context colour to cindex, regardless of whether we think it is |
| * needed or not. |
| */ |
| static void force_setcolor (int cindex) |
| { |
| currentcolor = cindex; |
| |
| if (gl_state.disp_type == SCREEN) { |
| #ifdef X11 |
| XSetForeground (display, current_gc, colors[cindex]); |
| #else /* Win32 */ |
| int win_linestyle; |
| LOGBRUSH lb; |
| lb.lbStyle = BS_SOLID; |
| lb.lbColor = win32_colors[cindex]; |
| lb.lbHatch = (LONG)NULL; |
| win_linestyle = win32_line_styles[currentlinestyle]; |
| |
| if(!DeleteObject(hGraphicsPen)) |
| DELETE_ERROR(); |
| |
| int linewidth = max (currentlinewidth, 1); // Win32 won't draw 0 width dashed lines. |
| hGraphicsPen = ExtCreatePen(PS_GEOMETRIC | win_linestyle | |
| PS_ENDCAP_FLAT, linewidth, &lb, (LONG)NULL, NULL); |
| if(!hGraphicsPen) |
| CREATE_ERROR(); |
| |
| if(!DeleteObject(hGraphicsBrush)) |
| DELETE_ERROR(); |
| hGraphicsBrush = CreateSolidBrush(win32_colors[currentcolor]); |
| if(!hGraphicsBrush) |
| CREATE_ERROR(); |
| #endif |
| } |
| else { |
| fprintf (ps,"%s\n", ps_cnames[cindex]); |
| } |
| } |
| |
| |
| /* Sets the current graphics context colour to cindex if it differs from the old colour */ |
| void setcolor (int cindex) |
| { |
| if (currentcolor != cindex) |
| force_setcolor (cindex); |
| |
| } |
| |
| |
| /* Sets the current graphics context color to the index that corresponds to the |
| * string name passed in. Slower, but maybe more convenient for simple |
| * client code. |
| */ |
| void setcolor (string cname) { |
| int icolor = -1; |
| for (int i = 0; i < NUM_COLOR; i++) { |
| if (cname == ps_cnames[i]) { |
| icolor = i; |
| break; |
| } |
| } |
| if (icolor == -1) { |
| cout << "Error: unknown color " << cname << endl; |
| } |
| else { |
| setcolor (icolor); |
| } |
| } |
| |
| int getcolor() { |
| return currentcolor; |
| } |
| |
| /* Sets the current linestyle to linestyle in the graphics context. |
| * Note SOLID is 0 and DASHED is 1 for linestyle. |
| */ |
| static void force_setlinestyle (int linestyle) |
| { |
| currentlinestyle = linestyle; |
| |
| if (gl_state.disp_type == SCREEN) { |
| |
| #ifdef X11 |
| static int x_vals[2] = {LineSolid, LineOnOffDash}; |
| XSetLineAttributes (display, current_gc, currentlinewidth, x_vals[linestyle], |
| CapButt, JoinMiter); |
| #else // Win32 |
| LOGBRUSH lb; |
| lb.lbStyle = BS_SOLID; |
| lb.lbColor = win32_colors[currentcolor]; |
| lb.lbHatch = (LONG)NULL; |
| int win_linestyle = win32_line_styles[linestyle]; |
| |
| if(!DeleteObject(hGraphicsPen)) |
| DELETE_ERROR(); |
| int linewidth = max (currentlinewidth, 1); // Win32 won't draw 0 width dashed lines. |
| hGraphicsPen = ExtCreatePen(PS_GEOMETRIC | win_linestyle | |
| PS_ENDCAP_FLAT, linewidth, &lb, (LONG)NULL, NULL); |
| if(!hGraphicsPen) |
| CREATE_ERROR(); |
| #endif |
| } |
| |
| else { |
| if (linestyle == SOLID) |
| fprintf (ps,"linesolid\n"); |
| else if (linestyle == DASHED) |
| fprintf (ps, "linedashed\n"); |
| else { |
| printf ("Error: invalid linestyle: %d\n", linestyle); |
| exit (1); |
| } |
| } |
| } |
| |
| |
| /* Change the linestyle in the graphics context only if it differs from the current |
| * linestyle. |
| */ |
| void setlinestyle (int linestyle) |
| { |
| if (linestyle != currentlinestyle) |
| force_setlinestyle (linestyle); |
| } |
| |
| |
| /* Sets current linewidth in the graphics context. |
| * linewidth should be greater than or equal to 0 to make any sense. |
| */ |
| static void force_setlinewidth (int linewidth) |
| { |
| currentlinewidth = linewidth; |
| |
| if (gl_state.disp_type == SCREEN) { |
| |
| #ifdef X11 |
| static int x_vals[2] = {LineSolid, LineOnOffDash}; |
| XSetLineAttributes (display, current_gc, linewidth, x_vals[currentlinestyle], |
| CapButt, JoinMiter); |
| #else /* Win32 */ |
| LOGBRUSH lb; |
| lb.lbStyle = BS_SOLID; |
| lb.lbColor = win32_colors[currentcolor]; |
| lb.lbHatch = (LONG)NULL; |
| int win_linestyle = win32_line_styles[currentlinestyle]; |
| |
| if(!DeleteObject(hGraphicsPen)) |
| DELETE_ERROR(); |
| if (linewidth == 0) |
| linewidth = 1; // Win32 won't draw dashed 0 width lines. |
| hGraphicsPen = ExtCreatePen(PS_GEOMETRIC | win_linestyle | |
| PS_ENDCAP_FLAT, linewidth, &lb, (LONG)NULL, NULL); |
| if(!hGraphicsPen) |
| CREATE_ERROR(); |
| #endif |
| } |
| |
| else { |
| fprintf(ps,"%d setlinewidth\n", linewidth); |
| } |
| } |
| |
| |
| /* Sets the linewidth in the grahpics context, if it differs from the current value. |
| */ |
| void setlinewidth (int linewidth) |
| { |
| if (linewidth != currentlinewidth) |
| force_setlinewidth (linewidth); |
| } |
| |
| |
| /* Force the selected fontsize to be applied to the graphics context, |
| * whether or not it appears to match the current fontsize. This is necessary |
| * when switching between postscript and window out, for example. |
| * Valid point sizes are between 1 and MAX_FONT_SIZE. |
| */ |
| static void force_setfontsize (int pointsize) |
| { |
| |
| if (pointsize < 1) |
| pointsize = 1; |
| #ifdef WIN32 |
| pointsize = (int)((float)pointsize * FONTMAG); |
| #endif |
| if (pointsize > MAX_FONT_SIZE) |
| pointsize = MAX_FONT_SIZE; |
| |
| currentfontsize = pointsize; |
| |
| if (gl_state.disp_type == SCREEN) { |
| load_font (pointsize); |
| #ifdef X11 |
| XSetFont(display, current_gc, font_info[pointsize]->fid); |
| #else /* Win32 */ |
| if(!DeleteObject(hGraphicsFont)) |
| DELETE_ERROR(); |
| hGraphicsFont = CreateFontIndirect(font_info[pointsize]); |
| if(!hGraphicsFont) |
| CREATE_ERROR(); |
| if(!SelectObject(hGraphicsDC, hGraphicsFont) ) |
| SELECT_ERROR(); |
| |
| #endif |
| } |
| |
| else { |
| /* PostScript: set up font and centering function */ |
| fprintf(ps,"%d setfontsize\n",pointsize); |
| } |
| } |
| |
| |
| /* For efficiency, this routine doesn't do anything if no change is |
| * implied. If you want to force the graphics context or PS file |
| * to have font info set, call force_setfontsize (this is necessary |
| * in initialization and X11 / Postscript switches). |
| */ |
| void setfontsize (int pointsize) |
| { |
| |
| if (pointsize != currentfontsize) |
| force_setfontsize (pointsize); |
| } |
| |
| |
| /* Puts a triangle in the poly array for button[bnum]. Haven't made this work for |
| * win32 yet and instead put "U", "D" excetra on the arrow buttons. |
| * VB To-do: make work for win32 someday. |
| */ |
| #ifdef X11 |
| static void setpoly (int bnum, int xc, int yc, int r, float theta) |
| { |
| int i; |
| |
| button[bnum].type = BUTTON_POLY; |
| for (i=0;i<3;i++) { |
| button[bnum].poly[i][0] = (int) (xc + r*cos(theta) + 0.5); |
| button[bnum].poly[i][1] = (int) (yc + r*sin(theta) + 0.5); |
| theta += (float)(2*PI/3); |
| } |
| } |
| #endif // X11 |
| |
| |
| /* Maps a button onto the screen and set it up for input, etc. */ |
| static void map_button (int bnum) |
| { |
| button[bnum].ispressed = 0; |
| |
| if (button[bnum].type != BUTTON_SEPARATOR) { |
| #ifdef X11 |
| button[bnum].win = XCreateSimpleWindow(display,menu, |
| button[bnum].xleft, button[bnum].ytop, button[bnum].width, |
| button[bnum].height, 0, colors[WHITE], colors[LIGHTGREY]); |
| XMapWindow (display, button[bnum].win); |
| XSelectInput (display, button[bnum].win, ButtonPressMask); |
| #else |
| button[bnum].hwnd = CreateWindow( TEXT("button"), TEXT(button[bnum].text), |
| WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, button[bnum].xleft, button[bnum].ytop, |
| button[bnum].width, button[bnum].height, hButtonsWnd, (HMENU)(200+bnum), |
| (HINSTANCE) GetWindowLong(hMainWnd, GWL_HINSTANCE), NULL); |
| if(!InvalidateRect(hButtonsWnd, NULL, TRUE)) |
| DRAW_ERROR(); |
| if(!UpdateWindow(hButtonsWnd)) |
| DRAW_ERROR(); |
| #endif |
| } |
| else { // Separator, not a button. |
| #ifdef X11 |
| button[bnum].win = -1; |
| #else // WIN32 |
| button[bnum].hwnd = NULL; |
| if(!InvalidateRect(hButtonsWnd, NULL, TRUE)) |
| DRAW_ERROR(); |
| if(!UpdateWindow(hButtonsWnd)) |
| DRAW_ERROR(); |
| #endif |
| } |
| } |
| |
| |
| static void unmap_button (int bnum) |
| { |
| /* Unmaps (removes) a button from the screen. */ |
| if (button[bnum].type != BUTTON_SEPARATOR) { |
| #ifdef X11 |
| XUnmapWindow (display, button[bnum].win); |
| #else |
| if(!DestroyWindow(button[bnum].hwnd)) |
| DRAW_ERROR(); |
| if(!InvalidateRect(hButtonsWnd, NULL, TRUE)) |
| DRAW_ERROR(); |
| if(!UpdateWindow(hButtonsWnd)) |
| DRAW_ERROR(); |
| #endif |
| } |
| } |
| |
| |
| /* Creates a new button below the button containing prev_button_text. * |
| * The text and button function are set according to button_text and * |
| * button_func, respectively. */ |
| void create_button (const char *prev_button_text , const char *button_text, |
| void (*button_func) (void (*drawscreen) (void))) |
| { |
| int i, bnum, space, bheight; |
| t_button_type button_type = BUTTON_TEXT; |
| |
| space = 8; |
| |
| /* Only allow new buttons that are text or separator (not poly) types. |
| * They can also only go after buttons that are text buttons. |
| */ |
| |
| bnum = -1; |
| |
| for (i=0; i < num_buttons;i++) { |
| if (button[i].type == BUTTON_TEXT && |
| strcmp (button[i].text, prev_button_text) == 0) { |
| bnum = i + 1; |
| break; |
| } |
| } |
| |
| if (bnum == -1) { |
| printf ("Error in create_button: button with text %s not found.\n", |
| prev_button_text); |
| exit (1); |
| } |
| |
| button = (t_button *) my_realloc (button, (num_buttons+1) * sizeof (t_button)); |
| /* NB: Requirement that you specify the button that this button goes under * |
| * guarantees that button[num_buttons-2] exists and is a text button. */ |
| |
| /* Special string to make a separator. */ |
| if (!strncmp(button_text, "---", 3)) { |
| bheight = 2; |
| button_type = BUTTON_SEPARATOR; |
| } |
| else |
| bheight = 26; |
| |
| for (i=num_buttons;i>bnum;i--) { |
| button[i].xleft = button[i-1].xleft; |
| button[i].ytop = button[i-1].ytop + bheight + space; |
| button[i].height = button[i-1].height; |
| button[i].width = button[i-1].width; |
| button[i].type = button[i-1].type; |
| strcpy (button[i].text, button[i-1].text); |
| button[i].fcn = button[i-1].fcn; |
| button[i].ispressed = button[i-1].ispressed; |
| button[i].enabled = button[i-1].enabled; |
| unmap_button (i-1); |
| } |
| |
| i = bnum; |
| button[i].xleft = 6; |
| button[i].ytop = button[i-1].ytop + button[i-1].height + space; |
| button[i].height = bheight; |
| button[i].width = 90; |
| button[i].type = button_type; |
| strncpy (button[i].text, button_text, BUTTON_TEXT_LEN); |
| button[i].fcn = button_func; |
| button[i].ispressed = false; |
| button[i].enabled = true; |
| |
| num_buttons++; |
| |
| for (i = 0; i<num_buttons;i++) |
| map_button (i); |
| } |
| |
| |
| /* Destroys the button with text button_text. */ |
| void |
| destroy_button (const char *button_text) |
| { |
| int i, bnum, space, bheight; |
| |
| bnum = -1; |
| space = 8; |
| for (i = 0; i < num_buttons; i++) { |
| if (button[i].type == BUTTON_TEXT && |
| strcmp (button[i].text, button_text) == 0) { |
| bnum = i; |
| break; |
| } |
| } |
| |
| if (bnum == -1) { |
| printf ("Error in destroy_button: button with text %s not found.\n", |
| button_text); |
| exit (1); |
| } |
| |
| bheight = button[bnum].height; |
| |
| for (i=bnum+1;i<num_buttons;i++) { |
| button[i-1].xleft = button[i].xleft; |
| button[i-1].ytop = button[i].ytop - bheight - space; |
| button[i-1].height = button[i].height; |
| button[i-1].width = button[i].width; |
| button[i-1].type = button[i].type; |
| strcpy (button[i-1].text, button[i].text); |
| button[i-1].fcn = button[i].fcn; |
| button[i-1].ispressed = button[i].ispressed; |
| button[i-1].enabled = button[i].enabled; |
| unmap_button (i); |
| } |
| unmap_button(bnum); |
| |
| button = (t_button *) my_realloc (button, (num_buttons-1) * sizeof (t_button)); |
| |
| num_buttons--; |
| |
| for (i=bnum; i<num_buttons;i++) |
| map_button (i); |
| } |
| |
| |
| /* Open the toplevel window, get the colors, 2 graphics * |
| * contexts, load a font, and set up the toplevel window * |
| * Calls build_default_menu to set up the default menu. */ |
| void |
| init_graphics (const char *window_name, int cindex) |
| { |
| if (gl_state.initialized) // Singleton graphics. |
| return; |
| |
| reset_common_state (); |
| #ifdef WIN32 |
| reset_win32_state (); |
| #endif |
| |
| gl_state.disp_type = SCREEN; |
| gl_state.background_cindex = cindex; |
| |
| |
| #ifdef X11 |
| char *display_name = NULL; |
| int x, y; /* window position */ |
| unsigned int border_width = 2; /* ignored by OpenWindows */ |
| XTextProperty windowName; |
| |
| /* X Windows' names for my colours. */ |
| const char *cnames[NUM_COLOR] = {"white", "black", "grey55", "grey75", "blue", |
| "green", "yellow", "cyan", "red", "RGBi:0.0/0.5/0.0", "magenta", |
| "bisque", "lightblue", "thistle", "plum", "khaki", "coral", |
| "turquoise", "mediumpurple", "darkslateblue", "darkkhaki" }; |
| |
| XColor exact_def; |
| Colormap cmap; |
| unsigned long valuemask = 0; /* ignore XGCvalues and use defaults */ |
| XGCValues values; |
| XEvent event; |
| |
| /* connect to X server */ |
| if ( (display=XOpenDisplay(display_name)) == NULL ) |
| { |
| fprintf( stderr, "Cannot connect to X server %s\n", |
| XDisplayName(display_name)); |
| exit( -1 ); |
| } |
| |
| /* get screen size from display structure macro */ |
| screen_num = DefaultScreen(display); |
| display_width = DisplayWidth(display, screen_num); |
| display_height = DisplayHeight(display, screen_num); |
| |
| x = 0; |
| y = 0; |
| |
| top_width = 2 * display_width / 3; |
| top_height = 4 * display_height / 5; |
| |
| cmap = DefaultColormap(display, screen_num); |
| private_cmap = None; |
| |
| for (int i=0;i<NUM_COLOR;i++) { |
| if (!XParseColor(display,cmap,cnames[i],&exact_def)) { |
| fprintf(stderr, "Color name %s not in database", cnames[i]); |
| exit(-1); |
| } |
| if (!XAllocColor(display, cmap, &exact_def)) { |
| fprintf(stderr, "Couldn't allocate color %s.\n",cnames[i]); |
| |
| if (private_cmap == None) { |
| fprintf(stderr, "Will try to allocate a private colourmap.\n"); |
| fprintf(stderr, "Colours will only display correctly when your " |
| "cursor is in the graphics window.\n" |
| "Exit other colour applications and rerun this " |
| "program if you don't like that.\n\n"); |
| |
| private_cmap = XCopyColormapAndFree (display, cmap); |
| cmap = private_cmap; |
| if (!XAllocColor (display, cmap, &exact_def)) { |
| fprintf (stderr, "Couldn't allocate color %s as private.\n", |
| cnames[i]); |
| exit (1); |
| } |
| } |
| |
| else { |
| fprintf (stderr, "Couldn't allocate color %s as private.\n", |
| cnames[i]); |
| exit (1); |
| } |
| } |
| colors[i] = exact_def.pixel; |
| } // End setting up colours |
| |
| toplevel = XCreateSimpleWindow(display,RootWindow(display,screen_num), |
| x, y, top_width, top_height, border_width, colors[BLACK], |
| colors[cindex]); |
| |
| if (private_cmap != None) |
| XSetWindowColormap (display, toplevel, private_cmap); |
| |
| XSelectInput (display, toplevel, ExposureMask | StructureNotifyMask | |
| ButtonPressMask | PointerMotionMask | KeyPressMask); |
| |
| /* Create default Graphics Contexts. valuemask = 0 -> use defaults. */ |
| current_gc = gc = XCreateGC(display, toplevel, valuemask, &values); |
| gc_menus = XCreateGC(display, toplevel, valuemask, &values); |
| |
| /* Create XOR graphics context for Rubber Banding */ |
| values.function = GXxor; |
| values.foreground = colors[cindex]; |
| gcxor = XCreateGC(display, toplevel, (GCFunction | GCForeground), |
| &values); |
| |
| /* specify font for menus. */ |
| load_font(menu_font_size); |
| XSetFont(display, gc_menus, font_info[menu_font_size]->fid); |
| |
| /* Set drawing defaults for user-drawable area. Use whatever the * |
| * initial values of the current stuff was set to. */ |
| force_setfontsize(currentfontsize); |
| force_setcolor (currentcolor); |
| force_setlinestyle (currentlinestyle); |
| force_setlinewidth (currentlinewidth); |
| |
| // Need a non-const name to pass to XStringListTo... |
| // (even though X11 won't change it). |
| char *window_name_copy = (char *) my_malloc (BUFSIZE * sizeof (char)); |
| strncpy (window_name_copy, window_name, BUFSIZE); |
| XStringListToTextProperty(&window_name_copy, 1, &windowName); |
| free (window_name_copy); |
| window_name_copy = NULL; |
| |
| XSetWMName (display, toplevel, &windowName); |
| /* XSetWMIconName (display, toplevel, &windowName); */ |
| |
| /* XStringListToTextProperty copies the window_name string into * |
| * windowName.value. Free this memory now. */ |
| |
| free (windowName.value); |
| |
| XMapWindow (display, toplevel); |
| build_textarea (); |
| build_default_menu (); |
| |
| /* The following is completely unnecessary if the user is using the * |
| * interactive (event_loop) graphics. It waits for the first Expose * |
| * event before returning so that I can tell the window manager has got * |
| * the top-level window up and running. Thus the user can start drawing * |
| * into this window immediately, and there's no danger of the window not * |
| * being ready and output being lost. */ |
| XPeekIfEvent (display, &event, test_if_exposed, NULL); |
| |
| #else /* WIN32 */ |
| WNDCLASS wndclass; |
| HINSTANCE hInstance = GetModuleHandle(NULL); |
| int x, y; |
| LOGBRUSH lb; |
| lb.lbStyle = BS_SOLID; |
| lb.lbColor = win32_colors[currentcolor]; |
| lb.lbHatch = (LONG)NULL; |
| x = 0; |
| y = 0; |
| |
| /* get screen size from display structure macro */ |
| display_width = GetSystemMetrics( SM_CXSCREEN ); |
| if (!(display_width)) |
| CREATE_ERROR(); |
| display_height = GetSystemMetrics( SM_CYSCREEN ); |
| if (!(display_height)) |
| CREATE_ERROR(); |
| top_width = 2*display_width/3; |
| top_height = 4*display_height/5; |
| |
| /* Grab the Application name */ |
| wsprintf(szAppName, TEXT(window_name)); |
| |
| //hGraphicsPen = CreatePen(win32_line_styles[SOLID], 1, win32_colors[BLACK]); |
| hGraphicsPen = ExtCreatePen(PS_GEOMETRIC | win32_line_styles[currentlinestyle] | |
| PS_ENDCAP_FLAT, 1, &lb, (LONG)NULL, NULL); |
| if(!hGraphicsPen) |
| CREATE_ERROR(); |
| hGraphicsBrush = CreateSolidBrush(win32_colors[DARKGREY]); |
| if(!hGraphicsBrush) |
| CREATE_ERROR(); |
| hGrayBrush = CreateSolidBrush(win32_colors[LIGHTGREY]); |
| if(!hGrayBrush) |
| CREATE_ERROR(); |
| |
| load_font (currentfontsize); |
| hGraphicsFont = CreateFontIndirect(font_info[currentfontsize]); |
| if (!hGraphicsFont) |
| CREATE_ERROR(); |
| |
| /* Register the Main Window class */ |
| wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; |
| wndclass.lpfnWndProc = MainWND; |
| wndclass.cbClsExtra = 0; |
| wndclass.cbWndExtra = 0; |
| wndclass.hInstance = hInstance; |
| wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION); |
| wndclass.hCursor = LoadCursor( NULL, IDC_ARROW); |
| wndclass.hbrBackground = (HBRUSH) CreateSolidBrush(win32_colors[cindex]); |
| wndclass.lpszMenuName = NULL; |
| wndclass.lpszClassName = szAppName; |
| |
| if (!RegisterClass(&wndclass)) { |
| printf ("Error code: %d\n", GetLastError()); |
| MessageBox(NULL, TEXT("Initialization of Windows graphics (init_graphics) failed."), |
| szAppName, MB_ICONERROR); |
| exit(-1); |
| } |
| |
| /* Register the Graphics Window class */ |
| wndclass.lpfnWndProc = GraphicsWND; |
| wndclass.hIcon = NULL; |
| wndclass.lpszClassName = szGraphicsName; |
| |
| if(!RegisterClass(&wndclass)) |
| DRAW_ERROR(); |
| |
| /* Register the Status Window class */ |
| wndclass.lpfnWndProc = StatusWND; |
| wndclass.hIcon = NULL; |
| wndclass.lpszClassName = szStatusName; |
| wndclass.hbrBackground = hGrayBrush; |
| |
| if(!RegisterClass(&wndclass)) |
| DRAW_ERROR(); |
| |
| /* Register the Buttons Window class */ |
| wndclass.lpfnWndProc = ButtonsWND; |
| wndclass.hIcon = NULL; |
| wndclass.lpszClassName = szButtonsName; |
| wndclass.hbrBackground = hGrayBrush; |
| |
| if (!RegisterClass(&wndclass)) |
| DRAW_ERROR(); |
| |
| hMainWnd = CreateWindow(szAppName, TEXT(window_name), |
| WS_OVERLAPPEDWINDOW, x, y, top_width, top_height, |
| NULL, NULL, hInstance, NULL); |
| |
| if(!hMainWnd) |
| DRAW_ERROR(); |
| |
| /* Set drawing defaults for user-drawable area. Use whatever the * |
| * initial values of the current stuff was set to. */ |
| |
| if (ShowWindow(hMainWnd, SW_SHOWNORMAL)) |
| DRAW_ERROR(); |
| build_default_menu(); |
| if (!UpdateWindow(hMainWnd)) |
| DRAW_ERROR(); |
| win32_drain_message_queue (); |
| #endif |
| gl_state.initialized = true; |
| } |
| |
| |
| static void reset_common_state () { |
| currentcolor = BLACK; |
| currentlinestyle = SOLID; |
| currentlinewidth = 0; |
| currentfontsize = 12; |
| current_draw_mode = DRAW_NORMAL; |
| |
| for (int i=0;i<=MAX_FONT_SIZE;i++) |
| font_is_loaded[i] = false; /* No fonts loaded yet. */ |
| |
| ProceedPressed = false; |
| get_keypress_input = false; |
| get_mouse_move_input = false; |
| } |
| |
| |
| static void |
| update_transform (void) |
| { |
| /* Set up the factors for transforming from the user world to X Windows * |
| * coordinates. */ |
| |
| float mult, y1, y2, x1, x2; |
| |
| /* X Window coordinates go from (0,0) to (width-1,height-1) */ |
| xmult = (top_width - 1 - MWIDTH) / (xright - xleft); |
| ymult = (top_height - 1 - T_AREA_HEIGHT)/ (ybot - ytop); |
| |
| /* Need to use same scaling factor to preserve aspect ratio */ |
| if (fabs(xmult) <= fabs(ymult)) { |
| mult = (float)(fabs(ymult/xmult)); |
| y1 = ytop - (ybot-ytop)*(mult-1)/2; |
| y2 = ybot + (ybot-ytop)*(mult-1)/2; |
| ytop = y1; |
| ybot = y2; |
| } |
| else { |
| mult = (float)(fabs(xmult/ymult)); |
| x1 = xleft - (xright-xleft)*(mult-1)/2; |
| x2 = xright + (xright-xleft)*(mult-1)/2; |
| xleft = x1; |
| xright = x2; |
| } |
| xmult = (top_width - 1 - MWIDTH) / (xright - xleft); |
| ymult = (top_height - 1 - T_AREA_HEIGHT)/ (ybot - ytop); |
| |
| xdiv = 1/xmult; |
| ydiv = 1/ymult; |
| } |
| |
| |
| static void |
| update_ps_transform (void) |
| { |
| |
| /* Postscript coordinates start at (0,0) for the lower left hand corner * |
| * of the page and increase upwards and to the right. For 8.5 x 11 * |
| * sheet, coordinates go from (0,0) to (612,792). Spacing is 1/72 inch.* |
| * I'm leaving a minimum of half an inch (36 units) of border around * |
| * each edge. */ |
| |
| float ps_width, ps_height; |
| |
| ps_width = 540.; /* 72 * 7.5 */ |
| ps_height = 720.; /* 72 * 10 */ |
| |
| ps_xmult = ps_width / (xright - xleft); |
| ps_ymult = ps_height / (ytop - ybot); |
| /* Need to use same scaling factor to preserve aspect ratio. * |
| * I show exactly as much on paper as the screen window shows, * |
| * or the user specifies. */ |
| if (fabs(ps_xmult) <= fabs(ps_ymult)) { |
| ps_left = 36.; |
| ps_right = (float)(36. + ps_width); |
| ps_bot = (float)(396. - fabs(ps_xmult * (ytop - ybot))/2); |
| ps_top = (float)(396. + fabs(ps_xmult * (ytop - ybot))/2); |
| /* Maintain aspect ratio but watch signs */ |
| ps_ymult = (ps_xmult*ps_ymult < 0) ? -ps_xmult : ps_xmult; |
| } |
| else { |
| ps_bot = 36.; |
| ps_top = (float)(36. + ps_height); |
| ps_left = (float)(306. - fabs(ps_ymult * (xright - xleft))/2); |
| ps_right = (float)(306. + fabs(ps_ymult * (xright - xleft))/2); |
| /* Maintain aspect ratio but watch signs */ |
| ps_xmult = (ps_xmult*ps_ymult < 0) ? -ps_ymult : ps_ymult; |
| } |
| } |
| |
| |
| /* The program's main event loop. Must be passed a user routine |
| * drawscreen which redraws the screen. It handles all window resizing |
| * zooming etc. itself. If the user clicks a mousebutton in the graphics |
| * (toplevel) area, the act_on_mousebutton routine passed in is called. |
| */ |
| void |
| event_loop (void (*act_on_mousebutton)(float x, float y), |
| void (*act_on_mousemove)(float x, float y), |
| void (*act_on_keypress)(char key_pressed), |
| void (*drawscreen) (void)) |
| { |
| #ifdef X11 |
| XEvent report; |
| int bnum; |
| float x, y; |
| |
| #define OFF 1 |
| #define ON 0 |
| |
| turn_on_off (ON); |
| while (1) { |
| XNextEvent (display, &report); |
| switch (report.type) { |
| case Expose: |
| #ifdef VERBOSE |
| printf("Got an expose event.\n"); |
| printf("Count is: %d.\n",report.xexpose.count); |
| printf("Window ID is: %d.\n",report.xexpose.window); |
| #endif |
| if (report.xexpose.count != 0) |
| break; |
| if (report.xexpose.window == menu) |
| drawmenu(); |
| else if (report.xexpose.window == toplevel) |
| drawscreen(); |
| else if (report.xexpose.window == textarea) |
| draw_message(); |
| break; |
| case ConfigureNotify: |
| top_width = report.xconfigure.width; |
| top_height = report.xconfigure.height; |
| update_transform(); |
| drawmenu(); |
| draw_message(); |
| #ifdef VERBOSE |
| printf("Got a ConfigureNotify.\n"); |
| printf("New width: %d New height: %d.\n",top_width,top_height); |
| #endif |
| break; |
| case ButtonPress: |
| #ifdef VERBOSE |
| printf("Got a buttonpress.\n"); |
| printf("Window ID is: %d.\n",report.xbutton.window); |
| #endif |
| if (report.xbutton.window == toplevel) { |
| x = XTOWORLD(report.xbutton.x); |
| y = YTOWORLD(report.xbutton.y); |
| act_on_mousebutton (x, y); |
| } |
| else { /* A menu button was pressed. */ |
| bnum = which_button(report.xbutton.window); |
| #ifdef VERBOSE |
| printf("Button number is %d\n",bnum); |
| #endif |
| if (button[bnum].enabled) { |
| button[bnum].ispressed = 1; |
| drawbut(bnum); |
| XFlush(display); /* Flash the button */ |
| button[bnum].fcn (drawscreen); |
| button[bnum].ispressed = 0; |
| drawbut(bnum); |
| if (button[bnum].fcn == proceed) { |
| turn_on_off(OFF); |
| flushinput (); |
| return; /* Rather clumsy way of returning * |
| * control to the simulator */ |
| } |
| } |
| } |
| break; |
| case MotionNotify: |
| #ifdef VERBOSE |
| printf("Got a MotionNotify Event.\n"); |
| printf("x: %d y: %d\n",report.xmotion.x,report.xmotion.y); |
| #endif |
| if (get_mouse_move_input && |
| report.xmotion.x <= top_width-MWIDTH && |
| report.xmotion.y <= top_height-T_AREA_HEIGHT) |
| act_on_mousemove(XTOWORLD(report.xmotion.x), YTOWORLD(report.xmotion.y)); |
| break; |
| case KeyPress: |
| #ifdef VERBOSE |
| printf("Got a KeyPress Event.\n"); |
| #endif |
| if (get_keypress_input) |
| { |
| char keyb_buffer[20]; |
| XComposeStatus composestatus; |
| KeySym keysym; |
| int length, max_bytes; |
| |
| max_bytes = 1; |
| |
| length = XLookupString( &report.xkey, keyb_buffer, max_bytes, &keysym, |
| &composestatus ); |
| |
| keyb_buffer[length] = '\0'; /* terminating NULL */ |
| act_on_keypress(keyb_buffer[0]); |
| } |
| |
| break; |
| } |
| } |
| #else /* Win32 */ |
| MSG msg; |
| |
| mouseclick_ptr = act_on_mousebutton; |
| mousemove_ptr = act_on_mousemove; |
| keypress_ptr = act_on_keypress; |
| drawscreen_ptr = drawscreen; |
| ProceedPressed = FALSE; |
| InEventLoop = TRUE; |
| |
| invalidate_screen(); |
| |
| while(!ProceedPressed && GetMessage(&msg, NULL, 0, 0)) { |
| //TranslateMessage(&msg); |
| if (msg.message == WM_CHAR) { // only the top window can get keyboard events |
| msg.hwnd = hMainWnd; |
| } |
| DispatchMessage(&msg); |
| } |
| InEventLoop = FALSE; |
| #endif |
| } |
| |
| void |
| clearscreen (void) |
| { |
| int savecolor; |
| if (gl_state.disp_type == SCREEN) { |
| #ifdef X11 |
| XClearWindow (display, toplevel); |
| #else /* Win32 */ |
| savecolor = currentcolor; |
| setcolor(gl_state.background_cindex); |
| fillrect (xleft, ytop, xright, ybot); |
| setcolor(savecolor); |
| #endif |
| } |
| else { // Postscript |
| /* erases current page. Don't use erasepage, since this will erase * |
| * everything, (even stuff outside the clipping path) causing * |
| * problems if this picture is incorporated into a larger document. */ |
| savecolor = currentcolor; |
| setcolor (gl_state.background_cindex); |
| fprintf(ps,"clippath fill\n\n"); |
| setcolor (savecolor); |
| } |
| } |
| |
| /* Return 1 if I can quarantee no part of this rectangle will * |
| * lie within the user drawing area. Otherwise return 0. * |
| * Note: this routine is only used to help speed (and to shrink ps * |
| * files) -- it will be highly effective when the graphics are zoomed * |
| * in and lots are off-screen. I don't have to pre-clip for * |
| * correctness. */ |
| static int |
| rect_off_screen (float x1, float y1, float x2, float y2) |
| { |
| |
| float xmin, xmax, ymin, ymax; |
| |
| xmin = min (xleft, xright); |
| if (x1 < xmin && x2 < xmin) |
| return (1); |
| |
| xmax = max (xleft, xright); |
| if (x1 > xmax && x2 > xmax) |
| return (1); |
| |
| ymin = min (ytop, ybot); |
| if (y1 < ymin && y2 < ymin) |
| return (1); |
| |
| ymax = max (ytop, ybot); |
| if (y1 > ymax && y2 > ymax) |
| return (1); |
| |
| return (0); |
| } |
| |
| void |
| drawline (float x1, float y1, float x2, float y2) |
| { |
| /* Draw a line from (x1,y1) to (x2,y2) in the user-drawable area. * |
| * Coordinates are in world (user) space. */ |
| |
| #ifdef WIN32 |
| HPEN hOldPen; |
| #endif |
| |
| if (rect_off_screen(x1,y1,x2,y2)) |
| return; |
| |
| if (gl_state.disp_type == SCREEN) { |
| #ifdef X11 |
| /* Xlib.h prototype has x2 and y1 mixed up. */ |
| XDrawLine(display, toplevel, current_gc, xcoord(x1), ycoord(y1), xcoord(x2), ycoord(y2)); |
| #else /* Win32 */ |
| hOldPen = (HPEN)SelectObject(hGraphicsDC, hGraphicsPen); |
| if(!(hOldPen)) |
| SELECT_ERROR(); |
| if (!BeginPath(hGraphicsDC)) |
| DRAW_ERROR(); |
| if(!MoveToEx (hGraphicsDC, xcoord(x1), ycoord(y1), NULL)) |
| DRAW_ERROR(); |
| if(!LineTo (hGraphicsDC, xcoord(x2), ycoord(y2))) |
| DRAW_ERROR(); |
| if (!EndPath(hGraphicsDC)) |
| DRAW_ERROR(); |
| if (!StrokePath(hGraphicsDC)) |
| DRAW_ERROR(); |
| if(!SelectObject(hGraphicsDC, hOldPen)) |
| SELECT_ERROR(); |
| #endif |
| } |
| else { |
| fprintf(ps,"%.2f %.2f %.2f %.2f drawline\n",XPOST(x1),YPOST(y1), |
| XPOST(x2),YPOST(y2)); |
| } |
| } |
| |
| /* (x1,y1) and (x2,y2) are diagonally opposed corners, in world coords. */ |
| void |
| drawrect (float x1, float y1, float x2, float y2) |
| { |
| int xw1, yw1, xw2, yw2; |
| #ifdef WIN32 |
| HPEN hOldPen; |
| HBRUSH hOldBrush; |
| #else |
| unsigned int width, height; |
| int xl, yt; |
| #endif |
| |
| if (rect_off_screen(x1,y1,x2,y2)) |
| return; |
| |
| if (gl_state.disp_type == SCREEN) { |
| /* translate to X Windows calling convention. */ |
| xw1 = xcoord(x1); |
| xw2 = xcoord(x2); |
| yw1 = ycoord(y1); |
| yw2 = ycoord(y2); |
| #ifdef X11 |
| xl = min(xw1,xw2); |
| yt = min(yw1,yw2); |
| width = abs (xw1-xw2); |
| height = abs (yw1-yw2); |
| XDrawRectangle(display, toplevel, current_gc, xl, yt, width, height); |
| #else /* Win32 */ |
| if(xw1 > xw2) { |
| int temp = xw1; |
| xw1 = xw2; |
| xw2 = temp; |
| } |
| if(yw1 > yw2) { |
| int temp = yw1; |
| yw1 = yw2; |
| yw2 = temp; |
| } |
| |
| hOldPen = (HPEN)SelectObject(hGraphicsDC, hGraphicsPen); |
| if(!(hOldPen)) |
| SELECT_ERROR(); |
| hOldBrush = (HBRUSH)SelectObject(hGraphicsDC, GetStockObject(NULL_BRUSH)); |
| if(!(hOldBrush)) |
| SELECT_ERROR(); |
| if(!Rectangle(hGraphicsDC, xw1, yw1, xw2, yw2)) |
| DRAW_ERROR(); |
| if(!SelectObject(hGraphicsDC, hOldPen)) |
| SELECT_ERROR(); |
| if(!SelectObject(hGraphicsDC, hOldBrush)) |
| SELECT_ERROR(); |
| #endif |
| |
| } |
| else { |
| fprintf(ps,"%.2f %.2f %.2f %.2f drawrect\n",XPOST(x1),YPOST(y1), |
| XPOST(x2),YPOST(y2)); |
| } |
| } |
| |
| |
| /* (x1,y1) and (x2,y2) are diagonally opposed corners in world coords. */ |
| void |
| fillrect (float x1, float y1, float x2, float y2) |
| { |
| int xw1, yw1, xw2, yw2; |
| #ifdef WIN32 |
| HPEN hOldPen; |
| HBRUSH hOldBrush; |
| #else |
| unsigned int width, height; |
| int xl, yt; |
| #endif |
| |
| if (rect_off_screen(x1,y1,x2,y2)) |
| return; |
| |
| if (gl_state.disp_type == SCREEN) { |
| /* translate to X Windows calling convention. */ |
| xw1 = xcoord(x1); |
| xw2 = xcoord(x2); |
| yw1 = ycoord(y1); |
| yw2 = ycoord(y2); |
| #ifdef X11 |
| xl = min(xw1,xw2); |
| yt = min(yw1,yw2); |
| width = abs (xw1-xw2); |
| height = abs (yw1-yw2); |
| XFillRectangle(display, toplevel, current_gc, xl, yt, width, height); |
| #else /* Win32 */ |
| if(xw1 > xw2) { |
| int temp = xw1; |
| xw1 = xw2; |
| xw2 = temp; |
| } |
| if(yw1 > yw2) { |
| int temp = yw1; |
| yw1 = yw2; |
| yw2 = temp; |
| } |
| |
| hOldPen = (HPEN)SelectObject(hGraphicsDC, hGraphicsPen); |
| if(!(hOldPen)) |
| SELECT_ERROR(); |
| hOldBrush = (HBRUSH)SelectObject(hGraphicsDC, hGraphicsBrush); |
| if(!(hOldBrush)) |
| SELECT_ERROR(); |
| if(!Rectangle(hGraphicsDC, xw1, yw1, xw2, yw2)) |
| DRAW_ERROR(); |
| if(!SelectObject(hGraphicsDC, hOldPen)) |
| SELECT_ERROR(); |
| if(!SelectObject(hGraphicsDC, hOldBrush)) |
| SELECT_ERROR(); |
| #endif |
| } |
| else { |
| fprintf(ps,"%.2f %.2f %.2f %.2f fillrect\n",XPOST(x1),YPOST(y1), |
| XPOST(x2),YPOST(y2)); |
| } |
| } |
| |
| |
| /* Normalizes an angle to be between 0 and 360 degrees. */ |
| static float |
| angnorm (float ang) |
| { |
| int scale; |
| |
| if (ang < 0) { |
| scale = (int) (ang / 360. - 1); |
| } |
| else { |
| scale = (int) (ang / 360.); |
| } |
| ang = ang - scale * 360; |
| return (ang); |
| } |
| |
| void |
| drawellipticarc (float xc, float yc, float radx, float rady, float startang, float angextent) |
| { |
| int xl, yt; |
| unsigned int width, height; |
| #ifdef WIN32 |
| HPEN hOldPen; |
| int p1, p2, p3, p4; |
| #endif |
| |
| /* Conservative (but fast) clip test -- check containing rectangle of * |
| * an ellipse. */ |
| |
| if (rect_off_screen (xc-radx,yc-rady,xc+radx,yc+rady)) |
| return; |
| |
| /* X Windows has trouble with very large angles. (Over 360). * |
| * Do following to prevent its inaccurate (overflow?) problems. */ |
| if (fabs(angextent) > 360.) |
| angextent = 360.; |
| |
| startang = angnorm (startang); |
| |
| if (gl_state.disp_type == SCREEN) { |
| xl = (int) (xcoord(xc) - fabs(xmult*radx)); |
| yt = (int) (ycoord(yc) - fabs(ymult*rady)); |
| width = (unsigned int) (2*fabs(xmult*radx)); |
| height = (unsigned int) (2*fabs(ymult*rady)); |
| #ifdef X11 |
| XDrawArc (display, toplevel, current_gc, xl, yt, width, height, |
| (int) (startang*64), (int) (angextent*64)); |
| #else // Win32 |
| /* set arc direction */ |
| if (angextent > 0) { |
| p1 = (int)(xcoord(xc) + fabs(xmult*radx)*cos(DEGTORAD(startang))); |
| p2 = (int)(ycoord(yc) - fabs(ymult*rady)*sin(DEGTORAD(startang))); |
| p3 = (int)(xcoord(xc) + fabs(xmult*radx)*cos(DEGTORAD(startang+angextent-.001))); |
| p4 = (int)(ycoord(yc) - fabs(ymult*rady)*sin(DEGTORAD(startang+angextent-.001))); |
| } |
| else { |
| p1 = (int)(xcoord(xc) + fabs(xmult*radx)*cos(DEGTORAD(startang+angextent+.001))); |
| p2 = (int)(ycoord(yc) - fabs(ymult*rady)*sin(DEGTORAD(startang+angextent+.001))); |
| p3 = (int)(xcoord(xc) + fabs(xmult*radx)*cos(DEGTORAD(startang))); |
| p4 = (int)(ycoord(yc) - fabs(ymult*rady)*sin(DEGTORAD(startang))); |
| } |
| |
| hOldPen = (HPEN)SelectObject(hGraphicsDC, hGraphicsPen); |
| if(!(hOldPen)) |
| SELECT_ERROR(); |
| if(!Arc(hGraphicsDC, xl, yt, xl+width, yt+height, p1, p2, p3, p4)) |
| DRAW_ERROR(); |
| if(!SelectObject(hGraphicsDC, hOldPen)) |
| SELECT_ERROR(); |
| #endif |
| } |
| else { |
| fprintf(ps, "gsave\n"); |
| fprintf(ps, "%.2f %.2f translate\n", XPOST(xc), YPOST(yc)); |
| fprintf(ps, "%.2f 1 scale\n", fabs(radx*ps_xmult)/fabs(rady*ps_ymult)); |
| fprintf(ps, "0 0 %.2f %.2f %.2f %s\n", /*XPOST(xc)*/ |
| /*YPOST(yc)*/ fabs(rady*ps_xmult), startang, startang+angextent, |
| (angextent < 0) ? "drawarcn" : "drawarc") ; |
| fprintf(ps, "grestore\n"); |
| } |
| } |
| |
| /* Startang is relative to the Window's positive x direction. Angles in degrees. |
| */ |
| void |
| drawarc (float xc, float yc, float rad, float startang, |
| float angextent) |
| { |
| drawellipticarc(xc, yc, rad, rad, startang, angextent); |
| } |
| |
| |
| /* Fills a elliptic arc. Startang is relative to the Window's positive x |
| * direction. Angles in degrees. |
| */ |
| void |
| fillellipticarc (float xc, float yc, float radx, float rady, float startang, |
| float angextent) |
| { |
| int xl, yt; |
| unsigned int width, height; |
| #ifdef WIN32 |
| HPEN hOldPen; |
| HBRUSH hOldBrush; |
| int p1, p2, p3, p4; |
| #endif |
| |
| /* Conservative (but fast) clip test -- check containing rectangle of * |
| * a circle. */ |
| |
| if (rect_off_screen (xc-radx,yc-rady,xc+radx,yc+rady)) |
| return; |
| |
| /* X Windows has trouble with very large angles. (Over 360). * |
| * Do following to prevent its inaccurate (overflow?) problems. */ |
| |
| if (fabs(angextent) > 360.) |
| angextent = 360.; |
| |
| startang = angnorm (startang); |
| |
| if (gl_state.disp_type == SCREEN) { |
| xl = (int) (xcoord(xc) - fabs(xmult*radx)); |
| yt = (int) (ycoord(yc) - fabs(ymult*rady)); |
| width = (unsigned int) (2*fabs(xmult*radx)); |
| height = (unsigned int) (2*fabs(ymult*rady)); |
| #ifdef X11 |
| XFillArc (display, toplevel, current_gc, xl, yt, width, height, |
| (int) (startang*64), (int) (angextent*64)); |
| #else // Win32 |
| /* set pie direction */ |
| if (angextent > 0) { |
| p1 = (int)(xcoord(xc) + fabs(xmult*radx)*cos(DEGTORAD(startang))); |
| p2 = (int)(ycoord(yc) - fabs(ymult*rady)*sin(DEGTORAD(startang))); |
| p3 = (int)(xcoord(xc) + fabs(xmult*radx)*cos(DEGTORAD(startang+angextent-.001))); |
| p4 = (int)(ycoord(yc) - fabs(ymult*rady)*sin(DEGTORAD(startang+angextent-.001))); |
| } |
| else { |
| p1 = (int)(xcoord(xc) + fabs(xmult*radx)*cos(DEGTORAD(startang+angextent+.001))); |
| p2 = (int)(ycoord(yc) - fabs(ymult*rady)*sin(DEGTORAD(startang+angextent+.001))); |
| p3 = (int)(xcoord(xc) + fabs(xmult*radx)*cos(DEGTORAD(startang))); |
| p4 = (int)(ycoord(yc) - fabs(ymult*rady)*sin(DEGTORAD(startang))); |
| } |
| |
| hOldPen = (HPEN)SelectObject(hGraphicsDC, GetStockObject(NULL_PEN)); |
| if(!(hOldPen)) |
| SELECT_ERROR(); |
| hOldBrush = (HBRUSH)SelectObject(hGraphicsDC, hGraphicsBrush); |
| if(!(hOldBrush)) |
| SELECT_ERROR(); |
| // Win32 API says a zero return value indicates an error, but it seems to always |
| // return zero. Don't check for an error on Pie. |
| Pie(hGraphicsDC, xl, yt, xl+width, yt+height, p1, p2, p3, p4); |
| |
| // if(!Pie(hGraphicsDC, xl, yt, xl+width, yt+height, p1, p2, p3, p4)); |
| // DRAW_ERROR(); |
| if(!SelectObject(hGraphicsDC, hOldPen)) |
| SELECT_ERROR(); |
| if(!SelectObject(hGraphicsDC, hOldBrush)) |
| SELECT_ERROR(); |
| #endif |
| } |
| else { |
| fprintf(ps, "gsave\n"); |
| fprintf(ps, "%.2f %.2f translate\n", XPOST(xc), YPOST(yc)); |
| fprintf(ps, "%.2f 1 scale\n", fabs(radx*ps_xmult)/fabs(rady*ps_ymult)); |
| fprintf(ps, "%.2f %.2f %.2f 0 0 %s\n", /*XPOST(xc)*/ |
| /*YPOST(yc)*/ fabs(rady*ps_xmult), startang, startang+angextent, |
| (angextent < 0) ? "fillarcn" : "fillarc") ; |
| fprintf(ps, "grestore\n"); |
| } |
| } |
| |
| void |
| fillarc (float xc, float yc, float rad, float startang, float angextent) { |
| fillellipticarc(xc, yc, rad, rad, startang, angextent); |
| } |
| |
| void |
| fillpoly (t_point *points, int npoints) |
| { |
| #ifdef X11 |
| XPoint transpoints[MAXPTS]; |
| #else |
| POINT transpoints[MAXPTS]; |
| HPEN hOldPen; |
| HBRUSH hOldBrush; |
| #endif |
| int i; |
| float xmin, ymin, xmax, ymax; |
| |
| if (npoints > MAXPTS) { |
| printf("Error in fillpoly: Only %d points allowed per polygon.\n", |
| MAXPTS); |
| printf("%d points were requested. Polygon is not drawn.\n",npoints); |
| return; |
| } |
| |
| /* Conservative (but fast) clip test -- check containing rectangle of * |
| * polygon. */ |
| |
| xmin = xmax = points[0].x; |
| ymin = ymax = points[0].y; |
| |
| for (i=1;i<npoints;i++) { |
| xmin = min (xmin,points[i].x); |
| xmax = max (xmax,points[i].x); |
| ymin = min (ymin,points[i].y); |
| ymax = max (ymax,points[i].y); |
| } |
| |
| if (rect_off_screen(xmin,ymin,xmax,ymax)) |
| return; |
| |
| if (gl_state.disp_type == SCREEN) { |
| for (i=0;i<npoints;i++) { |
| transpoints[i].x = (short) xcoord (points[i].x); |
| transpoints[i].y = (short) ycoord (points[i].y); |
| } |
| #ifdef X11 |
| XFillPolygon(display, toplevel, current_gc, transpoints, npoints, Complex, |
| CoordModeOrigin); |
| #else |
| hOldPen = (HPEN)SelectObject(hGraphicsDC, GetStockObject(NULL_PEN)); |
| if(!(hOldPen)) |
| SELECT_ERROR(); |
| hOldBrush = (HBRUSH)SelectObject(hGraphicsDC, hGraphicsBrush); |
| if(!(hOldBrush)) |
| SELECT_ERROR(); |
| if(!Polygon (hGraphicsDC, transpoints, npoints)) |
| DRAW_ERROR(); |
| if(!SelectObject(hGraphicsDC, hOldPen)) |
| SELECT_ERROR(); |
| if(!SelectObject(hGraphicsDC, hOldBrush)) |
| SELECT_ERROR(); |
| #endif |
| } |
| else { |
| fprintf(ps,"\n"); |
| |
| for (i=npoints-1;i>=0;i--) |
| fprintf (ps, "%.2f %.2f\n", XPOST(points[i].x), YPOST(points[i].y)); |
| |
| fprintf (ps, "%d fillpoly\n", npoints); |
| } |
| } |
| |
| |
| /* Draws text centered on xc,yc if it fits in boundx */ |
| void |
| drawtext (float xc, float yc, const char *text, float boundx) |
| { |
| int len, width, xw_off, yw_off, font_ascent, font_descent; |
| |
| #ifdef X11 |
| len = strlen(text); |
| width = XTextWidth(font_info[currentfontsize], text, len); |
| font_ascent = font_info[currentfontsize]->ascent; |
| font_descent = font_info[currentfontsize]->descent; |
| #else /* WC : WIN32 */ |
| HFONT hOldFont; |
| SIZE textsize; |
| TEXTMETRIC textmetric; |
| |
| hOldFont = (HFONT)SelectObject(hGraphicsDC, hGraphicsFont); |
| if(!(hOldFont)) |
| SELECT_ERROR(); |
| if(SetTextColor(hGraphicsDC, win32_colors[currentcolor]) == CLR_INVALID) |
| DRAW_ERROR(); |
| |
| len = strlen(text); |
| if (!GetTextExtentPoint32(hGraphicsDC, text, len, &textsize)) |
| DRAW_ERROR(); |
| width = textsize.cx; |
| if (!GetTextMetrics(hGraphicsDC, &textmetric)) |
| DRAW_ERROR(); |
| font_ascent = textmetric.tmAscent; |
| font_descent = textmetric.tmDescent; |
| #endif |
| if (width > fabs(boundx*xmult)) { |
| #ifdef WIN32 |
| if(!SelectObject(hGraphicsDC, hOldFont)) |
| SELECT_ERROR(); |
| #endif |
| return; /* Don't draw if it won't fit */ |
| } |
| |
| xw_off = (int)(width/(2.*xmult)); /* NB: sign doesn't matter. */ |
| |
| /* NB: 2 * descent makes this slightly conservative but simplifies code. */ |
| yw_off = (int)((font_ascent + 2 * font_descent)/(2.*ymult)); |
| |
| /* Note: text can be clipped when a little bit of it would be visible * |
| * right now. Perhaps X doesn't return extremely accurate width and * |
| * ascent values, etc? Could remove this completely by multiplying * |
| * xw_off and yw_off by, 1.2 or 1.5. */ |
| if (rect_off_screen(xc-xw_off, yc-yw_off, xc+xw_off, yc+yw_off)) { |
| #ifdef WIN32 |
| if(!SelectObject(hGraphicsDC, hOldFont)) |
| SELECT_ERROR(); |
| #endif |
| return; |
| } |
| |
| if (gl_state.disp_type == SCREEN) { |
| #ifdef X11 |
| XDrawString(display, toplevel, current_gc, xcoord(xc)-width/2, ycoord(yc) + |
| (font_info[currentfontsize]->ascent - font_info[currentfontsize]->descent)/2, |
| text, len); |
| #else /* Win32 */ |
| SetBkMode(hGraphicsDC, TRANSPARENT); |
| if(!TextOut (hGraphicsDC, xcoord(xc)-width/2, ycoord(yc) - (font_ascent + font_descent)/2, |
| text, len)) |
| DRAW_ERROR(); |
| if(!SelectObject(hGraphicsDC, hOldFont)) |
| SELECT_ERROR(); |
| #endif |
| } |
| else { |
| fprintf(ps,"(%s) %.2f %.2f censhow\n",text,XPOST(xc),YPOST(yc)); |
| } |
| } |
| |
| |
| void |
| flushinput (void) |
| { |
| if (gl_state.disp_type != SCREEN) |
| return; |
| #ifdef X11 |
| XFlush(display); |
| #endif |
| } |
| |
| |
| void |
| init_world (float x1, float y1, float x2, float y2) |
| { |
| /* Sets the coordinate system the user wants to draw into. */ |
| |
| xleft = x1; |
| xright = x2; |
| ytop = y1; |
| ybot = y2; |
| |
| saved_xleft = xleft; /* Save initial world coordinates to allow full */ |
| saved_xright = xright; /* view button to zoom all the way out. */ |
| saved_ytop = ytop; |
| saved_ybot = ybot; |
| |
| if (gl_state.disp_type == SCREEN) { |
| update_transform(); |
| } |
| else { |
| update_ps_transform(); |
| } |
| } |
| |
| |
| /* Draw the current message in the text area at the screen bottom. */ |
| void |
| draw_message (void) |
| { |
| int savefontsize, savecolor; |
| float ylow; |
| #ifdef X11 |
| int len, width; |
| #endif |
| |
| if (gl_state.disp_type == SCREEN) { |
| #ifdef X11 |
| XClearWindow (display, textarea); |
| len = strlen (statusMessage); |
| width = XTextWidth(font_info[menu_font_size], statusMessage, len); |
| XSetForeground(display, gc_menus,colors[WHITE]); |
| XDrawRectangle(display, textarea, gc_menus, 0, 0, top_width - MWIDTH, T_AREA_HEIGHT); |
| XSetForeground(display, gc_menus,colors[BLACK]); |
| XDrawLine(display, textarea, gc_menus, 0, T_AREA_HEIGHT-1, top_width-MWIDTH, T_AREA_HEIGHT-1); |
| XDrawLine(display, textarea, gc_menus, top_width-MWIDTH-1, 0, top_width-MWIDTH-1, T_AREA_HEIGHT-1); |
| |
| XDrawString(display, textarea, gc_menus, |
| (top_width - MWIDTH - width)/2, |
| T_AREA_HEIGHT/2 + (font_info[menu_font_size]->ascent - |
| font_info[menu_font_size]->descent)/2, statusMessage, len); |
| #else |
| if(!InvalidateRect(hStatusWnd, NULL, TRUE)) |
| DRAW_ERROR(); |
| if(!UpdateWindow(hStatusWnd)) |
| DRAW_ERROR(); |
| #endif |
| } |
| |
| else { |
| /* Draw the message in the bottom margin. Printer's generally can't * |
| * print on the bottom 1/4" (area with y < 18 in PostScript coords.) */ |
| |
| savecolor = currentcolor; |
| setcolor (BLACK); |
| savefontsize = currentfontsize; |
| setfontsize (menu_font_size - 2); /* Smaller OK on paper */ |
| ylow = ps_bot - 8; |
| fprintf(ps,"(%s) %.2f %.2f censhow\n",statusMessage,(ps_left+ps_right)/2., |
| ylow); |
| setcolor (savecolor); |
| setfontsize (savefontsize); |
| } |
| } |
| |
| |
| /* Changes the message to be displayed on screen. */ |
| void |
| update_message (const char *msg) |
| { |
| strncpy (statusMessage, msg, BUFSIZE); |
| draw_message (); |
| #ifdef X11 |
| // Make this appear immediately. Win32 does that automaticaly. |
| XFlush (display); |
| #endif // X11 |
| } |
| |
| |
| /* Zooms in by a factor of 1.666. */ |
| static void |
| zoom_in (void (*drawscreen) (void)) |
| { |
| float xdiff, ydiff; |
| |
| xdiff = xright - xleft; |
| ydiff = ybot - ytop; |
| xleft += xdiff/5; |
| xright -= xdiff/5; |
| ytop += ydiff/5; |
| ybot -= ydiff/5; |
| |
| update_transform (); |
| drawscreen(); |
| } |
| |
| |
| /* Zooms out by a factor of 1.666. */ |
| static void |
| zoom_out (void (*drawscreen) (void)) |
| { |
| float xdiff, ydiff; |
| |
| xdiff = xright - xleft; |
| ydiff = ybot - ytop; |
| xleft -= xdiff/3; |
| xright += xdiff/3; |
| ytop -= ydiff/3; |
| ybot += ydiff/3; |
| |
| update_transform (); |
| drawscreen(); |
| } |
| |
| |
| /* Sets the view back to the initial view set by init_world (i.e. a full * |
| * view) of all the graphics. */ |
| static void |
| zoom_fit (void (*drawscreen) (void)) |
| { |
| xleft = saved_xleft; |
| xright = saved_xright; |
| ytop = saved_ytop; |
| ybot = saved_ybot; |
| |
| update_transform (); |
| drawscreen(); |
| } |
| |
| |
| /* Moves view 1/2 screen up. */ |
| static void |
| translate_up (void (*drawscreen) (void)) |
| { |
| float ystep; |
| |
| ystep = (ybot - ytop)/2; |
| ytop -= ystep; |
| ybot -= ystep; |
| update_transform(); |
| drawscreen(); |
| } |
| |
| |
| /* Moves view 1/2 screen down. */ |
| static void |
| translate_down (void (*drawscreen) (void)) |
| { |
| float ystep; |
| |
| ystep = (ybot - ytop)/2; |
| ytop += ystep; |
| ybot += ystep; |
| update_transform(); |
| drawscreen(); |
| } |
| |
| |
| /* Moves view 1/2 screen left. */ |
| static void |
| translate_left (void (*drawscreen) (void)) |
| { |
| |
| float xstep; |
| |
| xstep = (xright - xleft)/2; |
| xleft -= xstep; |
| xright -= xstep; |
| update_transform(); |
| drawscreen(); |
| } |
| |
| |
| /* Moves view 1/2 screen right. */ |
| static void |
| translate_right (void (*drawscreen) (void)) |
| { |
| float xstep; |
| |
| xstep = (xright - xleft)/2; |
| xleft += xstep; |
| xright += xstep; |
| update_transform(); |
| drawscreen(); |
| } |
| |
| |
| static void |
| update_win (int x[2], int y[2], void (*drawscreen)(void)) |
| { |
| float x1, x2, y1, y2; |
| |
| x[0] = min(x[0],top_width-MWIDTH); /* Can't go under menu */ |
| x[1] = min(x[1],top_width-MWIDTH); |
| y[0] = min(y[0],top_height-T_AREA_HEIGHT); /* Can't go under text area */ |
| y[1] = min(y[1],top_height-T_AREA_HEIGHT); |
| |
| if ((x[0] == x[1]) || (y[0] == y[1])) { |
| printf("Illegal (zero area) window. Window unchanged.\n"); |
| return; |
| } |
| x1 = XTOWORLD(min(x[0],x[1])); |
| x2 = XTOWORLD(max(x[0],x[1])); |
| y1 = YTOWORLD(min(y[0],y[1])); |
| y2 = YTOWORLD(max(y[0],y[1])); |
| xleft = x1; |
| xright = x2; |
| ytop = y1; |
| ybot = y2; |
| update_transform(); |
| drawscreen(); |
| } |
| |
| |
| /* The window button was pressed. Let the user click on the two * |
| * diagonally opposed corners, and zoom in on this area. */ |
| static void |
| adjustwin (void (*drawscreen) (void)) |
| { |
| #ifdef X11 |
| |
| XEvent report; |
| int corner, xold, yold, x[2], y[2]; |
| |
| corner = 0; |
| xold = -1; |
| yold = -1; /* Don't need to init yold, but stops compiler warning. */ |
| |
| while (corner<2) { |
| XNextEvent (display, &report); |
| switch (report.type) { |
| case Expose: |
| #ifdef VERBOSE |
| printf("Got an expose event.\n"); |
| printf("Count is: %d.\n",report.xexpose.count); |
| printf("Window ID is: %d.\n",report.xexpose.window); |
| #endif |
| if (report.xexpose.count != 0) |
| break; |
| if (report.xexpose.window == menu) |
| drawmenu(); |
| else if (report.xexpose.window == toplevel) { |
| drawscreen(); |
| xold = -1; /* No rubber band on screen */ |
| } |
| else if (report.xexpose.window == textarea) |
| draw_message(); |
| break; |
| case ConfigureNotify: |
| top_width = report.xconfigure.width; |
| top_height = report.xconfigure.height; |
| update_transform(); |
| drawmenu(); |
| draw_message(); |
| #ifdef VERBOSE |
| printf("Got a ConfigureNotify.\n"); |
| printf("New width: %d New height: %d.\n",top_width,top_height); |
| #endif |
| break; |
| case ButtonPress: |
| #ifdef VERBOSE |
| printf("Got a buttonpress.\n"); |
| printf("Window ID is: %d.\n",report.xbutton.window); |
| printf("Location (%d, %d).\n", report.xbutton.x, |
| report.xbutton.y); |
| #endif |
| if (report.xbutton.window != toplevel) break; |
| x[corner] = report.xbutton.x; |
| y[corner] = report.xbutton.y; |
| if (corner == 0) { |
| /* XSelectInput (display, toplevel, ExposureMask | |
| StructureNotifyMask | ButtonPressMask | PointerMotionMask); */ |
| } |
| else { |
| update_win(x,y,drawscreen); |
| } |
| corner++; |
| break; |
| case MotionNotify: |
| if (corner) { |
| #ifdef VERBOSE |
| printf("Got a MotionNotify Event.\n"); |
| printf("x: %d y: %d\n",report.xmotion.x,report.xmotion.y); |
| #endif |
| if (xold >= 0) { /* xold set -ve before we draw first box */ |
| // Erase prior box. |
| set_draw_mode(DRAW_XOR); |
| XDrawRectangle(display,toplevel,gcxor,min(x[0],xold), |
| min(y[0],yold),abs(x[0]-xold),abs(y[0]-yold)); |
| set_draw_mode(DRAW_NORMAL); |
| } |
| /* Don't allow user to window under menu region */ |
| xold = min(report.xmotion.x,top_width-1-MWIDTH); |
| yold = report.xmotion.y; |
| set_draw_mode(DRAW_XOR); |
| |
| // Use forcing versions, as we want these modes to apply |
| // to the xor drawing context, and the regular versions |
| // won't update the drawing context if there is no change in line |
| // width etc. (but they might only be on the normal context) |
| force_setlinewidth(1); |
| force_setlinestyle(DASHED); |
| force_setcolor(gl_state.background_cindex); |
| |
| // Draw rubber band box. |
| XDrawRectangle(display,toplevel,gcxor,min(x[0],xold), |
| min(y[0],yold),abs(x[0]-xold),abs(y[0]-yold)); |
| set_draw_mode(DRAW_NORMAL); |
| } |
| break; |
| } |
| } |
| /* XSelectInput (display, toplevel, ExposureMask | StructureNotifyMask |
| | ButtonPressMask); */ |
| #else /* Win32 */ |
| /* Implemented as WM_LB... events */ |
| |
| /* Begin window adjust */ |
| if (!windowAdjustFlag) { |
| windowAdjustFlag = 1; |
| } |
| #endif |
| } |
| |
| |
| static void |
| postscript (void (*drawscreen) (void)) |
| { |
| /* Takes a snapshot of the screen and stores it in pic?.ps. The * |
| * first picture goes in pic1.ps, the second in pic2.ps, etc. */ |
| |
| static int piccount = 1; |
| int success; |
| char fname[BUFSIZE]; |
| |
| sprintf(fname,"pic%d.ps",piccount); |
| printf("Writing postscript output to file %s\n", fname); |
| success = init_postscript (fname); |
| |
| if (success) { |
| |
| drawscreen(); |
| close_postscript (); |
| piccount++; |
| } |
| else { |
| printf ("Error initializing for postscript output.\n"); |
| #ifdef WIN32 |
| MessageBox(hMainWnd, "Error initializing postscript output.", NULL, MB_OK); |
| #endif |
| } |
| } |
| |
| |
| static void |
| proceed (void (*drawscreen) (void)) |
| { |
| ProceedPressed = TRUE; |
| } |
| |
| |
| static void |
| quit (void (*drawscreen) (void)) |
| { |
| close_graphics(); |
| exit(0); |
| } |
| |
| |
| /* Release all my drawing structures (through the X server) and * |
| * close down the connection. */ |
| void |
| close_graphics (void) |
| { |
| if (!gl_state.initialized) |
| return; |
| #ifdef X11 |
| int i; |
| for (i=0;i<=MAX_FONT_SIZE;i++) { |
| if (font_is_loaded[i]) |
| XFreeFont(display,font_info[i]); |
| } |
| |
| XFreeGC(display,gc); |
| XFreeGC(display,gcxor); |
| XFreeGC(display,gc_menus); |
| |
| if (private_cmap != None) |
| XFreeColormap (display, private_cmap); |
| |
| XCloseDisplay(display); |
| #else /* Win32 */ |
| int i; |
| // Free the font data structure for each loaded font. |
| for (i = 0; i <= MAX_FONT_SIZE; i++) { |
| if (font_is_loaded[i]) { |
| free (font_info[i]); |
| } |
| } |
| |
| // Destroy the window |
| if(!DestroyWindow(hMainWnd)) |
| DRAW_ERROR(); |
| |
| // free the window class (type information held by MS Windows) |
| // for each of the four window types we created. Otherwise a |
| // later call to init_graphics to open the graphics window up again |
| // will fail. |
| if (!UnregisterClass (szAppName, GetModuleHandle(NULL)) ) |
| DRAW_ERROR(); |
| if (!UnregisterClass (szGraphicsName, GetModuleHandle(NULL)) ) |
| DRAW_ERROR(); |
| if (!UnregisterClass (szStatusName, GetModuleHandle(NULL)) ) |
| DRAW_ERROR(); |
| if (!UnregisterClass (szButtonsName, GetModuleHandle(NULL)) ) |
| DRAW_ERROR(); |
| #endif |
| |
| free(button); |
| button = NULL; |
| |
| for (i = 0; i <= MAX_FONT_SIZE; i++) { |
| font_is_loaded[i] = false; |
| font_info[i] = NULL; |
| } |
| gl_state.initialized = false; |
| } |
| |
| |
| /* Opens a file for PostScript output. The header information, * |
| * clipping path, etc. are all dumped out. If the file could * |
| * not be opened, the routine returns 0; otherwise it returns 1. */ |
| int init_postscript (const char *fname) |
| { |
| |
| ps = fopen (fname,"w"); |
| if (ps == NULL) { |
| printf("Error: could not open %s for PostScript output.\n",fname); |
| printf("Drawing to screen instead.\n"); |
| return (0); |
| } |
| gl_state.disp_type = POSTSCRIPT; /* Graphics go to postscript file now. */ |
| |
| /* Header for minimal conformance with the Adobe structuring convention */ |
| fprintf(ps,"%%!PS-Adobe-1.0\n"); |
| fprintf(ps,"%%%%DocumentFonts: Helvetica\n"); |
| fprintf(ps,"%%%%Pages: 1\n"); |
| /* Set up postscript transformation macros and page boundaries */ |
| update_ps_transform(); |
| /* Bottom margin is at ps_bot - 15. to leave room for the on-screen message. */ |
| fprintf(ps,"%%%%HiResBoundingBox: %.2f %.2f %.2f %.2f\n", |
| ps_left, ps_bot - 15., ps_right, ps_top); |
| fprintf(ps,"%%%%EndComments\n"); |
| |
| fprintf(ps,"/censhow %%draw a centered string\n"); |
| fprintf(ps," { moveto %% move to proper spot\n"); |
| fprintf(ps," dup stringwidth pop %% get x length of string\n"); |
| fprintf(ps," -2 div %% Proper left start\n"); |
| fprintf(ps," yoff rmoveto %% Move left that much and down half font height\n"); |
| fprintf(ps," show newpath } def %% show the string\n\n"); |
| |
| fprintf(ps,"/setfontsize %% set font to desired size and compute " |
| "centering yoff\n"); |
| fprintf(ps," { /Helvetica findfont\n"); |
| fprintf(ps," 8 scalefont\n"); |
| fprintf(ps," setfont %% Font size set ...\n\n"); |
| fprintf(ps," 0 0 moveto %% Get vertical centering offset\n"); |
| fprintf(ps," (Xg) true charpath\n"); |
| fprintf(ps," flattenpath pathbbox\n"); |
| fprintf(ps," /ascent exch def pop -1 mul /descent exch def pop\n"); |
| fprintf(ps," newpath\n"); |
| fprintf(ps," descent ascent sub 2 div /yoff exch def } def\n\n"); |
| |
| fprintf(ps,"%% Next two lines for debugging only.\n"); |
| fprintf(ps,"/str 20 string def\n"); |
| fprintf(ps,"/pnum {str cvs print ( ) print} def\n"); |
| |
| fprintf(ps,"/drawline %% draw a line from (x2,y2) to (x1,y1)\n"); |
| fprintf(ps," { moveto lineto stroke } def\n\n"); |
| |
| fprintf(ps,"/rect %% outline a rectangle \n"); |
| fprintf(ps," { /y2 exch def /x2 exch def /y1 exch def /x1 exch def\n"); |
| fprintf(ps," x1 y1 moveto\n"); |
| fprintf(ps," x2 y1 lineto\n"); |
| fprintf(ps," x2 y2 lineto\n"); |
| fprintf(ps," x1 y2 lineto\n"); |
| fprintf(ps," closepath } def\n\n"); |
| |
| fprintf(ps,"/drawrect %% draw outline of a rectanagle\n"); |
| fprintf(ps," { rect stroke } def\n\n"); |
| |
| fprintf(ps,"/fillrect %% fill in a rectanagle\n"); |
| fprintf(ps," { rect fill } def\n\n"); |
| |
| fprintf (ps,"/drawarc { arc stroke } def %% draw an arc\n"); |
| fprintf (ps,"/drawarcn { arcn stroke } def " |
| " %% draw an arc in the opposite direction\n\n"); |
| |
| fprintf (ps,"%%Fill a counterclockwise or clockwise arc sector, " |
| "respectively.\n"); |
| fprintf (ps,"/fillarc { moveto currentpoint 5 2 roll arc closepath fill } " |
| "def\n"); |
| fprintf (ps,"/fillarcn { moveto currentpoint 5 2 roll arcn closepath fill } " |
| "def\n\n"); |
| |
| fprintf (ps,"/fillpoly { 3 1 roll moveto %% move to first point\n" |
| " 2 exch 1 exch {pop lineto} for %% line to all other points\n" |
| " closepath fill } def\n\n"); |
| |
| |
| fprintf(ps,"%%Color Definitions:\n"); |
| fprintf(ps,"/white { 1 setgray } def\n"); |
| fprintf(ps,"/black { 0 setgray } def\n"); |
| fprintf(ps,"/grey55 { .55 setgray } def\n"); |
| fprintf(ps,"/grey75 { .75 setgray } def\n"); |
| fprintf(ps,"/blue { 0 0 1 setrgbcolor } def\n"); |
| fprintf(ps,"/green { 0 1 0 setrgbcolor } def\n"); |
| fprintf(ps,"/yellow { 1 1 0 setrgbcolor } def\n"); |
| fprintf(ps,"/cyan { 0 1 1 setrgbcolor } def\n"); |
| fprintf(ps,"/red { 1 0 0 setrgbcolor } def\n"); |
| fprintf(ps,"/darkgreen { 0 0.5 0 setrgbcolor } def\n"); |
| fprintf(ps,"/magenta { 1 0 1 setrgbcolor } def\n"); |
| fprintf(ps,"/bisque { 1 0.89 0.77 setrgbcolor } def\n"); |
| fprintf(ps,"/lightblue { 0.68 0.85 0.9 setrgbcolor } def\n"); |
| fprintf(ps,"/thistle { 0.85 0.75 0.85 setrgbcolor } def\n"); |
| fprintf(ps,"/plum { 0.87 0.63 0.87 setrgbcolor } def\n"); |
| fprintf(ps,"/khaki { 0.94 0.9 0.55 setrgbcolor } def\n"); |
| fprintf(ps,"/coral { 1 0.5 0.31 setrgbcolor } def\n"); |
| fprintf(ps,"/turquoise { 0.25 0.88 0.82 setrgbcolor } def\n"); |
| fprintf(ps,"/mediumpurple { 0.58 0.44 0.86 setrgbcolor } def\n"); |
| fprintf(ps,"/darkslateblue { 0.28 0.24 0.55 setrgbcolor } def\n"); |
| fprintf(ps,"/darkkhaki { 0.74 0.72 0.42 setrgbcolor } def\n"); |
| |
| fprintf(ps,"\n%%Solid and dashed line definitions:\n"); |
| fprintf(ps,"/linesolid {[] 0 setdash} def\n"); |
| fprintf(ps,"/linedashed {[3 3] 0 setdash} def\n"); |
| |
| fprintf(ps,"\n%%%%EndProlog\n"); |
| fprintf(ps,"%%%%Page: 1 1\n\n"); |
| |
| /* Set up PostScript graphics state to match current one. */ |
| force_setcolor (currentcolor); |
| force_setlinestyle (currentlinestyle); |
| force_setlinewidth (currentlinewidth); |
| force_setfontsize (currentfontsize); |
| |
| /* Draw this in the bottom margin -- must do before the clippath is set */ |
| draw_message (); |
| |
| /* Set clipping on page. */ |
| fprintf(ps,"%.2f %.2f %.2f %.2f rect ",ps_left, ps_bot,ps_right,ps_top); |
| fprintf(ps,"clip newpath\n\n"); |
| |
| return (1); |
| } |
| |
| /* Properly ends postscript output and redirects output to screen. */ |
| void close_postscript (void) |
| { |
| |
| fprintf(ps,"showpage\n"); |
| fprintf(ps,"\n%%%%Trailer\n"); |
| fclose (ps); |
| gl_state.disp_type = SCREEN; |
| update_transform(); /* Ensure screen world reflects any changes * |
| * made while printing. */ |
| |
| /* Need to make sure that we really set up the graphics context. |
| * The current font set indicates the last font used in a postscript call, |
| * etc., *NOT* the font set in the X11 or Win32 graphics context. Force the |
| * current font, colour etc. to be applied to the graphics context, so |
| * subsequent drawing commands work properly. |
| */ |
| |
| force_setcolor (currentcolor); |
| force_setlinestyle (currentlinestyle); |
| force_setlinewidth (currentlinewidth); |
| force_setfontsize (currentfontsize); |
| } |
| |
| |
| /* Sets up the default menu buttons on the right hand side of the window. */ |
| static void |
| build_default_menu (void) |
| { |
| int i, xcen, x1, y1, bwid, bheight, space; |
| const int NUM_ARROW_BUTTONS = 4, NUM_STANDARD_BUTTONS = 12, SEPARATOR_BUTTON_INDEX = 8; |
| |
| |
| #ifdef X11 |
| unsigned long valuemask; |
| XSetWindowAttributes menu_attributes; |
| |
| menu = XCreateSimpleWindow(display,toplevel, |
| top_width-MWIDTH, 0, MWIDTH, display_height, 0, |
| colors[BLACK], colors[LIGHTGREY]); |
| menu_attributes.event_mask = ExposureMask; |
| /* Ignore button presses on the menu background. */ |
| menu_attributes.do_not_propagate_mask = ButtonPressMask; |
| /* Keep menu on top right */ |
| menu_attributes.win_gravity = NorthEastGravity; |
| valuemask = CWWinGravity | CWEventMask | CWDontPropagate; |
| XChangeWindowAttributes(display, menu, valuemask, &menu_attributes); |
| XMapWindow (display, menu); |
| #endif |
| |
| button = (t_button *) my_malloc (NUM_STANDARD_BUTTONS * sizeof (t_button)); |
| |
| /* Now do the arrow buttons */ |
| bwid = 28; |
| space = 3; |
| y1 = 10; |
| xcen = 51; |
| x1 = xcen - bwid/2; |
| button[0].xleft = x1; |
| button[0].ytop = y1; |
| #ifdef X11 |
| setpoly (0, bwid/2, bwid/2, bwid/3, -PI/2.); /* Up */ |
| #else |
| button[0].type = BUTTON_TEXT; |
| strcpy(button[0].text, "U"); |
| #endif |
| button[0].fcn = translate_up; |
| |
| y1 += bwid + space; |
| x1 = xcen - 3*bwid/2 - space; |
| button[1].xleft = x1; |
| button[1].ytop = y1; |
| #ifdef X11 |
| setpoly (1, bwid/2, bwid/2, bwid/3, PI); /* Left */ |
| #else |
| button[1].type = BUTTON_TEXT; |
| strcpy(button[1].text, "L"); |
| #endif |
| button[1].fcn = translate_left; |
| |
| x1 = xcen + bwid/2 + space; |
| button[2].xleft = x1; |
| button[2].ytop = y1; |
| #ifdef X11 |
| setpoly (2, bwid/2, bwid/2, bwid/3, 0); /* Right */ |
| #else |
| button[2].type = BUTTON_TEXT; |
| strcpy(button[2].text, "R"); |
| #endif |
| button[2].fcn = translate_right; |
| |
| y1 += bwid + space; |
| x1 = xcen - bwid/2; |
| button[3].xleft = x1; |
| button[3].ytop = y1; |
| #ifdef X11 |
| setpoly (3, bwid/2, bwid/2, bwid/3, +PI/2.); /* Down */ |
| #else |
| button[3].type = BUTTON_TEXT; |
| strcpy(button[3].text, "D"); |
| #endif |
| button[3].fcn = translate_down; |
| |
| for (i = 0; i < NUM_ARROW_BUTTONS; i++) { |
| button[i].width = bwid; |
| button[i].height = bwid; |
| button[i].enabled = 1; |
| } |
| |
| /* Rectangular buttons */ |
| |
| y1 += bwid + space + 6; |
| space = 8; |
| bwid = 90; |
| bheight = 26; |
| x1 = xcen - bwid/2; |
| for (i = NUM_ARROW_BUTTONS; i < NUM_STANDARD_BUTTONS; i++) { |
| button[i].xleft = x1; |
| button[i].ytop = y1; |
| button[i].type = BUTTON_TEXT; |
| button[i].width = bwid; |
| button[i].enabled = 1; |
| if (i != SEPARATOR_BUTTON_INDEX) { |
| button[i].height = bheight; |
| y1 += bheight + space; |
| } |
| else { |
| button[i].height = 2; |
| button[i].type = BUTTON_SEPARATOR; |
| y1 += 2 + space; |
| } |
| } |
| |
| strcpy (button[4].text,"Zoom In"); |
| strcpy (button[5].text,"Zoom Out"); |
| strcpy (button[6].text,"Zoom Fit"); |
| strcpy (button[7].text,"Window"); |
| strcpy (button[8].text,"---1"); |
| strcpy (button[9].text,"PostScript"); |
| strcpy (button[10].text,"Proceed"); |
| strcpy (button[11].text,"Exit"); |
| |
| button[4].fcn = zoom_in; |
| button[5].fcn = zoom_out; |
| button[6].fcn = zoom_fit; |
| button[7].fcn = adjustwin; // see 'adjustButton' below in WIN32 section |
| button[8].fcn = NULL; |
| button[9].fcn = postscript; |
| button[10].fcn = proceed; |
| button[11].fcn = quit; |
| |
| for (i = 0; i < NUM_STANDARD_BUTTONS; i++) |
| map_button (i); |
| num_buttons = NUM_STANDARD_BUTTONS; |
| |
| #ifdef WIN32 |
| adjustButton = 7; |
| if(!InvalidateRect(hButtonsWnd, NULL, TRUE)) |
| DRAW_ERROR(); |
| if(!UpdateWindow(hButtonsWnd)) |
| DRAW_ERROR(); |
| #endif |
| } |
| |
| /* Makes sure the font of the specified size is loaded. Point_size * |
| * MUST be between 1 and MAX_FONT_SIZE. */ |
| static void |
| load_font(int pointsize) |
| { |
| |
| if (pointsize > MAX_FONT_SIZE || pointsize < 1) { |
| printf ("Error: font size %d is out of valid range, 1 to %d.\n", |
| pointsize, MAX_FONT_SIZE); |
| return; |
| } |
| |
| if (font_is_loaded[pointsize]) // Nothing to do. |
| return; |
| |
| #ifdef X11 |
| #define NUM_FONT_TYPES 3 |
| char fontname[NUM_FONT_TYPES][BUFSIZE]; |
| int ifont; |
| bool success = false; |
| |
| /* Use proper point-size medium-weight upright helvetica font */ |
| // Exists on most X11 systems. |
| // Backup font: lucidasans, in the new naming style. |
| sprintf(fontname[0],"-*-helvetica-medium-r-*--*-%d0-*-*-*-*-*-*", |
| pointsize); |
| sprintf(fontname[1], "lucidasans-%d", pointsize); |
| sprintf(fontname[2],"-schumacher-clean-medium-r-*--*-%d0-*-*-*-*-*-*", |
| pointsize); |
| |
| |
| |
| |
| for (ifont = 0; ifont < NUM_FONT_TYPES; ifont++) { |
| #ifdef VERBOSE |
| printf ("Loading font: point size: %d, fontname: %s\n",pointsize, |
| fontname[ifont]); |
| #endif |
| /* Load font and get font information structure. */ |
| if ((font_info[pointsize] = XLoadQueryFont(display,fontname[ifont])) == NULL) { |
| #ifdef VERBOSE |
| fprintf( stderr, "Cannot open font %s\n", fontname[ifont]); |
| #endif |
| } |
| else { |
| success = true; |
| break; |
| } |
| } |
| if (!success) { |
| printf ("Error in load_font: cannot load any font of pointsize %d.\n", |
| pointsize); |
| printf ("Use xlsfonts to list available fonts, and modify load_font\n"); |
| printf ("in graphics.cpp.\n"); |
| exit (1); |
| } |
| #else /* WIN32 */ |
| LOGFONT *lf = font_info[pointsize] = (LOGFONT*)my_malloc(sizeof(LOGFONT)); |
| ZeroMemory(lf, sizeof(LOGFONT)); |
| lf->lfHeight = pointsize; |
| lf->lfWeight = FW_NORMAL; |
| lf->lfCharSet = ANSI_CHARSET; |
| lf->lfOutPrecision = OUT_DEFAULT_PRECIS; |
| lf->lfClipPrecision = CLIP_DEFAULT_PRECIS; |
| lf->lfQuality = PROOF_QUALITY; |
| lf->lfPitchAndFamily = VARIABLE_PITCH | FF_SWISS; |
| strcpy(lf->lfFaceName, "Arial"); |
| #endif |
| |
| font_is_loaded[pointsize] = true; |
| } |
| |
| |
| /* Return information useful for debugging. |
| * Used to return the top-level window object too, but that made graphics.h |
| * export all windows and X11 headers to the client program, so VB deleted |
| * that object (mainwnd) from this structure. |
| */ |
| void report_structure(t_report *report) { |
| report->xmult = xmult; |
| report->ymult = ymult; |
| report->xleft = xleft; |
| report->xright = xright; |
| report->ytop = ytop; |
| report->ybot = ybot; |
| report->ps_xmult = ps_xmult; |
| report->ps_ymult = ps_ymult; |
| report->top_width = top_width; |
| report->top_height = top_height; |
| } |
| |
| |
| void set_mouse_move_input (bool enable) { |
| get_mouse_move_input = enable; |
| } |
| |
| |
| void set_keypress_input (bool enable) { |
| get_keypress_input = enable; |
| } |
| |
| |
| void enable_or_disable_button (int ibutton, bool enabled) { |
| |
| if (button[ibutton].type != BUTTON_SEPARATOR) { |
| button[ibutton].enabled = enabled; |
| #ifdef WIN32 |
| EnableWindow(button[ibutton].hwnd, button[ibutton].enabled); |
| #else // X11 |
| drawbut(ibutton); |
| XFlush(display); |
| #endif |
| } |
| } |
| |
| |
| void set_draw_mode (enum e_draw_mode draw_mode) { |
| /* Set normal (overwrite) or xor (useful for rubber-banding) |
| * drawing mode. |
| */ |
| |
| if (draw_mode == DRAW_NORMAL) { |
| #ifdef X11 |
| current_gc = gc; |
| #else |
| if (!SetROP2(hGraphicsDC, R2_COPYPEN)) |
| SELECT_ERROR(); |
| #endif |
| } |
| else { // DRAW_XOR |
| #ifdef X11 |
| current_gc = gcxor; |
| #else |
| if (!SetROP2(hGraphicsDC, R2_XORPEN)) |
| SELECT_ERROR(); |
| #endif |
| } |
| current_draw_mode = draw_mode; |
| } |
| |
| |
| void change_button_text(const char *button_name, const char *new_button_text) { |
| /* Change the text on a button with button_name to new_button_text. |
| * Not a strictly necessary function, since you could intead just |
| * destroy button_name and make a new buton. |
| */ |
| int i, bnum; |
| |
| bnum = -1; |
| |
| for (i=4;i<num_buttons;i++) { |
| if (button[i].type == BUTTON_TEXT && |
| strcmp (button[i].text, button_name) == 0) { |
| bnum = i; |
| break; |
| } |
| } |
| |
| if (bnum != -1) { |
| strncpy (button[i].text, new_button_text, BUTTON_TEXT_LEN); |
| #ifdef X11 |
| drawbut (i); |
| #else // Win32 |
| SetWindowText(button[bnum].hwnd, new_button_text); |
| #endif |
| } |
| } |
| |
| |
| |
| |
| /********************************** |
| * X-Windows Specific Definitions * |
| *********************************/ |
| #ifdef X11 |
| |
| /* Creates a small window at the top of the graphics area for text messages */ |
| static void build_textarea (void) |
| { |
| XSetWindowAttributes menu_attributes; |
| unsigned long valuemask; |
| |
| textarea = XCreateSimpleWindow(display,toplevel, |
| 0, top_height-T_AREA_HEIGHT, display_width-MWIDTH, T_AREA_HEIGHT, 0, |
| colors[BLACK], colors[LIGHTGREY]); |
| menu_attributes.event_mask = ExposureMask; |
| /* ButtonPresses in this area are ignored. */ |
| menu_attributes.do_not_propagate_mask = ButtonPressMask; |
| /* Keep text area on bottom left */ |
| menu_attributes.win_gravity = SouthWestGravity; |
| valuemask = CWWinGravity | CWEventMask | CWDontPropagate; |
| XChangeWindowAttributes(display, textarea, valuemask, &menu_attributes); |
| XMapWindow (display, textarea); |
| } |
| |
| |
| |
| static Bool test_if_exposed (Display *disp, XEvent *event_ptr, XPointer dummy) |
| /* Returns True if the event passed in is an exposure event. Note that |
| * the bool type returned by this function is defined in Xlib.h. |
| */ |
| { |
| |
| |
| if (event_ptr->type == Expose) { |
| return (True); |
| } |
| |
| return (False); |
| } |
| |
| |
| static void menutext(Window win, int xc, int yc, const char *text) |
| { |
| |
| /* draws text center at xc, yc -- used only by menu drawing stuff */ |
| |
| int len, width; |
| |
| len = strlen(text); |
| width = XTextWidth(font_info[menu_font_size], text, len); |
| XDrawString(display, win, gc_menus, xc-width/2, yc + |
| (font_info[menu_font_size]->ascent - font_info[menu_font_size]->descent)/2, |
| text, len); |
| } |
| |
| |
| static void drawbut (int bnum) |
| { |
| |
| /* Draws button bnum in either its pressed or unpressed state. */ |
| |
| int width, height, thick, i, ispressed; |
| XPoint mypoly[6]; |
| |
| width = button[bnum].width; |
| height = button[bnum].height; |
| |
| if (button[bnum].type == BUTTON_SEPARATOR) { |
| int x,y; |
| |
| x = button[bnum].xleft; |
| y = button[bnum].ytop; |
| XSetForeground(display, gc_menus,colors[WHITE]); |
| XDrawLine(display, menu, gc_menus, x, y+1, x+width, y+1); |
| XSetForeground(display, gc_menus,colors[BLACK]); |
| XDrawLine(display, menu, gc_menus, x, y, x+width, y); |
| return; |
| } |
| |
| ispressed = button[bnum].ispressed; |
| thick = 2; |
| /* Draw top and left edges of 3D box. */ |
| if (ispressed) { |
| XSetForeground(display, gc_menus,colors[BLACK]); |
| } |
| else { |
| XSetForeground(display, gc_menus,colors[WHITE]); |
| } |
| |
| /* Note: X Windows doesn't appear to draw the bottom pixel of * |
| * a polygon with XFillPolygon, so I make this 1 pixel thicker * |
| * to compensate. */ |
| mypoly[0].x = 0; |
| mypoly[0].y = height; |
| mypoly[1].x = 0; |
| mypoly[1].y = 0; |
| mypoly[2].x = width; |
| mypoly[2].y = 0; |
| mypoly[3].x = width-thick; |
| mypoly[3].y = thick; |
| mypoly[4].x = thick; |
| mypoly[4].y = thick; |
| mypoly[5].x = thick; |
| mypoly[5].y = height-thick; |
| XFillPolygon(display,button[bnum].win,gc_menus,mypoly,6,Convex, |
| CoordModeOrigin); |
| |
| /* Draw bottom and right edges of 3D box. */ |
| if (ispressed) { |
| XSetForeground(display, gc_menus,colors[WHITE]); |
| } |
| else { |
| XSetForeground(display, gc_menus,colors[BLACK]); |
| } |
| mypoly[0].x = 0; |
| mypoly[0].y = height; |
| mypoly[1].x = width; |
| mypoly[1].y = height; |
| mypoly[2].x = width; |
| mypoly[2].y = 0; |
| mypoly[3].x = width-thick; |
| mypoly[3].y = thick; |
| mypoly[4].x = width-thick; |
| mypoly[4].y = height-thick; |
| mypoly[5].x = thick; |
| mypoly[5].y = height-thick; |
| XFillPolygon(display,button[bnum].win,gc_menus,mypoly,6,Convex, |
| CoordModeOrigin); |
| |
| /* Draw background */ |
| if (ispressed) { |
| XSetForeground(display, gc_menus,colors[DARKGREY]); |
| } |
| else { |
| XSetForeground(display, gc_menus,colors[LIGHTGREY]); |
| } |
| |
| /* Give x,y of top corner and width and height */ |
| XFillRectangle (display,button[bnum].win,gc_menus,thick,thick, |
| width-2*thick, height-2*thick); |
| |
| /* Draw polygon, if there is one */ |
| if (button[bnum].type == BUTTON_POLY) { |
| for (i=0;i<3;i++) { |
| mypoly[i].x = button[bnum].poly[i][0]; |
| mypoly[i].y = button[bnum].poly[i][1]; |
| } |
| XSetForeground(display, gc_menus,colors[BLACK]); |
| XFillPolygon(display,button[bnum].win,gc_menus,mypoly,3,Convex, |
| CoordModeOrigin); |
| } |
| |
| /* Draw text, if there is any */ |
| if (button[bnum].type == BUTTON_TEXT) { |
| if (button[bnum].enabled) |
| XSetForeground(display, gc_menus,colors[BLACK]); |
| else |
| XSetForeground(display, gc_menus,colors[DARKGREY]); |
| menutext(button[bnum].win,button[bnum].width/2, |
| button[bnum].height/2,button[bnum].text); |
| } |
| } |
| |
| |
| static int which_button (Window win) |
| { |
| int i; |
| |
| for (i=0;i<num_buttons;i++) { |
| if (button[i].win == win) |
| return(i); |
| } |
| printf("Error: Unknown button ID in which_button.\n"); |
| return(0); |
| } |
| |
| |
| static void turn_on_off (int pressed) { |
| /* Shows when the menu is active or inactive by colouring the |
| * buttons. |
| */ |
| int i; |
| |
| for (i=0;i<num_buttons;i++) { |
| button[i].ispressed = pressed; |
| drawbut(i); |
| } |
| } |
| |
| |
| static void drawmenu(void) |
| { |
| int i; |
| |
| XClearWindow (display, menu); |
| XSetForeground(display, gc_menus,colors[WHITE]); |
| XDrawRectangle(display, menu, gc_menus, 0, 0, MWIDTH, top_height); |
| XSetForeground(display, gc_menus,colors[BLACK]); |
| XDrawLine(display, menu, gc_menus, 0, top_height-1, MWIDTH, top_height-1); |
| XDrawLine(display, menu, gc_menus, MWIDTH-1, top_height, MWIDTH-1, 0); |
| |
| for (i=0;i<num_buttons;i++) { |
| drawbut(i); |
| } |
| } |
| |
| #endif /* X-Windows Specific Definitions */ |
| |
| |
| |
| /************************************************* |
| * Microsoft Windows (WIN32) Specific Definitions * |
| *************************************************/ |
| #ifdef WIN32 |
| |
| static LRESULT CALLBACK |
| MainWND(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) |
| { |
| MINMAXINFO FAR *lpMinMaxInfo; |
| |
| switch(message) |
| { |
| |
| case WM_CREATE: |
| hStatusWnd = CreateWindow(szStatusName, NULL, WS_CHILDWINDOW | WS_VISIBLE, |
| 0, 0, 0, 0, hwnd, (HMENU) 102, (HINSTANCE) GetWindowLong(hwnd, GWL_HINSTANCE), NULL); |
| hButtonsWnd = CreateWindow(szButtonsName, NULL, WS_CHILDWINDOW | WS_VISIBLE, |
| 0, 0, 0, 0, hwnd, (HMENU) 103, (HINSTANCE) GetWindowLong(hwnd, GWL_HINSTANCE), NULL); |
| hGraphicsWnd = CreateWindow(szGraphicsName, NULL, WS_CHILDWINDOW | WS_VISIBLE, |
| 0, 0, 0, 0, hwnd, (HMENU) 101, (HINSTANCE) GetWindowLong(hwnd, GWL_HINSTANCE), NULL); |
| return 0; |
| |
| case WM_SIZE: |
| /* Window has been resized. Save the new client dimensions */ |
| top_width = LOWORD (lParam); |
| top_height = HIWORD (lParam); |
| |
| /* Resize the children windows */ |
| if(!MoveWindow(hGraphicsWnd, 1, 1, top_width - MWIDTH - 1, top_height - T_AREA_HEIGHT - 1, TRUE)) |
| DRAW_ERROR(); |
| // if (drawscreen_ptr) |
| // zoom_fit(drawscreen_ptr); |
| if(!MoveWindow(hStatusWnd, 0, top_height - T_AREA_HEIGHT, top_width - MWIDTH, T_AREA_HEIGHT, TRUE)) |
| DRAW_ERROR(); |
| if(!MoveWindow(hButtonsWnd, top_width - MWIDTH, 0, MWIDTH, top_height, TRUE)) |
| DRAW_ERROR(); |
| |
| return 0; |
| |
| // WC : added to solve window resizing problem |
| case WM_GETMINMAXINFO: |
| // set the MINMAXINFO structure pointer |
| lpMinMaxInfo = (MINMAXINFO FAR *) lParam; |
| lpMinMaxInfo->ptMinTrackSize.x = display_width / 2; |
| lpMinMaxInfo->ptMinTrackSize.y = display_height / 2; |
| |
| return 0; |
| |
| |
| case WM_DESTROY: |
| if(!DeleteObject(hGrayBrush)) |
| DELETE_ERROR(); |
| PostQuitMessage(0); |
| return 0; |
| |
| case WM_KEYDOWN: |
| if (get_keypress_input) |
| keypress_ptr((char) wParam); |
| return 0; |
| } |
| |
| return DefWindowProc(hwnd, message, wParam, lParam); |
| } |
| |
| |
| static LRESULT CALLBACK |
| GraphicsWND(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) |
| { |
| static TEXTMETRIC tm; |
| |
| PAINTSTRUCT ps; |
| static RECT oldAdjustRect; |
| static HPEN hDotPen = 0; |
| static HBITMAP hbmBuffer = 0, hbmObjtest, hbmAllObjtest; |
| static int X, Y, i; |
| |
| switch(message) |
| { |
| case WM_CREATE: |
| |
| /* Get the text metrics once upon creation (system font cannot change) */ |
| hCurrentDC = hGraphicsDC = hForegroundDC = GetDC (hwnd); |
| if(!hGraphicsDC) |
| DRAW_ERROR(); |
| |
| hBackgroundDC = CreateCompatibleDC(hForegroundDC); |
| if (!hBackgroundDC) |
| CREATE_ERROR(); |
| if (!SetMapMode(hBackgroundDC, MM_TEXT)) |
| CREATE_ERROR(); |
| hbmBuffer = CreateCompatibleBitmap(hForegroundDC, display_width, display_height); |
| if (!(hbmBuffer)) |
| CREATE_ERROR(); |
| if (!SelectObject(hBackgroundDC, hbmBuffer)) |
| SELECT_ERROR(); |
| |
| // monochrome bitmap |
| hObjtestDC = CreateCompatibleDC(hForegroundDC); |
| if (!hObjtestDC) |
| CREATE_ERROR(); |
| if (!SetMapMode(hObjtestDC, MM_TEXT)) |
| CREATE_ERROR(); |
| hbmObjtest = CreateCompatibleBitmap(hObjtestDC, display_width, display_height); |
| if (!(hbmObjtest)) |
| CREATE_ERROR(); |
| if (!SelectObject(hObjtestDC, hbmObjtest)) |
| SELECT_ERROR(); |
| |
| // monochrome bitmap |
| hAllObjtestDC = CreateCompatibleDC(hForegroundDC); |
| if (!hObjtestDC) |
| CREATE_ERROR(); |
| if (!SetMapMode(hAllObjtestDC, MM_TEXT)) |
| CREATE_ERROR(); |
| hbmAllObjtest = CreateCompatibleBitmap(hAllObjtestDC, display_width, display_height); |
| if (!(hbmAllObjtest)) |
| CREATE_ERROR(); |
| if (!SelectObject(hAllObjtestDC, hbmAllObjtest)) |
| SELECT_ERROR(); |
| |
| //if(!GetTextMetrics (hGraphicsDC, &tm)) |
| // DRAW_ERROR(); |
| if(!SetBkMode(hGraphicsDC, TRANSPARENT)) |
| DRAW_ERROR(); |
| |
| /* Setup the pens, etc */ |
| currentlinestyle = SOLID; |
| currentcolor = BLACK; |
| currentlinewidth = 1; |
| |
| /* |
| if(!ReleaseDC (hwnd, hGraphicsDC)) |
| DRAW_ERROR(); |
| |
| hGraphicsDC = 0; |
| */ currentfontsize = 12; |
| return 0; |
| |
| case WM_PAINT: |
| // was in xor mode, but got a general redraw. |
| // switch to normal drawing so we repaint properly. |
| if (current_draw_mode == DRAW_XOR) { |
| set_draw_mode(DRAW_NORMAL); |
| invalidate_screen(); |
| return 0; |
| } |
| hCurrentDC = hGraphicsDC; |
| drawtoscreen(); |
| /*hGraphicsDC =*/ BeginPaint(hwnd, &ps); |
| if(!hGraphicsDC) |
| DRAW_ERROR(); |
| |
| if (InEventLoop) { |
| if(!GetUpdateRect(hwnd, &updateRect, FALSE)) { |
| updateRect.left = 0; |
| updateRect.right = top_width; |
| updateRect.top = 0; |
| updateRect.bottom = top_height; |
| } |
| |
| if(windowAdjustFlag > 1) { |
| hDotPen = CreatePen(PS_DASH, 1, win32_colors[gl_state.background_cindex]); |
| if(!hDotPen) |
| CREATE_ERROR(); |
| if (!SetROP2(hGraphicsDC, R2_XORPEN)) |
| SELECT_ERROR(); |
| if(!SelectObject(hGraphicsDC, GetStockObject(NULL_BRUSH))) |
| SELECT_ERROR(); |
| if(!SelectObject(hGraphicsDC, hDotPen)) |
| SELECT_ERROR(); |
| if(!Rectangle(hGraphicsDC, oldAdjustRect.left, oldAdjustRect.top, |
| oldAdjustRect.right, oldAdjustRect.bottom)) |
| DRAW_ERROR(); |
| if(!Rectangle(hGraphicsDC, adjustRect.left, adjustRect.top, adjustRect.right, |
| adjustRect.bottom)) |
| DRAW_ERROR(); |
| oldAdjustRect = adjustRect; |
| if (!SetROP2(hGraphicsDC, R2_COPYPEN)) |
| SELECT_ERROR(); |
| if(!SelectObject(hGraphicsDC, GetStockObject(NULL_PEN))) |
| SELECT_ERROR(); |
| if(!DeleteObject(hDotPen)) |
| DELETE_ERROR(); |
| } |
| else |
| drawscreen_ptr(); |
| } |
| EndPaint(hwnd, &ps); |
| hGraphicsDC = hCurrentDC; |
| |
| /* Crash hard if called at wrong time */ |
| /* hGraphicsDC = NULL;*/ |
| return 0; |
| |
| case WM_SIZE: |
| /* Window has been resized. Save the new client dimensions */ |
| cxClient = LOWORD (lParam); |
| cyClient = HIWORD (lParam); |
| update_transform(); |
| |
| return 0; |
| |
| case WM_DESTROY: |
| if(!DeleteObject(hGraphicsPen)) |
| DELETE_ERROR(); |
| if(!DeleteObject(hGraphicsBrush)) |
| DELETE_ERROR(); |
| if(!DeleteObject(hGraphicsFont)) |
| DELETE_ERROR(); |
| if (!DeleteObject(hbmBuffer)) |
| DELETE_ERROR(); |
| if (!DeleteObject(hbmObjtest)) |
| DELETE_ERROR(); |
| if (!DeleteObject(hbmAllObjtest)) |
| DELETE_ERROR(); |
| if(!DeleteDC(hBackgroundDC)) |
| DELETE_ERROR(); |
| if(!DeleteDC(hObjtestDC)) |
| DELETE_ERROR(); |
| if(!DeleteDC(hAllObjtestDC)) |
| DELETE_ERROR(); |
| if(!ReleaseDC(hwnd, hForegroundDC)) |
| DELETE_ERROR(); |
| PostQuitMessage(0); |
| return 0; |
| |
| case WM_LBUTTONDOWN: |
| if (!windowAdjustFlag) { |
| mouseclick_ptr(XTOWORLD(LOWORD(lParam)), YTOWORLD(HIWORD(lParam))); |
| } |
| else { |
| // Special handling for the "Window" command, which takes multiple clicks. |
| // First you push the button, then you click for one corner, then you click for the other |
| // corner. |
| if(windowAdjustFlag == 1) { |
| windowAdjustFlag ++; |
| X = adjustRect.left = adjustRect.right = LOWORD(lParam); |
| Y = adjustRect.top = adjustRect.bottom = HIWORD(lParam); |
| oldAdjustRect = adjustRect; |
| } |
| else { |
| int i; |
| int adjustx[2], adjusty[2]; |
| |
| windowAdjustFlag = 0; |
| button[adjustButton].ispressed = 0; |
| SendMessage(button[adjustButton].hwnd, BM_SETSTATE, 0, 0); |
| |
| for (i=0; i<num_buttons; i++) { |
| if (button[i].type != BUTTON_SEPARATOR && button[i].enabled) { |
| if(!EnableWindow (button[i].hwnd, TRUE)) |
| DRAW_ERROR(); |
| } |
| } |
| adjustx[0] = adjustRect.left; |
| adjustx[1] = adjustRect.right; |
| adjusty[0] = adjustRect.top; |
| adjusty[1] = adjustRect.bottom; |
| |
| update_win(adjustx, adjusty, invalidate_screen); |
| } |
| } |
| return 0; |
| |
| // right click : a quick way to zoom in |
| case WM_RBUTTONDOWN: |
| if (!windowAdjustFlag) { |
| // first disable some buttons |
| //adjustButton = LOWORD(wParam) - 200; |
| button[adjustButton].ispressed = 1; |
| for (i=0; i<num_buttons; i++) { |
| EnableWindow(button[i].hwnd, FALSE); |
| SendMessage(button[i].hwnd, BM_SETSTATE, button[i].ispressed, 0); |
| } |
| |
| windowAdjustFlag = 2; |
| X = adjustRect.left = adjustRect.right = LOWORD(lParam); |
| Y = adjustRect.top = adjustRect.bottom = HIWORD(lParam); |
| oldAdjustRect = adjustRect; |
| } |
| else { |
| int i; |
| int adjustx[2], adjusty[2]; |
| |
| windowAdjustFlag = 0; |
| button[adjustButton].ispressed = 0; |
| SendMessage(button[adjustButton].hwnd, BM_SETSTATE, 0, 0); |
| |
| for (i=0; i<num_buttons; i++) { |
| if (button[i].type != BUTTON_SEPARATOR && button[i].enabled) { |
| if(!EnableWindow (button[i].hwnd, TRUE)) |
| DRAW_ERROR(); |
| } |
| } |
| adjustx[0] = adjustRect.left; |
| adjustx[1] = adjustRect.right; |
| adjusty[0] = adjustRect.top; |
| adjusty[1] = adjustRect.bottom; |
| |
| update_win(adjustx, adjusty, invalidate_screen); |
| } |
| return 0; |
| |
| case WM_MOUSEMOVE: |
| if(windowAdjustFlag == 1) { |
| return 0; |
| } |
| else if (windowAdjustFlag >= 2) { |
| if ( X > LOWORD(lParam)) { |
| adjustRect.left = LOWORD(lParam); |
| adjustRect.right = X; |
| } |
| else { |
| adjustRect.left = X; |
| adjustRect.right = LOWORD(lParam); |
| } |
| if ( Y > HIWORD(lParam)) { |
| adjustRect.top = HIWORD(lParam); |
| adjustRect.bottom = Y; |
| } |
| else { |
| adjustRect.top = Y; |
| adjustRect.bottom = HIWORD(lParam); |
| } |
| if(!InvalidateRect(hGraphicsWnd, &oldAdjustRect, FALSE)) |
| DRAW_ERROR(); |
| if(!InvalidateRect(hGraphicsWnd, &adjustRect, FALSE)) |
| DRAW_ERROR(); |
| if(!UpdateWindow(hGraphicsWnd)) |
| DRAW_ERROR(); |
| |
| return 0; |
| } |
| else if (get_mouse_move_input) |
| mousemove_ptr(XTOWORLD(LOWORD(lParam)), YTOWORLD(HIWORD(lParam))); |
| |
| return 0; |
| } |
| |
| return DefWindowProc(hwnd, message, wParam, lParam); |
| } |
| |
| |
| static LRESULT CALLBACK |
| StatusWND(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) |
| { |
| HDC hdc; |
| PAINTSTRUCT ps; |
| RECT rect; |
| |
| switch(message) |
| { |
| case WM_CREATE: |
| hdc = GetDC(hwnd); |
| if(!hdc) |
| DRAW_ERROR(); |
| if(!SetBkMode(hdc, TRANSPARENT)) |
| DRAW_ERROR(); |
| if(!ReleaseDC(hwnd, hdc)) |
| DRAW_ERROR(); |
| return 0; |
| |
| case WM_PAINT: |
| hdc = BeginPaint(hwnd, &ps); |
| if(!hdc) |
| DRAW_ERROR(); |
| |
| if(!GetClientRect(hwnd, &rect)) |
| DRAW_ERROR(); |
| |
| if(!SelectObject(hdc, GetStockObject(NULL_BRUSH))) |
| SELECT_ERROR(); |
| if(!SelectObject(hdc, GetStockObject(WHITE_PEN))) |
| SELECT_ERROR(); |
| if(!Rectangle(hdc, rect.left, rect.top, rect.right, rect.bottom)) |
| DRAW_ERROR(); |
| if(!SelectObject(hdc, GetStockObject(BLACK_PEN))) |
| SELECT_ERROR(); |
| if(!MoveToEx(hdc, rect.left, rect.bottom-1, NULL)) |
| DRAW_ERROR(); |
| if(!LineTo(hdc, rect.right-1, rect.bottom-1)) |
| DRAW_ERROR(); |
| if(!LineTo(hdc, rect.right-1, rect.top)) |
| DRAW_ERROR(); |
| |
| if(!DrawText(hdc, TEXT(statusMessage), -1, &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE)) |
| DRAW_ERROR(); |
| |
| if(!EndPaint(hwnd, &ps)) |
| DRAW_ERROR(); |
| return 0; |
| |
| case WM_SIZE: |
| return 0; |
| |
| case WM_DESTROY: |
| PostQuitMessage(0); |
| return 0; |
| } |
| |
| return DefWindowProc(hwnd, message, wParam, lParam); |
| } |
| |
| |
| static LRESULT CALLBACK |
| ButtonsWND(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) |
| { |
| HDC hdc; |
| PAINTSTRUCT ps; |
| RECT rect; |
| static HBRUSH hBrush; |
| int i; |
| |
| switch(message) |
| { |
| case WM_COMMAND: |
| if (!windowAdjustFlag) { |
| button[LOWORD(wParam) - 200].fcn(invalidate_screen); |
| if (windowAdjustFlag) { |
| adjustButton = LOWORD(wParam) - 200; |
| button[adjustButton].ispressed = 1; |
| for (i=0; i<num_buttons; i++) { |
| EnableWindow(button[i].hwnd, FALSE); |
| SendMessage(button[i].hwnd, BM_SETSTATE, button[i].ispressed, 0); |
| } |
| } |
| } |
| SetFocus(hMainWnd); |
| return 0; |
| |
| case WM_CREATE: |
| hdc = GetDC(hwnd); |
| if(!hdc) |
| DRAW_ERROR(); |
| hBrush = CreateSolidBrush(win32_colors[LIGHTGREY]); |
| if(!hBrush) |
| CREATE_ERROR(); |
| if(!SelectObject(hdc, hBrush)) |
| SELECT_ERROR(); |
| if(!SetBkMode(hdc, TRANSPARENT)) |
| DRAW_ERROR(); |
| if(!ReleaseDC(hwnd, hdc)) |
| DRAW_ERROR(); |
| |
| return 0; |
| |
| case WM_PAINT: |
| hdc = BeginPaint(hwnd, &ps); |
| if(!hdc) |
| DRAW_ERROR(); |
| |
| if(!GetClientRect(hwnd, &rect)) |
| DRAW_ERROR(); |
| |
| if(!SelectObject(hdc, GetStockObject(NULL_BRUSH))) |
| SELECT_ERROR(); |
| if(!SelectObject(hdc, GetStockObject(WHITE_PEN))) |
| SELECT_ERROR(); |
| if(!Rectangle(hdc, rect.left, rect.top, rect.right, rect.bottom)) |
| DRAW_ERROR(); |
| if(!SelectObject(hdc, GetStockObject(BLACK_PEN))) |
| SELECT_ERROR(); |
| if(!MoveToEx(hdc, rect.left, rect.bottom-1, NULL)) |
| DRAW_ERROR(); |
| if(!LineTo(hdc, rect.right-1, rect.bottom-1)) |
| DRAW_ERROR(); |
| if(!LineTo(hdc, rect.right-1, rect.top)) |
| DRAW_ERROR(); |
| |
| for (i=0; i < num_buttons; i++) { |
| if(button[i].type == BUTTON_SEPARATOR) { |
| int x, y, w; |
| |
| x = button[i].xleft; |
| y = button[i].ytop; |
| w = button[i].width; |
| |
| if(!MoveToEx (hdc, x, y, NULL)) |
| DRAW_ERROR(); |
| if(!LineTo (hdc, x + w, y)) |
| DRAW_ERROR(); |
| if(!SelectObject(hdc, GetStockObject(WHITE_PEN))) |
| SELECT_ERROR(); |
| if(!MoveToEx (hdc, x, y+1, NULL)) |
| DRAW_ERROR(); |
| if(!LineTo (hdc, x + w, y+1)) |
| DRAW_ERROR(); |
| if(!SelectObject(hdc, GetStockObject(BLACK_PEN))) |
| SELECT_ERROR(); |
| } |
| } |
| if(!EndPaint(hwnd, &ps)) |
| DRAW_ERROR(); |
| return 0; |
| |
| case WM_DESTROY: |
| for (i=0; i<num_buttons; i++) { |
| } |
| if(!DeleteObject(hBrush)) |
| DELETE_ERROR(); |
| PostQuitMessage(0); |
| return 0; |
| } |
| |
| return DefWindowProc(hwnd, message, wParam, lParam); |
| } |
| |
| |
| void reset_win32_state () { |
| // Not sure exactly what needs to be reset to NULL etc. |
| // Resetting everthing to be safe. |
| hGraphicsPen = 0; |
| hGraphicsBrush = 0; |
| hGrayBrush = 0; |
| hGraphicsDC = 0; |
| hForegroundDC = 0; |
| hBackgroundDC = 0; |
| hCurrentDC = 0, /* WC : double-buffer */ |
| hObjtestDC = 0; |
| hAllObjtestDC = 0; /* object test */ |
| |
| hGraphicsFont = 0; |
| |
| /* These are used for the "Window" graphics button. They keep track of whether we're entering |
| * the window rectangle to zoom to, etc. |
| */ |
| windowAdjustFlag = 0; |
| adjustButton = -1; |
| InEventLoop = FALSE; |
| } |
| |
| |
| void win32_drain_message_queue () { |
| // Drain the message queue, so we don't have a quit message lying around |
| // that will stop us from re-opening a window later if desired. |
| MSG msg; |
| while (PeekMessage(&msg, hMainWnd, 0, 0, PM_REMOVE)) { |
| if (msg.message == WM_QUIT) { |
| printf ("Got the quit message.\n"); |
| } |
| } |
| } |
| |
| |
| void drawtobuffer(void) { |
| hGraphicsDC = hBackgroundDC; |
| } |
| |
| |
| void drawtoscreen(void) { |
| hGraphicsDC = hForegroundDC; |
| } |
| |
| |
| void displaybuffer(void) { |
| if (!BitBlt(hForegroundDC, xcoord(xleft), ycoord(ytop), |
| xcoord(xright)-xcoord(xleft), ycoord(ybot)-ycoord(ytop), hBackgroundDC,//hAllObjtestDC, |
| 0, 0, SRCCOPY)) |
| DRAW_ERROR(); |
| } |
| |
| |
| static void _drawcurve(t_point *points, int npoints, int fill) { |
| /* Draw a beizer curve. |
| * Must have 3I+1 points, since each Beizer curve needs 3 points and we also |
| * need an initial starting point |
| */ |
| HPEN hOldPen; |
| HBRUSH hOldBrush; |
| float xmin, ymin, xmax, ymax; |
| int i; |
| |
| if ((npoints - 1) % 3 != 0 || npoints > MAXPTS) |
| DRAW_ERROR(); |
| |
| /* Conservative (but fast) clip test -- check containing rectangle of * |
| * polygon. */ |
| |
| xmin = xmax = points[0].x; |
| ymin = ymax = points[0].y; |
| |
| for (i=1;i<npoints;i++) { |
| xmin = min (xmin,points[i].x); |
| xmax = max (xmax,points[i].x); |
| ymin = min (ymin,points[i].y); |
| ymax = max (ymax,points[i].y); |
| } |
| |
| if (rect_off_screen(xmin,ymin,xmax,ymax)) |
| return; |
| |
| if (gl_state.disp_type == SCREEN) { |
| #ifdef X11 |
| /* implement X11 version here */ |
| #else /* Win32 */ |
| // create POINT array |
| POINT pts[MAXPTS]; |
| int i; |
| |
| for (i = 0; i < npoints; i++) { |
| pts[i].x = xcoord(points[i].x); |
| pts[i].y = ycoord(points[i].y); |
| } |
| |
| if (!fill) { |
| hOldPen = (HPEN)SelectObject(hGraphicsDC, hGraphicsPen); |
| if(!(hOldPen)) |
| SELECT_ERROR(); |
| } |
| else { |
| hOldPen = (HPEN)SelectObject(hGraphicsDC, GetStockObject(NULL_PEN)); |
| if(!(hOldPen)) |
| SELECT_ERROR(); |
| hOldBrush = (HBRUSH)SelectObject(hGraphicsDC, hGraphicsBrush); |
| if(!(hOldBrush)) |
| SELECT_ERROR(); |
| } |
| |
| if (!BeginPath(hGraphicsDC)) |
| DRAW_ERROR(); |
| if(!PolyBezier(hGraphicsDC, pts, npoints)) |
| DRAW_ERROR(); |
| if (!EndPath(hGraphicsDC)) |
| DRAW_ERROR(); |
| |
| if (!fill) { |
| if (!StrokePath(hGraphicsDC)) |
| DRAW_ERROR(); |
| } |
| else { |
| if (!FillPath(hGraphicsDC)) |
| DRAW_ERROR(); |
| } |
| |
| if(!SelectObject(hGraphicsDC, hOldPen)) |
| SELECT_ERROR(); |
| |
| if (fill) { |
| if(!SelectObject(hGraphicsDC, hOldBrush)) |
| SELECT_ERROR(); |
| } |
| #endif |
| } |
| else { |
| int i; |
| |
| fprintf(ps, "newpath\n"); |
| fprintf(ps, "%.2f %.2f moveto\n", XPOST(points[0].x), YPOST(points[0].y)); |
| for (i = 1; i < npoints; i+= 3) |
| fprintf(ps,"%.2f %.2f %.2f %.2f %.2f %.2f curveto\n", XPOST(points[i].x), YPOST(points[i].y), |
| XPOST(points[i+1].x), YPOST(points[i+1].y), XPOST(points[i+2].x), YPOST(points[i+2].y)); |
| if (!fill) |
| fprintf(ps, "stroke\n"); |
| else |
| fprintf(ps, "fill\n"); |
| } |
| } |
| |
| |
| void drawcurve(t_point *points, |
| int npoints) { |
| _drawcurve(points, npoints, 0); |
| } |
| |
| |
| void fillcurve(t_point *points, |
| int npoints) { |
| _drawcurve(points, npoints, 1); |
| } |
| |
| |
| void object_start(int all) { |
| if (all) |
| hGraphicsDC = hAllObjtestDC; |
| else |
| hGraphicsDC = hObjtestDC; |
| setcolor(WHITE); |
| fillrect (xleft, ytop, xright, ybot); |
| setcolor(BLACK); |
| } |
| |
| |
| void object_end() { |
| hGraphicsDC = hCurrentDC; |
| |
| } |
| |
| |
| int pt_on_object(int all, float x, float y) { |
| COLORREF c; |
| |
| if (all) |
| c = GetPixel(hAllObjtestDC, xcoord(x), ycoord(y)); |
| else |
| c = GetPixel(hObjtestDC, xcoord(x), ycoord(y)); |
| |
| // printf("c = %x\n", c); |
| |
| return c == win32_colors[BLACK]; |
| } |
| |
| static int check_fontsize(int pointsize, |
| float ymax) { |
| // return 0 if matches, 1 if font too big, -1 if font too small |
| // a font matches if it's height is 90-100% of ymax tall |
| float height; |
| TEXTMETRIC textmetric; |
| HFONT hOldFont; |
| int ret; |
| |
| setfontsize(pointsize); |
| |
| hOldFont = (HFONT)SelectObject(hGraphicsDC, hGraphicsFont); |
| if(!(hOldFont)) |
| SELECT_ERROR(); |
| |
| if (!GetTextMetrics(hGraphicsDC, &textmetric)) |
| DRAW_ERROR(); |
| height = (textmetric.tmAscent + 2 * textmetric.tmDescent) / ymult; |
| |
| if (height >= ymax * 0.9) { |
| if (height <= ymax) |
| ret = 0; |
| else |
| ret = 1; |
| } |
| else |
| ret = -1; |
| |
| if(!SelectObject(hGraphicsDC, hOldFont)) |
| SELECT_ERROR(); |
| |
| return ret; |
| } |
| |
| int findfontsize(float ymax) { |
| // find the correct point size which will fit in the specified ymax as the max |
| // height of the font, using a binary search |
| int bot = 1; |
| int top = MAX_FONT_SIZE; |
| int mid, check; |
| |
| while (bot <= top) { |
| mid = (bot+top)/2; |
| |
| check = check_fontsize(mid, ymax); |
| if (!(check)) |
| return mid; |
| else if (check > 0) // too big |
| top = mid - 1; |
| else // too small |
| bot = mid + 1; |
| } |
| if (bot > MAX_FONT_SIZE) |
| return MAX_FONT_SIZE; |
| |
| return -1; // can't fit |
| } |
| |
| #endif /******** Win32 Specific Definitions ********************/ |
| |
| |
| #else /***** NO_GRAPHICS *******/ |
| /* No graphics at all. Stub everything out so calling program doesn't have to change |
| * but of course graphics won't do anything. |
| */ |
| |
| #include "graphics.h" |
| |
| void event_loop (void (*act_on_mousebutton) (float x, float y), |
| void (*act_on_mousemove) (float x, float y), |
| void (*act_on_keypress) (char key_pressed), |
| void (*drawscreen) (void)) { } |
| |
| void init_graphics (const char *window_name, int cindex) { } |
| void close_graphics (void) { } |
| void update_message (const char *msg) { } |
| void draw_message (void) { } |
| void init_world (float xl, float yt, float xr, float yb) { } |
| void flushinput (void) { } |
| void setcolor (int cindex) { } |
| int getcolor (void) { return 0; } |
| void setlinestyle (int linestyle) { } |
| void setlinewidth (int linewidth) { } |
| void setfontsize (int pointsize) { } |
| void drawline (float x1, float y1, float x2, float y2) { } |
| void drawrect (float x1, float y1, float x2, float y2) { } |
| void fillrect (float x1, float y1, float x2, float y2) { } |
| void fillpoly (t_point *points, int npoints) { } |
| void drawarc (float xcen, float ycen, float rad, float startang, |
| float angextent) { } |
| void drawellipticarc (float xc, float yc, float radx, float rady, float startang, float angextent) { } |
| |
| void fillarc (float xcen, float ycen, float rad, float startang, |
| float angextent) { } |
| void fillellipticarc (float xc, float yc, float radx, float rady, float startang, float angextent) { } |
| |
| void drawtext (float xc, float yc, const char *text, float boundx) { } |
| void clearscreen (void) { } |
| |
| void create_button (const char *prev_button_text , const char *button_text, |
| void (*button_func) (void (*drawscreen) (void))) { } |
| |
| void destroy_button (const char *button_text) { } |
| |
| int init_postscript (const char *fname) { |
| return (1); |
| } |
| |
| void close_postscript (void) { } |
| |
| void report_structure(t_report*) { } |
| |
| void set_mouse_move_input (bool) { } |
| |
| void set_keypress_input (bool) { } |
| |
| void set_draw_mode (enum e_draw_mode draw_mode) { } |
| |
| void enable_or_disable_button(int ibutton, bool enabled) { } |
| |
| void change_button_text(const char *button_text, const char *new_button_text) { } |
| |
| #ifdef WIN32 |
| void drawtobuffer(void) { } |
| |
| void drawtoscreen(void) { } |
| |
| void displaybuffer(void) { } |
| |
| void drawcurve(t_point *points, int npoints) { } |
| |
| void fillcurve(t_point *points, int npoints) { } |
| |
| void object_start(int all) { } |
| |
| void object_end() { } |
| |
| int pt_on_object(float x, float y) { } |
| |
| int findfontsize(float ymax) { } |
| |
| |
| #endif // WIN32 (subset of commands) |
| |
| #endif // NO_GRAPHICS |