00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include <iostream>
00029 #include <sstream>
00030 #include <map>
00031
00032 #include <boost/function.hpp>
00033 #include <boost/foreach.hpp>
00034 #define foreach BOOST_FOREACH
00035
00036 #include "platform.h"
00037 #include "display.h"
00038 #include "display_internal.h"
00039 #include "simple_math.h"
00040
00041 using namespace std;
00042
00043 namespace pangolin
00044 {
00045
00046 const int panal_v_margin = 6;
00047
00048 typedef boost::ptr_unordered_map<string,PangolinGl> ContextMap;
00049
00050
00051 ContextMap contexts;
00052
00053
00054 __thread PangolinGl* context = 0;
00055
00056 PangolinGl::PangolinGl()
00057 : quit(false), mouse_state(0), activeDisplay(0)
00058 {
00059 }
00060
00061 void BindToContext(std::string name)
00062 {
00063 ContextMap::iterator ic = contexts.find(name);
00064
00065 if( ic == contexts.end() )
00066 {
00067
00068 ic = contexts.insert( name,new PangolinGl ).first;
00069 context = ic->second;
00070 View& dc = context->base;
00071 dc.left = 0.0;
00072 dc.bottom = 0.0;
00073 dc.top = 1.0;
00074 dc.right = 1.0;
00075 dc.aspect = 0;
00076 dc.handler = &StaticHandler;
00077 context->is_fullscreen = false;
00078 #ifdef HAVE_GLUT
00079 process::Resize(
00080 glutGet(GLUT_WINDOW_WIDTH),
00081 glutGet(GLUT_WINDOW_HEIGHT)
00082 );
00083 #else
00084 process::Resize(640,480);
00085 #endif //HAVE_GLUT
00086 }
00087 else
00088 {
00089 context = ic->second;
00090 }
00091 }
00092
00093 void Quit()
00094 {
00095 context->quit = true;
00096 }
00097
00098 bool ShouldQuit()
00099 {
00100 #ifdef HAVE_GLUT
00101 return context->quit || !glutGetWindow();
00102 #else
00103 return context->quit;
00104 #endif
00105 }
00106
00107 bool HadInput()
00108 {
00109 if( context->had_input > 0 )
00110 {
00111 --context->had_input;
00112 return true;
00113 }
00114 return false;
00115 }
00116
00117 bool HasResized()
00118 {
00119 if( context->has_resized > 0 )
00120 {
00121 --context->has_resized;
00122 return true;
00123 }
00124 return false;
00125 }
00126
00127 void RenderViews()
00128 {
00129 DisplayBase().Render();
00130 }
00131
00132 View& DisplayBase()
00133 {
00134 return context->base;
00135 }
00136
00137 View& CreateDisplay()
00138 {
00139 int iguid = rand();
00140 std::stringstream ssguid;
00141 ssguid << iguid;
00142 return Display(ssguid.str());
00143 }
00144
00145 View& Display(const std::string& name)
00146 {
00147
00148 boost::ptr_unordered_map<std::string,View>::iterator vi = context->named_managed_views.find(name);
00149 if( vi != context->named_managed_views.end() )
00150 {
00151 return *(vi->second);
00152 }
00153 else
00154 {
00155 View * v = new View();
00156 bool inserted = context->named_managed_views.insert(name, v).second;
00157 if(!inserted) throw exception();
00158 v->handler = &StaticHandler;
00159 context->base.views.push_back(v);
00160 return *v;
00161 }
00162 }
00163
00164 void RegisterKeyPressCallback(int key, boost::function<void(void)> func)
00165 {
00166 context->keypress_hooks[key] = func;
00167 }
00168
00169 namespace process
00170 {
00171 unsigned int last_x;
00172 unsigned int last_y;
00173
00174 void Keyboard( unsigned char key, int x, int y)
00175 {
00176 context->had_input = context->is_double_buffered ? 2 : 1;
00177
00178
00179 y = context->base.v.h - y;
00180
00181 if( key == GLUT_KEY_ESCAPE)
00182 {
00183 context->quit = true;
00184 }
00185 #ifdef HAVE_CVARS
00186 else if(key == '`')
00187 {
00188 context->console.ToggleConsole();
00189
00190 context->had_input = 60*2;
00191 }
00192 else if(context->console.IsOpen())
00193 {
00194
00195 if( key > 128 )
00196 {
00197 context->console.SpecialFunc(key - 128 );
00198 }
00199 else
00200 {
00201 context->console.KeyboardFunc(key);
00202 }
00203 }
00204 #endif // HAVE_CVARS
00205 #ifdef HAVE_GLUT
00206 else if( key == GLUT_KEY_TAB)
00207 {
00208 if( context->is_fullscreen )
00209 {
00210 glutReshapeWindow(context->windowed_size[0],context->windowed_size[1]);
00211 context->is_fullscreen = false;
00212 }
00213 else
00214 {
00215 glutFullScreen();
00216 context->is_fullscreen = true;
00217 }
00218 }
00219 #endif // HAVE_GLUT
00220 else if(context->keypress_hooks.find(key) != context->keypress_hooks.end() )
00221 {
00222 context->keypress_hooks[key]();
00223 }
00224 else if(context->activeDisplay && context->activeDisplay->handler)
00225 {
00226 context->activeDisplay->handler->Keyboard(*(context->activeDisplay),key,x,y,true);
00227 }
00228 }
00229
00230 void KeyboardUp(unsigned char key, int x, int y)
00231 {
00232
00233 y = context->base.v.h - y;
00234
00235 if(context->activeDisplay && context->activeDisplay->handler)
00236 {
00237 context->activeDisplay->handler->Keyboard(*(context->activeDisplay),key,x,y,false);
00238 }
00239 }
00240
00241 void SpecialFunc(int key, int x, int y)
00242 {
00243 Keyboard(key+128,x,y);
00244 }
00245
00246 void SpecialFuncUp(int key, int x, int y)
00247 {
00248 KeyboardUp(key+128,x,y);
00249 }
00250
00251
00252 void Mouse( int button_raw, int state, int x, int y)
00253 {
00254 last_x = x;
00255 last_y = y;
00256
00257 const MouseButton button = (MouseButton)(1 << button_raw);
00258 const bool pressed = (state == 0);
00259
00260 context->had_input = context->is_double_buffered ? 2 : 1;
00261
00262
00263 y = context->base.v.h - y;
00264
00265 const bool fresh_input = (context->mouse_state == 0);
00266
00267 if( pressed )
00268 {
00269 context->mouse_state |= button;
00270 }
00271 else
00272 {
00273 context->mouse_state &= ~button;
00274 }
00275
00276 if(fresh_input)
00277 {
00278 context->base.handler->Mouse(context->base,button,x,y,pressed,context->mouse_state);
00279 }
00280 else if(context->activeDisplay && context->activeDisplay->handler)
00281 {
00282 context->activeDisplay->handler->Mouse(*(context->activeDisplay),button,x,y,pressed,context->mouse_state);
00283 }
00284 }
00285
00286 void MouseMotion( int x, int y)
00287 {
00288 last_x = x;
00289 last_y = y;
00290
00291 context->had_input = context->is_double_buffered ? 2 : 1;
00292
00293
00294 y = context->base.v.h - y;
00295
00296 if( context->activeDisplay)
00297 {
00298 if( context->activeDisplay->handler )
00299 context->activeDisplay->handler->MouseMotion(*(context->activeDisplay),x,y,context->mouse_state);
00300 }
00301 else
00302 {
00303 context->base.handler->MouseMotion(context->base,x,y,context->mouse_state);
00304 }
00305 }
00306
00307 void PassiveMouseMotion(int x, int y)
00308 {
00309 last_x = x;
00310 last_y = y;
00311 }
00312
00313 void Resize( int width, int height )
00314 {
00315 if( !context->is_fullscreen )
00316 {
00317 context->windowed_size[0] = width;
00318 context->windowed_size[1] = width;
00319 }
00320
00321 context->had_input = 20;
00322 context->has_resized = 20;
00323 Viewport win(0,0,width,height);
00324 context->base.Resize(win);
00325 }
00326
00327 void Scroll(float x, float y)
00328 {
00329 cout << "Scroll: " << x << ", " << y << endl;
00330
00331 if(x==0)
00332 {
00333 Mouse(y>0?3:4,0, last_x, last_y);
00334 context->mouse_state &= !MouseWheelUp;
00335 context->mouse_state &= !MouseWheelDown;
00336 }
00337 }
00338
00339 void Zoom(float m)
00340 {
00341 cout << "Zoom: " << m << endl;
00342 }
00343 }
00344
00345 #ifdef HAVE_GLUT
00346 void PangoGlutRedisplay()
00347 {
00348 glutPostRedisplay();
00349
00350
00351
00352 }
00353
00354 void TakeGlutCallbacks()
00355 {
00356 glutKeyboardFunc(&process::Keyboard);
00357 glutKeyboardUpFunc(&process::KeyboardUp);
00358 glutReshapeFunc(&process::Resize);
00359 glutMouseFunc(&process::Mouse);
00360 glutMotionFunc(&process::MouseMotion);
00361 glutPassiveMotionFunc(&process::PassiveMouseMotion);
00362 glutSpecialFunc(&process::SpecialFunc);
00363 glutSpecialUpFunc(&process::SpecialFuncUp);
00364
00365 #ifdef HAVE_APPLE_OPENGL_FRAMEWORK
00366 glutDisplayFunc(&PangoGlutRedisplay);
00367
00368
00369
00370 typedef void (*glutScrollFunc_t)(void (*)(float, float));
00371 glutScrollFunc_t glutScrollFunc = (glutScrollFunc_t)glutGetProcAddress("glutScrollFunc");
00372 if(glutScrollFunc)
00373 {
00374 glutScrollFunc(&process::Scroll);
00375 }
00376 typedef void (*glutZoomFunc_t)(void (*)(float));
00377 glutZoomFunc_t glutZoomFunc = (glutZoomFunc_t)glutGetProcAddress("glutZoomFunc");
00378 if(glutZoomFunc)
00379 {
00380 cout << "Registering zoom func" << endl;
00381 glutZoomFunc(&process::Zoom);
00382 }
00383
00384 #endif
00385 }
00386
00387 void CreateGlutWindowAndBind(string window_title, int w, int h, unsigned int mode)
00388 {
00389 #ifdef HAVE_FREEGLUT
00390 if( glutGet(GLUT_INIT_STATE) == 0)
00391 #endif
00392 {
00393 int argc = 0;
00394 glutInit(&argc, 0);
00395 glutInitDisplayMode(mode);
00396 }
00397 glutInitWindowSize(w,h);
00398 glutCreateWindow(window_title.c_str());
00399 BindToContext(window_title);
00400
00401 #ifdef HAVE_FREEGLUT
00402 glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_GLUTMAINLOOP_RETURNS);
00403 #endif
00404
00405 context->is_double_buffered = mode & GLUT_DOUBLE;
00406 TakeGlutCallbacks();
00407 }
00408
00409 void FinishGlutFrame()
00410 {
00411 RenderViews();
00412 DisplayBase().Activate();
00413 Viewport::DisableScissor();
00414 #ifdef HAVE_CVARS
00415 context->console.RenderConsole();
00416 #endif // HAVE_CVARS
00417 SwapGlutBuffersProcessGlutEvents();
00418 }
00419
00420 void SwapGlutBuffersProcessGlutEvents()
00421 {
00422 glutSwapBuffers();
00423
00424 #ifdef HAVE_FREEGLUT
00425 glutMainLoopEvent();
00426 #endif
00427
00428 #ifdef HAVE_GLUT_APPLE_FRAMEWORK
00429 glutCheckLoop();
00430 #endif
00431 }
00432 #endif // HAVE_GLUT
00433
00434 void Viewport::Activate() const
00435 {
00436 glViewport(l,b,w,h);
00437 }
00438
00439 void Viewport::Scissor() const
00440 {
00441 glEnable(GL_SCISSOR_TEST);
00442 glScissor(l,b,w,h);
00443 }
00444
00445 void Viewport::ActivateAndScissor() const
00446 {
00447 glViewport(l,b,w,h);
00448 glEnable(GL_SCISSOR_TEST);
00449 glScissor(l,b,w,h);
00450 }
00451
00452
00453 void Viewport::DisableScissor()
00454 {
00455 glDisable(GL_SCISSOR_TEST);
00456 }
00457
00458 bool Viewport::Contains(int x, int y) const
00459 {
00460 return l <= x && x < (l+w) && b <= y && y < (b+h);
00461 }
00462
00463 Viewport Viewport::Inset(int i) const
00464 {
00465 return Viewport(l+i, b+i, w-2*i, h-2*i);
00466 }
00467
00468 Viewport Viewport::Inset(int horiz, int vert) const
00469 {
00470 return Viewport(l+horiz, b+vert, w-horiz, h-vert);
00471 }
00472
00473 void OpenGlMatrix::Load() const
00474 {
00475 glLoadMatrixd(m);
00476 }
00477
00478 void OpenGlMatrix::Multiply() const
00479 {
00480 glMultMatrixd(m);
00481 }
00482
00483 void OpenGlMatrix::SetIdentity()
00484 {
00485 m[0] = 1.0f;
00486 m[1] = 0.0f;
00487 m[2] = 0.0f;
00488 m[3] = 0.0f;
00489 m[4] = 0.0f;
00490 m[5] = 1.0f;
00491 m[6] = 0.0f;
00492 m[7] = 0.0f;
00493 m[8] = 0.0f;
00494 m[9] = 0.0f;
00495 m[10] = 1.0f;
00496 m[11] = 0.0f;
00497 m[12] = 0.0f;
00498 m[13] = 0.0f;
00499 m[14] = 0.0f;
00500 m[15] = 1.0f;
00501 }
00502
00503 void OpenGlRenderState::Apply() const
00504 {
00505
00506 for(map<OpenGlStack,OpenGlMatrix>::const_iterator i = stacks.begin(); i != stacks.end(); ++i )
00507 {
00508 glMatrixMode(i->first);
00509 i->second.Load();
00510 }
00511
00512
00513 glMatrixMode(GL_MODELVIEW);
00514 }
00515
00516 OpenGlRenderState::OpenGlRenderState()
00517 {
00518 }
00519
00520 OpenGlRenderState::OpenGlRenderState(const OpenGlMatrix& projection_matrix)
00521 {
00522 stacks[GlProjectionStack] = projection_matrix;
00523 stacks[GlModelViewStack] = IdentityMatrix();
00524 }
00525
00526 OpenGlRenderState::OpenGlRenderState(const OpenGlMatrix& projection_matrix, const OpenGlMatrix& modelview_matrx)
00527 {
00528 stacks[GlProjectionStack] = projection_matrix;
00529 stacks[GlModelViewStack] = modelview_matrx;
00530 }
00531
00532 void OpenGlRenderState::ApplyIdentity()
00533 {
00534 glMatrixMode(GL_PROJECTION);
00535 glLoadIdentity();
00536 glMatrixMode(GL_MODELVIEW);
00537 glLoadIdentity();
00538 }
00539
00540 void OpenGlRenderState::ApplyWindowCoords()
00541 {
00542 context->base.v.Activate();
00543 glMatrixMode(GL_PROJECTION);
00544 glLoadIdentity();
00545 gluOrtho2D(0, context->base.v.w, 0, context->base.v.h);
00546 glMatrixMode(GL_MODELVIEW);
00547 glLoadIdentity();
00548 }
00549
00550 OpenGlRenderState& OpenGlRenderState::SetProjectionMatrix(OpenGlMatrix spec)
00551 {
00552 stacks[GlProjectionStack] = spec;
00553 return *this;
00554 }
00555
00556 OpenGlRenderState& OpenGlRenderState::SetModelViewMatrix(OpenGlMatrix spec)
00557 {
00558 stacks[GlModelViewStack] = spec;
00559 return *this;
00560 }
00561
00562 OpenGlRenderState& OpenGlRenderState::Set(OpenGlMatrixSpec spec)
00563 {
00564 stacks[spec.type] = spec;
00565 return *this;
00566 }
00567
00568 OpenGlMatrix& OpenGlRenderState::GetProjectionMatrix()
00569 {
00570 return stacks[GlProjectionStack];
00571 }
00572
00573 OpenGlMatrix OpenGlRenderState::GetProjectionMatrix() const
00574 {
00575 std::map<OpenGlStack,OpenGlMatrix>::const_iterator i = stacks.find(GlProjectionStack);
00576 if( i == stacks.end() )
00577 {
00578 return IdentityMatrix();
00579 }
00580 else
00581 {
00582 return i->second;
00583 }
00584 }
00585
00586 OpenGlMatrix& OpenGlRenderState::GetModelViewMatrix()
00587 {
00588 return stacks[GlModelViewStack];
00589 }
00590
00591 OpenGlMatrix OpenGlRenderState::GetModelViewMatrix() const
00592 {
00593 std::map<OpenGlStack,OpenGlMatrix>::const_iterator i = stacks.find(GlModelViewStack);
00594 if( i == stacks.end() )
00595 {
00596 return IdentityMatrix();
00597 }
00598 else
00599 {
00600 return i->second;
00601 }
00602 }
00603
00604 int AttachAbs( int low, int high, Attach a)
00605 {
00606 if( a.unit == Pixel ) return low + a.p;
00607 if( a.unit == ReversePixel ) return high - a.p;
00608 return low + a.p * (high - low);
00609 }
00610
00611 float AspectAreaWithinTarget(double target, double test)
00612 {
00613 if( test < target )
00614 return test / target;
00615 else
00616 return target / test;
00617 }
00618
00619 void View::Resize(const Viewport& p)
00620 {
00621
00622 v.l = AttachAbs(p.l,p.r(),left);
00623 v.b = AttachAbs(p.b,p.t(),bottom);
00624 int r = AttachAbs(p.l,p.r(),right);
00625 int t = AttachAbs(p.b,p.t(),top);
00626
00627
00628 if( t < v.b ) swap(t,v.b);
00629 if( r < v.l ) swap(r,v.l);
00630
00631 v.w = r - v.l;
00632 v.h = t - v.b;
00633
00634 vp = v;
00635
00636
00637 if( aspect != 0 )
00638 {
00639 const float current_aspect = (float)v.w / (float)v.h;
00640 if( aspect > 0 )
00641 {
00642
00643 if( current_aspect < aspect )
00644 {
00645
00646 const int nh = (int)(v.w / aspect);
00647 v.b += vlock == LockBottom ? 0 : (vlock == LockCenter ? (v.h-nh)/2 : (v.h-nh) );
00648 v.h = nh;
00649 }
00650 else if( current_aspect > aspect )
00651 {
00652
00653 const int nw = (int)(v.h * aspect);
00654 v.l += hlock == LockLeft? 0 : (hlock == LockCenter ? (v.w-nw)/2 : (v.w-nw) );
00655 v.w = nw;
00656 }
00657 }
00658 else
00659 {
00660
00661 double true_aspect = -aspect;
00662 if( current_aspect < true_aspect )
00663 {
00664
00665 const int nw = (int)(v.h * true_aspect);
00666 v.l += hlock == LockLeft? 0 : (hlock == LockCenter ? (v.w-nw)/2 : (v.w-nw) );
00667 v.w = nw;
00668 }
00669 else if( current_aspect > true_aspect )
00670 {
00671
00672 const int nh = (int)(v.w / true_aspect);
00673 v.b += vlock == LockBottom ? 0 : (vlock == LockCenter ? (v.h-nh)/2 : (v.h-nh) );
00674 v.h = nh;
00675 }
00676 }
00677 }
00678
00679 ResizeChildren();
00680 }
00681
00682 void View::ResizeChildren()
00683 {
00684 if( layout == LayoutOverlay )
00685 {
00686 foreach(View* i, views)
00687 i->Resize(v);
00688 }
00689 else if( layout == LayoutVertical )
00690 {
00691
00692 Viewport space = v.Inset(panal_v_margin);
00693 int num_children = 0;
00694 foreach(View* i, views )
00695 {
00696 num_children++;
00697 if(scroll_offset > num_children )
00698 {
00699 i->show = false;
00700 }
00701 else
00702 {
00703 i->show = true;
00704 i->Resize(space);
00705 space.h = i->v.b - panal_v_margin - space.b;
00706 }
00707 }
00708 }
00709 else if(layout == LayoutHorizontal )
00710 {
00711
00712 const int margin = 8;
00713 Viewport space = v.Inset(margin);
00714 foreach(View* i, views )
00715 {
00716 i->Resize(space);
00717 space.w = i->v.l + margin + space.l;
00718 }
00719 }
00720 else if(layout == LayoutEqual )
00721 {
00722
00723 if( views.size() > 0 )
00724 {
00725 const double this_a = abs(v.aspect());
00726 const double child_a = abs(views[0]->aspect);
00727 double a = views.size()*child_a;
00728 double area = AspectAreaWithinTarget(this_a, a);
00729
00730 int cols = views.size()-1;
00731 for(; cols > 0; --cols)
00732 {
00733 const int rows = views.size() / cols + (views.size() % cols == 0 ? 0 : 1);
00734 const double na = cols * child_a / rows;
00735 const double new_area = views.size()*AspectAreaWithinTarget(this_a,na)/(rows*cols);
00736 if( new_area <= area )
00737 break;
00738 area = new_area;
00739 a = na;
00740 }
00741
00742 cols++;
00743 const int rows = views.size() / cols + (views.size() % cols == 0 ? 0 : 1);
00744 int cw,ch;
00745 if( a > this_a )
00746 {
00747 cw = v.w / cols;
00748 ch = cw / child_a;
00749 }
00750 else
00751 {
00752 ch = v.h / rows;
00753 cw = ch * child_a;
00754 }
00755
00756 for( unsigned int i=0; i< views.size(); ++i )
00757 {
00758 int c = i % cols;
00759 int r = i / cols;
00760 Viewport space(v.l + c*cw, v.t() - (r+1)*ch, cw,ch);
00761 views[i]->Resize(space);
00762 }
00763 }
00764 }
00765
00766 }
00767
00768 void View::Render()
00769 {
00770 if(!extern_draw_function.empty())
00771 {
00772 extern_draw_function(*this);
00773 }
00774 RenderChildren();
00775 }
00776
00777 void View::RenderChildren()
00778 {
00779 foreach(View* v, views)
00780 if(v->show) v->Render();
00781 }
00782
00783 void View::Activate() const
00784 {
00785 v.Activate();
00786 }
00787
00788 void View::ActivateAndScissor() const
00789 {
00790 vp.Scissor();
00791 v.Activate();
00792 }
00793
00794 void View::ActivateScissorAndClear() const
00795 {
00796 vp.Scissor();
00797 v.Activate();
00798 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00799 }
00800
00801 void View::Activate(const OpenGlRenderState& state ) const
00802 {
00803 v.Activate();
00804 state.Apply();
00805 }
00806
00807 void View::ActivateAndScissor(const OpenGlRenderState& state) const
00808 {
00809 vp.Scissor();
00810 v.Activate();
00811 state.Apply();
00812 }
00813
00814 void View::ActivateScissorAndClear(const OpenGlRenderState& state ) const
00815 {
00816 vp.Scissor();
00817 v.Activate();
00818 state.Apply();
00819 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00820 }
00821
00822 GLfloat View::GetClosestDepth(int x, int y, int radius) const
00823 {
00824 glReadBuffer(GL_FRONT);
00825 const int zl = (radius*2+1);
00826 const int zsize = zl*zl;
00827 GLfloat zs[zsize];
00828 glReadPixels(x-radius,y-radius,zl,zl,GL_DEPTH_COMPONENT,GL_FLOAT,zs);
00829 const GLfloat mindepth = *(std::min_element(zs,zs+zsize));
00830 return mindepth;
00831 }
00832
00833 void View::GetObjectCoordinates(const OpenGlRenderState& cam_state, double winx, double winy, double winzdepth, double& x, double& y, double& z) const
00834 {
00835 const GLint viewport[4] = {v.l,v.b,v.w,v.h};
00836 const OpenGlMatrix proj = cam_state.GetProjectionMatrix();
00837 const OpenGlMatrix mv = cam_state.GetModelViewMatrix();
00838 gluUnProject(winx, winy, winzdepth, mv.m, proj.m, viewport, &x, &y, &z);
00839 }
00840
00841 void View::GetCamCoordinates(const OpenGlRenderState& cam_state, double winx, double winy, double winzdepth, double& x, double& y, double& z) const
00842 {
00843 const GLint viewport[4] = {v.l,v.b,v.w,v.h};
00844 const OpenGlMatrix proj = cam_state.GetProjectionMatrix();
00845 gluUnProject(winx, winy, winzdepth, Identity4d, proj.m, viewport, &x, &y, &z);
00846 }
00847
00848 View& View::SetFocus()
00849 {
00850 context->activeDisplay = this;
00851 return *this;
00852 }
00853
00854 View& View::SetBounds(Attach bottom, Attach top, Attach left, Attach right, bool keep_aspect)
00855 {
00856 SetBounds(top,bottom,left,right,0.0);
00857 aspect = keep_aspect ? v.aspect() : 0;
00858 return *this;
00859 }
00860
00861 View& View::SetBounds(Attach bottom, Attach top, Attach left, Attach right, double aspect)
00862 {
00863 this->left = left;
00864 this->top = top;
00865 this->right = right;
00866 this->bottom = bottom;
00867 this->aspect = aspect;
00868 this->Resize(context->base.v);
00869 return *this;
00870 }
00871
00872 View& View::SetAspect(double aspect)
00873 {
00874 this->aspect = aspect;
00875 this->Resize(context->base.v);
00876 return *this;
00877 }
00878
00879 View& View::SetLock(Lock horizontal, Lock vertical )
00880 {
00881 vlock = vertical;
00882 hlock = horizontal;
00883 return *this;
00884 }
00885
00886 View& View::SetLayout(Layout l)
00887 {
00888 layout = l;
00889 return *this;
00890 }
00891
00892
00893 View& View::AddDisplay(View& child)
00894 {
00895
00896 vector<View*>::iterator f = std::find(
00897 context->base.views.begin(), context->base.views.end(), &child
00898 );
00899
00900 if( f != context->base.views.end() )
00901 context->base.views.erase(f);
00902
00903 views.push_back(&child);
00904 return *this;
00905 }
00906
00907 View& View::operator[](int i)
00908 {
00909 return *views[i];
00910 }
00911
00912 View& View::SetHandler(Handler* h)
00913 {
00914 handler = h;
00915 return *this;
00916 }
00917
00918 View& View::SetDrawFunction(const boost::function<void(View&)>& drawFunc)
00919 {
00920 extern_draw_function = drawFunc;
00921 return *this;
00922 }
00923
00924 View* FindChild(View& parent, int x, int y)
00925 {
00926
00927 for( vector<View*>::const_reverse_iterator i = parent.views.rbegin(); i != parent.views.rend(); ++i )
00928 if( (*i)->show && (*i)->vp.Contains(x,y) )
00929 return (*i);
00930 return 0;
00931 }
00932
00933 void Handler::Keyboard(View& d, unsigned char key, int x, int y, bool pressed)
00934 {
00935 View* child = FindChild(d,x,y);
00936 if( child)
00937 {
00938 context->activeDisplay = child;
00939 if( child->handler)
00940 child->handler->Keyboard(*child,key,x,y,pressed);
00941 }
00942 }
00943
00944 void Handler::Mouse(View& d, MouseButton button, int x, int y, bool pressed, int button_state)
00945 {
00946 View* child = FindChild(d,x,y);
00947 if( child )
00948 {
00949 context->activeDisplay = child;
00950 if( child->handler)
00951 child->handler->Mouse(*child,button,x,y,pressed,button_state);
00952 }
00953 }
00954
00955 void Handler::MouseMotion(View& d, int x, int y, int button_state)
00956 {
00957 View* child = FindChild(d,x,y);
00958 if( child )
00959 {
00960 context->activeDisplay = child;
00961 if( child->handler)
00962 child->handler->MouseMotion(*child,x,y,button_state);
00963 }
00964 }
00965
00966 void HandlerScroll::Mouse(View& d, MouseButton button, int x, int y, bool pressed, int button_state)
00967 {
00968 if( button == button_state && (button == MouseWheelUp || button == MouseWheelDown) )
00969 {
00970 if( button == MouseWheelUp) d.scroll_offset -= 1;
00971 if( button == MouseWheelDown) d.scroll_offset += 1;
00972 d.scroll_offset = max(0, min(d.scroll_offset, (int)d.views.size()) );
00973 d.ResizeChildren();
00974 }
00975 else
00976 {
00977 Handler::Mouse(d,button,x,y,pressed,button_state);
00978 }
00979
00980 }
00981
00982 void Handler3D::Keyboard(View&, unsigned char key, int x, int y, bool pressed)
00983 {
00984
00985 }
00986
00987 void Handler3D::Mouse(View& display, MouseButton button, int x, int y, bool pressed, int button_state)
00988 {
00989
00990 last_pos[0] = x;
00991 last_pos[1] = y;
00992
00993 double T_nc[3*4];
00994 LieSetIdentity(T_nc);
00995
00996 if( pressed && cam_state->stacks.find(GlProjectionStack) != cam_state->stacks.end() )
00997 {
00998 const GLfloat mindepth = display.GetClosestDepth(x,y,hwin);
00999 last_z = mindepth != 1 ? mindepth : last_z;
01000
01001 if( last_z != 1 )
01002 {
01003 display.GetCamCoordinates(*cam_state, x, y, last_z, rot_center[0], rot_center[1], rot_center[2]);
01004 }
01005 else
01006 {
01007 SetZero<3,1>(rot_center);
01008 }
01009
01010 if( button == MouseWheelUp || button == MouseWheelDown)
01011 {
01012
01013 LieSetIdentity(T_nc);
01014 const double t[] = { 0,0,(button==MouseWheelUp?1:-1)*100*tf};
01015 LieSetTranslation<>(T_nc,t);
01016 if( !(button_state & MouseButtonRight) && !(rot_center[0]==0 && rot_center[1]==0 && rot_center[2]==0) )
01017 {
01018 LieSetTranslation<>(T_nc,rot_center);
01019 MatMul<3,1>(T_nc+(3*3),(button==MouseWheelUp?-1.0:1.0)/5.0);
01020 }
01021 OpenGlMatrix& spec = cam_state->stacks[GlModelViewStack];
01022 LieMul4x4bySE3<>(spec.m,T_nc,spec.m);
01023 }
01024 }
01025 }
01026
01027
01028 const static GLdouble AxisDirectionVector[][3] =
01029 {
01030 {0,0,0},
01031 {-1,0,0}, {1,0,0},
01032 {0,-1,0}, {0,1,0},
01033 {0,0,-1}, {0,0,1}
01034 };
01035
01036 void Handler3D::MouseMotion(View& display, int x, int y, int button_state)
01037 {
01038 const int delta[2] = {(x-last_pos[0]),(y-last_pos[1])};
01039 const float mag = delta[0]*delta[0] + delta[1]*delta[1];
01040
01041
01042
01043
01044 if( mag < 50*50 )
01045 {
01046 OpenGlMatrix& mv = cam_state->GetModelViewMatrix();
01047 const GLdouble* up = AxisDirectionVector[enforce_up];
01048 double T_nc[3*4];
01049 LieSetIdentity(T_nc);
01050 bool rotation_changed = false;
01051
01052 if( button_state == MouseButtonMiddle )
01053 {
01054
01055 Rotation<>(T_nc,-delta[1]*0.01, -delta[0]*0.01, 0.0);
01056 }
01057 else if( button_state == MouseButtonLeft )
01058 {
01059
01060 if( last_z != 1 )
01061 {
01062 GLdouble np[3];
01063 display.GetCamCoordinates(*cam_state,x,y,last_z, np[0], np[1], np[2]);
01064 const double t[] = { np[0] - rot_center[0], np[1] - rot_center[1], 0};
01065 LieSetTranslation<>(T_nc,t);
01066 std::copy(np,np+3,rot_center);
01067 }
01068 else
01069 {
01070 const double t[] = { -10*delta[0]*tf, 10*delta[1]*tf, 0};
01071 LieSetTranslation<>(T_nc,t);
01072 }
01073 }
01074 else if( button_state == (MouseButtonLeft | MouseButtonRight) )
01075 {
01076
01077
01078
01079 double T_2c[3*4];
01080 Rotation<>(T_2c,0.0,0.0, delta[0]*0.01);
01081 double mrotc[3];
01082 MatMul<3,1>(mrotc, rot_center, -1.0);
01083 LieApplySO3<>(T_2c+(3*3),T_2c,mrotc);
01084 double T_n2[3*4];
01085 LieSetIdentity<>(T_n2);
01086 LieSetTranslation<>(T_n2,rot_center);
01087 LieMulSE3(T_nc, T_n2, T_2c );
01088 rotation_changed = true;
01089 }
01090 else if( button_state == MouseButtonRight)
01091 {
01092 double aboutx = -0.01 * delta[1];
01093 double abouty = 0.01 * delta[0];
01094
01095 if(enforce_up)
01096 {
01097
01098 const double updotz = mv.m[2]*up[0] + mv.m[6]*up[1] + mv.m[10]*up[2];
01099 if(updotz > 0.98) aboutx = std::min(aboutx,0.0);
01100 if(updotz <-0.98) aboutx = std::max(aboutx,0.0);
01101
01102 abouty *= (1-0.6*abs(updotz));
01103 }
01104
01105
01106 double T_2c[3*4];
01107 Rotation<>(T_2c, aboutx, abouty, 0.0);
01108 double mrotc[3];
01109 MatMul<3,1>(mrotc, rot_center, -1.0);
01110 LieApplySO3<>(T_2c+(3*3),T_2c,mrotc);
01111 double T_n2[3*4];
01112 LieSetIdentity<>(T_n2);
01113 LieSetTranslation<>(T_n2,rot_center);
01114 LieMulSE3(T_nc, T_n2, T_2c );
01115 rotation_changed = true;
01116 }
01117
01118 LieMul4x4bySE3<>(mv.m,T_nc,mv.m);
01119
01120 if(enforce_up != AxisNone && rotation_changed)
01121 {
01122 EnforceUpT_cw(mv.m, up);
01123 }
01124 }
01125
01126 last_pos[0] = x;
01127 last_pos[1] = y;
01128 }
01129
01130
01131 OpenGlMatrixSpec ProjectionMatrix(int w, int h, double fu, double fv, double u0, double v0, double zNear, double zFar )
01132 {
01133 return ProjectionMatrixRUB_BottomLeft(w,h,fu,fv,u0,v0,zNear,zFar);
01134 }
01135
01136 OpenGlMatrixSpec ProjectionMatrixOrthographic(double t, double b, double l, double r, double n, double f )
01137 {
01138 OpenGlMatrixSpec P;
01139 P.type = GlProjectionStack;
01140 std::fill_n(P.m,4*4,0);
01141
01142 P.m[0] = 2/(r-l);
01143 P.m[1] = 0;
01144 P.m[2] = 0;
01145 P.m[3] = 0;
01146
01147 P.m[4] = 0;
01148 P.m[5] = 2/(t-b);
01149 P.m[6] = 0;
01150 P.m[7] = 0;
01151
01152 P.m[8] = 0;
01153 P.m[9] = 0;
01154 P.m[10] = -2/(f-n);
01155 P.m[11] = 0;
01156
01157 P.m[12] = -(r+l)/(r-l);
01158 P.m[13] = -(t+b)/(t-b);
01159 P.m[14] = -(f+n)/(f-n);
01160 P.m[15] = 1;
01161
01162 return P;
01163 }
01164
01165
01166
01167
01168
01169
01170
01171
01172
01173 OpenGlMatrixSpec ProjectionMatrixRUB_BottomLeft(int w, int h, double fu, double fv, double u0, double v0, double zNear, double zFar )
01174 {
01175
01176 const double L = +(u0) * zNear / -fu;
01177 const double T = +(v0) * zNear / fv;
01178 const double R = -(w-u0) * zNear / -fu;
01179 const double B = -(h-v0) * zNear / fv;
01180
01181 OpenGlMatrixSpec P;
01182 P.type = GlProjectionStack;
01183 std::fill_n(P.m,4*4,0);
01184
01185 P.m[0*4+0] = 2 * zNear / (R-L);
01186 P.m[1*4+1] = 2 * zNear / (T-B);
01187 P.m[2*4+2] = -(zFar +zNear) / (zFar - zNear);
01188 P.m[2*4+0] = (R+L)/(R-L);
01189 P.m[2*4+1] = (T+B)/(T-B);
01190 P.m[2*4+3] = -1.0;
01191 P.m[3*4+2] = -(2*zFar*zNear)/(zFar-zNear);
01192
01193 return P;
01194 }
01195
01196
01197
01198
01199
01200
01201 OpenGlMatrixSpec ProjectionMatrixRDF_TopLeft(int w, int h, double fu, double fv, double u0, double v0, double zNear, double zFar )
01202 {
01203
01204 const double L = -(u0) * zNear / fu;
01205 const double R = +(w-u0) * zNear / fu;
01206 const double T = -(v0) * zNear / fv;
01207 const double B = +(h-v0) * zNear / fv;
01208
01209 OpenGlMatrixSpec P;
01210 P.type = GlProjectionStack;
01211 std::fill_n(P.m,4*4,0);
01212
01213 P.m[0*4+0] = 2 * zNear / (R-L);
01214 P.m[1*4+1] = 2 * zNear / (T-B);
01215
01216 P.m[2*4+0] = (R+L)/(L-R);
01217 P.m[2*4+1] = (T+B)/(B-T);
01218 P.m[2*4+2] = (zFar +zNear) / (zFar - zNear);
01219 P.m[2*4+3] = 1.0;
01220
01221 P.m[3*4+2] = (2*zFar*zNear)/(zNear - zFar);
01222 return P;
01223 }
01224
01225
01226
01227
01228
01229
01230 OpenGlMatrixSpec ProjectionMatrixRDF_BottomLeft(int w, int h, double fu, double fv, double u0, double v0, double zNear, double zFar )
01231 {
01232
01233 const double L = -(u0) * zNear / fu;
01234 const double R = +(w-u0) * zNear / fu;
01235 const double B = -(v0) * zNear / fv;
01236 const double T = +(h-v0) * zNear / fv;
01237
01238 OpenGlMatrixSpec P;
01239 P.type = GlProjectionStack;
01240 std::fill_n(P.m,4*4,0);
01241
01242 P.m[0*4+0] = 2 * zNear / (R-L);
01243 P.m[1*4+1] = 2 * zNear / (T-B);
01244
01245 P.m[2*4+0] = (R+L)/(L-R);
01246 P.m[2*4+1] = (T+B)/(B-T);
01247 P.m[2*4+2] = (zFar +zNear) / (zFar - zNear);
01248 P.m[2*4+3] = 1.0;
01249
01250 P.m[3*4+2] = (2*zFar*zNear)/(zNear - zFar);
01251 return P;
01252 }
01253
01254 OpenGlMatrix ModelViewLookAt(double ex, double ey, double ez, double lx, double ly, double lz, double ux, double uy, double uz)
01255 {
01256 OpenGlMatrix mat;
01257 GLdouble* m = mat.m;
01258
01259 const double u_o[3] = {ux,uy,uz};
01260
01261 GLdouble x[3], y[3];
01262 GLdouble z[] = {ex - lx, ey - ly, ez - lz};
01263 Normalise<3>(z);
01264
01265 CrossProduct(x,u_o,z);
01266 CrossProduct(y,z,x);
01267
01268 Normalise<3>(x);
01269 Normalise<3>(y);
01270
01271 #define M(row,col) m[col*4+row]
01272 M(0,0) = x[0];
01273 M(0,1) = x[1];
01274 M(0,2) = x[2];
01275 M(1,0) = y[0];
01276 M(1,1) = y[1];
01277 M(1,2) = y[2];
01278 M(2,0) = z[0];
01279 M(2,1) = z[1];
01280 M(2,2) = z[2];
01281 M(3,0) = 0.0;
01282 M(3,1) = 0.0;
01283 M(3,2) = 0.0;
01284 M(0,3) = -(M(0,0)*ex + M(0,1)*ey + M(0,2)*ez);
01285 M(1,3) = -(M(1,0)*ex + M(1,1)*ey + M(1,2)*ez);
01286 M(2,3) = -(M(2,0)*ex + M(2,1)*ey + M(2,2)*ez);
01287 M(3,3) = 1.0;
01288 #undef M
01289
01290 return mat;
01291 }
01292
01293 OpenGlMatrix ModelViewLookAt(double ex, double ey, double ez, double lx, double ly, double lz, AxisDirection up)
01294 {
01295 const double* u = AxisDirectionVector[up];
01296 return ModelViewLookAt(ex,ey,ez,lx,ly,lz,u[0],u[1],u[2]);
01297 }
01298
01299 OpenGlMatrix IdentityMatrix()
01300 {
01301 OpenGlMatrix P;
01302 std::fill_n(P.m,4*4,0);
01303 for( int i=0; i<4; ++i ) P.m[i*4+i] = 1;
01304 return P;
01305 }
01306
01307 OpenGlMatrixSpec IdentityMatrix(OpenGlStack type)
01308 {
01309 OpenGlMatrixSpec P;
01310 P.type = type;
01311 std::fill_n(P.m,4*4,0);
01312 for( int i=0; i<4; ++i ) P.m[i*4+i] = 1;
01313 return P;
01314 }
01315
01316 OpenGlMatrixSpec negIdentityMatrix(OpenGlStack type)
01317 {
01318 OpenGlMatrixSpec P;
01319 P.type = type;
01320 std::fill_n(P.m,4*4,0);
01321 for( int i=0; i<4; ++i ) P.m[i*4+i] = -1;
01322
01323 P.m[3*4+3] =1;
01324 return P;
01325 }
01326
01327 void DrawTextureToViewport(GLuint texid)
01328 {
01329 OpenGlRenderState::ApplyIdentity();
01330 glBindTexture(GL_TEXTURE_2D, texid);
01331 glEnable(GL_TEXTURE_2D);
01332 glBegin(GL_QUADS);
01333 glTexCoord2f(0, 0);
01334 glVertex2d(-1,-1);
01335 glTexCoord2f(1, 0);
01336 glVertex2d(1,-1);
01337 glTexCoord2f(1, 1);
01338 glVertex2d(1,1);
01339 glTexCoord2f(0, 1);
01340 glVertex2d(-1,1);
01341 glEnd();
01342 glDisable(GL_TEXTURE_2D);
01343 }
01344
01345 }