-
Notifications
You must be signed in to change notification settings - Fork 0
/
graphics.cpp
4475 lines (3775 loc) · 154 KB
/
graphics.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/* *
* 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, Guy Lemieux of the University of Brish *
* Columbia, and Long Yu (Mike) Wang of the University of Toronto. *
* 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.2 May 2013 - June 2013 (Mike Wang) *
* - In Win32, removed "Window" operation with right mouse click to align *
* with X11. *
* - Fixed a bug in Win32 where when the "Window" button is clicked, if the *
* application window gets minimized then returned back up, the screen *
* background would not be redrawn before new rubber band gets drawn. *
* - Grouped file scope variables into structures, factored out functions *
* that were too long, and formatted code spacings etc. *
* - Cleaned up Win32 code by removing the inefficient saving and updating *
* of graphics contexts. *
* - Added zooming with respect to cursor location. *
* - Added panning with middle mouse button (or mousewheel) click and drag. *
* - Ran experiment to test the impact of rect_off_screen() on drawscreen() *
* runtime. Found rect_off_screen() to be effective in speeding up screen *
* redraw. *
* - Added zooming using mousewheel. *
* *
* 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 win32_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. */
/**************************** Top-level summary ******************************
This graphics package provides API for client program that wishes to implement
a graphical user interface. The client program will first call init_graphics()
for initial setup, which includes opening up an application window, setting up
the specified window_name and background colour, creating sublevel windows,
etc. Then the program will call a few more setup functions such as
init_world(), which sets up world coordinates, create_button(), which sets up
menu buttons, and update_message(), which updates status bar message. After
all the setup, the program will call the main routine for the graphics,
event_loop(), which will take control of the program until the "Proceed"
button is pressed. Event_loop() directly communicates with X11/Win32 to
receive event notifications, and it either calls other event-handling
functions in the graphics package or callbacks passed as function pointers
from the client program. The most important callback function which the
client should provide is drawscreen(). Whenever the graphics need to be
redrawn, drawscreen() will be called. There are a number drawing routines
which the client can use to update the graphic contexts (ie. setcolor,
setfontsize, setlinewidth, and setlinestyle) and draw simple shapes as
desired. When the program is done executing the graphics, it should call
close_graphics() to release all drawing structures and close the graphics.*/
#ifndef NO_GRAPHICS // Strip everything out and just put in stubs if NO_GRAPHICS defined
/**********************************
* Common Preprocessor Directives *
**********************************/
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <string>
#include <iostream>
#include <algorithm>
#include "graphics.h"
using namespace std;
#if defined(X11) || defined(WIN32)
// VERBOSE is very helpful for developing event handling features. Outputs
// useful information when user interacts with the graphic interface.
// Uncomment the line below to turn on VERBOSE.
// #define VERBOSE
#define MWIDTH 104 /* Width of menu window */
#define MENU_FONT_SIZE 12 /* Font for menus and dialog boxes. */
#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
#define ZOOM_FACTOR 1.6667 /* For zooming on the graphics */
#endif
#ifdef X11
/*********************************************
* X-Windows Specific Preprocessor Directives *
*********************************************/
#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; */
#endif /* X11 Preprocessor Directives */
#ifdef WIN32
/*************************************************************
* Microsoft Windows (WIN32) Specific Preprocessor Directives *
*************************************************************/
#pragma warning(disable : 4996) // Turn off annoying warnings about strcmp.
#include <windows.h>
#include <WindowsX.h>
/* Using large values of pixel limits in order to preserve the slope of diagonal
* lines when their endpoints are clipped (one at a time) to these pixel limits.
* However, if these values are too large, then Windows will not draw the lines
* when zoomed way in. I have increased MAXPIXEL and MINPIXEL to these values so
* the diagonal lines do not change slope when zoomed way in. Also, I have tested
* to make sure these values are safe. Adding one more digit to these values
* may cause problems when zoomed way in.
* As a last note, specifying these values does not affect line clipping in X11.
* The most probable reason is that X11 does line clipping automatically.
* MW, June 2013.
*/
#define MAXPIXEL 21474836
#define MINPIXEL -21474836
/* Windows work in degrees, where as X11 and PostScript both work in radians.
* Thus, a conversion is needed for Windows.
*/
#define DEGTORAD(x) ((x)/180.*PI)
#endif /* Win32 preprocessor Directives */
/*************************************************************
* Common Structure 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 all the buttons created in the menu region.
* button: array of pointers to all the buttons created [0..num_buttons-1]
* num_buttons: number of menu buttons created
*/
typedef struct {
t_button *button;
int num_buttons;
} t_button_state;
/* Structure used to store overall graphics state variables.
* 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
* currentcolor: current color in the graphics context
* currentlinestyle: current linestyle in the graphics context
* currentlinewidth: current linewidth in the graphics context
* currentfontsize: current font size in the graphics context
* current_draw_mode: select DRAW_NORMAL (for overwrite) or DRAW_XOR (for rubber-banding)
* ps: for PostScript output
* ProceedPressed: whether the Proceed button has been pressed
* statusMessage: user message to display
* font_is_loaded: whether a specified font size is loaded
* get_keypress_input: whether keypresses are sent back to callback functions
* get_mouse_move_input: whether mouse movements are sent back to callback functions
*/
typedef struct {
bool initialized;
t_display_type disp_type;
int background_cindex;
int currentcolor;
int currentlinestyle;
int currentlinewidth;
int currentfontsize;
e_draw_mode current_draw_mode;
FILE *ps;
bool ProceedPressed;
char statusMessage[BUFSIZE];
bool font_is_loaded[MAX_FONT_SIZE + 1];
bool get_keypress_input, get_mouse_move_input;
} t_gl_state;
/* Structure used to store coordinate information used for
* graphic transformations.
* display_width and display_height: entire screen size
* top_width and top_height: application window size in pixels
* init_xleft, init_xright, init_ytop, and init_ybot: initial world coordinates
* (for use in zoom_fit() to restore initial coordinates)
* xleft, xright, ytop, and ybot: boundaries of the graphic child window in world
* coordinates
* ps_left, ps_right, ps_top, and ps_bot: figure boundaries for PostScript output,
* in PostScript coordinates
* ps_xmult and ps_ymult: world to PostScript transformation factors (number of
* PostScript coordinates per world coordinate)
* wtos_xmult and wtos_ymult: world to screen transformation factors (number of
* screen pixels per world coordinate)
* stow_xmult and stow_ymult: screen to world transformation factors (number of
* world coordinates per screen pixel)
*/
typedef struct {
int display_width, display_height;
int top_width, top_height;
float init_xleft, init_xright, init_ytop, init_ybot;
float xleft, xright, ytop, ybot;
float ps_left, ps_right, ps_top, ps_bot;
float ps_xmult, ps_ymult;
float wtos_xmult, wtos_ymult;
float stow_xmult, stow_ymult;
} t_transform_coordinates;
/* Structure used to store state variables used for panning.
* previous_x and previous_y: (in window (pixel) coordinates,) last location of
* the cursor before new motion
* panning_enabled: whether panning is activated or de-activated
*/
typedef struct {
int previous_x, previous_y;
bool panning_enabled;
} t_panning_state;
#ifdef X11
/*************************************************************
* X11 Structure Definitions *
*************************************************************/
/* Structure used to store X Windows state variables.
* display: Structure containing information needed to
* communicate with Xlib.
* screen_num: Value the Xlib server uses to identify every
* connected screen.
* colors: Color indices paased back from X Windows.
* private_cmap: "None" unless a private cmap was allocated.
* toplevel, menu, textarea: Toplevel window and 2 child windows.
* gc_normal, gc_xor, current_gc: Graphic contexts for drawing
* in the graphics area. (gc_normal for overwrite
* drawing, gc_xor for rubber band drawing, and
* current_gc is the current gc used)
* gc_menus: Graphic context for drawing in the status message
* and menu area
* font_info: Data for each font size.
*/
typedef struct {
Display *display;
int screen_num;
int colors[NUM_COLOR];
Colormap private_cmap;
Window toplevel, menu, textarea;
GC gc_normal, gc_xor, gc_menus, current_gc;
XFontStruct *font_info[MAX_FONT_SIZE+1];
} t_x11_state;
#endif
#ifdef WIN32
/*************************************************************
* WIN32 Structure Definitions *
*************************************************************/
/* Flag used for the "window" button. Before the user presses the button, the
* "window" operation is in WINDOW_DEACTIVATED state. After user presses the
* button, the operation proceeds to WAITING_FOR_FIRST_CORNER_POINT state and
* waits for the user to click the first point in the graphics area as the first
* corner for rubber band drawing. After user clicks the first point, the operation
* proceeds to WAITING_FOR_SECOND_CORNER_POINT and waits for the user to click on
* the second point to define the rectangular region enclosed by the rubber band.
* Then the application window will zoom in to the region defined and the "window"
* operation goes back to WINDOW_DEACTIVATED.
*/
typedef enum {
WINDOW_DEACTIVATED = 0,
WAITING_FOR_FIRST_CORNER_POINT,
WAITING_FOR_SECOND_CORNER_POINT
} t_window_button_state;
/* Structure used to store Win32 state variables.
* InEventLoop: Whether in event_loop(); used to indicate if part of the application window need
* to be redrawn when system makes request by sending WM_PAINT message in the
* WIN32_GraphicsWND callback function.
* windowAdjustFlag: Flag used for the "Window" button operation. This variable has 3 states
* which are defined above.
* adjustButton: Holds the index of the "Window" button in the array of buttons created
* adjustRect: Used for the "Window" button operation. Holds the boundary coordinates (in screen
* pixels) of the region enclosed by the rubber band.
* hMainWnd, hGraphicsWnd, hButtonsWnd, hStatusWnd: Handles to the top level window and
* 3 subwindows.
* hGraphicsDC: Handle to the graphics device context.
* hGraphicsPen, hGraphicsBrush, hGrayBrush, hGraphicsFont: Handles to Windows GDI objects used
* for drawing. (hGraphicsPen for drawing lines, hGraphicsBrush for filling shapes,
* and hGrayBrush for filling the background of the status message and menu areas)
* font_info: Data for each font size.
*/
typedef struct {
bool InEventLoop;
t_window_button_state windowAdjustFlag;
int adjustButton;
RECT adjustRect;
HWND hMainWnd, hGraphicsWnd, hButtonsWnd, hStatusWnd;
HDC hGraphicsDC;
HPEN hGraphicsPen;
HBRUSH hGraphicsBrush, hGrayBrush;
HFONT hGraphicsFont;
LOGFONT *font_info[MAX_FONT_SIZE+1];
} t_win32_state;
#endif
/*********************************************************************
* File scope variables. *
*********************************************************************/
// Need to initialize graphics_loaded to false, since checking it is
// how we avoid multiple construction or destruction of the graphics
// window. Initializing display type and background color index is not
// necessary since they are set in init_graphics(), but doing so
// just for safety.
static t_gl_state gl_state = {false, SCREEN, 0};
// Stores all the menu buttons created. Initialize the button pointer
// and num_buttons for safety.
static t_button_state button_state = {NULL, 0};
// Contains all coordinates useful for graphics transformation
static t_transform_coordinates trans_coord;
// Initialize panning_enabled to false, so panning is not activated
static t_panning_state pan_state = {0, 0, false};
// Color references
static const char *ps_cnames[NUM_COLOR] = {"white", "black", "grey55", "grey75",
"blue", "green", "yellow", "cyan", "red", "pink", "lightpink", "darkgreen",
"magenta", "bisque", "lightskyblue", "thistle", "plum", "khaki", "coral",
"turquoise", "mediumpurple", "darkslateblue", "darkkhaki"};
#ifdef X11
/*************************************************
* X-Windows Specific File-scope Variables *
**************************************************/
// Stores all state variables for X Windows
t_x11_state x11_state;
#endif /* X11 file scope variables */
#ifdef WIN32
/*****************************************************
* Microsoft Windows (Win32) File Scope Variables *
*****************************************************/
/* Linestyle references for Win32. */
static const int win32_line_styles[2] = { PS_SOLID, PS_DASH };
/* Color references for Win32. Colors have to be specified by RGB values for Win32. */
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(255, 192, 203),
RGB(255, 182, 193), RGB(0, 128, 0), RGB(255, 0, 255), RGB(255, 228, 196), RGB(135, 206, 250),
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)};
/* Name of each window */
static TCHAR szAppName[256], szGraphicsName[] = TEXT("VPR Graphics"),
szStatusName[] = TEXT("VPR Status"), szButtonsName[] = TEXT("VPR Buttons");
/* Stores all state variables for Win32 */
static t_win32_state win32_state = {false, WINDOW_DEACTIVATED, -1};
#endif /* WIN32 file scope variables */
/*********************************************
* Common Subroutine Declarations *
*********************************************/
static void *my_malloc(int ibytes);
static void *my_realloc(void *memblk, int ibytes);
/* translation from screen coordinates to the world coordinates *
* used by the client program. */
static float xscrn_to_world(int x);
static float yscrn_to_world(int y);
/* translation from world to screen coordinates */
static int xworld_to_scrn (float worldx);
static int yworld_to_scrn (float worldy);
/* translation from world to PostScript coordinates */
static float xworld_to_post(float worldx);
static float yworld_to_post(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 panning_execute (int x, int y, void (*drawscreen) (void));
static void panning_on (int start_x, int start_y);
static void panning_off (void);
static void zoom_in (void (*drawscreen) (void));
static void zoom_out (void (*drawscreen) (void));
static void handle_zoom_in (float x, float y, void (*drawscreen) (void));
static void handle_zoom_out (float x, float y, 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 Subroutine Declarations *
*****************************************************/
/* Helper functions for X11; not visible to client program. */
static void x11_init_graphics (const char* window_name, int cindex);
static void x11_event_loop (void (*act_on_mousebutton)
(float x, float y, t_event_buttonPressed button_info),
void (*act_on_mousemove)(float x, float y),
void (*act_on_keypress)(char key_pressed),
void (*drawscreen) (void));
static Bool x11_test_if_exposed (Display *disp, XEvent *event_ptr,
XPointer dummy);
static void x11_build_textarea (void);
static void x11_drawbut (int bnum);
static int x11_which_button (Window win);
static void x11_turn_on_off (int pressed);
static void x11_drawmenu(void);
static void x11_handle_expose (XEvent report, void (*drawscreen) (void));
static void x11_handle_configure_notify (XEvent report);
static void x11_handle_button_info (t_event_buttonPressed *button_info,
int buttonNumber, int Xbutton_state);
#endif /* X11 Declarations */
#ifdef WIN32
/*******************************************************************
* Win32-specific subroutine declarations *
*******************************************************************/
/* Helper function called by init_graphics(). Not visible to client program. */
static void win32_init_graphics (const char* window_name, int cindex);
/* 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 WIN32_GraphicsWND(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
static LRESULT CALLBACK WIN32_StatusWND(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
static LRESULT CALLBACK WIN32_ButtonsWND(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
static LRESULT CALLBACK WIN32_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 (WIN32_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 (*win32_mouseclick_ptr)(float x, float y, t_event_buttonPressed button_info);
static void (*win32_mousemove_ptr)(float x, float y);
static void (*win32_keypress_ptr)(char entered_char);
static void (*win32_drawscreen_ptr)(void);
// Helper functions for WIN32_GraphicsWND callback function
static void win32_GraphicsWND_handle_WM_PAINT(HWND hwnd, PAINTSTRUCT &ps, HPEN &hDotPen,
RECT &oldAdjustRect);
static void win32_GraphicsWND_handle_WM_LRBUTTONDOWN(UINT message, WPARAM wParam, LPARAM lParam,
int &X, int &Y, RECT &oldAdjustRect);
static void win32_GraphicsWND_handle_WM_MBUTTONDOWN(HWND hwnd, UINT message, WPARAM wParam,
LPARAM lParam);
static void win32_GraphicsWND_handle_WM_MOUSEMOVE(LPARAM lParam, int &X, int &Y,
RECT &oldAdjustRect);
// Functions for displaying errors in a message box on windows.
static void WIN32_SELECT_ERROR();
static void WIN32_DELETE_ERROR();
static void WIN32_CREATE_ERROR();
static void WIN32_DRAW_ERROR();
static void win32_invalidate_screen();
static void win32_reset_state ();
static void win32_drain_message_queue ();
static void win32_handle_mousewheel_zooming(WPARAM wParam, LPARAM lParam);
static void win32_handle_button_info (t_event_buttonPressed &button_info, UINT message,
WPARAM wParam);
#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;
}
/* translation from screen coordinates to the world coordinates *
* in the x direction. */
static float xscrn_to_world(int x)
{
float world_coord_x;
world_coord_x = ((float) x)*trans_coord.stow_xmult + trans_coord.xleft;
return world_coord_x;
}
/* translation from screen coordinates to the world coordinates *
* in the y direction. */
static float yscrn_to_world(int y)
{
float world_coord_y;
world_coord_y = ((float) y)*trans_coord.stow_ymult + trans_coord.ytop;
return world_coord_y;
}
/* Translates from world (client program) coordinates to screen coordinates
* (pixels) in the x direction. Add 0.5 at end for extra half-pixel accuracy.
*/
static int xworld_to_scrn (float worldx)
{
int winx;
winx = (int) ((worldx-trans_coord.xleft)*trans_coord.wtos_xmult + 0.5);
#ifdef WIN32
/* 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);
#endif
return (winx);
}
/* Translates from world (client program) coordinates to screen coordinates
* (pixels) in the y direction. Add 0.5 at end for extra half-pixel accuracy.
*/
static int yworld_to_scrn (float worldy)
{
int winy;
winy = (int) ((worldy-trans_coord.ytop)*trans_coord.wtos_ymult + 0.5);
#ifdef WIN32
/* Avoid overflow in the X/Win32 Window routines. */
winy = max (winy, MINPIXEL);
winy = min (winy, MAXPIXEL);
#endif
return (winy);
}
/* translation from world to PostScript coordinates in the x direction */
static float xworld_to_post(float worldx)
{
float ps_coord_x;
ps_coord_x = ((worldx)-trans_coord.xleft)*trans_coord.ps_xmult + trans_coord.ps_left;
return ps_coord_x;
}
/* translation from world to PostScript coordinates in the y direction */
static float yworld_to_post(float worldy)
{
float ps_coord_y;
ps_coord_y = ((worldy)-trans_coord.ybot)*trans_coord.ps_ymult + trans_coord.ps_bot;
return ps_coord_y;
}
/* Sets the current graphics context colour to cindex, regardless of whether we think it is
* needed or not.
*/
static void force_setcolor (int cindex)
{
gl_state.currentcolor = cindex;
if (gl_state.disp_type == SCREEN) {
#ifdef X11
XSetForeground (x11_state.display, x11_state.current_gc, x11_state.colors[cindex]);
#else /* Win32 */
int win_linestyle, linewidth;
LOGBRUSH lb;
lb.lbStyle = BS_SOLID;
lb.lbColor = win32_colors[cindex];
lb.lbHatch = (LONG)NULL;
win_linestyle = win32_line_styles[gl_state.currentlinestyle];
linewidth = max (gl_state.currentlinewidth, 1); // Win32 won't draw 0 width dashed lines.
/* Delete previously used pen */
if(!DeleteObject(win32_state.hGraphicsPen))
WIN32_DELETE_ERROR();
/* Create a new pen */
win32_state.hGraphicsPen = ExtCreatePen(PS_GEOMETRIC | win_linestyle |
PS_ENDCAP_FLAT, linewidth, &lb, (LONG)NULL, NULL);
if(!win32_state.hGraphicsPen)
WIN32_CREATE_ERROR();
/* Select created pen into specified device context */
if(!SelectObject(win32_state.hGraphicsDC, win32_state.hGraphicsPen))
WIN32_SELECT_ERROR();
/* Delete previously used brush */
if(!DeleteObject(win32_state.hGraphicsBrush))
WIN32_DELETE_ERROR();
/* Create a new brush */
win32_state.hGraphicsBrush = CreateSolidBrush(win32_colors[gl_state.currentcolor]);
if(!win32_state.hGraphicsBrush)
WIN32_CREATE_ERROR();
/* Select created brush into specified device context */
if(!SelectObject(win32_state.hGraphicsDC, win32_state.hGraphicsBrush))
WIN32_SELECT_ERROR();
#endif
}
else {
fprintf (gl_state.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 (gl_state.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_by_name (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 gl_state.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)
{
gl_state.currentlinestyle = linestyle;
if (gl_state.disp_type == SCREEN) {
#ifdef X11
static int x_vals[2] = {LineSolid, LineOnOffDash};
XSetLineAttributes (x11_state.display, x11_state.current_gc, gl_state.currentlinewidth,
x_vals[linestyle], CapButt, JoinMiter);
#else // Win32
LOGBRUSH lb;
lb.lbStyle = BS_SOLID;
lb.lbColor = win32_colors[gl_state.currentcolor];
lb.lbHatch = (LONG)NULL;
int win_linestyle = win32_line_styles[linestyle];
/* Win32 won't draw 0 width dashed lines. */
int linewidth = max (gl_state.currentlinewidth, 1);
/* Delete previously used pen */
if(!DeleteObject(win32_state.hGraphicsPen))
WIN32_DELETE_ERROR();
/* Create a new pen */
win32_state.hGraphicsPen = ExtCreatePen(PS_GEOMETRIC | win_linestyle |
PS_ENDCAP_FLAT, linewidth, &lb, (LONG)NULL, NULL);
if(!win32_state.hGraphicsPen)
WIN32_CREATE_ERROR();
/* Select created pen into specified device context */
if(!SelectObject(win32_state.hGraphicsDC, win32_state.hGraphicsPen))
WIN32_SELECT_ERROR();
#endif
}
else {
if (linestyle == SOLID)
fprintf (gl_state.ps,"linesolid\n");
else if (linestyle == DASHED)
fprintf (gl_state.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 != gl_state.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)
{
gl_state.currentlinewidth = linewidth;
if (gl_state.disp_type == SCREEN) {
#ifdef X11
static int x_vals[2] = {LineSolid, LineOnOffDash};
XSetLineAttributes (x11_state.display, x11_state.current_gc, linewidth,
x_vals[gl_state.currentlinestyle], CapButt, JoinMiter);
#else /* Win32 */
LOGBRUSH lb;
lb.lbStyle = BS_SOLID;
lb.lbColor = win32_colors[gl_state.currentcolor];
lb.lbHatch = (LONG)NULL;
int win_linestyle = win32_line_styles[gl_state.currentlinestyle];
if (linewidth == 0)
linewidth = 1; // Win32 won't draw dashed 0 width lines.
/* Delete previously used pen */
if(!DeleteObject(win32_state.hGraphicsPen))
WIN32_DELETE_ERROR();
/* Create a new pen */
win32_state.hGraphicsPen = ExtCreatePen(PS_GEOMETRIC | win_linestyle |
PS_ENDCAP_FLAT, linewidth, &lb, (LONG)NULL, NULL);
if(!win32_state.hGraphicsPen)
WIN32_CREATE_ERROR();
/* Select created pen into specified device context */
if(!SelectObject(win32_state.hGraphicsDC, win32_state.hGraphicsPen))
WIN32_SELECT_ERROR();
#endif
}
else {
fprintf(gl_state.ps,"%d setlinewidth\n", linewidth);
}
}
/* Sets the linewidth in the grahpics context, if it differs from the current value.
*/
void setlinewidth (int linewidth)
{