Preliminary, but functional, autotoolsification
[proto.git] / src / shared / visualizer.cpp
blob43391f7e22d7b0a57b3b45081eb485b4373af873
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. */
9 #include "config.h"
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";
31 char* name =
32 (args->extract_switch("-window-name")) ? name=args->pop_next()
33 : default_name;
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(); }
43 // set up the palette
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);
52 glLineWidth(1);
53 glPointSize(1);
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);
58 glEnable(GL_BLEND);
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 /*****************************************************************************
82 * EVENT MANAGEMENT *
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) {
98 if(key->normal) {
99 if(key->ctrl) {
100 switch(key->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
104 } else {
105 switch(key->key) {
106 case 'f':
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);
111 glutFullScreen();
112 } else { // restore pre-zoom window parameters
113 glutPositionWindow(left, top);
114 glutReshapeWindow(width, height);
116 return TRUE;
117 case 'z': reset_view(); return TRUE;
120 } else {
121 if(!key->ctrl) {
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) {
137 if(!mouse->shift) {
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);
142 return TRUE;
143 case 2: // drag continue
144 on_mouse_move(mouse->x,mouse->y);
145 return TRUE;
146 case 3: // drag end
147 on_left_button_up(mouse->x,mouse->y);
148 return TRUE;
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);
154 return TRUE;
155 case 2: // drag continue
156 on_mouse_move(mouse->x,mouse->y);
157 return TRUE;
158 case 3: // drag end
159 on_right_button_up(mouse->x,mouse->y);
160 return TRUE;
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;
168 return FALSE;
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() {
177 // nothing at all
180 // start drawing a frame
181 void Visualizer::prepare_frame() {
182 palette = my_palette; // set current palette
183 glMatrixMode(GL_PROJECTION);
184 glLoadIdentity();
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);
195 glPushMatrix();
196 glLoadIdentity();
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);
207 glPushMatrix();
208 load_trackball_transformation();
209 load_trackball_zoom_translate();
212 void Visualizer::end_3D() {
213 glMatrixMode(GL_PROJECTION);
214 glPopMatrix();
215 glMatrixMode(GL_MODELVIEW);
216 glPopMatrix();
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) {
225 view_3D();
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]);
238 end_3D();
241 GLuint* vis_select_buf;
242 void Visualizer::start_select_3D(Rect* rgn, int max_names) {
243 GLint hits;
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);
248 glInitNames();
249 glPushName((GLuint)-1);
251 // setup picking matrix
252 glMatrixMode(GL_PROJECTION);
253 glPushMatrix();
254 glLoadIdentity();
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);
268 glPushMatrix();
269 load_trackball_transformation();
270 load_trackball_zoom_translate();
273 void Visualizer::end_select_3D(int max_names, Population* result) {
274 glMatrixMode(GL_PROJECTION);
275 glPopMatrix();
276 glMatrixMode(GL_MODELVIEW);
277 glPopMatrix();
278 glFlush(); // make sure drawing completes
279 // process hits to find selection
280 result->clear();
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