1 /* OpenGL container for drawing
2 Copyright (C) 2005-2008, Jonathan Bachrach, Jacob Beal, and contributors
3 listed in the AUTHORS file in the MIT Proto distribution's top directory.
5 This file is part of MIT Proto, and is distributed under the terms of
6 the GNU General Public License, with a linking exception, as described
7 in the file LICENSE in the MIT Proto distribution's top directory. */
10 #include "visualizer.h"
11 #include "Trackball.h"
12 #include "drawing_primitives.h"
14 Palette
* palette
; // current palette
15 // NOTE: these interfaces need fixing!
16 extern float xscale
, yscale
; // kludge connection to drawing_primitives.cpp
17 extern float view_width
, view_height
; // kludge connection to Trackball.cpp
19 /*****************************************************************************
20 * CREATION AND DESTRUCTION *
21 *****************************************************************************/
22 // glutInit consumes a standard set of command-line arguments.
23 // Of importance are: -display DISPLAY and -geometry WxH +X +Y
24 Visualizer::Visualizer(Args
* args
)
25 : bounds(0,1,0,1) { // default computer size, changed by spatialcomputer
26 glutInitWindowSize(640, 480); // default size
27 glutInitWindowPosition (100, 100); // default position
28 glutInitDisplayMode (GLUT_DEPTH
| GLUT_ACCUM
| GLUT_RGBA
| GLUT_DOUBLE
);
29 glutInit(&args
->argc
, args
->argv
); // allows user override of geometry
30 char* default_name
= "Proto Simulator";
32 (args
->extract_switch("-window-name")) ? name
=args
->pop_next()
34 window
= glutCreateWindow(name
); // title window with cmd line
35 // get dimensions from window, since they might've been set by cmd line
36 left
=glutGet(GLUT_WINDOW_X
); top
=glutGet(GLUT_WINDOW_Y
);
37 width
=glutGet(GLUT_WINDOW_WIDTH
); height
=glutGet(GLUT_WINDOW_HEIGHT
);
38 aspect_ratio
= (flo
)width
/(flo
)height
;
40 is_full_screen
= args
->extract_switch("-f");
41 if(is_full_screen
) { glutFullScreen(); }
44 palette
= my_palette
= new Palette();
45 while(args
->extract_switch("-palette",FALSE
)) { // may use many palette files
46 palette
->overlay_from_file(args
->pop_next()); // patch the palette
49 // set up drawing environment
50 glClear(GL_ACCUM_BUFFER_BIT
| GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
51 palette
->set_background(BACKGROUND
);
54 glEnable(GL_DEPTH_TEST
); // Enables Depth Testing
55 glDepthFunc(GL_LEQUAL
); // The Type Of Depth Testing (Less Or Equal)
56 glClearDepth(1.0f
); // Depth Buffer Setup
57 glEnable(GL_LINE_SMOOTH
);
59 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
60 glHint(GL_LINE_SMOOTH_HINT
, GL_DONT_CARE
);
61 glShadeModel (GL_SMOOTH
); // Select Smooth Shading
62 glEnable(GL_TEXTURE_2D
);
63 glHint (GL_PERSPECTIVE_CORRECTION_HINT
, GL_NICEST
);
64 // select modulate to mix texture with color for shading
65 glTexEnvf( GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_MODULATE
);
66 glTexParameteri(GL_TEXTURE_2D
,GL_TEXTURE_MIN_FILTER
,GL_LINEAR
);
67 glTexParameteri(GL_TEXTURE_2D
,GL_TEXTURE_MAG_FILTER
,GL_LINEAR
);
68 reset_view(); // reset the trackball
69 init_drawing_primitives(); // make sure the drawing primitives are live
71 // patch kludge-connections to un-fixed files
72 xscale
= width
/ (bounds
.r
-bounds
.l
);
73 yscale
= height
/ (bounds
.t
-bounds
.b
);
74 view_width
=width
; view_height
=height
;
77 Visualizer::~Visualizer() {
78 glutDestroyWindow(window
);
81 /*****************************************************************************
83 *****************************************************************************/
84 // when the window is resized, reset the view parameters
85 void Visualizer::resize(int width
, int height
) {
86 // set the rendering area to equal the new window size
87 glViewport(0, 0, width
, height
);
88 aspect_ratio
= (flo
)width
/(flo
)height
;
89 if(!is_full_screen
) { this->width
=width
; this->height
=height
; }
91 // patch kludge-connections to un-fixed files
92 xscale
= width
/ (bounds
.r
-bounds
.l
);
93 yscale
= height
/ (bounds
.t
-bounds
.b
);
94 view_width
=width
; view_height
=height
;
97 BOOL
Visualizer::handle_key(KeyEvent
* key
) {
101 case 24: /*zoom_out(2.0);*/ return TRUE
; // X = zoom out
102 case 26: /*zoom_in(2.0);*/ return TRUE
; // Z = zoom in
107 is_full_screen
= !is_full_screen
;
108 if (is_full_screen
) { // remember position and then fullscreen
109 left
=glutGet(GLUT_WINDOW_X
); top
=glutGet(GLUT_WINDOW_Y
);
110 width
=glutGet(GLUT_WINDOW_WIDTH
); height
=glutGet(GLUT_WINDOW_HEIGHT
);
112 } else { // restore pre-zoom window parameters
113 glutPositionWindow(left
, top
);
114 glutReshapeWindow(width
, height
);
117 case 'z': reset_view(); return TRUE
;
122 switch(key
->special
) {
123 case GLUT_KEY_RIGHT
: on_joy_move(-2, 0); break;
124 case GLUT_KEY_LEFT
: on_joy_move(2, 0); break;
125 case GLUT_KEY_UP
: on_joy_move(0, 2); break;
126 case GLUT_KEY_DOWN
: on_joy_move(0, -2); break;
127 case GLUT_KEY_PAGE_UP
: on_key_zoom(5); break;
128 case GLUT_KEY_PAGE_DOWN
: on_key_zoom(-5); break;
135 // Left-Drag rotates the display, Right-Drag zooms the display
136 BOOL
Visualizer::handle_mouse(MouseEvent
* mouse
) {
138 if(mouse
->button
==GLUT_LEFT_BUTTON
) { // drag = rotate
139 switch(mouse
->state
) {
140 case 1: // drag start
141 on_left_button_down(mouse
->x
,mouse
->y
);
143 case 2: // drag continue
144 on_mouse_move(mouse
->x
,mouse
->y
);
147 on_left_button_up(mouse
->x
,mouse
->y
);
150 } else if(mouse
->button
==GLUT_RIGHT_BUTTON
) { // drag = zoom
151 switch(mouse
->state
) {
152 case 1: // drag start
153 on_right_button_down(mouse
->x
,mouse
->y
);
155 case 2: // drag continue
156 on_mouse_move(mouse
->x
,mouse
->y
);
159 on_right_button_up(mouse
->x
,mouse
->y
);
162 } else if (mouse
->button
== GLUT_WHEEL_UP
) {
163 on_key_zoom(5); return TRUE
;
164 } else if (mouse
->button
== GLUT_WHEEL_DOWN
) {
165 on_key_zoom(-5); return TRUE
;
171 /*****************************************************************************
172 * DRAWING - SETUP AND EXECUTION *
173 *****************************************************************************/
174 // Sets the view to fit the standard space populated by agents.
175 // visualizer's contribution to frame
176 void Visualizer::visualize() {
180 // start drawing a frame
181 void Visualizer::prepare_frame() {
182 palette
= my_palette
; // set current palette
183 glMatrixMode(GL_PROJECTION
);
185 gluOrtho2D(-width
/2,width
/2,-height
/2,height
/2);
186 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
187 glMatrixMode(GL_MODELVIEW
);
190 // shift from 2D overlay to spatial computer drawing mode
191 #define Z_NEAR (1.0f)
192 #define Z_FAR (5000.0f) // used to be 50K
193 void Visualizer::view_3D() {
194 glMatrixMode(GL_PROJECTION
);
197 // using the viewport's aspect ratio means there's no X/Y distortion
198 gluPerspective(45.0f
, aspect_ratio
, Z_NEAR
, Z_FAR
);
199 // We want to pull back until the XY plane contains all the
200 // agents (plus a little extra space)
201 float y_angle
= M_PI
/8; // half of 45 degrees, in radians
202 float fit_zy
= ((bounds
.t
-bounds
.b
)/2) / tan(y_angle
);
203 float x_angle
= atan(tan(y_angle
)*aspect_ratio
);
204 float fit_zx
= ((bounds
.r
-bounds
.l
)/2) / tan(x_angle
);
205 glTranslatef( 0, 0, -MAX(fit_zx
,fit_zy
)*1.05);
206 glMatrixMode(GL_MODELVIEW
);
208 load_trackball_transformation();
209 load_trackball_zoom_translate();
212 void Visualizer::end_3D() {
213 glMatrixMode(GL_PROJECTION
);
215 glMatrixMode(GL_MODELVIEW
);
219 // finish drawing a frame
220 void Visualizer::complete_frame() {
221 glutSwapBuffers(); // implicitly makes sure drawing completes
224 void Visualizer::click_3d(int winx
, int winy
, double *pt
) {
226 GLint viewport
[4]; glGetIntegerv(GL_VIEWPORT
, viewport
);
227 GLdouble model
[16]; glGetDoublev(GL_MODELVIEW_MATRIX
,model
);
228 GLdouble proj
[16]; glGetDoublev(GL_PROJECTION_MATRIX
,proj
);
229 // calculate where to put the Z at
230 float y_angle
= M_PI
/8; // half of 45 degrees, in radians
231 float fit_zy
= ((bounds
.t
-bounds
.b
)/2) / tan(y_angle
);
232 float x_angle
= atan(tan(y_angle
)*aspect_ratio
);
233 float fit_zx
= ((bounds
.r
-bounds
.l
)/2) / tan(x_angle
);
234 float Z
= MAX(fit_zx
,fit_zy
)*1.05;
235 float z
= (1.0/Z_NEAR
- 1.0/Z
) / (1.0/Z_NEAR
- 1.0/Z_FAR
); //depth->screen
236 winy
= viewport
[3]-winy
; // convert the y coordinate
237 gluUnProject(winx
,winy
,z
,model
,proj
,viewport
,&pt
[0],&pt
[1],&pt
[2]);
241 GLuint
* vis_select_buf
;
242 void Visualizer::start_select_3D(Rect
* rgn
, int max_names
) {
244 // setup selection buffer
245 vis_select_buf
= (GLuint
*)calloc(max_names
,4*sizeof(GLuint
));
246 glSelectBuffer(max_names
*4, vis_select_buf
);
247 glRenderMode(GL_SELECT
);
249 glPushName((GLuint
)-1);
251 // setup picking matrix
252 glMatrixMode(GL_PROJECTION
);
255 GLint viewport
[4]; glGetIntegerv(GL_VIEWPORT
, viewport
);
256 gluPickMatrix((rgn
->l
+rgn
->r
)/2, viewport
[3]-(rgn
->t
+rgn
->b
)/2,
257 rgn
->r
-rgn
->l
, rgn
->t
-rgn
->b
, viewport
);
258 // using the viewport's aspect ratio means there's no X/Y distortion
259 gluPerspective(45.0f
, aspect_ratio
, 1.0f
, 50000.0f
);
260 // We want to pull back until the XY plane contains all the
261 // agents (plus a little extra space)
262 float y_angle
= M_PI
/8; // half of 45 degrees, in radians
263 float fit_zy
= ((bounds
.t
-bounds
.b
)/2) / tan(y_angle
);
264 float x_angle
= atan(tan(y_angle
)*aspect_ratio
);
265 float fit_zx
= ((bounds
.r
-bounds
.l
)/2) / tan(x_angle
);
266 glTranslatef( 0, 0, -MAX(fit_zx
,fit_zy
)*1.05);
267 glMatrixMode(GL_MODELVIEW
);
269 load_trackball_transformation();
270 load_trackball_zoom_translate();
273 void Visualizer::end_select_3D(int max_names
, Population
* result
) {
274 glMatrixMode(GL_PROJECTION
);
276 glMatrixMode(GL_MODELVIEW
);
278 glFlush(); // make sure drawing completes
279 // process hits to find selection
281 int hits
= glRenderMode(GL_RENDER
);
282 GLuint
* ptr
= (GLuint
*)vis_select_buf
;
283 for(int i
=0;i
<hits
;i
++) {
284 int names
=*ptr
++; ptr
++; ptr
++;
285 for(int j
=0;j
<names
;j
++) {
286 result
->add((void*)*ptr
++);
289 free(vis_select_buf
); // clean up selection buffer