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_ENTER_WINDOW(GLViewer::MouseEnter)
00192     EVT_LEAVE_WINDOW(GLViewer::MouseLeave)
00193     // mouse buttons
00194     EVT_MOUSEWHEEL(GLViewer::MouseWheel)
00195     EVT_MOUSE_EVENTS(GLViewer::MouseButtons)
00196     // keyboard events
00197     EVT_KEY_DOWN(GLViewer::KeyDown)
00198     EVT_KEY_UP(GLViewer::KeyUp)
00199 END_EVENT_TABLE()
00200 
00201 
00202 GLViewer::GLViewer(
00203             wxWindow* parent, 
00204             HuginBase::Panorama &pano, 
00205             int args[], 
00206             GLPreviewFrame *frame_in,
00207             wxGLContext * shared_context
00208             ) :
00209 #if defined __WXGTK__ || wxCHECK_VERSION(2,9,0)
00210           wxGLCanvas(parent, wxID_ANY, args, wxDefaultPosition, wxDefaultSize,
00211                      0, wxT("GLPreviewCanvas"), wxNullPalette)
00212 #else
00213           wxGLCanvas(parent,shared_context,wxID_ANY,wxDefaultPosition,
00214                      wxDefaultSize,0,wxT("GLPreviewCanvas"),args,wxNullPalette)
00215 #endif
00216 {
00217     /* The openGL display context doesn't seem to be created automatically on
00218      * wxGTK, (wxMSW and wxMac 2.8 does implicit create wxGLContext,
00219      * wxWidgets 2.9 requires to explicit create wxGLContext, 
00220      * so I create a new context... */
00221 #if defined __WXGTK__ || wxCHECK_VERSION(2,9,0)
00222     m_glContext = new wxGLContext(this, shared_context);
00223 #endif
00224   
00225     m_renderer = 0;
00226     m_visualization_state = 0;
00227     
00228     m_pano = &pano;
00229     m_overlay=false;
00230 
00231     frame = frame_in;
00232 
00233     m_background_color = frame->GetPreviewBackgroundColor();
00234     
00235     started_creation = false;
00236     redrawing = false;
00237 
00238     active = true;
00239 }
00240 
00241 GLViewer::~GLViewer()
00242 {
00243 #if defined __WXGTK__ || wxCHECK_VERSION(2,9,0)
00244     delete m_glContext;
00245 #endif
00246     if (m_renderer)
00247     {
00248       delete m_tool_helper;
00249       delete m_renderer;
00250       // because m_view_state is a static member variable we need to check
00251       // if other class has already deleted it
00252       if(m_view_state)
00253       {
00254         delete m_view_state;
00255         m_view_state=NULL;
00256       }
00257     }
00258 }
00259 
00260 void GLViewer::SetUpContext()
00261 {
00262     // set the context
00263     DEBUG_INFO("Setting rendering context...");
00264     Show();
00265 #if defined __WXGTK__ || wxCHECK_VERSION(2,9,0)
00266     m_glContext->SetCurrent(*this);
00267 #else
00268     SetCurrent();
00269 #endif
00270     DEBUG_INFO("...got a rendering context.");
00271     if (!started_creation)
00272     {
00273         // It appears we are setting up for the first time.
00274         started_creation = true;
00275         
00276         if (!initialised_glew)
00277         {
00278             // initialise the glew library, if not done it before.
00279             GLenum error_state = glewInit();
00280             initialised_glew = true;
00281             if (error_state != GLEW_OK)
00282             {
00283                 // glewInit failed
00284                 started_creation=false;
00285                 DEBUG_ERROR("Error initialising GLEW: "
00286                         << glewGetErrorString(error_state) << ".");
00287                 frame->Close();
00288                 wxMessageBox(_("Error initializing GLEW\nFast preview window can not be opened."),_("Error"), wxOK | wxICON_ERROR);
00289                 return;
00290             }
00291         }
00292         // check the openGL capabilities.
00293         if (!(GLEW_VERSION_1_1 && GLEW_ARB_multitexture))
00294         {
00295             started_creation=false;
00296             wxConfigBase::Get()->Write(wxT("DisableOpenGL"), 1l);
00297             wxConfigBase::Get()->Flush();
00298             DEBUG_ERROR("Sorry, OpenGL 1.1 + GL_ARB_multitexture extension required.");
00299             frame->Close();
00300             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);
00301             return;
00302         }
00303 
00304         setUp();
00305     }
00306 }
00307 
00308 void GLPreview::setUp()
00309 {
00310     DEBUG_DEBUG("Preview Setup");
00311     // we need something to store the state of the view and control updates
00312     if (!m_view_state) {
00313         GLint countMultiTexture;
00314         glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB,&countMultiTexture);
00315         m_view_state = new ViewState(m_pano, countMultiTexture>1);
00316     }
00317     m_visualization_state = new VisualizationState(m_pano, m_view_state, this, RefreshWrapper, this, (PreviewMeshManager*) NULL);
00318     //Start the tools going:
00319     PreviewToolHelper *helper = new PreviewToolHelper(m_pano, m_visualization_state, frame);
00320     m_tool_helper = static_cast<ToolHelper*>(helper);
00321     frame->MakePreviewTools(helper);
00322     // now make a renderer
00323     m_renderer =  new GLPreviewRenderer(m_pano, m_view_state->GetTextureManager(),
00324                                  m_visualization_state->GetMeshManager(),
00325                                  m_visualization_state, helper, m_background_color);
00326 }
00327 
00328 void GLOverview::setUp()
00329 {
00330 DEBUG_DEBUG("Overview Setup");
00331     // we need something to store the state of the view and control updates
00332     if (!m_view_state) {
00333         GLint countMultiTexture;
00334         glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB,&countMultiTexture);
00335         m_view_state = new ViewState(m_pano, countMultiTexture>1);
00336     }
00337 
00338     panosphere_m_visualization_state = new PanosphereOverviewVisualizationState(m_pano, m_view_state, this, RefreshWrapper, this);
00339     plane_m_visualization_state = new PlaneOverviewVisualizationState(m_pano, m_view_state, this, RefreshWrapper, this);
00340 
00341     m_visualization_state = panosphere_m_visualization_state;
00342 
00343     //Start the tools going:
00344     panosphere_m_tool_helper = new PanosphereOverviewToolHelper(m_pano, panosphere_m_visualization_state, frame);
00345     frame->MakePanosphereOverviewTools(panosphere_m_tool_helper);
00346 
00347     plane_m_tool_helper = new PlaneOverviewToolHelper(m_pano, plane_m_visualization_state, frame);
00348     frame->MakePlaneOverviewTools(plane_m_tool_helper);
00349 
00350     // now make a renderer
00351     panosphere_m_renderer =  new GLPanosphereOverviewRenderer(m_pano, m_view_state->GetTextureManager(),
00352                                  panosphere_m_visualization_state->GetMeshManager(),
00353                                  panosphere_m_visualization_state, panosphere_m_tool_helper, m_background_color);
00354     plane_m_renderer =  new GLPlaneOverviewRenderer(m_pano, m_view_state->GetTextureManager(),
00355                                  plane_m_visualization_state->GetMeshManager(),
00356                                  plane_m_visualization_state, plane_m_tool_helper, m_background_color);
00357                                  
00358     switch(mode) {
00359         case PANOSPHERE:
00360             m_visualization_state = panosphere_m_visualization_state;
00361             m_tool_helper = panosphere_m_tool_helper;
00362             m_renderer = panosphere_m_renderer;
00363             break;
00364         case PLANE:
00365             m_visualization_state = plane_m_visualization_state;
00366             m_tool_helper = plane_m_tool_helper;
00367             m_renderer = plane_m_renderer;
00368             break;
00369     }
00370 }
00371 
00372 void GLViewer::SetPhotometricCorrect(bool state)
00373 {
00374     m_view_state->GetTextureManager()->SetPhotometricCorrect(state);
00375     Refresh();
00376 }
00377 
00378 void GLViewer::SetLayoutMode(bool state)
00379 {
00380     m_visualization_state->GetMeshManager()->SetLayoutMode(state);
00381     Refresh();
00382 }
00383 
00384 void GLViewer::SetLayoutScale(double scale)
00385 {
00386     m_visualization_state->GetMeshManager()->SetLayoutScale(scale);
00387     Refresh();
00388 }
00389 
00390 void GLOverview::SetLayoutMode(bool state)
00391 {
00392     panosphere_m_visualization_state->GetMeshManager()->SetLayoutMode(state);
00393     plane_m_visualization_state->GetMeshManager()->SetLayoutMode(state);
00394     Refresh();
00395 }
00396 
00397 void GLOverview::SetLayoutScale(double scale)
00398 {
00399     panosphere_m_visualization_state->GetMeshManager()->SetLayoutScale(scale*MeshManager::PanosphereOverviewMeshInfo::scale_diff);
00400     plane_m_visualization_state->GetMeshManager()->SetLayoutScale(scale);
00401     Refresh();
00402 }
00403 
00404 
00405 void GLViewer::RedrawE(wxPaintEvent& e)
00406 {
00407     if (!IsActive()) {
00408         return;
00409     }
00410     
00411     //TODO: CanResize specific to a viewer?
00412     DEBUG_DEBUG("REDRAW_E");
00413     if(!IsShown()) return;
00414     // don't redraw during a redraw.
00415     if (!(frame->CanResize())) {
00416         DEBUG_DEBUG("RESIZE IN REDRAW");
00417         frame->ContinueResize();
00418         return;
00419     }
00420         
00421     if (!redrawing)
00422     {
00423         DEBUG_DEBUG("REDRAW_E IN");
00424         redrawing = true;
00425         SetUpContext();
00426         wxPaintDC dc(this); // we need this object on the stack to draw.
00427         Redraw();
00428         redrawing = false;
00429     }
00430     DEBUG_DEBUG("END OF REDRAW_E");
00431 }
00432 
00433 void GLViewer::RefreshWrapper(void * obj)
00434 {
00435     DEBUG_DEBUG("REFRESH WRAPPER");
00436     GLViewer* self = static_cast<GLViewer*>(obj);
00437     self->Refresh();
00438 }
00439 
00440 void GLViewer::Resized(wxSizeEvent& e)
00441 {
00442 
00443     if (!IsActive()) {
00444         return;
00445     }
00446 
00447     DEBUG_DEBUG("RESIZED_OUT");
00448    
00449     if (frame->CanResize()) {
00450         DEBUG_DEBUG("RESIZED_IN");
00451 #if !wxCHECK_VERSION(3,0,1)
00452         wxGLCanvas::OnSize(e);
00453 #endif
00454         if(!IsShown()) return;
00455         // if we have a render at this point, tell it the new size.
00456         DEBUG_DEBUG("RESIZED_IN_SHOWN");
00457         if (m_renderer)
00458         {
00459           int w, h;
00460           DEBUG_DEBUG("RESIZED_IN_RENDERER");
00461           GetClientSize(&w, &h);    
00462           SetUpContext();
00463           offset = m_renderer->Resize(w, h);
00464           Redraw();
00465         };
00466     }
00467 }
00468 
00469 void GLViewer::Redraw()
00470 {
00471     // get the renderer to redraw the OpenGL stuff
00472     if(!m_renderer) return;
00473     // don't redraw if we are in middle of a pending change of the panorama object
00474     if(m_pano->hasPendingChanges()) return;
00475     DEBUG_INFO("Rendering.");
00476     
00477     // we should use the window background colour outside the panorama
00478     // FIXME shouldn't this work on textured backrounds?
00479     wxColour col = wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE);
00480     m_renderer->SetBackground(col.Red(), col.Green(), col.Blue());
00481     if (m_visualization_state->RequireRecalculateViewport())
00482     {
00483         // resize the viewport in case the panorama dimensions have changed.
00484         int w, h;
00485         GetClientSize(&w, &h);
00486         offset = m_renderer->Resize(w, h);
00487     }
00488     m_visualization_state->DoUpdates();
00489     m_renderer->Redraw();
00490     glFlush();
00491     SwapBuffers();
00492     // tell the view state we did all the updates and redrew.
00493     m_visualization_state->FinishedDraw();
00494     //finally draw the overlay text above all
00495     if(m_overlay && !m_overlayText.IsEmpty())
00496     {
00497         int w, h;
00498         GetClientSize(&w, &h);
00499         wxClientDC dc(this);
00500         PrepareDC(dc);
00501         dc.SetBackgroundMode(wxSOLID);
00502         dc.DrawLabel(WrapText(this,m_overlayText,w/4),wxRect(0,0,w,h),wxALIGN_RIGHT|wxALIGN_TOP);
00503     };
00504     DEBUG_INFO("Finished Rendering.");
00505 }
00506 
00507 void GLViewer::OnEraseBackground(wxEraseEvent& e)
00508 {
00509     // Do nothing, to avoid flashing on MSW
00510 }
00511 
00512 void GLViewer::MouseMotion(wxMouseEvent& e)
00513 {
00514     if(m_renderer)
00515         m_tool_helper->MouseMoved((int) e.m_x - offset.x,
00516                               (int) e.m_y - offset.y, e);
00517 }
00518 
00519 void GLViewer::MouseEnter(wxMouseEvent & e)
00520 {
00521     if(m_renderer)
00522         m_tool_helper->MouseEnter((int) e.m_x - offset.x,
00523                               (int) e.m_y - offset.y, e);
00524 }
00525 
00526 void GLViewer::MouseLeave(wxMouseEvent & e)
00527 {
00528     if(m_renderer)
00529         m_tool_helper->MouseLeave();
00530 }
00531 
00532 void GLViewer::MouseButtons(wxMouseEvent& e)
00533 {
00534     if(m_renderer) {
00535         //disregard non button events
00536         if (e.IsButton()) {
00537             m_tool_helper->MouseButtonEvent(e);
00538         }
00539     }
00540 #ifdef __WXMSW__
00541     //use normal mouse button processing of GLCanvas 
00542     //otherwise the mouse wheel is not working
00543     e.Skip();
00544 #endif
00545 }
00546 
00547 void GLViewer::MouseWheel(wxMouseEvent& e)
00548 {
00549     if(m_renderer) {
00550         m_tool_helper->MouseWheelEvent(e);
00551     }
00552 }
00553 
00554 
00555 void GLViewer::KeyDown(wxKeyEvent& e)
00556 {
00557     if(m_renderer)
00558         m_tool_helper->KeypressEvent(e.GetKeyCode(), e.GetModifiers(), true);
00559 }
00560 
00561 void GLViewer::KeyUp(wxKeyEvent& e)
00562 {
00563     if(m_renderer)
00564         m_tool_helper->KeypressEvent(e.GetKeyCode(), e.GetModifiers(), false);
00565 }
00566 
00567 void GLViewer::SetViewerBackground(wxColour col)
00568 {
00569     this->m_background_color = col;
00570     if(m_renderer)
00571         m_renderer->SetPreviewBackgroundColor(col);
00572 }
00573 
00574 void GLOverview::SetMode(OverviewMode mode)
00575 {
00576     this->mode = mode;
00577     if (panosphere_m_renderer != 0 && plane_m_renderer != 0) {
00578         switch(mode) {
00579             case PANOSPHERE:
00580                 m_visualization_state = panosphere_m_visualization_state;
00581                 m_tool_helper = panosphere_m_tool_helper;
00582                 m_renderer = panosphere_m_renderer;
00583                 break;
00584             case PLANE:
00585                 m_visualization_state = plane_m_visualization_state;
00586                 m_tool_helper = plane_m_tool_helper;
00587                 m_renderer = plane_m_renderer;
00588                 break;
00589         }
00590         this->Refresh();
00591     }
00592 }
00593 
00594 void GLViewer::SetOverlayText(const wxString text)
00595 {
00596     m_overlayText=text;
00597 };
00598 
00599 void GLViewer::SetOverlayVisibility(const bool isVisible)
00600 {
00601     m_overlay=isVisible;
00602 };
00603 

Generated on 2 Sep 2015 for Hugintrunk by  doxygen 1.4.7