GLViewer.cpp

Go to the documentation of this file.
00001 // -*- c-basic-offset: 4 -*-
00023 #ifdef __APPLE__
00024 #include "panoinc_WX.h"
00025 #endif
00026 
00027 #include "hugin_utils/utils.h"
00028 
00029 #include "panoinc.h"
00030 #include <config.h>
00031 #if !defined Hugin_shared || !defined _WINDOWS
00032 #define GLEW_STATIC
00033 #endif
00034 #include <GL/glew.h>
00035 #include <base_wx/platform.h>
00036 #include <wx/settings.h>
00037 #include <wx/dcclient.h>
00038 #include <wx/event.h>
00039 
00040 #include "GLViewer.h"
00041 #include "GLRenderer.h"
00042 #include "TextureManager.h"
00043 #include "MeshManager.h"
00044 #include "ToolHelper.h"
00045 #include "GLPreviewFrame.h"
00046 #include "hugin/huginApp.h"
00047 
00048 #if wxCHECK_VERSION(2,9,0)
00049 #include "wx/textwrapper.h"
00050 #else
00051 // in wxWidgets 2.8 the text wrapper functions are in private scope of wxWidgets
00052 // so we can't use them, used lines from src/common/dlgcmn.cpp
00053 class wxTextWrapper
00054 {
00055 public:
00056     wxTextWrapper() { m_eol = false; }
00057 
00058     // win is used for getting the font, text is the text to wrap, width is the
00059     // max line width or -1 to disable wrapping
00060     void Wrap(wxWindow *win, const wxString& text, int widthMax)
00061     {
00062         const wxChar *lastSpace = NULL;
00063         wxString line;
00064 
00065         const wxChar *lineStart = text.c_str();
00066         for ( const wxChar *p = lineStart; ; p++ )
00067         {
00068             if ( IsStartOfNewLine() )
00069             {
00070                 OnNewLine();
00071 
00072                 lastSpace = NULL;
00073                 line.clear();
00074                 lineStart = p;
00075             }
00076 
00077             if ( *p == _T('\n') || *p == _T('\0') )
00078             {
00079                 DoOutputLine(line);
00080 
00081                 if ( *p == _T('\0') )
00082                     break;
00083             }
00084             else // not EOL
00085             {
00086                 if ( *p == _T(' ') )
00087                     lastSpace = p;
00088 
00089                 line += *p;
00090 
00091                 if ( widthMax >= 0 && lastSpace )
00092                 {
00093                     int width;
00094                     win->GetTextExtent(line, &width, NULL);
00095 
00096                     if ( width > widthMax )
00097                     {
00098                         // remove the last word from this line
00099                         line.erase(lastSpace - lineStart, p + 1 - lineStart);
00100                         DoOutputLine(line);
00101 
00102                         // go back to the last word of this line which we didn't
00103                         // output yet
00104                         p = lastSpace;
00105                     }
00106                 }
00107                 //else: no wrapping at all or impossible to wrap
00108             }
00109         }
00110     }
00111 
00112     // we don't need it, but just to avoid compiler warnings
00113     virtual ~wxTextWrapper() { }
00114 
00115 protected:
00116     // line may be empty
00117     virtual void OnOutputLine(const wxString& line) = 0;
00118 
00119     // called at the start of every new line (except the very first one)
00120     virtual void OnNewLine() { }
00121 
00122 private:
00123     // call OnOutputLine() and set m_eol to true
00124     void DoOutputLine(const wxString& line)
00125     {
00126         OnOutputLine(line);
00127 
00128         m_eol = true;
00129     }
00130 
00131     // this function is a destructive inspector: when it returns true it also
00132     // resets the flag to false so calling it again woulnd't return true any
00133     // more
00134     bool IsStartOfNewLine()
00135     {
00136         if ( !m_eol )
00137             return false;
00138 
00139         m_eol = false;
00140 
00141         return true;
00142     }
00143 
00144 
00145     bool m_eol;
00146 };
00147 #endif
00148 
00149 // utility function to wrap text to given width, from wxWidgets help
00150 wxString WrapText(wxWindow *win, const wxString& text, int widthMax)
00151 {
00152     class HardBreakWrapper : public wxTextWrapper
00153     {
00154     public:
00155         HardBreakWrapper(wxWindow *win, const wxString& text, int widthMax)
00156         {
00157             Wrap(win, text, widthMax);
00158         }
00159 
00160         wxString const& GetWrapped() const { return m_wrapped; }
00161 
00162     protected:
00163         virtual void OnOutputLine(const wxString& line)
00164         {
00165             m_wrapped += line;
00166         }
00167 
00168         virtual void OnNewLine()
00169         {
00170             m_wrapped += '\n';
00171         }
00172 
00173     private:
00174         wxString m_wrapped;
00175     };
00176 
00177     HardBreakWrapper wrapper(win, text, widthMax);
00178     return wrapper.GetWrapped();
00179 }
00180 
00181 bool GLViewer::initialised_glew=false;
00182 ViewState * GLViewer::m_view_state = NULL;
00183 
00184 BEGIN_EVENT_TABLE(GLViewer, wxGLCanvas)
00185     EVT_PAINT (GLViewer::RedrawE)
00186     EVT_SIZE  (GLViewer::Resized)
00187     EVT_ERASE_BACKGROUND(GLViewer::OnEraseBackground)
00188     // mouse motion
00189     EVT_MOTION (GLViewer::MouseMotion)
00190     // mouse entered or left the preview
00191     EVT_LEAVE_WINDOW(GLViewer::MouseLeave)
00192     // mouse buttons
00193     EVT_MOUSEWHEEL(GLViewer::MouseWheel)
00194     EVT_MOUSE_EVENTS(GLViewer::MouseButtons)
00195     // keyboard events
00196     EVT_KEY_DOWN(GLViewer::KeyDown)
00197     EVT_KEY_UP(GLViewer::KeyUp)
00198 END_EVENT_TABLE()
00199 
00200 
00201 GLViewer::GLViewer(
00202             wxWindow* parent, 
00203             PT::Panorama &pano, 
00204             int args[], 
00205             GLPreviewFrame *frame_in,
00206             wxGLContext * shared_context
00207             ) :
00208 #if defined __WXGTK__ || wxCHECK_VERSION(2,9,0)
00209           wxGLCanvas(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize,
00210                      0, wxT("GLPreviewCanvas"), args, wxNullPalette)
00211 #else
00212           wxGLCanvas(parent,shared_context,wxID_ANY,wxDefaultPosition,
00213                      wxDefaultSize,0,wxT("GLPreviewCanvas"),args,wxNullPalette)
00214 #endif
00215 {
00216     /* The openGL display context doesn't seem to be created automatically on
00217      * wxGTK, (wxMSW and wxMac 2.8 does implicit create wxGLContext,
00218      * wxWidgets 2.9 requires to explicit create wxGLContext, 
00219      * so I create a new context... */
00220 #if defined __WXGTK__ || wxCHECK_VERSION(2,9,0)
00221     m_glContext = new wxGLContext(this, shared_context);
00222 #endif
00223   
00224     m_renderer = 0;
00225     m_visualization_state = 0;
00226     
00227     m_pano = &pano;
00228     m_overlay=false;
00229 
00230     frame = frame_in;
00231 
00232     m_background_color = frame->GetPreviewBackgroundColor();
00233     
00234     started_creation = false;
00235     redrawing = false;
00236 
00237     active = true;
00238 }
00239 
00240 GLViewer::~GLViewer()
00241 {
00242 #if defined __WXGTK__ || wxCHECK_VERSION(2,9,0)
00243     delete m_glContext;
00244 #endif
00245     if (m_renderer)
00246     {
00247       delete m_tool_helper;
00248       delete m_renderer;
00249       // because m_view_state is a static member variable we need to check
00250       // if other class has already deleted it
00251       if(m_view_state)
00252       {
00253         delete m_view_state;
00254         m_view_state=NULL;
00255       }
00256     }
00257 }
00258 
00259 void GLViewer::SetUpContext()
00260 {
00261     // set the context
00262     DEBUG_INFO("Setting rendering context...");
00263     Show();
00264 #if defined __WXGTK__ || wxCHECK_VERSION(2,9,0)
00265     m_glContext->SetCurrent(*this);
00266 #else
00267     SetCurrent();
00268 #endif
00269     DEBUG_INFO("...got a rendering context.");
00270     if (!started_creation)
00271     {
00272         // It appears we are setting up for the first time.
00273         started_creation = true;
00274         
00275         if (!initialised_glew)
00276         {
00277             // initialise the glew library, if not done it before.
00278             GLenum error_state = glewInit();
00279             initialised_glew = true;
00280             if (error_state != GLEW_OK)
00281             {
00282                 // glewInit failed
00283                 started_creation=false;
00284                 DEBUG_ERROR("Error initialising GLEW: "
00285                         << glewGetErrorString(error_state) << ".");
00286                 frame->Close();
00287                 wxMessageBox(_("Error initializing GLEW\nFast preview window can not be opened."),_("Error"), wxOK | wxICON_ERROR,wxTheApp->GetTopWindow());
00288                 return;
00289             }
00290         }
00291         // check the openGL capabilities.
00292         if (!(GLEW_VERSION_1_1 && GLEW_ARB_multitexture))
00293         {
00294             started_creation=false;
00295             wxConfigBase::Get()->Write(wxT("DisableOpenGL"), 1l);
00296             wxConfigBase::Get()->Flush();
00297             DEBUG_ERROR("Sorry, OpenGL 1.1 + GL_ARB_multitexture extension required.");
00298             frame->Close();
00299             wxMessageBox(_("Sorry, the fast preview window requires a system which supports OpenGL version 1.1 with the GL_ARB_multitexture extension.\nThe fast preview cannot be opened.\n\nHugin has been configured to start without fast preview.\nPlease restart Hugin."),_("Error"), wxOK | wxICON_ERROR,wxTheApp->GetTopWindow());
00300             return;
00301         }
00302 
00303         setUp();
00304     }
00305 }
00306 
00307 void GLPreview::setUp()
00308 {
00309     DEBUG_DEBUG("Preview Setup");
00310     // we need something to store the state of the view and control updates
00311     if (!m_view_state) {
00312         GLint countMultiTexture;
00313         glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB,&countMultiTexture);
00314         m_view_state = new ViewState(m_pano, countMultiTexture>1);
00315     }
00316     m_visualization_state = new VisualizationState(m_pano, m_view_state, this, RefreshWrapper, this, (PreviewMeshManager*) NULL);
00317     //Start the tools going:
00318     PreviewToolHelper *helper = new PreviewToolHelper(m_pano, m_visualization_state, frame);
00319     m_tool_helper = (ToolHelper*) helper;
00320     frame->MakePreviewTools(helper);
00321     // now make a renderer
00322     m_renderer =  new GLPreviewRenderer(m_pano, m_view_state->GetTextureManager(),
00323                                  m_visualization_state->GetMeshManager(),
00324                                  m_visualization_state, helper, m_background_color);
00325 }
00326 
00327 void GLOverview::setUp()
00328 {
00329 DEBUG_DEBUG("Overview Setup");
00330     // we need something to store the state of the view and control updates
00331     if (!m_view_state) {
00332         GLint countMultiTexture;
00333         glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB,&countMultiTexture);
00334         m_view_state = new ViewState(m_pano, countMultiTexture>1);
00335     }
00336 
00337     panosphere_m_visualization_state = new PanosphereOverviewVisualizationState(m_pano, m_view_state, this, RefreshWrapper, this);
00338     plane_m_visualization_state = new PlaneOverviewVisualizationState(m_pano, m_view_state, this, RefreshWrapper, this);
00339 
00340     m_visualization_state = panosphere_m_visualization_state;
00341 
00342     //Start the tools going:
00343     panosphere_m_tool_helper = new PanosphereOverviewToolHelper(m_pano, panosphere_m_visualization_state, frame);
00344     frame->MakePanosphereOverviewTools(panosphere_m_tool_helper);
00345 
00346     plane_m_tool_helper = new PlaneOverviewToolHelper(m_pano, plane_m_visualization_state, frame);
00347     frame->MakePlaneOverviewTools(plane_m_tool_helper);
00348 
00349     // now make a renderer
00350     panosphere_m_renderer =  new GLPanosphereOverviewRenderer(m_pano, m_view_state->GetTextureManager(),
00351                                  panosphere_m_visualization_state->GetMeshManager(),
00352                                  panosphere_m_visualization_state, panosphere_m_tool_helper, m_background_color);
00353     plane_m_renderer =  new GLPlaneOverviewRenderer(m_pano, m_view_state->GetTextureManager(),
00354                                  plane_m_visualization_state->GetMeshManager(),
00355                                  plane_m_visualization_state, plane_m_tool_helper, m_background_color);
00356                                  
00357     switch(mode) {
00358         case PANOSPHERE:
00359             m_visualization_state = panosphere_m_visualization_state;
00360             m_tool_helper = panosphere_m_tool_helper;
00361             m_renderer = panosphere_m_renderer;
00362             break;
00363         case PLANE:
00364             m_visualization_state = plane_m_visualization_state;
00365             m_tool_helper = plane_m_tool_helper;
00366             m_renderer = plane_m_renderer;
00367             break;
00368     }
00369 }
00370 
00371 void GLViewer::SetPhotometricCorrect(bool state)
00372 {
00373     m_view_state->GetTextureManager()->SetPhotometricCorrect(state);
00374     Refresh();
00375 }
00376 
00377 void GLViewer::SetLayoutMode(bool state)
00378 {
00379     m_visualization_state->GetMeshManager()->SetLayoutMode(state);
00380     Refresh();
00381 }
00382 
00383 void GLViewer::SetLayoutScale(double scale)
00384 {
00385     m_visualization_state->GetMeshManager()->SetLayoutScale(scale);
00386     Refresh();
00387 }
00388 
00389 void GLOverview::SetLayoutMode(bool state)
00390 {
00391     panosphere_m_visualization_state->GetMeshManager()->SetLayoutMode(state);
00392     plane_m_visualization_state->GetMeshManager()->SetLayoutMode(state);
00393     Refresh();
00394 }
00395 
00396 void GLOverview::SetLayoutScale(double scale)
00397 {
00398     panosphere_m_visualization_state->GetMeshManager()->SetLayoutScale(scale*MeshManager::PanosphereOverviewMeshInfo::scale_diff);
00399     plane_m_visualization_state->GetMeshManager()->SetLayoutScale(scale);
00400     Refresh();
00401 }
00402 
00403 
00404 void GLViewer::RedrawE(wxPaintEvent& e)
00405 {
00406     if (!IsActive()) {
00407         return;
00408     }
00409     
00410     //TODO: CanResize specific to a viewer?
00411     DEBUG_DEBUG("REDRAW_E");
00412     if(!IsShown()) return;
00413     // don't redraw during a redraw.
00414     if (!(frame->CanResize())) {
00415         DEBUG_DEBUG("RESIZE IN REDRAW");
00416         frame->ContinueResize();
00417         return;
00418     }
00419         
00420     if (!redrawing)
00421     {
00422         DEBUG_DEBUG("REDRAW_E IN");
00423         redrawing = true;
00424         SetUpContext();
00425         wxPaintDC dc(this); // we need this object on the stack to draw.
00426         Redraw();
00427         redrawing = false;
00428     }
00429     DEBUG_DEBUG("END OF REDRAW_E");
00430 }
00431 
00432 void GLViewer::RefreshWrapper(void * obj)
00433 {
00434     DEBUG_DEBUG("REFRESH WRAPPER");
00435     GLViewer* self = (GLViewer*) obj;
00436     self->Refresh();
00437 }
00438 
00439 void GLViewer::Resized(wxSizeEvent& e)
00440 {
00441 
00442     if (!IsActive()) {
00443         return;
00444     }
00445 
00446     DEBUG_DEBUG("RESIZED_OUT");
00447    
00448     if (frame->CanResize()) {
00449         DEBUG_DEBUG("RESIZED_IN");
00450         wxGLCanvas::OnSize(e);
00451         if(!IsShown()) return;
00452         // if we have a render at this point, tell it the new size.
00453         DEBUG_DEBUG("RESIZED_IN_SHOWN");
00454         if (m_renderer)
00455         {
00456           int w, h;
00457           DEBUG_DEBUG("RESIZED_IN_RENDERER");
00458           GetClientSize(&w, &h);    
00459           SetUpContext();
00460           offset = m_renderer->Resize(w, h);
00461           Redraw();
00462         };
00463     }
00464 }
00465 
00466 void GLViewer::Redraw()
00467 {
00468     // get the renderer to redraw the OpenGL stuff
00469     if(!m_renderer) return;
00470     DEBUG_INFO("Rendering.");
00471     
00472     // we should use the window background colour outside the panorama
00473     // FIXME shouldn't this work on textured backrounds?
00474     wxColour col = wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE);
00475     m_renderer->SetBackground(col.Red(), col.Green(), col.Blue());
00476     if (m_visualization_state->RequireRecalculateViewport())
00477     {
00478         // resize the viewport in case the panorama dimensions have changed.
00479         int w, h;
00480         GetClientSize(&w, &h);
00481         offset = m_renderer->Resize(w, h);
00482     }
00483     m_visualization_state->DoUpdates();
00484     m_renderer->Redraw();
00485     glFlush();
00486     SwapBuffers();
00487     // tell the view state we did all the updates and redrew.
00488     m_visualization_state->FinishedDraw();
00489     //finally draw the overlay text above all
00490     if(m_overlay && !m_overlayText.IsEmpty())
00491     {
00492         int w, h;
00493         GetClientSize(&w, &h);
00494         wxClientDC dc(this);
00495         PrepareDC(dc);
00496         dc.SetBackgroundMode(wxSOLID);
00497         dc.DrawLabel(WrapText(this,m_overlayText,w/4),wxRect(0,0,w,h),wxALIGN_RIGHT|wxALIGN_TOP);
00498     };
00499     DEBUG_INFO("Finished Rendering.");
00500 }
00501 
00502 void GLViewer::OnEraseBackground(wxEraseEvent& e)
00503 {
00504     // Do nothing, to avoid flashing on MSW
00505 }
00506 
00507 void GLViewer::MouseMotion(wxMouseEvent& e)
00508 {
00509     if(m_renderer)
00510         m_tool_helper->MouseMoved((int) e.m_x - offset.x,
00511                               (int) e.m_y - offset.y, e);
00512 }
00513 
00514 void GLViewer::MouseLeave(wxMouseEvent & e)
00515 {
00516     if(m_renderer)
00517         m_tool_helper->MouseLeave();
00518 }
00519 
00520 void GLViewer::MouseButtons(wxMouseEvent& e)
00521 {
00522     if(m_renderer) {
00523         //disregard non button events
00524         if (e.IsButton()) {
00525             m_tool_helper->MouseButtonEvent(e);
00526         }
00527     }
00528 #ifdef __WXMSW__
00529     //use normal mouse button processing of GLCanvas 
00530     //otherwise the mouse wheel is not working
00531     e.Skip();
00532 #endif
00533 }
00534 
00535 void GLViewer::MouseWheel(wxMouseEvent& e)
00536 {
00537     if(m_renderer) {
00538         m_tool_helper->MouseWheelEvent(e);
00539     }
00540 }
00541 
00542 
00543 void GLViewer::KeyDown(wxKeyEvent& e)
00544 {
00545     if(m_renderer)
00546         m_tool_helper->KeypressEvent(e.GetKeyCode(), e.GetModifiers(), true);
00547 }
00548 
00549 void GLViewer::KeyUp(wxKeyEvent& e)
00550 {
00551     if(m_renderer)
00552         m_tool_helper->KeypressEvent(e.GetKeyCode(), e.GetModifiers(), false);
00553 }
00554 
00555 void GLViewer::SetViewerBackground(wxColour col)
00556 {
00557     this->m_background_color = col;
00558     if(m_renderer)
00559         m_renderer->SetPreviewBackgroundColor(col);
00560 }
00561 
00562 void GLOverview::SetMode(OverviewMode mode)
00563 {
00564     this->mode = mode;
00565     if (panosphere_m_renderer != 0 && plane_m_renderer != 0) {
00566         switch(mode) {
00567             case PANOSPHERE:
00568                 m_visualization_state = panosphere_m_visualization_state;
00569                 m_tool_helper = panosphere_m_tool_helper;
00570                 m_renderer = panosphere_m_renderer;
00571                 break;
00572             case PLANE:
00573                 m_visualization_state = plane_m_visualization_state;
00574                 m_tool_helper = plane_m_tool_helper;
00575                 m_renderer = plane_m_renderer;
00576                 break;
00577         }
00578         this->Refresh();
00579     }
00580 }
00581 
00582 void GLViewer::SetOverlayText(const wxString text)
00583 {
00584     m_overlayText=text;
00585 };
00586 
00587 void GLViewer::SetOverlayVisibility(const bool isVisible)
00588 {
00589     m_overlay=isVisible;
00590 };
00591 

Generated on 5 Dec 2014 for Hugintrunk by  doxygen 1.4.7