/* Callback for button press in the directory tree area */ static int dirtree_select_cb( GtkWidget *ctree_w, GdkEventButton *ev_button ) { GNode *dnode; int row; /* If About presentation is up, end it */ about( ABOUT_END ); if (globals.fsv_mode == FSV_SPLASH) return FALSE; gtk_clist_get_selection_info( GTK_CLIST(ctree_w), ev_button->x, ev_button->y, &row, NULL ); if (row < 0) return FALSE; dnode = (GNode *)gtk_clist_get_row_data( GTK_CLIST(ctree_w), row ); if (dnode == NULL) return FALSE; /* A single-click from button 1 highlights the node, shows the * name, and updates the file list if necessary. (and also selects * the row, but GTK+ does that automatically for us) */ if ((ev_button->button == 1) && (ev_button->type == GDK_BUTTON_PRESS)) { geometry_highlight_node( dnode, FALSE ); window_statusbar( SB_RIGHT, node_absname( dnode ) ); if (dnode != dirtree_current_dnode) filelist_populate( dnode ); dirtree_current_dnode = dnode; return FALSE; } /* A double-click from button 1 gets the camera moving */ if ((ev_button->button == 1) && (ev_button->type == GDK_2BUTTON_PRESS)) { camera_look_at( dnode ); /* Preempt the forthcoming tree expand/collapse * (the standard action spawned by a double-click) */ gtk_signal_emit_stop_by_name( GTK_OBJECT(ctree_w), "button_press_event" ); return TRUE; } /* A click from button 3 selects the row, highlights the node, * shows the name, updates the file list if necessary, and brings * up a context-sensitive menu */ if (ev_button->button == 3) { gtk_clist_select_row( GTK_CLIST(ctree_w), row, 0 ); geometry_highlight_node( dnode, FALSE ); window_statusbar( SB_RIGHT, node_absname( dnode ) ); if (dnode != dirtree_current_dnode) filelist_populate( dnode ); dirtree_current_dnode = dnode; context_menu( dnode, ev_button ); return FALSE; } return FALSE; }
/* Callback for a click in the file list area */ static int filelist_select_cb( GtkWidget *clist_w, GdkEventButton *ev_button ) { GNode *node; int row; /* If About presentation is up, end it */ about( ABOUT_END ); if (globals.fsv_mode == FSV_SPLASH) return FALSE; gtk_clist_get_selection_info( GTK_CLIST(clist_w), ev_button->x, ev_button->y, &row, NULL ); if (row < 0) return FALSE; node = (GNode *)gtk_clist_get_row_data( GTK_CLIST(clist_w), row ); if (node == NULL) return FALSE; /* A single-click from button 1 highlights the node and shows the * name (and also selects the row, but GTK+ does that for us) */ if ((ev_button->button == 1) && (ev_button->type == GDK_BUTTON_PRESS)) { geometry_highlight_node( node, FALSE ); window_statusbar( SB_RIGHT, node_absname( node ) ); return FALSE; } /* A double-click from button 1 gets the camera moving */ if ((ev_button->button == 1) && (ev_button->type == GDK_2BUTTON_PRESS)) { camera_look_at( node ); return FALSE; } /* A click from button 3 selects the row, highlights the node, * shows the name, and pops up a context-sensitive menu */ if (ev_button->button == 3) { gtk_clist_select_row( GTK_CLIST(clist_w), row, 0 ); geometry_highlight_node( node, FALSE ); window_statusbar( SB_RIGHT, node_absname( node ) ); context_menu( node, ev_button ); return FALSE; } return FALSE; }
/* This callback catches all events for the viewport */ int viewport_cb( GtkWidget *gl_area_w, GdkEvent *event ) { GdkEventButton *ev_button; GdkEventMotion *ev_motion; GNode *node; double dx, dy; unsigned int face_id; int x, y; boolean btn1, btn2, btn3; boolean ctrl_key; /* Handle low-level GL area widget events */ switch (event->type) { case GDK_EXPOSE: ogl_refresh( ); return FALSE; case GDK_CONFIGURE: ogl_resize( ); return FALSE; default: /* Event is probably coming from the mouse */ break; } if (event->type == GDK_BUTTON_PRESS) { /* Exit the About presentation if it is up */ if (about( ABOUT_END )) { indicated_node = NULL; return FALSE; } } /* If we're in splash screen mode, proceed no further */ if (globals.fsv_mode == FSV_SPLASH) return FALSE; /* Mouse-related events */ switch (event->type) { case GDK_BUTTON_PRESS: ev_button = (GdkEventButton *)event; btn1 = ev_button->button == 1; btn2 = ev_button->button == 2; btn3 = ev_button->button == 3; ctrl_key = ev_button->state & GDK_CONTROL_MASK; x = (int)ev_button->x; y = (int)ev_button->y; if (camera_moving( )) { /* Yipe! Impatient user */ camera_pan_finish( ); indicated_node = NULL; } else if (!ctrl_key) { if (btn2) indicated_node = NULL; else indicated_node = node_at_location( x, y, &face_id ); if (indicated_node == NULL) { geometry_highlight_node( NULL, FALSE ); window_statusbar( SB_RIGHT, "" ); } else { if (geometry_should_highlight( indicated_node, face_id ) || btn1) geometry_highlight_node( indicated_node, btn1 ); else geometry_highlight_node( NULL, FALSE ); window_statusbar( SB_RIGHT, node_absname( indicated_node ) ); if (btn3) { /* Bring up context-sensitive menu */ context_menu( indicated_node, ev_button ); filelist_show_entry( indicated_node ); } } } prev_x = x; prev_y = y; break; case GDK_2BUTTON_PRESS: /* Ignore second click of a double-click */ break; case GDK_BUTTON_RELEASE: ev_button = (GdkEventButton *)event; btn1 = ev_button->state & GDK_BUTTON1_MASK; ctrl_key = ev_button->state & GDK_CONTROL_MASK; if (btn1 && !ctrl_key && !camera_moving( ) && (indicated_node != NULL)) camera_look_at( indicated_node ); gui_cursor( gl_area_w, -1 ); break; case GDK_MOTION_NOTIFY: ev_motion = (GdkEventMotion *)event; btn1 = ev_motion->state & GDK_BUTTON1_MASK; btn2 = ev_motion->state & GDK_BUTTON2_MASK; btn3 = ev_motion->state & GDK_BUTTON3_MASK; ctrl_key = ev_motion->state & GDK_CONTROL_MASK; x = (int)ev_motion->x; y = (int)ev_motion->y; if (!camera_moving( ) && !gtk_events_pending( )) { if (btn2) { /* Dolly the camera */ gui_cursor( gl_area_w, GDK_DOUBLE_ARROW ); dy = MOUSE_SENSITIVITY * (y - prev_y); camera_dolly( - dy ); indicated_node = NULL; } else if (ctrl_key && btn1) { /* Revolve the camera */ gui_cursor( gl_area_w, GDK_FLEUR ); dx = MOUSE_SENSITIVITY * (x - prev_x); dy = MOUSE_SENSITIVITY * (y - prev_y); camera_revolve( dx, dy ); indicated_node = NULL; } else if (!ctrl_key && (btn1 || btn3)) { /* Pointless dragging */ if (indicated_node != NULL) { node = node_at_location( x, y, &face_id ); if (node != indicated_node) indicated_node = NULL; } } else indicated_node = node_at_location( x, y, &face_id ); /* Update node highlighting */ if (indicated_node == NULL) { geometry_highlight_node( NULL, FALSE ); window_statusbar( SB_RIGHT, "" ); } else { if (geometry_should_highlight( indicated_node, face_id ) || btn1) geometry_highlight_node( indicated_node, btn1 ); else geometry_highlight_node( NULL, FALSE); window_statusbar( SB_RIGHT, node_absname( indicated_node ) ); } prev_x = x; prev_y = y; } break; case GDK_LEAVE_NOTIFY: /* The mouse has left the viewport */ geometry_highlight_node( NULL, FALSE ); window_statusbar( SB_RIGHT, "" ); gui_cursor( gl_area_w, -1 ); indicated_node = NULL; break; default: /* Ignore event */ break; } return FALSE; }
static void draw_screen() { static double last_frame_time; static int frame_index; static float frame_rates[FRAME_INDEX_MAX]; static float frame_times[FRAME_INDEX_MAX]; double start_time = time_now_double(); glClearColor(0.0, 0.0, 0.0, 0.0); graph_dev_start_frame(); sng_set_foreground(WHITE); sng_abs_xy_draw_string("F1 FOR HELP", NANO_FONT, SCREEN_WIDTH - 100, 10); static struct entity_context *cx; if (!cx) cx = entity_context_new(50, 50); if (wireframe != oldwireframe) { oldwireframe = wireframe; if (wireframe) set_renderer(cx, WIREFRAME_RENDERER | BLACK_TRIS); else set_renderer(cx, FLATSHADING_RENDERER); } float r = target_mesh->radius / tan(FOV / 3.0); /* 50% size for middle zoom */ float r_cam = r * lobby_zoom / 255.0; camera_set_parameters(cx, 0.1f, r * 2.2, SCREEN_WIDTH, SCREEN_HEIGHT, FOV); camera_set_pos(cx, r_cam, 0, 0); camera_look_at(cx, 0, 0, 0); camera_assign_up_direction(cx, 0, 1, 0); union vec3 light_pos = { { 1.01 * r, 0, 0 } }; quat_rot_vec_self(&light_pos, &light_orientation); set_lighting(cx, light_pos.v.x, light_pos.v.y, light_pos.v.z); calculate_camera_transform(cx); struct entity *e = add_entity(cx, target_mesh, 0, 0, 0, WHITE); struct entity *ae = NULL; if (planet_mode) { update_entity_material(e, &planet_material); if (draw_atmosphere) { ae = add_entity(cx, atmosphere_mesh, 0, 0, 0, WHITE); update_entity_scale(ae, 1.03); update_entity_material(ae, &atmosphere_material); } } update_entity_orientation(e, &lobby_orientation); if (isDraggingLight) { union vec3 light_dir = { { 10.75 * r_cam, 0, 0 } }; quat_rot_vec_self(&light_dir, &light_orientation); sng_set_foreground(WHITE); render_line(cx, light_dir.v.x, light_dir.v.y, light_dir.v.z, 0, 0, 0); e = add_entity(cx, light_mesh, light_dir.v.x, light_dir.v.y, light_dir.v.z, WHITE); } else { e = add_entity(cx, light_mesh, light_pos.v.x, light_pos.v.y, light_pos.v.z, WHITE); } render_entities(cx); remove_all_entity(cx); if (helpmode) draw_help_screen(0); if (display_frame_stats > 0) { float avg_frame_rate = 0; float avg_frame_time = 0; int i; for (i = 0; i < FRAME_INDEX_MAX; i++) { avg_frame_rate += frame_rates[i]; avg_frame_time += frame_times[i]; } avg_frame_rate /= (float)FRAME_INDEX_MAX; avg_frame_time /= (float)FRAME_INDEX_MAX; sng_set_foreground(WHITE); char stat_buffer[30]; sprintf(stat_buffer, "fps %5.2f", 1.0/avg_frame_rate); sng_abs_xy_draw_string(stat_buffer, NANO_FONT, 2, 10); sprintf(stat_buffer, "t %0.2f ms", avg_frame_time * 1000.0); sng_abs_xy_draw_string(stat_buffer, NANO_FONT, 92, 10); } if (display_frame_stats > 1) graph_dev_display_debug_menu_show(); graph_dev_end_frame(); glFinish(); /* * Swap the buffers. This this tells the driver to * render the next frame from the contents of the * back-buffer, and to set all rendering operations * to occur on what was the front-buffer. * * Double buffering prevents nasty visual tearing * from the application drawing on areas of the * screen that are being updated at the same time. */ SDL_GL_SwapBuffers(); if (display_frame_stats > 0) { double end_time = time_now_double(); frame_rates[frame_index] = start_time - last_frame_time; frame_times[frame_index] = end_time - start_time; frame_index = (frame_index + 1) % FRAME_INDEX_MAX; last_frame_time = start_time; } }