From: <jl...@us...> - 2008-06-26 14:21:14
|
Revision: 3148 http://hugin.svn.sourceforge.net/hugin/?rev=3148&view=rev Author: jlegg Date: 2008-06-26 07:21:10 -0700 (Thu, 26 Jun 2008) Log Message: ----------- Created a ViewState object to handle the properties of the visible area in the preview, and detect and report when things change, to reduce unwanted expensive computations. It can also handle changes not applied to the actual panorama object yet due to real time controls (implemented in the projection sliders, will be implemented for dragging the images). Real time photometric correction has been half fixed, now it multiplies the image until it is of the correct brightness (can be slow when brightening significantly, and may break partially transparent masked pixels when the image is brightened, after masking is implemented). Started precalculated photometric correctoin (Warning: broken). TextureManager changed from using filenames to identify images to image numbers, so that loading a file twice and using different photometric correction will create two differently corrected textures. There are still some missing bits in the new update mechanism, e.g. handeling deleted images. Modified Paths: -------------- hugin/branches/gsoc2008_opengl_preview/src/hugin1/hugin/CMakeLists.txt hugin/branches/gsoc2008_opengl_preview/src/hugin1/hugin/GLPreviewFrame.cpp hugin/branches/gsoc2008_opengl_preview/src/hugin1/hugin/GLRenderer.cpp hugin/branches/gsoc2008_opengl_preview/src/hugin1/hugin/GLRenderer.h hugin/branches/gsoc2008_opengl_preview/src/hugin1/hugin/GLViewer.cpp hugin/branches/gsoc2008_opengl_preview/src/hugin1/hugin/GLViewer.h hugin/branches/gsoc2008_opengl_preview/src/hugin1/hugin/MainFrame.cpp hugin/branches/gsoc2008_opengl_preview/src/hugin1/hugin/MeshManager.cpp hugin/branches/gsoc2008_opengl_preview/src/hugin1/hugin/MeshManager.h hugin/branches/gsoc2008_opengl_preview/src/hugin1/hugin/TextureManager.cpp hugin/branches/gsoc2008_opengl_preview/src/hugin1/hugin/TextureManager.h hugin/branches/gsoc2008_opengl_preview/src/hugin1/hugin/xrc/preview_frame.xrc hugin/branches/gsoc2008_opengl_preview/src/hugin_base/algorithms/MeshRemapper.cpp hugin/branches/gsoc2008_opengl_preview/src/hugin_base/algorithms/MeshRemapper.h Added Paths: ----------- hugin/branches/gsoc2008_opengl_preview/src/hugin1/hugin/ViewState.cpp hugin/branches/gsoc2008_opengl_preview/src/hugin1/hugin/ViewState.h Modified: hugin/branches/gsoc2008_opengl_preview/src/hugin1/hugin/CMakeLists.txt =================================================================== --- hugin/branches/gsoc2008_opengl_preview/src/hugin1/hugin/CMakeLists.txt 2008-06-26 12:19:31 UTC (rev 3147) +++ hugin/branches/gsoc2008_opengl_preview/src/hugin1/hugin/CMakeLists.txt 2008-06-26 14:21:10 UTC (rev 3148) @@ -29,7 +29,7 @@ CropPanel.cpp OptimizePhotometricPanel.cpp OptimizePanel.cpp CPListFrame.cpp TextKillFocusHandler.cpp PanoDruid.cpp PreferencesDialog.cpp LocalizedFileTipProvider.cpp wxPanoCommand.cpp AssistantPanel.cpp -HFOVDialog.cpp TextureManager.cpp MeshManager.cpp) +HFOVDialog.cpp TextureManager.cpp MeshManager.cpp ViewState.cpp) IF(APPLE) if (MAC_SELF_CONTAINED_BUNDLE) Modified: hugin/branches/gsoc2008_opengl_preview/src/hugin1/hugin/GLPreviewFrame.cpp =================================================================== --- hugin/branches/gsoc2008_opengl_preview/src/hugin1/hugin/GLPreviewFrame.cpp 2008-06-26 12:19:31 UTC (rev 3147) +++ hugin/branches/gsoc2008_opengl_preview/src/hugin1/hugin/GLPreviewFrame.cpp 2008-06-26 14:21:10 UTC (rev 3148) @@ -813,11 +813,11 @@ #endif } // we only actually update the panorama fully when the mouse is released. - // as we are dragging it we don't want to create undo events, but we would - // like to update the display as if the panormama change was complete. - // FIXME breaks undo /redo for FOV sliders anyway. - m_pano.setOptions(opt); - m_GLViewer->panoramaChanged(m_pano); + // As we are dragging it we don't want to create undo events, but we would + // like to update the display, so we change the GLViewer's ViewState and + // request a redraw. + m_GLViewer->m_view_state->SetOptions(&opt); + m_GLViewer->Refresh(); } void GLPreviewFrame::OnBlendChoice(wxCommandEvent & e) Modified: hugin/branches/gsoc2008_opengl_preview/src/hugin1/hugin/GLRenderer.cpp =================================================================== --- hugin/branches/gsoc2008_opengl_preview/src/hugin1/hugin/GLRenderer.cpp 2008-06-26 12:19:31 UTC (rev 3147) +++ hugin/branches/gsoc2008_opengl_preview/src/hugin1/hugin/GLRenderer.cpp 2008-06-26 14:21:10 UTC (rev 3148) @@ -31,14 +31,17 @@ #include "TextureManager.h" #include "MeshManager.h" +#include "ViewState.h" #include "GLRenderer.h" #include "panodata/PanoramaOptions.h" -GLRenderer::GLRenderer(PT::Panorama *pano, TextureManager *tex_man, MeshManager *mesh_man) +GLRenderer::GLRenderer(PT::Panorama *pano, TextureManager *tex_man, + MeshManager *mesh_man, ViewState *view_state) { m_pano = pano; m_tex_man = tex_man; m_mesh_man = mesh_man; + m_view_state =view_state; } GLRenderer::~GLRenderer() @@ -50,9 +53,10 @@ width = in_width; height = in_height; glViewport(0, 0, width, height); - const HuginBase::PanoramaOptions options = m_pano->getOptions(); - width_o = options.getWidth(); - height_o = options.getHeight(); + // we use the view_state rather than the panorama to allow interactivity. + HuginBase::PanoramaOptions *options = m_view_state->GetOptions(); + width_o = options->getWidth(); + height_o = options->getHeight(); float aspect_screen = float(width) / float (height), aspect_pano = width_o / height_o; glMatrixMode(GL_PROJECTION); @@ -106,8 +110,7 @@ { if (m_pano->getImage(img).getOptions().active) { - m_tex_man->BindTexture(img); - m_mesh_man->RenderMesh(img); + m_tex_man->BindTexture(img, m_mesh_man->GetDisplayList(img)); } } m_tex_man->End(); Modified: hugin/branches/gsoc2008_opengl_preview/src/hugin1/hugin/GLRenderer.h =================================================================== --- hugin/branches/gsoc2008_opengl_preview/src/hugin1/hugin/GLRenderer.h 2008-06-26 12:19:31 UTC (rev 3147) +++ hugin/branches/gsoc2008_opengl_preview/src/hugin1/hugin/GLRenderer.h 2008-06-26 14:21:10 UTC (rev 3148) @@ -42,7 +42,8 @@ public: /** ctor. */ - GLRenderer(PT::Panorama * pano, TextureManager *tex_man, MeshManager *mesh_man); + GLRenderer(PT::Panorama * pano, TextureManager *tex_man, + MeshManager *mesh_man, ViewState *veiw_state); /** dtor. */ @@ -59,6 +60,7 @@ PT::Panorama * m_pano; TextureManager * m_tex_man; MeshManager * m_mesh_man; + ViewState * m_view_state; int width, height; }; Modified: hugin/branches/gsoc2008_opengl_preview/src/hugin1/hugin/GLViewer.cpp =================================================================== --- hugin/branches/gsoc2008_opengl_preview/src/hugin1/hugin/GLViewer.cpp 2008-06-26 12:19:31 UTC (rev 3147) +++ hugin/branches/gsoc2008_opengl_preview/src/hugin1/hugin/GLViewer.cpp 2008-06-26 14:21:10 UTC (rev 3148) @@ -46,10 +46,7 @@ m_tex_manager = 0; m_pano = &pano; - m_pano->addObserver(this); - update_images = true; - update_meshes = true; started_creation = false; } @@ -60,8 +57,8 @@ { delete m_renderer; delete m_tex_manager; + delete m_view_state; } - m_pano->removeObserver(this); } void GLViewer::SetUpContext() @@ -78,21 +75,21 @@ { started_creation = true; // It appears we are setting up for the first time. - // Explicitly create (and use) a new rendering context - //m_glContext = new wxGLContext(this, 0); - // now set the texture manager up - m_tex_manager = new TextureManager(*m_pano); + // we need something to store the state of the view and control updates + m_view_state = new ViewState(m_pano, RefreshWrapper, this); + // now set the texture manager up. + m_tex_manager = new TextureManager(*m_pano, m_view_state); // same for the mesh manager - m_mesh_manager = new MeshManager(m_pano); + m_mesh_manager = new MeshManager(m_pano, m_view_state); // now make a renderer - m_renderer = new GLRenderer(m_pano, m_tex_manager, m_mesh_manager); + m_renderer = new GLRenderer(m_pano, m_tex_manager, m_mesh_manager, m_view_state); } } void GLViewer::SetPhotometricCorrect(bool state) { m_tex_manager->SetPhotometricCorrect(state); - update_images = true; + m_view_state->MakePhotometricsDirty(); Refresh(); } @@ -100,71 +97,55 @@ { if(!IsShown()) return; SetUpContext(); - wxPaintDC dc(this); + wxPaintDC dc(this); // we need this object on the stack to draw. Redraw(); } +void GLViewer::RefreshWrapper(void * obj) +{ + GLViewer* self = (GLViewer*) obj; + self->Refresh(); +} + void GLViewer::Resized(wxSizeEvent& e) { wxGLCanvas::OnSize(e); if(!IsShown()) return; - // The renderer needs to adjust to the new viewport size. - int w, h; - GetClientSize(&w, &h); - // if we have a render at this point, tell it the new size. It will need - // the display context to adjust its viewport. + // if we have a render at this point, tell it the new size. if (m_renderer) { + int w, h; + GetClientSize(&w, &h); SetUpContext(); - scale = m_renderer->Resize(w, h); + m_view_state->SetScale(m_renderer->Resize(w, h)); }; } -void GLViewer::panoramaImagesChanged(PT::Panorama &pano, const PT::UIntSet &changed) -{ - update_images = true; - update_meshes = true; - Refresh(); -} - -void GLViewer::panoramaChanged(PT::Panorama &pano) -{ - update_meshes = true; - Refresh(); -} - void GLViewer::Redraw() { // get the renderer to redraw the OpenGL stuff if(!m_renderer) return; std::cout << "Rendering.\n"; + // we should use the window background colour outside the panorama + // FIXME shouldn't this work on textured backrounds? wxColour col = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); m_renderer->SetBackground(col.Red(), col.Green(), col.Blue()); - if (update_images) + if (m_view_state->RequireRecalculateViewport()) { - m_tex_manager->panoramaImagesChanged(*m_pano); - update_images = false; - } - - if (update_meshes) - { // resize the viewport in case the panorama dimensions have changed. int w, h; GetClientSize(&w, &h); - scale = m_renderer->Resize(w, h); - // TODO work out which images need to change - unsigned int num_images = m_pano->getNrOfImages(); - for (unsigned int img = 0; img < num_images; img++) - { - m_mesh_manager->UpdateMesh(img, scale); - } - update_meshes = false; + m_view_state->SetScale(m_renderer->Resize(w, h)); } - + m_tex_manager->CheckUpdate(); + m_mesh_manager->CheckUpdate(); m_renderer->Redraw(); glFlush(); SwapBuffers(); + // tell the view state we did all the updates and redrew. + m_view_state->FinishedDraw(); + } Modified: hugin/branches/gsoc2008_opengl_preview/src/hugin1/hugin/GLViewer.h =================================================================== --- hugin/branches/gsoc2008_opengl_preview/src/hugin1/hugin/GLViewer.h 2008-06-26 12:19:31 UTC (rev 3147) +++ hugin/branches/gsoc2008_opengl_preview/src/hugin1/hugin/GLViewer.h 2008-06-26 14:21:10 UTC (rev 3148) @@ -25,12 +25,13 @@ #define _GL_VIEWER_H #include "wx/glcanvas.h" +#include "ViewState.h" class GLRenderer; class TextureManager; class MeshManager; -class GLViewer: public wxGLCanvas, public PT::PanoramaObserver +class GLViewer: public wxGLCanvas { public: GLViewer(wxFrame* parent, PT::Panorama &pano, int args[]); @@ -38,10 +39,10 @@ void RedrawE(wxPaintEvent& e); void Resized(wxSizeEvent& e); void Redraw(); - void panoramaChanged(PT::Panorama &pano); - void panoramaImagesChanged(PT::Panorama &pano, const PT::UIntSet &changed); + static void RefreshWrapper(void *obj); void SetUpContext(); void SetPhotometricCorrect(bool state); + ViewState * m_view_state; protected: DECLARE_EVENT_TABLE() GLRenderer *m_renderer; @@ -49,8 +50,6 @@ MeshManager *m_mesh_manager; wxGLContext *m_glContext; PT::Panorama * m_pano; - bool update_images; - bool update_meshes; bool started_creation; float scale; }; Modified: hugin/branches/gsoc2008_opengl_preview/src/hugin1/hugin/MainFrame.cpp =================================================================== --- hugin/branches/gsoc2008_opengl_preview/src/hugin1/hugin/MainFrame.cpp 2008-06-26 12:19:31 UTC (rev 3147) +++ hugin/branches/gsoc2008_opengl_preview/src/hugin1/hugin/MainFrame.cpp 2008-06-26 14:21:10 UTC (rev 3148) @@ -667,13 +667,6 @@ wxCommandEvent dummy; preview_frame->OnUpdate(dummy); } - - // force update of GL preview window - // TODO decide if needed - James - /*if ( !(gl_preview_frame->IsIconized() ||(! gl_preview_frame->IsShown()) ) ) { - wxCommandEvent dummy; - gl_preview_frame->OnUpdate(dummy); - } */ } #ifdef __WXMAC__ @@ -728,8 +721,6 @@ pano.clearDirty(); wxCommandEvent dummy; preview_frame->OnUpdate(dummy); - // TODO Decide if needed - James - //gl_preview_frame->OnUpdate(dummy); } void MainFrame::OnAddImages( wxCommandEvent& event ) @@ -1128,9 +1119,6 @@ } gl_preview_frame->Show(); gl_preview_frame->Raise(); - // TODO - decide if needed - James -/* wxCommandEvent (dummy); - gl_preview_frame->OnUpdate(dummy);*/ } void MainFrame::OnShowCPFrame(wxCommandEvent & e) Modified: hugin/branches/gsoc2008_opengl_preview/src/hugin1/hugin/MeshManager.cpp =================================================================== --- hugin/branches/gsoc2008_opengl_preview/src/hugin1/hugin/MeshManager.cpp 2008-06-26 12:19:31 UTC (rev 3147) +++ hugin/branches/gsoc2008_opengl_preview/src/hugin1/hugin/MeshManager.cpp 2008-06-26 14:21:10 UTC (rev 3148) @@ -26,13 +26,15 @@ #endif #include "panoinc.h" +#include "ViewState.h" #include "MeshManager.h" #include "algorithms/MeshRemapper.h" #include <iostream> -MeshManager::MeshManager(PT::Panorama *pano) +MeshManager::MeshManager(PT::Panorama *pano, ViewState *view_state_in) { m_pano = pano; + view_state = view_state_in; } MeshManager::~MeshManager() @@ -40,17 +42,42 @@ meshes.clear(); } -void MeshManager::UpdateMesh(unsigned int image_number, float scale) +void MeshManager::CheckUpdate() { + // update what the view_state deems necessary. + if (view_state->ImagesRemoved()) + { + CleanMeshes(); + // we can't trust anything after images have been removed + unsigned int num_images = m_pano->getNrOfImages(); + for (unsigned int i = 0; i < num_images; i++) + { + UpdateMesh(i); + } + } else { + // check each image individualy. + unsigned int num_images = m_pano->getNrOfImages(); + for (unsigned int i = 0; i < num_images; i++) + { + if (view_state->RequireRecalculateMesh(i)) + { + UpdateMesh(i); + } + } + } +} + +void MeshManager::UpdateMesh(unsigned int image_number) +{ // try to find if it is already here std::map<unsigned int, MeshInfo>::iterator mesh_info = meshes.find(image_number); if (mesh_info != meshes.end()) { - mesh_info->second.Update(scale); + mesh_info->second.Update(); } else { // not found, make a new one std::cout << "Making new mesh remapper for image " << image_number << ".\n"; - meshes[image_number].SetSource(m_pano, image_number, scale); + meshes[image_number].SetSource(m_pano, image_number, view_state); } } @@ -59,6 +86,11 @@ meshes[image_number].CallList(); } +unsigned int MeshManager::GetDisplayList(unsigned int image_number) +{ + return meshes[image_number].display_list_number; +} + void MeshManager::CleanMeshes() { // remove meshes that we no longer need. @@ -77,12 +109,13 @@ } void MeshManager::MeshInfo::SetSource(PT::Panorama *m_pano_in, - unsigned int image_number_in, float scale) + unsigned int image_number_in, + ViewState *view_state) { image_number = image_number_in; m_pano = m_pano_in; - remap = new MeshRemapper(m_pano, image_number); - CompileList(scale); + remap = new MeshRemapper(m_pano, image_number, view_state); + CompileList(); } MeshManager::MeshInfo::~MeshInfo() @@ -91,9 +124,9 @@ if (remap) delete remap; } -void MeshManager::MeshInfo::Update(float scale) +void MeshManager::MeshInfo::Update() { - CompileList(scale); + CompileList(); } void MeshManager::MeshInfo::CallList() @@ -102,13 +135,13 @@ } -void MeshManager::MeshInfo::CompileList(float scale) +void MeshManager::MeshInfo::CompileList() { // build the display list from the coordinates generated by the remapper std::cout << "Preparing to compile a display list for " << image_number << ".\n"; glNewList(display_list_number, GL_COMPILE); - remap->UpdateAndResetIndex(scale); + remap->UpdateAndResetIndex(); std::cout << "Specifying faces.\n"; glBegin(GL_QUADS); // get each face's coordinates from the remapper @@ -127,7 +160,7 @@ glVertex2dv(coords.vertex_c[1][1]); glTexCoord2dv(coords.tex_c[1][0]); glVertex2dv(coords.vertex_c[1][0]); - //glEnd(); + // glEnd(); } glEnd(); glEndList(); Modified: hugin/branches/gsoc2008_opengl_preview/src/hugin1/hugin/MeshManager.h =================================================================== --- hugin/branches/gsoc2008_opengl_preview/src/hugin1/hugin/MeshManager.h 2008-06-26 12:19:31 UTC (rev 3147) +++ hugin/branches/gsoc2008_opengl_preview/src/hugin1/hugin/MeshManager.h 2008-06-26 14:21:10 UTC (rev 3148) @@ -23,41 +23,41 @@ * by creating OpenGL display lists that draw a remapped image. * The coordinates used in the display list are calculated by a MeshRemapper */ - - // TODO replace "float scale" with complete view information #ifndef _MESHMANAGER_H #define _MESHMANAGER_H - + class MeshRemapper; class MeshManager { public: - MeshManager(PT::Panorama *pano); + MeshManager(PT::Panorama *pano, ViewState *view_state); ~MeshManager(); - // scale is the number of screen pixels that make a panorma pixel - void UpdateMesh(unsigned int image_number, float scale); + void CheckUpdate(); void RenderMesh(unsigned int image_number); + unsigned int GetDisplayList(unsigned int image_number); // remove meshes for images that have been deleted. - void CleanMeshes(); + void CleanMeshes(); private: PT::Panorama * m_pano; + ViewState * view_state; + void UpdateMesh(unsigned int image_number); class MeshInfo { public: MeshInfo(); void SetSource(PT::Panorama *m_pano, unsigned int image_number, - float scale); + ViewState *view_state); ~MeshInfo(); void CallList(); - void Update(float scale); + void Update(); + unsigned int display_list_number; private: unsigned int image_number; PT::Panorama *m_pano; MeshRemapper *remap; - unsigned int display_list_number; - void CompileList(float scale); + void CompileList(); }; std::map<unsigned int, MeshInfo> meshes; }; Modified: hugin/branches/gsoc2008_opengl_preview/src/hugin1/hugin/TextureManager.cpp =================================================================== --- hugin/branches/gsoc2008_opengl_preview/src/hugin1/hugin/TextureManager.cpp 2008-06-26 12:19:31 UTC (rev 3147) +++ hugin/branches/gsoc2008_opengl_preview/src/hugin1/hugin/TextureManager.cpp 2008-06-26 14:21:10 UTC (rev 3148) @@ -34,6 +34,7 @@ #include "panoinc_WX.h" #include "panoinc.h" +#include "ViewState.h" #include "TextureManager.h" #include "vigra/stdimage.hxx" @@ -41,53 +42,89 @@ #include "vigra/impex.hxx" #include <vigra_ext/Pyramid.h> #include "base_wx/ImageCache.h" +#include "photometric/ResponseTransform.h" -TextureManager::TextureManager(PT::Panorama &pano) + +TextureManager::TextureManager(PT::Panorama &pano, ViewState *view_state_in) { m_pano = &pano; photometric_correct = false; + view_state = view_state_in; } TextureManager::~TextureManager() { // free up the textures textures.clear(); - // stop observing changes - //m_pano->removeObserver(this); } -void TextureManager::BindTexture(unsigned int image_number) +void TextureManager::BindTexture(unsigned int image_number, + unsigned int display_list) { // bind the texture that represents the given image number. - HuginBase::SrcPanoImage img = m_pano->getSrcImage(image_number); - TextureInfo *tex = &textures[img.getFilename()]; - glBindTexture(GL_TEXTURE_2D, tex->num); - // we should adjust the lighting to match the exposure and white balance - float es = tex->exposure; - float scale[4] = {es / img.getWhiteBalanceRed(), - es, - es / img.getWhiteBalanceBlue(), - 1.0}; - glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, scale); + textures[image_number].Bind(); + if (!photometric_correct) + { + HuginBase::SrcPanoImage *img = view_state->GetSrcImage(image_number); + // we adjust the intensity by using a darker colour + // FIXME clamped at 1.0, overdraw in multiple passes to get brighter? + float es = viewer_exposure / img->getExposure(); + float scale[4] = {es / img->getWhiteBalanceRed(), + es, + es / img->getWhiteBalanceBlue(), + 1.0}; + glColor3fv(scale); + glCallList(display_list); + glDisable(GL_TEXTURE_2D); + glEnable(GL_BLEND); + glBlendFunc(GL_DST_COLOR, GL_ONE); + glColor4f(1.0, 1.0, 1.0, 1.0); + // double the brightness for colour components until it is almost right + bool r, g, b; + while ((r = (scale[0] > 2.0)) || (g = (scale[1] > 2.0)) || (b = (scale[2] > 2.0))) + { + glColor4f(r ? 1.0 : 0.0, g ? 1.0 : 0.0, b ? 1.0 : 0.0, 1.0); + glCallList(display_list); + if (r) scale[0] /= 2.0; + if (g) scale[1] /= 2.0; + if (b) scale[2] /= 2.0; + } + // double the brightness for red, leaving everythign else unaffected + // now add on anything remaining. + if (scale[0] > 1.0 || scale[1] > 1.0 || scale[2] > 1.0) + { + // clamped to 0.0-1.0, so it won't get darker. + scale[0] -= 1.0; scale[1] -= 1.0; scale[2] -= 1.0; + glColor3fv(scale); + glCallList(display_list); + } + glEnable(GL_TEXTURE_2D); + glDisable(GL_BLEND); + } else { + glCallList(display_list); + } } void TextureManager::Begin() { - // we change the exposure and white balance using the scene's ambient light. - glEnable(GL_LIGHTING); - // make the material properties use the ambient light fully. - // find the exposure factor to scale by. - viewer_exposure = pow(2.0, m_pano->getOptions().outputExposureValue); - float exp[4] = {viewer_exposure, viewer_exposure, viewer_exposure, 1.0}; - glLightModelfv(GL_LIGHT_MODEL_AMBIENT, exp); + if (!photometric_correct) + { + // find the exposure factor to scale by. + // fixme- doesn't seem to work the same. + viewer_exposure = 1.0 / pow(2.0, + m_pano->getOptions().outputExposureValue); + }; }; void TextureManager::End() { - glDisable(GL_LIGHTING); + if (!photometric_correct) + { + glColor3f(1.0, 1.0, 1.0); + } } -void TextureManager::panoramaImagesChanged(PT::Panorama &pano/*, const PT::UIntSet &changed*/) +void TextureManager::CheckUpdate() { // The images or their lenses have changed. // Find what size we should have the textures. @@ -95,249 +132,172 @@ // takes up more space, the others should take up less. // Switch OpenGL context in case we need to change the textures. - std::cout << "----\n Updating textures\n"; - - // Recalculuate the ideal image density - unsigned int num_images = pano.getNrOfImages(); + unsigned int num_images = m_pano->getNrOfImages(); if (num_images == 0) { - CleanTextures(); + if (view_state->ImagesRemoved()) + { + CleanTextures(); + } return; } - // find the total of fields of view of the images, in degrees squared - // we assume each image has the same density across all it's pixels - double total_fov = 0.0; - for (unsigned int image_index = 0; image_index < num_images; image_index++) - { - double aspect = double(pano.getImage(image_index).getHeight()) - / double(pano.getImage(image_index).getWidth()); - total_fov += - pano.getLens(pano.getImage(image_index).getLensNr()).getHFOV() * aspect; - }; - // now find the ideal density - texel_density = double(GetMaxTotalTexels()) / total_fov; - - - // now recalculate the best image sizes - // The actual texture size is the biggest one possible withouth scaling the - // image up in any direction. We only specifiy mipmap levels we can fit in - // a given amount of texture memory, while respecting the image's FOV. - int texels_used = 0; - double ideal_texels_used = 0.0; - for (unsigned int image_index = 0; image_index < num_images; image_index++) + HuginBase::PanoramaOptions dest_img = m_pano->getOptions(); + // Recalculuate the ideal image density if required + if (view_state->RequireRecalculateImageSizes()) { - // find this texture - // if it has not been created before, it will be created now. - std::map<std::string, TextureInfo>::iterator it; - it = textures.find(pano.getImage(image_index).getFilename()); - TextureInfo *texinfo; - if (it == textures.end()) + std::cout << "Updating texture sizes\n"; + // find the total of fields of view of the images, in degrees squared + // we assume each image has the same density across all it's pixels + double total_fov = 0.0; + for (unsigned int image_index = 0; image_index < num_images; image_index++) { - // We haven't seen this image before. - // Find a size for it and make its texture. - // store the power that 2 is raised to, not the actual size - unsigned int max_tex_width_p = int(log2(pano.getImage(image_index).getWidth())), - max_tex_height_p = int(log2(pano.getImage(image_index).getHeight())); - // check this is hardware supported. + double aspect = double(m_pano->getImage(image_index).getHeight()) + / double(m_pano->getImage(image_index).getWidth()); + total_fov += + m_pano->getLens(m_pano->getImage(image_index).getLensNr()).getHFOV() + * aspect; + }; + // now find the ideal density + texel_density = double(GetMaxTotalTexels()) / total_fov; + + // now recalculate the best image sizes + // The actual texture size is the biggest one possible withouth scaling the + // image up in any direction. We only specifiy mipmap levels we can fit in + // a given amount of texture memory, while respecting the image's FOV. + int texels_used = 0; + double ideal_texels_used = 0.0; + for (unsigned int image_index = 0; image_index < num_images; image_index++) + { + // find this texture + // if it has not been created before, it will be created now. + std::map<unsigned int, TextureInfo>::iterator it; + it = textures.find(image_index); + TextureInfo *texinfo; + if (it == textures.end()) { - unsigned int biggest = GetMaxTextureSizePower(); - if (biggest < max_tex_width_p) max_tex_width_p = biggest; - if (biggest < max_tex_height_p) max_tex_height_p = biggest; + // We haven't seen this image before. + // Find a size for it and make its texture. + // store the power that 2 is raised to, not the actual size + unsigned int max_tex_width_p = int(log2(m_pano->getImage(image_index).getWidth())), + max_tex_height_p = int(log2(m_pano->getImage(image_index).getHeight())); + // check this is hardware supported. + { + unsigned int biggest = GetMaxTextureSizePower(); + if (biggest < max_tex_width_p) max_tex_width_p = biggest; + if (biggest < max_tex_height_p) max_tex_height_p = biggest; + } + std::cout << "Texture size for image " << image_index << " is " + << (1 << max_tex_width_p) << " by " + << (1 << max_tex_height_p) << "\n"; + // create a new texinfo and store the texture details. + std::cout << "About to create new TextureInfo for " + << m_pano->getImage(image_index).getFilename() + << ".\n"; + texinfo = &textures[image_index]; + texinfo->width = 1 << max_tex_width_p; + texinfo->width_p = max_tex_width_p; + texinfo->height = 1 << max_tex_height_p; + texinfo->height_p = max_tex_height_p; } - std::cout << "Texture size for image " << image_index << " is " - << (1 << max_tex_width_p) << " by " - << (1 << max_tex_height_p) << "\n"; - // create a new texinfo and store the texture details. - std::cout << "About to create new TextureInfo for " << pano.getImage(image_index).getFilename() << ".\n"; - texinfo = &textures[pano.getImage(image_index).getFilename()]; - texinfo->width = 1 << max_tex_width_p; - texinfo->width_p = max_tex_width_p; - texinfo->height = 1 << max_tex_height_p; - texinfo->height_p = max_tex_height_p; - } - else - { - texinfo = &(it->second); - } - - // find the highest mipmap we want to use. - double hfov = pano.getLens(pano.getImage(image_index).getLensNr()).getHFOV(), - aspect = double (texinfo->height) / double (texinfo->width), - ideal_texels = texel_density * hfov * aspect, - // we would like a mipmap with this size: - ideal_tex_width = sqrt(ideal_texels / aspect), - ideal_tex_height = aspect * ideal_tex_width; - // Ideally this mipmap would bring us up to this many texels - ideal_texels_used += ideal_texels; - std::cout << "Ideal mip size: " << ideal_tex_width << " by " - << ideal_tex_height << "\n"; - // Find the smallest mipmap level that is at least this size. - unsigned int max_mip_level = (texinfo->width_p > texinfo->height_p) - ? texinfo->width_p : texinfo->height_p; - unsigned int mip_level = max_mip_level - ceil((ideal_tex_width > ideal_tex_height) - ? log2(ideal_tex_width) : log2(ideal_tex_height)); - // move to the next mipmap level if we are over budget. - if ((texels_used + (1 << (texinfo->width_p + texinfo->height_p - mip_level * 2))) > ideal_texels_used) - { - // scale down - mip_level ++; - } - // don't allow any mipmaps smaller than the 1 by 1 pixel one. - if (mip_level > max_mip_level) mip_level = max_mip_level; - // don't allow any mipmaps with a negative level of detail (will scale up) - if (mip_level < 0) mip_level = 0; - // find the size of this level - int mip_width_p = texinfo->width_p - mip_level, - mip_height_p = texinfo->height_p - mip_level; - // check if we have scaled down to a single line, and make sure we. - // limit the line's width to 1 pixel. - if (mip_width_p < 0) mip_width_p = 0; - if (mip_height_p < 0) mip_height_p = 0; - - // now count these texels as used- we are ignoring the smaller mip - // levels, they add 1/3 on to the size. - texels_used += 1 << (mip_width_p + mip_height_p); - std::cout << "biggest mipmap of image " << image_index << " is " - << (1 << mip_width_p) << " by " << (1 << mip_height_p) - << " (level " << mip_level <<").\n"; - std::cout << "Ideal texels used " << int(ideal_texels_used) - << ", actually used " << texels_used << ".\n\n"; + else + { + texinfo = &(it->second); + } + + // find the highest mipmap we want to use. + double hfov = m_pano->getLens( + m_pano->getImage(image_index).getLensNr() + ).getHFOV(), + aspect = double (texinfo->height) / double (texinfo->width), + ideal_texels = texel_density * hfov * aspect, + // we would like a mipmap with this size: + ideal_tex_width = sqrt(ideal_texels / aspect), + ideal_tex_height = aspect * ideal_tex_width; + // Ideally this mipmap would bring us up to this many texels + ideal_texels_used += ideal_texels; + std::cout << "Ideal mip size: " << ideal_tex_width << " by " + << ideal_tex_height << "\n"; + // Find the smallest mipmap level that is at least this size. + unsigned int max_mip_level = (texinfo->width_p > texinfo->height_p) + ? texinfo->width_p : texinfo->height_p; + unsigned int mip_level = max_mip_level - ceil((ideal_tex_width > ideal_tex_height) + ? log2(ideal_tex_width) : log2(ideal_tex_height)); + // move to the next mipmap level if we are over budget. + if ((texels_used + (1 << (texinfo->width_p + texinfo->height_p + - mip_level * 2))) + > ideal_texels_used) + { + // scale down + mip_level ++; + } + // don't allow any mipmaps smaller than the 1 by 1 pixel one. + if (mip_level > max_mip_level) mip_level = max_mip_level; + // don't allow any mipmaps with a negative level of detail (will scale up) + if (mip_level < 0) mip_level = 0; + // find the size of this level + int mip_width_p = texinfo->width_p - mip_level, + mip_height_p = texinfo->height_p - mip_level; + // check if we have scaled down to a single line, and make sure we + // limit the line's width to 1 pixel. + if (mip_width_p < 0) mip_width_p = 0; + if (mip_height_p < 0) mip_height_p = 0; + + // now count these texels as used- we are ignoring the smaller mip + // levels, they add 1/3 on to the size. + texels_used += 1 << (mip_width_p + mip_height_p); + std::cout << "biggest mipmap of image " << image_index << " is " + << (1 << mip_width_p) << " by " << (1 << mip_height_p) + << " (level " << mip_level <<").\n"; + std::cout << "Ideal texels used " << int(ideal_texels_used) + << ", actually used " << texels_used << ".\n\n"; - // update the exposure of the stored texture. - // if we are doing photometric correction, we will need to rebuild the - // texture. - float new_exposure = pano.getSrcImage(image_index).getExposure(); - if (texinfo->exposure != new_exposure) - { - texinfo->exposure = new_exposure; - if (photometric_correct) + if (view_state->RequireRecalculatePhotometric(image_index) + && photometric_correct) { - texinfo->min_lod = 1000; + // we will need to define all the levels again + texinfo->SetMaxLevel(mip_level); + texinfo->DefineLevels(mip_level, max_mip_level, true, &dest_img, + view_state->GetSrcImage(image_index)); + } else if (texinfo->min_lod != mip_level) { + // maximum level required changed. + texinfo->SetMaxLevel(mip_level); + if (texinfo->min_lod > mip_level) + { + // generate more levels + texinfo->DefineLevels(mip_level, texinfo->min_lod + 1, + photometric_correct, &dest_img, + view_state->GetSrcImage(image_index)); + } } } - // now we have a new desired level of detail, is it different? - if (texinfo->min_lod != mip_level) + } else if (photometric_correct) { + // not recalculating images sizes, but photometrics may have changed + for (unsigned int image_index = 0; image_index < num_images; + image_index++) { - std::cout << "Building mipmaps for image " << image_index << ".\n"; - // tell openGL our new level of detail - glBindTexture(GL_TEXTURE_2D, texinfo->num); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, mip_level); - // we should define any new levels - if (mip_level < texinfo->min_lod) - { - // add more detail textures. We need to get the biggest one first. - // find the original image to scale down. - // TODO cache mipmaps generated to disk for future use? - ImageCache::EntryPtr entry = ImageCache::getInstance().getImage( - pano.getImage(image_index).getFilename()); - vigra::BRGBImage img = *(entry->get8BitImage()); - // first make the biggest mip level. - unsigned int wo = 1 << mip_width_p, ho = 1 << mip_height_p; - // use Vigra to resize image - vigra::BRGBImage out_img(wo, ho); - // TODO check img is bigger than 1 px in both directions - // I think this takes to long, although it should be prettier. - // vigra::resizeImageLinearInterpolation(srcImageRange(img), destImageRange(out_img)); - // much faster - vigra::resizeImageNoInterpolation(srcImageRange(img), - destImageRange(out_img)); - // make all of the smaller ones until we are done. - // this will use a box filter. - // dependent on OpenGL 1.3. Might need an alternative for 1.2. - // TODO use texture compresion? - gluBuild2DMipmapLevels(GL_TEXTURE_2D, GL_RGB8, - wo, ho, - GL_RGB, GL_UNSIGNED_BYTE, - mip_level, mip_level, - texinfo->min_lod > max_mip_level ? - max_mip_level : texinfo->min_lod, - (unsigned char *) out_img.data()); - if (texinfo->min_lod > max_mip_level) - { - // this one is new here - glEnable(GL_TEXTURE_2D); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, - GL_LINEAR_MIPMAP_LINEAR); - // we don't want the edges to repeat the other side of the texture - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - // use anistropic filtering if supported. This is good because we are - // sretching and distorting the textures rather a lot. - static bool checked_anisotropic = false; - static bool has_anisotropic; - static float anisotropy; - if (!checked_anisotropic) - { - // check if it is supported - char *extensions = (char*)glGetString(GL_EXTENSIONS); - if (strstr(extensions, "GL_EXT_texture_filter_anisotropic")) - { - has_anisotropic = true; - glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &anisotropy); - std::cout << "Using anisotropic filtering at maximum value " - << anisotropy << ".\n"; - } else { - has_anisotropic = false; - std::cout << "Anisotropic filtering is not available.\n"; - } - checked_anisotropic = true; - } - if (has_anisotropic) - { - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, - anisotropy); - } - } - // could possibly use something like this instead to lower OpenGL - // dependancy to version 1.2: - /*for (unsigned int lod = mip_level; lod < texinfo->min_lod; lod++) - { - // give result to OpenGL - // TODO use mask and HDR textures? - std::cout << "Defining image " << image_index << "'s " << lod << " level of detail, which is " << wo << " by " << ho << "pixels."; - glTexImage2D(GL_TEXTURE_2D, lod, GL_RGB8, - wo, ho, 0, - GL_RGB, GL_UNSIGNED_BYTE, - (unsigned char *) out_img.data()); - // stop after the 1 by 1 image. - std::cout << "..\n"; - if (wo == 1 && ho == 1) break; - // scale by a half in each direction, clamp to minimum 1. - wo >>= 1; if (!wo) wo = 1; - ho >>= 1; if (!ho) ho = 1; - // use vigra to resize the image. - vigra::BRGBImage out_img2(wo, ho); - if (wo < 2 || ho < 2) - { - //vigra won't scale down smaller than 2x2. Do it ourselves. - // TODO - } else { - vigra::resizeImageLinearInterpolation(srcImageRange(out_img), destImageRange(out_img2)); - } - out_img = out_img2; - }*/ - } - // now store the new value - texinfo->min_lod = mip_level; - } + if (view_state->RequireRecalculatePhotometric(image_index)) + { + // we will need to define all the levels again + TextureInfo *texinfo = &textures[image_index]; + texinfo->DefineLevels(texinfo->min_lod, + (texinfo->width_p > texinfo->height_p) ? + texinfo->width_p : texinfo->height_p, + true, &dest_img, + view_state->GetSrcImage(image_index)); + } + } } // We should remove any images' texture when it is no longer in the panorama - CleanTextures(); + if (view_state->ImagesRemoved()) + { + CleanTextures(); + } } void TextureManager::SetPhotometricCorrect(bool state) { - if (state != photometric_correct) - { - photometric_correct = state; - // make all the textures rebuild next time. - for (std::map<std::string, TextureInfo>::iterator - it = textures.begin(); it != textures.end(); it++) - { - it->second.min_lod = 1000; - } - } + photometric_correct = state; } unsigned int TextureManager::GetMaxTotalTexels() @@ -382,14 +342,14 @@ while (retry) { retry = false; - std::map<std::string, TextureInfo>::iterator tex; + std::map<unsigned int, TextureInfo>::iterator tex; for (tex = textures.begin(); tex != textures.end(); tex++) { bool found = false; // try and find an image with this filename for (unsigned int img = 0; img < num_images; img++) { - if (m_pano->getImage(img).getFilename() == tex->first) + if (img == tex->first) { found = true; break; @@ -411,7 +371,43 @@ // Get an number for an OpenGL texture glGenTextures(1, &num); // we want to generate all levels of detail, they are all undefined. - min_lod= 1000; + min_lod = 1000; + glBindTexture(GL_TEXTURE_2D, num); + glEnable(GL_TEXTURE_2D); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, + GL_LINEAR_MIPMAP_LINEAR); + // we don't want the edges to repeat the other side of the texture + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + // use anistropic filtering if supported. This is good because we are + // sretching and distorting the textures rather a lot in places. + /* FIXME I think on some systems the renderer can change if you move the + * window to a display managed by a different graphics card, but we assume + * the capabilities are constant. */ + static bool checked_anisotropic = false; + static bool has_anisotropic; + static float anisotropy; + if (!checked_anisotropic) + { + // check if it is supported + char *extensions = (char*)glGetString(GL_EXTENSIONS); + if (strstr(extensions, "GL_EXT_texture_filter_anisotropic")) + { + has_anisotropic = true; + glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &anisotropy); + std::cout << "Using anisotropic filtering at maximum value " + << anisotropy << ".\n"; + } else { + has_anisotropic = false; + std::cout << "Anisotropic filtering is not available.\n"; + } + checked_anisotropic = true; + } + if (has_anisotropic) + { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, + anisotropy); + } } TextureManager::TextureInfo::~TextureInfo() @@ -420,3 +416,118 @@ glDeleteTextures(1, &num); } +void TextureManager::TextureInfo::Bind() +{ + glBindTexture(GL_TEXTURE_2D, num); +} + +// Note min and max refer to the mipmap levels, not the sizes of them. min has +// the biggest size. +void TextureManager::TextureInfo::DefineLevels(unsigned int min, + unsigned int max, + bool photometric_correct, + HuginBase::PanoramaOptions *dest_img, + HuginBase::SrcPanoImage *src_img) +{ + // activate the texture so we can change it. + Bind(); + // find the highest allowable mip level + unsigned int max_mip_level = (width_p > height_p) ? width_p : height_p; + if (max > max_mip_level) max = max_mip_level; + + // add more detail textures. We need to get the biggest one first. + // find the original image to scale down. + // TODO cache full texture to disk? + // TODO masks? + // It is also possible to use HDR textures, but I can't see the point using + // them as there would be no difference on an LDR display. (float & uint16) + ImageCache::EntryPtr entry = ImageCache::getInstance().getImage( + src_img->getFilename()); + vigra::BRGBImage img = *(entry->get8BitImage()); + // first make the biggest mip level. + int wo = 1 << (width_p - min), ho = 1 << (height_p - min); + if (wo < 1) wo = 1; if (ho < 1) ho = 1; + // use Vigra to resize image + vigra::BRGBImage out_img(wo, ho); + if (wo < 2 || ho < 2) + { + // too small for vigra to scale + // we still need to define some mipmap levels though. + for (unsigned int mip = min; mip < max; mip++) + { + // TODO + // glTexImage2D(GL_TEXURE_2D, GL_RGB8, + } + } else { + // I think this takes to long, although it should be prettier. + // vigra::resizeImageLinearInterpolation(srcImageRange(img), + // destImageRange(out_img)); + // much faster + vigra::resizeImageNoInterpolation(srcImageRange(img), + destImageRange(out_img)); + // now perform photometric correction + if (photometric_correct) + { + // setup photometric transform for this image type + // this corrects for response curve, white balance, exposure and + // radial vignetting + HuginBase::Photometric::InvResponseTransform + <unsigned char, double> + invResponse(*src_img); + // Assume LDR for now. + // if (m_destImg.outputMode == PanoramaOptions::OUTPUT_LDR) { + // select exposure and response curve for LDR output + std::vector<double> outLut; + vigra_ext::EMoR::createEMoRLUT(dest_img->outputEMoRParams, outLut); + vigra_ext::enforceMonotonicity(outLut); + // scale up to desired output format (I assume 8 bit output here) + double maxVal = 255.0; + invResponse.setOutput(1.0/pow(2.0,dest_img->outputExposureValue), + outLut, maxVal); + /*} else { + // HDR output. not sure how that would be handled by the opengl + // preview, though. It might be possible to apply a logarithmic + // lookup table here, and average the overlapping pixels + // in the OpenGL renderer? + // TODO + invResponse.setHDROutput(); + }*/ + // now perform the corrections + double scale_x = (double) src_img->getSize().width() / (double) wo, + scale_y = (double) src_img->getSize().height() / (double) ho; + for (int x = 0; x < wo; x++) + { + for (int y = 0; y < ho; y++) + { + double sx = x * scale_x, + sy = y * scale_y; + // vigra::RGBValue<vigra::UInt8> pixelval; + // vigra::RGBValue<vigra::UInt8> pixelval_corr; + out_img[x][y] = invResponse(out_img(x,y), + hugin_utils::FDiff2D(sx, sy)); + } + } + + } + // make all of the smaller ones until we are done. + // this will use a box filter. + // dependent on OpenGL 1.3. Might need an alternative for 1.2. + // TODO use texture compresion? + GLint error = gluBuild2DMipmapLevels(GL_TEXTURE_2D, GL_RGB8, wo, ho, + GL_RGB, GL_UNSIGNED_BYTE, min, min, max, + (unsigned char *) out_img.data()); + if (error) + { + std::cout << "Error when building mipmap levels: " + << gluErrorString(error) << ".\n"; + } + } +} + +void TextureManager::TextureInfo::SetMaxLevel(unsigned int level) +{ + // we want to tell openGL the highest defined mip level of our texture. + Bind(); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, level); +} + Modified: hugin/branches/gsoc2008_opengl_preview/src/hugin1/hugin/TextureManager.h =================================================================== --- hugin/branches/gsoc2008_opengl_preview/src/hugin1/hugin/TextureManager.h 2008-06-26 12:19:31 UTC (rev 3147) +++ hugin/branches/gsoc2008_opengl_preview/src/hugin1/hugin/TextureManager.h 2008-06-26 14:21:10 UTC (rev 3148) @@ -42,17 +42,18 @@ #include <map> class GLViewer; +class ViewState; -class TextureManager: public PT::PanoramaObserver +class TextureManager { public: - TextureManager(PT::Panorama &pano); + TextureManager(PT::Panorama &pano, ViewState *view); virtual ~TextureManager(); // selct the texture for the requested image in opengl - void BindTexture(unsigned int image_number); + void BindTexture(unsigned int image_number, unsigned int display_list); // react to the images & fields of view changing. We can update the // textures here. - void panoramaImagesChanged(PT::Panorama &pano/*, const PT::UIntSet &changed*/); + void CheckUpdate(); // change the OpenGL state for rendering the textures. void Begin(); void End(); @@ -60,12 +61,10 @@ void SetPhotometricCorrect(bool state); protected: PT::Panorama * m_pano; + ViewState *view_state; float viewer_exposure; // remove textures for deleted images. void CleanTextures(); - // FIXME TextureInfo should probably take care of the texture completely, - // but it needs to know what filename it is attached to to generate the - // texture maps. class TextureInfo { public: @@ -73,23 +72,27 @@ ~TextureInfo(); // width and height are the size of the texture. This can be different // to the image size, we have to scale to powers of two. The texture - // size is the biggest we can use for the image without scalling up - // (unless the hardware doesn't support this) - // we generally have only small mip levels loaded though. + // size is the biggest we can use for the image without scaling up + // (unless the hardware doesn't support textures that big) + // we generally have only lower mip levels defined though. unsigned int width, height; // log base 2 of the above, cached. unsigned int width_p, height_p; // min_lod is the most detailed mipmap level defined unsigned int min_lod; + + void DefineLevels(unsigned int min, unsigned int max, + bool photometric_correct, + HuginBase::PanoramaOptions *dest_img, + HuginBase::SrcPanoImage *state); + void SetMaxLevel(unsigned int level); + void Bind(); + private: unsigned int num; // num is the openGL texture name - // this is the exposure the texture content is stored as. For real time - // correction it should be the same of the original file, for - // precalculated correction it is what ever it was last updated to. - double exposure; // TODO same for white balance, vignetting and response curve? }; // we map filenames to TexturesInfos, so we can keep track of // images' textures when the numbers change. - std::map<std::string, TextureInfo> textures; + std::map<unsigned int, TextureInfo> textures; // Our pixel budget for all textures. unsigned int GetMaxTotalTexels(); // this is the maximum size a single texture is supported on the hardware. Added: hugin/branches/gsoc2008_opengl_preview/src/hugin1/hugin/ViewState.cpp =================================================================== --- hugin/branches/gsoc2008_opengl_preview/src/hugin1/hugin/ViewState.cpp (rev 0) +++ hugin/branches/gsoc2008_opengl_preview/src/hugin1/hugin/ViewState.cpp 2008-06-26 14:21:10 UTC (rev 3148) @@ -0,0 +1,302 @@ +// -*- c-basic-offset: 4 -*- + +/** @file ViewState.cpp + * + * @author James Legg + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "ViewState.h" + +ViewState::ViewState(HuginBase::Panorama *pano, + void (*RefreshFunction)(void *), void * arg) +{ + m_pano = pano; + RefreshFunc = RefreshFunction; + refreshArg = arg; + m_pano->addObserver(this); + // we will need to update everything for this panorama. + dirty_image_sizes = true; + dirty_viewport = true; + dirty_draw = true; + number_of_images = m_pano->getNrOfImages(); + for (unsigned int img = 0; img < number_of_images; img++) + { + img_states[img] = m_pano->getSrcImage(img); + dirty_mesh[img].val = true; + dirty_img_photometrics[img].val = true; + } + opts = m_pano->getOptions(); +} + +ViewState::~ViewState() +{ + m_pano->removeObserver(this); +} + +float ViewState::GetScale() +{ + return scale; +} + +void ViewState::SetScale(float scale_in) +{ + scale = scale_in; +} + +void ViewState::panoramaChanged(HuginBase::PanoramaData &pano) +{ + // anything could have happened, check everything. + HuginBase::PanoramaOptions new_opts = m_pano->getOptions(); + SetOptions(&new_opts); + unsigned int imgs = m_pano->getNrOfImages(); + for (unsigned int img = 0; img < imgs; img++) + { + HuginBase::SrcPanoImage new_image = m_pano->getSrcImage(img); + SetSrcImage(img, &new_image); + // has the enabled state changed in the preview? + bool new_active = m_pano->getImage(img).getOptions().active; + if (new_active != active[img]) + { + dirty_draw = true; + active[img] = new_active; + } + { + } + } + // has the number of images changed? + if (imgs < number_of_images) + { + // we've lost some + dirty_image_sizes = true; + dirty_draw = true; + images_removed = true; + } else if (imgs > number_of_images) + { + // added images. Assume it doesn't affect the rest. + dirty_image_sizes = true; + dirty_draw = true; + // FIXME more might need to be done, if the new images are not the last + // ones in order of image number. + } + number_of_images = imgs; + // check if it is worth redrawing. This will update everything else as + // necessary. + if (RequireDraw()) + { + RefreshFunc(refreshArg); + } +} + +void ViewState::panoramaImagesChanged(HuginBase::PanoramaData&, + const HuginBase::UIntSet&) +{ + // actually this stuff is handled by panoramaChanged. +} + +void ViewState::SetOptions(const HuginBase::PanoramaOptions *new_opts) +{ + // compare the... [truncated message content] |