22 #ifndef KJB_GR_GENERIC_VIEWER_H
23 #define KJB_GR_GENERIC_VIEWER_H
25 #ifdef KJB_HAVE_OPENGL
48 #include <boost/function.hpp>
49 #include <boost/foreach.hpp>
50 #include <boost/utility/enable_if.hpp>
51 #include <boost/type_traits.hpp>
52 #include <boost/ref.hpp>
53 #include <boost/any.hpp>
54 #include <boost/concept_check.hpp>
55 #include <boost/shared_ptr.hpp>
56 #include <boost/optional.hpp>
57 #include <boost/none.hpp>
58 #include <boost/utility/in_place_factory.hpp>
97 enum Stereo_mode {no_stereo, horizontal_stereo, anaglyph_stereo, anaglyph_swap_stereo};
100 typedef boost::shared_ptr<Overlay> Overlay_ptr;
101 typedef std::list<boost::any> Overlay_storage_list;
102 typedef Overlay_storage_list::iterator Overlay_storage_iterator;
103 typedef std::map<Overlay*, Overlay_storage_iterator> Overlay_ownership_map;
104 typedef std::list<Overlay_ptr> Overlay_list;
105 typedef Overlay_list::iterator Overlay_iterator;
109 typedef boost::function4<bool, int, int, int, int> Mouse_listener;
110 typedef std::list<Mouse_listener> Mouse_listeners;
112 typedef boost::function2<bool, int, int> Motion_listener;
113 typedef std::list<Motion_listener> Motion_listeners;
115 typedef boost::function3<bool, unsigned int, int, int> Keyboard_listener;
116 typedef std::list<Keyboard_listener> Keyboard_listeners;
118 typedef boost::function3<bool, int, int, int> Special_listener;
119 typedef std::list<Special_listener> Special_listeners;
121 typedef std::list<boost::shared_ptr<Selectable> > Selectables;
123 typedef Keyboard_listeners::iterator Keyboard_listener_iterator;
124 typedef Special_listeners::iterator Special_listener_iterator;
125 typedef Motion_listeners::iterator Motion_listener_iterator;
126 typedef Mouse_listeners::iterator Mouse_listener_iterator;
127 typedef Selectables::iterator Selectable_iterator;
129 struct Event_listener_iterators
131 Mouse_listener_iterator mouse;
132 Mouse_listener_iterator mouse_double;
133 Motion_listener_iterator motion;
134 Motion_listener_iterator passive_motion;
135 Keyboard_listener_iterator keyboard;
136 Special_listener_iterator special;
139 typedef std::map<Event_listener*, Event_listener_iterators> Event_listeners;
141 typedef Event_listeners::iterator Event_listener_iterator;
143 typedef std::list<boost::shared_ptr<Window> > Window_stack;
144 struct Window_iterators
146 Overlay_iterator overlay;
147 Event_listener_iterator events;
148 Window_stack::iterator window_stack;
150 typedef std::map<Window*, Window_iterators> Windows;
152 typedef Windows::iterator Window_iterator;
158 typedef boost::function0<void> Callback;
159 typedef std::list<Callback> Callback_list;
160 typedef std::map<const Callback*, char> Render_visibility_map;
163 typedef boost::function2<void, int, int> Reshape_callback;
164 typedef std::list<Reshape_callback> Reshape_callback_list;
166 typedef Callback_list::iterator Render_callback_iterator;
167 typedef Callback_list::const_iterator Render_callback_const_iterator;
169 typedef Reshape_callback_list::iterator Reshape_callback_iterator;
170 typedef Reshape_callback_list::const_iterator Reshape_callback_const_iterator;
178 boost::function0<void> f_,
179 unsigned int period_,
188 boost::function0<void> f;
197 Perspective_camera src;
198 Perspective_camera
dest;
205 void operator()(
void const*)
const
209 Viewer(
size_t width = 300,
size_t height = 300) :
212 display_origin_(false),
214 reshape_callbacks_(),
215 render_visibility_(),
218 overlay_ownership_(),
219 overlay_attachments_(),
223 front_mouse_listeners_(),
224 back_mouse_listeners_(),
225 mouse_double_listeners_(),
227 passive_motion_listeners_(),
228 keyboard_listeners_(),
229 special_listeners_(),
231 selectable_indices_(),
232 old_rotation_origin_(),
238 bg_mode_(gradient_bg),
239 bg_color_(1.0, 1.0, 1.0, 1.0),
240 bg_gradient_bot_(128.0/255.0, 128.0/255.0, 128.0/255.0, 1.0),
241 bg_gradient_top_(0.0, 0.0, 0.0, 1.0),
244 stereo_mode_(no_stereo),
245 stereo_eye_offset_(),
246 stereo_pixel_offset_()
249 glEnable(GL_LIGHTING);
251 glEnable(GL_DEPTH_TEST);
253 trackball_.attach(*
this);
260 void attach(kjb::opengl::Glut_window& wnd)
262 using namespace boost;
263 wnd.set_size(width(),
height());
265 wnd.set_display_callback(boost::bind(&Viewer::display,
this));
266 wnd.set_reshape_callback(boost::bind(&Viewer::reshape,
this, _1, _2));
267 wnd.set_keyboard_callback(boost::bind(&Self::process_keyboard_,
this, _1, _2, _3));
268 wnd.set_mouse_callback(boost::bind(&Self::process_mouse_,
this, _1, _2, _3, _4));
269 wnd.set_motion_callback(boost::bind(&Self::process_motion_,
this, _1, _2));
270 wnd.set_passive_motion_callback(boost::bind(&Self::process_passive_motion_,
this, _1, _2));
272 add_timer(boost::bind(&Self::tick,
this), TICK_PERIOD);
274 trackball_.update_viewport();
280 trackball_.set_extrinsic(m);
283 void set_clipping_planes(
double near,
double far)
285 trackball_.set_clipping_planes(near, far);
301 trackball_.set_camera(cam, image_height);
315 trackball_.set_camera(cam, height_);
320 return trackball_.get_camera();
329 camera_tween_ = Camera_tween();
330 camera_tween_->src = trackball_.get_camera();
331 camera_tween_->dest = destination_cam;
332 camera_tween_->elapsed = 0;
333 camera_tween_->duration = duration_msec;
345 trackball_.set_camera(cam);
348 void enable_anaglyph_stereo(
349 double screen_distance,
350 double eye_separation,
351 double pixels_per_meter,
352 double world_scale = 1.0,
353 bool swap_left_right =
false)
357 Stereo_mode stereo_mode = (swap_left_right ? anaglyph_swap_stereo : anaglyph_stereo);
359 setup_stereo(stereo_mode, screen_distance, eye_separation, pixels_per_meter, world_scale);
363 void enable_horizontal_stereo(
364 double screen_distance,
365 double eye_separation,
366 double pixels_per_meter,
367 double world_scale = 1.0)
374 setup_stereo(horizontal_stereo, screen_distance, eye_separation, pixels_per_meter, world_scale);
388 double screen_distance,
389 double eye_separation,
390 double pixels_per_meter,
391 double world_scale = 1.0)
395 stereo_eye_offset_ = eye_separation/2.0;
396 stereo_pixel_offset_ = pixels_per_meter * stereo_eye_offset_;
397 double stereo_focal_length = screen_distance * pixels_per_meter;
399 Perspective_camera cam = trackball_.get_camera();
403 cam.set_world_scale(world_scale);
414 void set_background_gradient()
416 bg_mode_ = gradient_bg;
421 bg_mode_ = gradient_bg;
422 bg_gradient_bot_ = bottom;
423 bg_gradient_top_ = top;
439 void set_background_image(
const kjb::Image& img)
442 bg_image_ = boost::in_place();
446 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
448 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
450 glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
465 void set_background_image(
const kjb::opengl::Texture& img)
468 bg_image_.reset(kjb::opengl::Texture(img));
483 void set_rotation_origin(
const Vector3& o)
485 trackball_.set_object_origin(o);
489 Vector3 get_rotation_origin()
const
491 return trackball_.get_object_origin();
507 void push_rotation_origin(
const Vector3& o)
510 if(old_rotation_origin_)
512 old_rotation_origin_ = trackball_.get_object_origin();
513 trackball_.set_object_origin(o);
523 void pop_rotation_origin()
526 if(!old_rotation_origin_)
528 trackball_.set_object_origin(*old_rotation_origin_);
530 old_rotation_origin_ = boost::none;
536 void render_rotation_origin()
539 trackball_.render_object_origin();
544 glMatrixMode(GL_PROJECTION);
546 glMatrixMode(GL_MODELVIEW);
549 glClearColor(bg_color_[0], bg_color_[1], bg_color_[2], bg_color_[3]);
550 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
553 if(stereo_mode_ != no_stereo)
556 draw_dispatch(trackball_.get_camera());
558 glMatrixMode(GL_PROJECTION);
560 glMatrixMode(GL_MODELVIEW);
564 void draw_background()
569 draw_gradient_background();
575 draw_image_background();
580 void draw_gradient_background()
583 glPushAttrib(GL_ENABLE_BIT);
584 glPushAttrib(GL_CURRENT_BIT);
585 glDisable(GL_DEPTH_TEST);
587 glMatrixMode(GL_PROJECTION);
589 glMatrixMode(GL_MODELVIEW);
592 glDisable(GL_LIGHTING);
594 glColor3ub(127, 127, 255);
607 void draw_image_background()
611 glPushAttrib(GL_ENABLE_BIT);
612 glDisable(GL_DEPTH_TEST);
613 glDisable(GL_LIGHTING);
615 glMatrixMode(GL_PROJECTION);
617 glMatrixMode(GL_MODELVIEW);
620 glEnable( GL_TEXTURE_2D);
624 glTexCoord2f(0.0, 0.0); glVertex2i(-1, -1);
625 glTexCoord2f(1.0, 0.0); glVertex2i( 1, -1);
626 glTexCoord2f(1.0, 1.0); glVertex2i( 1, 1);
627 glTexCoord2f(0.0, 1.0); glVertex2i(-1, 1);
637 Perspective_camera center = trackball_.get_camera();
639 Perspective_camera left = center;
640 Perspective_camera right = center;
642 Vector cur_center = center.get_world_origin();
643 cur_center.resize(3);
653 left.set_world_origin(cur_center + Vector(stereo_eye_offset_, 0.0, 0.0));
654 left.set_principal_point(Vector(-stereo_pixel_offset_, 0));
656 right.set_world_origin(cur_center + Vector(-stereo_eye_offset_, 0.0, 0.0));
657 right.set_principal_point(Vector(stereo_pixel_offset_, 0));
659 glPushAttrib(GL_ENABLE_BIT);
660 glPushAttrib(GL_VIEWPORT_BIT);
661 glDisable(GL_SCISSOR_TEST);
663 if(stereo_mode_ == anaglyph_stereo)
664 glColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_FALSE);
665 else if(stereo_mode_ == anaglyph_swap_stereo)
666 glColorMask(GL_FALSE, GL_TRUE, GL_TRUE, GL_TRUE);
667 else if(stereo_mode_ == horizontal_stereo)
669 glEnable(GL_SCISSOR_TEST);
670 glScissor(0, 0, width_/2.0, height_);
671 glViewport(0, 0, width_/2.0, height_);
682 if(stereo_mode_ == anaglyph_stereo)
684 glClear(GL_DEPTH_BUFFER_BIT);
685 glColorMask(GL_FALSE, GL_TRUE, GL_TRUE, GL_TRUE);
687 else if(stereo_mode_ == anaglyph_swap_stereo)
689 glClear(GL_DEPTH_BUFFER_BIT);
690 glColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_FALSE);
692 else if(stereo_mode_ == horizontal_stereo)
694 glScissor(width_/2.0, 0, width_/2.0, height_);
695 glViewport(width_/2.0, 0, width_/2.0, height_);
705 draw_dispatch(right);
707 if(stereo_mode_ == anaglyph_stereo ||
708 stereo_mode_ == anaglyph_swap_stereo)
709 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
719 glMatrixMode(GL_PROJECTION);
721 glScalef(resize_ratio_, resize_ratio_, 1.0);
724 glMatrixMode(GL_MODELVIEW);
729 render_rotation_origin();
734 BOOST_REVERSE_FOREACH(Callback& render_cb, render_callbacks_)
736 if(render_visibility_[&render_cb])
741 BOOST_REVERSE_FOREACH(
const boost::shared_ptr<Selectable> selectable, selectables_)
743 selectable->render(
false);
780 void reshape(
int width,
int height)
782 glViewport(0, 0, width, height);
787 resize_ratio_ =
std::min(((
double) width_)/base_width_, ((
double)height_) / base_height_);
789 if(stereo_mode_ == horizontal_stereo)
793 trackball_.update_viewport(0, 0, width/2.0, height);
797 trackball_.update_viewport(0, 0, width, height);
800 BOOST_FOREACH(Overlay* overlay, overlay_attachments_)
802 overlay->set_size(width, height);
805 BOOST_REVERSE_FOREACH(Reshape_callback& reshape_cb, reshape_callbacks_)
807 reshape_cb(width, height);
814 size_t num_renderables()
816 return render_callbacks_.size();
822 Render_callback_iterator add_renderable(
const kjb::Renderable* renderable)
830 Render_callback_iterator add_renderable(
const boost::shared_ptr<kjb::Renderable>& renderable)
838 template <
class RenderableType>
839 typename boost::enable_if<boost::is_convertible<RenderableType*, kjb::Renderable*>, Render_callback_iterator>::type
840 copy_renderable(
const RenderableType& renderable)
842 BOOST_CONCEPT_ASSERT((boost::Convertible<RenderableType*, kjb::Renderable*>));
858 template <
class Callback_type>
859 Render_callback_iterator add_render_callback(Callback_type callback)
861 return add_render_callback_dispatch_(callback);
864 template <
class Callback_type>
865 Render_callback_iterator add_render_callback(boost::reference_wrapper<Callback_type> callback)
867 return add_render_callback_dispatch_(boost::bind(callback));
870 Render_callback_iterator add_render_callback(
const Callback& callback)
872 return add_render_callback_dispatch_(boost::bind(callback));
875 Render_callback_iterator add_render_callback_dispatch_(
const Callback& cb)
877 render_callbacks_.push_front(cb);
878 render_visibility_[&render_callbacks_.front()] =
true;
879 return render_callbacks_.begin();
889 template <
class Callback>
890 Render_callback_iterator add_render_callback(
const Callback* callback)
893 return add_render_callback(boost::cref(*callback));
899 void remove_render_callback(Render_callback_iterator it)
901 render_visibility_.erase(&*it);
902 render_callbacks_.erase(it);
907 Reshape_callback_iterator add_reshape_callback(
const Reshape_callback& cb)
909 reshape_callbacks_.push_front(cb);
910 return reshape_callbacks_.begin();
937 template <
class Overlay2dType>
938 Overlay_iterator copy_overlay(
const Overlay2dType& overlay)
940 overlay_storage_.push_front(overlay);
942 Overlay_iterator item = add_overlay(&boost::any_cast<Overlay2dType&>(overlay_storage_.front()));
945 overlay_ownership_[&**item] = overlay_storage_.begin();
952 Overlay_iterator attach_overlay(Overlay* overlay)
954 overlay->set_position(0,0);
955 overlay->set_size(width(),
height());
956 Overlay_iterator it = add_overlay(overlay);
957 overlay_attachments_.insert(overlay);
970 Overlay_iterator add_overlay(Overlay* overlay)
974 overlays_.push_front(Overlay_ptr(overlay, null_deleter()));
975 return overlays_.begin();
982 Overlay_iterator add_overlay(Overlay_ptr overlay_ptr)
984 overlays_.push_front(overlay_ptr);
985 return overlays_.begin();
992 Overlay_iterator add_overlay_callback(
const boost::function0<void>& callback,
int x = 0,
int y = 0,
int width = -1,
int height = -1)
994 return copy_overlay(Overlay_callback_wrapper(
x, y, width, height, callback));
1001 void remove_overlay(Overlay_iterator it)
1003 if(overlay_ownership_.count(&**it))
1004 overlay_storage_.erase(overlay_ownership_[&**it]);
1005 overlay_attachments_.erase(&**it);
1006 overlays_.erase(it);
1016 Overlay_iterator raise_overlay(Overlay_iterator it)
1018 if(it == overlays_.begin())
return it;
1020 overlays_.splice(overlays_.begin(), overlays_, it);
1022 return overlays_.begin();
1032 void set_renderable_visibility(
bool v)
1034 BOOST_FOREACH(Render_visibility_map::value_type& pair, render_visibility_)
1041 bool get_renderable_visibility(Render_callback_const_iterator it)
const
1043 if(render_visibility_.count(&*it) == 0)
1046 return render_visibility_.at(&*it);
1050 bool get_renderable_visibility(
size_t i)
const
1052 if(i >= render_callbacks_.size())
1056 i = render_callbacks_.size() - i - 1;
1057 Render_callback_const_iterator it = render_callbacks_.begin();
1058 std::advance(it, i);
1059 return get_renderable_visibility(it);
1063 void set_renderable_visibility(Render_callback_iterator it,
bool v)
1065 if(render_visibility_.count(&*it) == 0)
1068 render_visibility_[&*it] = v;
1072 void set_renderable_visibility(
size_t i,
bool v)
1074 if(i >= render_callbacks_.size())
1078 i = render_callbacks_.size() - i - 1;
1080 Render_callback_iterator it = render_callbacks_.begin();
1081 std::advance(it, i);
1082 set_renderable_visibility(it, v);
1089 Window_iterator add_window(Window* window)
1091 return add_window(boost::shared_ptr<Window>(window, null_deleter()));
1097 Window_iterator add_window(boost::shared_ptr<Window> window)
1100 Window_iterators its;
1103 if(windows_.count(window.get()))
1104 remove_window(window.get());
1106 its.overlay = add_overlay(boost::static_pointer_cast<Overlay>(window));
1107 its.events = add_event_listener(boost::static_pointer_cast<Event_listener>(window));
1110 window_stack_.front()->yield_focus();
1111 window_stack_.push_front(window);
1112 window->claim_focus();
1114 its.window_stack = window_stack_.begin();
1117 typedef Windows::value_type Pair;
1118 std::pair<Window_iterator, bool> item = windows_.insert(Pair(window.get(), its));
1119 assert(item.second ==
true);
1122 window->set_close_callback(boost::bind(
1123 static_cast<void (Self::*)(
const Window_iterator)
>(&Self::remove_window),
1127 window->set_clicked_callback(boost::bind(
1128 static_cast<void (Self::*)(
const Window_iterator)
>(&Self::raise_window),
1134 void remove_window(
const Window_iterator window)
1136 remove_event_listener(window->second.events);
1137 remove_overlay(window->second.overlay);
1138 window_stack_.erase(window->second.window_stack);
1139 windows_.erase(window);
1142 std::cerr <<
"Window removed. Number of windows: " << windows_.size() << std::endl;
1146 void remove_window(boost::shared_ptr<Window> window)
1148 remove_window(window.get());
1151 void remove_window(Window* window)
1153 Window_iterator item = windows_.find(window);
1154 if(item == windows_.end())
1155 KJB_THROW_2(Illegal_argument,
"window not found");
1156 remove_window(item);
1159 void raise_window(Window_iterator window)
1161 raise_overlay(window->second.overlay);
1162 raise_event_listener(window->second.events);
1166 window_stack_.front()->yield_focus();
1167 window_stack_.splice(
1168 window_stack_.begin(),
1170 window->second.window_stack);
1171 window->second.window_stack = window_stack_.begin();
1172 window_stack_.front()->claim_focus();
1202 Event_listener_iterator add_event_listener(boost::shared_ptr<Event_listener> listener)
1205 if(event_listeners_.count(listener.get()))
1206 remove_event_listener(listener.get());
1212 Event_listener_iterators iterators;
1213 iterators.mouse = add_mouse_listener(
1221 iterators.mouse_double = add_mouse_double_listener(
1229 iterators.motion = add_motion_listener(
1235 iterators.passive_motion = add_passive_motion_listener(
1241 iterators.keyboard = add_keyboard_listener(
1248 iterators.special = add_special_listener(
1256 typedef Event_listeners::value_type Pair;
1257 std::pair<Event_listeners::iterator, bool> item = event_listeners_.insert(Pair(listener.get(), iterators));
1258 assert(item.second ==
true);
1267 inline Event_listener_iterator add_event_listener(
Event_listener* listener)
1269 boost::shared_ptr<Event_listener> ptr_wrapper(listener, null_deleter());
1270 return add_event_listener(ptr_wrapper);
1278 void remove_event_listener(
const Event_listener_iterator listener)
1280 remove_mouse_listener(listener->second.mouse);
1281 remove_mouse_double_listener(listener->second.mouse_double);
1282 remove_motion_listener(listener->second.motion);
1283 remove_passive_motion_listener(listener->second.passive_motion);
1284 remove_keyboard_listener(listener->second.keyboard);
1285 remove_special_listener(listener->second.special);
1287 event_listeners_.erase(listener);
1294 void remove_event_listener(boost::shared_ptr<Event_listener> listener)
1296 remove_event_listener(listener.get());
1305 Event_listeners::iterator item = event_listeners_.find(listener);
1306 if(item == event_listeners_.end())
1307 KJB_THROW_2(Illegal_argument,
"listener not found");
1308 remove_event_listener(item);
1311 void raise_event_listener(Event_listener_iterator listener)
1313 front_mouse_listeners_.splice(
1314 front_mouse_listeners_.begin(),
1315 front_mouse_listeners_,
1316 listener->second.mouse);
1317 listener->second.mouse = front_mouse_listeners_.begin();
1319 mouse_double_listeners_.splice(
1320 mouse_double_listeners_.begin(),
1321 mouse_double_listeners_,
1322 listener->second.mouse_double);
1323 listener->second.mouse_double = mouse_double_listeners_.begin();
1325 motion_listeners_.splice(
1326 motion_listeners_.begin(),
1328 listener->second.motion);
1329 listener->second.motion = motion_listeners_.begin();
1331 passive_motion_listeners_.splice(
1332 passive_motion_listeners_.begin(),
1333 passive_motion_listeners_,
1334 listener->second.passive_motion);
1335 listener->second.passive_motion = passive_motion_listeners_.begin();
1337 keyboard_listeners_.splice(
1338 keyboard_listeners_.begin(),
1339 keyboard_listeners_,
1340 listener->second.keyboard);
1341 listener->second.keyboard = keyboard_listeners_.begin();
1343 special_listeners_.splice(
1344 special_listeners_.begin(),
1346 listener->second.special);
1347 listener->second.special = special_listeners_.begin();
1350 #ifdef KJB_HAVE_GLUT
1351 template <
class Callback>
1352 void add_timer(
const Callback& cb,
size_t msec,
bool redraw =
false)
1354 boost::function0<void> f;
1356 timers_.push_back(Timer_entry(f, msec, redraw,
this));
1357 glutTimerFunc(msec, Self::tick_timer, timers_.size()-1);
1363 #ifdef KJB_HAVE_GLUT
1364 glutPostRedisplay();
1368 void key(
unsigned int key,
int ,
int )
1377 display_origin_ = !display_origin_;
1394 Mouse_listener_iterator
1396 const boost::function4<bool, int, int, int, int>& callback)
1398 front_mouse_listeners_.push_front(callback);
1399 return front_mouse_listeners_.begin();
1409 Mouse_listener_iterator
1410 add_after_mouse_listener(
1411 const boost::function4<bool, int, int, int, int>& callback)
1413 back_mouse_listeners_.push_front(callback);
1414 return back_mouse_listeners_.begin();
1420 Mouse_listener_iterator
1421 add_mouse_double_listener(
1422 const boost::function4<bool, int, int, int, int>& callback)
1424 mouse_double_listeners_.push_front(callback);
1425 return mouse_double_listeners_.begin();
1431 Motion_listener_iterator
1432 add_motion_listener(
1433 const boost::function2<bool, int, int>& callback)
1435 motion_listeners_.push_front(callback);
1436 return motion_listeners_.begin();
1442 Motion_listener_iterator
1443 add_passive_motion_listener(
1444 const boost::function2<bool, int, int>& callback)
1446 passive_motion_listeners_.push_front(callback);
1447 return passive_motion_listeners_.begin();
1453 Keyboard_listener_iterator
1454 add_keyboard_listener(
1455 const boost::function3<bool, unsigned int, int, int>& callback)
1457 keyboard_listeners_.push_front(callback);
1458 return keyboard_listeners_.begin();
1464 Special_listener_iterator
1465 add_special_listener(
1466 const boost::function3<bool, int, int, int>& callback)
1468 special_listeners_.push_front(callback);
1469 return special_listeners_.begin();
1475 void remove_mouse_listener( Mouse_listener_iterator item)
1477 front_mouse_listeners_.erase(item);
1480 void remove_after_mouse_listener(Mouse_listener_iterator item)
1482 back_mouse_listeners_.erase(item);
1488 void remove_mouse_double_listener(Mouse_listener_iterator item)
1490 mouse_double_listeners_.erase(item);
1496 void remove_motion_listener(Motion_listener_iterator item)
1498 motion_listeners_.erase(item);
1504 void remove_passive_motion_listener(Motion_listener_iterator item)
1506 passive_motion_listeners_.erase(item);
1512 void remove_keyboard_listener(Keyboard_listener_iterator item)
1514 keyboard_listeners_.erase(item);
1520 void remove_special_listener(Special_listener_iterator item)
1522 special_listeners_.erase(item);
1532 boost::shared_ptr<Selectable> listener)
1534 selectables_.push_front(listener);
1535 selectable_indices_.push_back(selectables_.begin());
1536 return selectables_.begin();
1546 Selectable* listener)
1548 return add_selectable(boost::shared_ptr<Selectable>(listener, null_deleter()));
1551 void remove_selectable(Selectable_iterator item)
1554 selectable_indices_.begin(),
1555 selectable_indices_.end(),
1557 selectables_.erase(item);
1565 tick_camera_tween_();
1569 void process_mouse_(
int button,
int state,
int x,
int y)
1573 #ifdef KJB_HAVE_GLUT
1574 if(state == GLUT_DOWN)
1576 static const double DBLCLICK_INTERVAL = 250;
1577 int cur_time = glutGet(GLUT_ELAPSED_TIME);
1578 int elapsed = cur_time - click_time_;
1579 click_time_ = cur_time;
1580 if(elapsed < DBLCLICK_INTERVAL)
1581 return process_mouse_double_(button, state, x, y);
1585 BOOST_REVERSE_FOREACH(
const Mouse_listener& callback, front_mouse_listeners_)
1587 if(callback(button, state, x,
height() - y - 1))
1591 if(selectables_.size() > 0)
1593 if(process_selection_click_(button, state, x,
height() - y - 1))
1597 BOOST_REVERSE_FOREACH(
const Mouse_listener& callback, back_mouse_listeners_)
1599 if(callback(button, state, x,
height() - y - 1))
1604 void process_mouse_double_(
int button,
int state,
int x,
int y)
1606 BOOST_REVERSE_FOREACH(
const Mouse_listener& callback, mouse_double_listeners_)
1608 if(callback(button, state, x,
height() - y - 1))
1613 void process_motion_(
int x,
int y)
1615 BOOST_REVERSE_FOREACH(
const Motion_listener& callback, motion_listeners_)
1617 if(callback(x,
height() - y - 1))
1622 void process_passive_motion_(
int x,
int y)
1624 BOOST_REVERSE_FOREACH(
const Motion_listener& callback, passive_motion_listeners_)
1626 if(callback(x,
height() - y - 1))
1631 void process_keyboard_(
unsigned int k,
int x,
int y)
1633 BOOST_REVERSE_FOREACH(
const Keyboard_listener& callback, keyboard_listeners_)
1635 if(callback(k, x,
height() - y - 1))
1639 this->key(k, x,
height() - y - 1);
1645 bool process_selection_click_(
int button,
int state,
int x,
int y)
1647 static const size_t BUFSIZE = 512;
1648 GLuint selectBuf[BUFSIZE];
1651 glSelectBuffer (BUFSIZE, selectBuf);
1652 (void) glRenderMode (GL_SELECT);
1659 glMatrixMode(GL_PROJECTION);
1661 glMatrixMode(GL_MODELVIEW);
1664 trackball_.prepare_for_picking(x, y, MARGIN, MARGIN);
1669 BOOST_REVERSE_FOREACH(boost::shared_ptr<Selectable> selectable, selectables_)
1673 selectable->render(
true);
1677 glMatrixMode(GL_PROJECTION);
1679 glMatrixMode(GL_MODELVIEW);
1684 hits = glRenderMode (GL_RENDER);
1690 return process_selection_hits_(hits, selectBuf, button, state);
1693 bool process_selection_hits_(GLint hits,
GLuint buffer[],
int button,
int state)
1703 for(
int i = 0; i < hits; i++)
1706 near_depth = (float) *ptr++/0x7fffffff;
1707 far_depth = (float) *ptr++/0x7fffffff;
1710 GLuint* next = ptr + num_names-1;
1711 assert(name < selectable_indices_.size());
1712 bool processed = (*selectable_indices_[name])->selection_hit(ptr, next, button, state);
1722 #ifdef KJB_HAVE_GLUT
1726 static void tick_timer(
int i)
1728 const Timer_entry& t = timers_[
i];
1734 t.viewer->redisplay();
1738 glutTimerFunc(t.period, Self::tick_timer, i);
1745 void tick_camera_tween_()
1750 camera_tween_->elapsed += TICK_PERIOD;
1751 if(camera_tween_->elapsed > camera_tween_->duration)
1754 set_camera(camera_tween_->dest);
1757 camera_tween_.reset();
1762 static const bool USE_SLERP =
false;
1764 set_extrinsic_matrix(
1766 camera_tween_->src.get_modelview_matrix(),
1767 camera_tween_->dest.get_modelview_matrix(),
1768 (double)(camera_tween_->elapsed) / camera_tween_->duration,
1781 void render_overlays_()
1785 if(overlays_.size() == 0)
return;
1787 glPushAttrib(GL_ENABLE_BIT);
1790 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1792 glDisable(GL_DEPTH_TEST);
1795 glMatrixMode(GL_PROJECTION);
1805 glMatrixMode(GL_MODELVIEW);
1809 Overlay_list::reverse_iterator it;
1810 for(it = overlays_.rbegin(); it != overlays_.rend(); ++it)
1823 Trackball trackball_;
1827 bool display_origin_;
1829 Callback_list render_callbacks_;
1830 Reshape_callback_list reshape_callbacks_;
1831 Render_visibility_map render_visibility_;
1833 std::list<Overlay_ptr> overlays_;
1834 Overlay_storage_list overlay_storage_;
1835 Overlay_ownership_map overlay_ownership_;
1836 std::set<Overlay*> overlay_attachments_;
1838 Event_listeners event_listeners_;
1840 Window_stack window_stack_;
1842 Mouse_listeners front_mouse_listeners_;
1843 Mouse_listeners back_mouse_listeners_;
1844 Mouse_listeners mouse_double_listeners_;
1845 Motion_listeners motion_listeners_;
1846 Motion_listeners passive_motion_listeners_;
1847 Keyboard_listeners keyboard_listeners_;
1848 Special_listeners special_listeners_;
1849 Selectables selectables_;
1850 std::vector<Selectable_iterator> selectable_indices_;
1852 boost::optional<Vector3> old_rotation_origin_;
1855 size_t base_height_;
1860 float resize_ratio_;
1862 enum Bg_mode { solid_bg, gradient_bg, image_bg };
1868 boost::optional<kjb::opengl::Texture> bg_image_;
1871 boost::optional<Camera_tween> camera_tween_;
1874 Stereo_mode stereo_mode_;
1875 double stereo_eye_offset_;
1876 double stereo_pixel_offset_;
1879 static std::vector<Timer_entry> timers_;
1880 static const size_t TICK_PERIOD;
1893 using kjb::gui::Viewer;
virtual bool keyboard_event(unsigned int key, int x, int y)=0
virtual bool mouse_double_event(int button, int state, int x, int y)=0
void mult_projection_matrix() const
Definition: perspective_camera.h:369
Vector_d< 3 > Vector3
Definition: g_quaternion.h:37
Object thrown when an index argument exceeds the size of a container.
Definition: l_exception.h:399
virtual void render() const =0
Renders this object with GL.
Abstract class to render this object with GL.
Definition: gr_renderable.h:78
virtual void set_focal_length(double ifocal)
sets the focal length
Definition: perspective_camera.cpp:872
for k
Definition: APPgetLargeConnectedEdges.m:61
virtual bool special_event(int key, int x, int y)=0
height
Definition: APPgetLargeConnectedEdges.m:33
#define KJB_THROW(ex)
Definition: l_exception.h:46
virtual bool mouse_event(int button, int state, int x, int y)=0
Matrix lerp_extrinsic_camera_matrix(const Matrix &m1, const Matrix &m2, double t, bool use_slerp)
Linearly-interpolate a two extrinsic camera matrices.
Definition: g_camera.cpp:128
St_perspective_camera for modeling a perspective camera using the classic Forsyth and Ponce parametri...
Abstract class to render this object with GL.
Definition: perspective_camera.h:93
x
Definition: APPgetLargeConnectedEdges.m:100
virtual bool passive_motion_event(int x, int y)=0
Definition: gui_event_listener.h:33
#define KJB_THROW_2(ex, msg)
Definition: l_exception.h:48
virtual bool motion_event(int x, int y)=0
#define dest(triedge, pointptr)
Definition: triangle.c:938
Int_matrix::Value_type min(const Int_matrix &mat)
Return the minimum value in this matrix.
Definition: l_int_matrix.h:1385
void mult_modelview_matrix() const
Definition: perspective_camera.cpp:359
void glOrtho(Matrix &state, double left, double right, double bottom, double top, double znear, double zfar)
Definition: gr_opengl.cpp:475
Definition: g_quaternion.h:37
get the indices of edges in each direction for i
Definition: APPgetLargeConnectedEdges.m:48
This class implements matrices, in the linear-algebra sense, with real-valued elements.
Definition: m_matrix.h:94
for m
Definition: APPgetLargeConnectedEdges.m:64
Wrapped version of the C struct KJB_image.
Definition: i_image.h:76