// -*- c-basic-offset: 4 -*- /** @file MeshManager.cpp * * @author James Legg * @author Darko Makreshanski * * This 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this software. If not, see * . * */ #include #include #include #ifdef __WXMAC__ #include #else #ifdef __WXMSW__ #include #endif #include #endif #include "panoinc.h" #include "ViewState.h" #include "MeshManager.h" #include "ChoosyRemapper.h" #include "LayoutRemapper.h" #include // If we want to draw the outline of each face instead of shading it normally, // uncomment this. Wireframe mode is for testing mesh quality. // #define WIREFRAME const double MeshManager::PanosphereOverviewMeshInfo::scale_diff=1.5; MeshManager::MeshManager(HuginBase::Panorama *pano, VisualizationState *visualization_state) : m_pano(pano), visualization_state(visualization_state), layout_mode_on(false) { } MeshManager::~MeshManager() { for (std::vector::iterator it = meshes.begin() ; it != meshes.end() ; ++it) { delete (*it); } meshes.clear(); } void MeshManager::CheckUpdate() { unsigned int old_size = meshes.size(); // Resize to fit if images were removed while (meshes.size() > m_pano->getNrOfImages()) { delete (meshes[meshes.size()-1]); meshes.pop_back(); } // check each existing image individualy. for (unsigned int i = 0; i < meshes.size(); i++) { if (visualization_state->RequireRecalculateMesh(i)) { DEBUG_DEBUG("Update mesh for " << i); meshes[i]->SetSrcImage(visualization_state->GetSrcImage(i)); meshes[i]->Update(); } } // add any new images. for (unsigned int i = old_size; i < m_pano->getNrOfImages(); i++) { DEBUG_INFO("Making new mesh remapper for image " << i << "."); //use the virtual method to get the right subclass for the MeshInfo meshes.push_back(this->ObtainMeshInfo(visualization_state->GetSrcImage(i), layout_mode_on)); } } void MeshManager::RenderMesh(unsigned int image_number) const { meshes[image_number]->CallList(); } unsigned int MeshManager::GetDisplayList(unsigned int image_number) const { return meshes[image_number]->display_list_number; } void MeshManager::SetLayoutMode(bool state) { if (layout_mode_on == state) return; layout_mode_on = state; /* All meshes must be recalculated, since the layout mode uses meshes that * do not resemble properly remapped images. */ for (std::vector::iterator it = meshes.begin() ; it != meshes.end() ; ++it) { delete (*it); } meshes.clear(); } bool MeshManager::GetLayoutMode() const { return layout_mode_on; } void MeshManager::SetLayoutScale(double scale) { for(unsigned int i=0;iSetScaleFactor(scale); }; MeshManager::MeshInfo::MeshInfo(HuginBase::Panorama * m_pano_in, HuginBase::SrcPanoImage * image, VisualizationState * visualization_state_in, bool layout_mode_on_in) : display_list_number(glGenLists(1)), // Find a free display list. image(*image), m_pano(m_pano_in), scale_factor(3.0), m_visualization_state(visualization_state_in), remap(layout_mode_on_in ? (MeshRemapper *) new LayoutRemapper(m_pano, &(this->image), m_visualization_state) : (MeshRemapper *) new ChoosyRemapper(m_pano, &(this->image), m_visualization_state)), layout_mode_on(layout_mode_on_in) { } MeshManager::MeshInfo::MeshInfo(const MeshInfo & source) // copy remap object and display list, instead of references. : display_list_number(glGenLists(1)), image(source.image), m_pano(source.m_pano), scale_factor(3.0), m_visualization_state(source.m_visualization_state), remap(source.layout_mode_on ? (MeshRemapper *) new LayoutRemapper(source.m_pano, (HuginBase::SrcPanoImage*) &(source.image), source.m_visualization_state) : (MeshRemapper *) new ChoosyRemapper(source.m_pano, (HuginBase::SrcPanoImage*) &(source.image), source.m_visualization_state)), layout_mode_on(source.layout_mode_on) { } MeshManager::MeshInfo::~MeshInfo() { glDeleteLists(display_list_number, 1); delete remap; } void MeshManager::MeshInfo::Update() { if (layout_mode_on) { /** @todo Maybe we should find the scale once, instead of for each * image, and find a more asthetic way to calculate it. */ double scale = m_visualization_state->GetVisibleArea().width() / sqrt((double) m_pano->getNrOfImages()) / scale_factor; MeshRemapper & remapper_ref = *remap; LayoutRemapper &r = dynamic_cast(remapper_ref); r.setScale(scale); } this->CompileList(); } MeshManager::MeshInfo::MeshCoords3D::MeshCoords3D(const MeshRemapper::Coords & coords) { for (int x = 0 ; x < 2 ; x++) { for (int y = 0 ; y < 2 ; y++) { tex_coords[x][y][0] = coords.tex_c[x][y][0]; tex_coords[x][y][1] = coords.tex_c[x][y][1]; vertex_coords[x][y][0] = coords.vertex_c[x][y][0]; vertex_coords[x][y][1] = coords.vertex_c[x][y][1]; vertex_coords[x][y][2] = 0; } } } void MeshManager::MeshInfo::SetScaleFactor(double scale) { scale_factor=scale; Update(); }; void MeshManager::MeshInfo::CallList() const { glCallList(display_list_number); } void MeshManager::MeshInfo::CompileList() { // build the display list from the coordinates generated by the remapper // DEBUG_INFO("Preparing to compile a display list for overview for " << image_number // << "."); DEBUG_ASSERT(remap); bool multiTexture=m_visualization_state->getViewState()->GetSupportMultiTexture(); unsigned int number_of_faces = 0; DEBUG_DEBUG("mesh update compile pano"); this->BeforeCompile(); glNewList(display_list_number, GL_COMPILE); remap->UpdateAndResetIndex(); DEBUG_INFO("Specifying faces in display list."); glPushMatrix(); this->Transform(); #ifndef WIREFRAME glBegin(GL_QUADS); #endif // get each face's coordinates from the remapper MeshRemapper::Coords coords; while (remap->GetNextFaceCoordinates(&coords)) { MeshCoords3D coords3d = m_visualization_state->GetMeshManager()->GetMeshCoords3D(coords); // DEBUG_DEBUG("mesh update " << coords3d.vertex_coords[0][0][0] << " " << coords3d.vertex_coords[0][0][1] << " " << coords3d.vertex_coords[0][0][2]); number_of_faces++; // go in an anticlockwise direction #ifdef WIREFRAME glBegin(GL_LINE_LOOP); #endif if(multiTexture) { glMultiTexCoord2dv(GL_TEXTURE0,coords3d.tex_coords[0][0]); glMultiTexCoord2dv(GL_TEXTURE1,coords3d.tex_coords[0][0]); } else glTexCoord2dv(coords3d.tex_coords[0][0]); glVertex3dv(coords3d.vertex_coords[0][0]); if(multiTexture) { glMultiTexCoord2dv(GL_TEXTURE0,coords3d.tex_coords[0][1]); glMultiTexCoord2dv(GL_TEXTURE1,coords3d.tex_coords[0][1]); } else glTexCoord2dv(coords3d.tex_coords[0][1]); glVertex3dv(coords3d.vertex_coords[0][1]); if(multiTexture) { glMultiTexCoord2dv(GL_TEXTURE0,coords3d.tex_coords[1][1]); glMultiTexCoord2dv(GL_TEXTURE1,coords3d.tex_coords[1][1]); } else glTexCoord2dv(coords3d.tex_coords[1][1]); glVertex3dv(coords3d.vertex_coords[1][1]); if(multiTexture) { glMultiTexCoord2dv(GL_TEXTURE0,coords3d.tex_coords[1][0]); glMultiTexCoord2dv(GL_TEXTURE1,coords3d.tex_coords[1][0]); } else glTexCoord2dv(coords3d.tex_coords[1][0]); glVertex3dv(coords3d.vertex_coords[1][0]); #ifdef WIREFRAME glEnd(); #endif } #ifndef WIREFRAME glEnd(); #endif glPopMatrix(); glEndList(); this->AfterCompile(); // DEBUG_INFO("Prepared a display list for " << image_number << ", using " // << number_of_faces << " face(s)."); DEBUG_DEBUG("after compile mesh"); } void MeshManager::PanosphereOverviewMeshInfo::Convert(double &x, double &y, double &z, double th, double ph, double r) { th /= 180.0; th *= M_PI; ph /= 180.0; ph *= M_PI; x = r * sin(th) * cos(ph); y = r * sin(ph); z = r * cos(th) * cos(ph); } void MeshManager::PanosphereOverviewMeshInfo::BeforeCompile() { yaw = image.getYaw(); pitch = image.getPitch(); image.setYaw(0); image.setPitch(0); } void MeshManager::PanosphereOverviewMeshInfo::Transform() { glRotated(yaw, 0,-1,0); glRotated(pitch, -1,0,0); } void MeshManager::PanosphereOverviewMeshInfo::AfterCompile() { image.setYaw(yaw); image.setPitch(pitch); } MeshManager::MeshInfo::Coord3D MeshManager::PanosphereOverviewMeshInfo::GetCoord3D(hugin_utils::FDiff2D & coord, VisualizationState * state) { double width, height, hfov, vfov; HuginBase::PanoramaOptions * opts = state->GetOptions(); width = opts->getWidth(); height = opts->getHeight(); hfov = 360; vfov = 180; MeshManager::MeshInfo::Coord3D res; double r = static_cast(state)->getSphereRadius(); double th, ph; th = ((coord.x / width) * hfov - hfov / 2.0); ph = ((coord.y / height) * vfov - vfov / 2.0); Convert( res.x, res.y, res.z, -th,-ph,r); return res; } MeshManager::MeshInfo::MeshCoords3D MeshManager::PanosphereOverviewMeshInfo::GetMeshCoords3D(MeshRemapper::Coords &coords, VisualizationState * state) { double width, height, hfov, vfov; HuginBase::PanoramaOptions * opts = state->GetOptions(); width = opts->getWidth(); height = opts->getHeight(); hfov = 360; vfov = 180; double r = static_cast(state)->getSphereRadius(); MeshCoords3D res; for (int x = 0 ; x < 2 ; x++) { for (int y = 0 ; y < 2 ; y++) { res.tex_coords[x][y][0] = coords.tex_c[x][y][0]; res.tex_coords[x][y][1] = coords.tex_c[x][y][1]; double th, ph; th = ((coords.vertex_c[x][y][0] / width) * hfov - hfov / 2.0); ph = ((coords.vertex_c[x][y][1] / height) * vfov - vfov / 2.0); Convert( res.vertex_coords[x][y][0], res.vertex_coords[x][y][1], res.vertex_coords[x][y][2], -th,-ph,r); // DEBUG_DEBUG("pano get " << res.vertex_coords[x][y][0] << " " << res.vertex_coords[x][y][1] << " " << res.vertex_coords[x][y][2]); // DEBUG_DEBUG("pano get " << coords.vertex_c[x][y][0] << " " << coords.vertex_c[x][y][1]); } } return res; } const double MeshManager::PlaneOverviewMeshInfo::scale = 100; MeshManager::MeshInfo::Coord3D MeshManager::PlaneOverviewMeshInfo::GetCoord3D(hugin_utils::FDiff2D &coord, VisualizationState * state) { double width, height; HuginBase::PanoramaOptions * opts = state->GetOptions(); width = opts->getWidth(); height = opts->getHeight(); Coord3D res; res.x = (coord.x - width / 2.0) * scale / width; res.y = (coord.y - height / 2.0) * (-scale) / width; res.z = 0; return res; } MeshManager::MeshInfo::MeshCoords3D MeshManager::PlaneOverviewMeshInfo::GetMeshCoords3D(MeshRemapper::Coords &coords, VisualizationState * state) { double width, height; HuginBase::PanoramaOptions * opts = state->GetOptions(); width = opts->getWidth(); height = opts->getHeight(); MeshCoords3D res; for (int x = 0 ; x < 2 ; x++) { for (int y = 0 ; y < 2 ; y++) { res.tex_coords[x][y][0] = coords.tex_c[x][y][0]; res.tex_coords[x][y][1] = coords.tex_c[x][y][1]; res.vertex_coords[x][y][0] = (coords.vertex_c[x][y][0] - width / 2.0) * scale / width; res.vertex_coords[x][y][1] = (coords.vertex_c[x][y][1] - height / 2.0) * (-scale) / width; res.vertex_coords[x][y][2] = 0; } } return res; } MeshManager::MeshInfo * PanosphereOverviewMeshManager::ObtainMeshInfo(HuginBase::SrcPanoImage * src, bool layout_mode_on) { return new MeshManager::PanosphereOverviewMeshInfo(m_pano, src, visualization_state, layout_mode_on); } MeshManager::MeshInfo * PlaneOverviewMeshManager::ObtainMeshInfo(HuginBase::SrcPanoImage * src, bool layout_mode_on) { return new MeshManager::PlaneOverviewMeshInfo(m_pano, src, visualization_state, layout_mode_on); } MeshManager::MeshInfo * PreviewMeshManager::ObtainMeshInfo(HuginBase::SrcPanoImage * src, bool layout_mode_on) { return new MeshManager::PreviewMeshInfo(m_pano, src, visualization_state, layout_mode_on); }