1 // -*- c-basic-offset: 4 -*-
2 /** @file MeshManager.cpp
3  *
4  *  @author James Legg
5  *  @author Darko Makreshanski
6  *
7  *  This is free software; you can redistribute it and/or
8  *  modify it under the terms of the GNU General Public
9  *  License as published by the Free Software Foundation; either
10  *  version 2 of the License, or (at your option) any later version.
11  *
12  *  This software is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  *  Lesser General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public
18  *  License along with this software. If not, see
19  *  <http://www.gnu.org/licenses/>.
20  *
21  */
22 
23 #include <wx/wx.h>
24 #include <wx/platform.h>
25 
26 #include <GL/glew.h>
27 
28 #ifdef __WXMAC__
29 #include <OpenGL/gl.h>
30 #else
31 #ifdef __WXMSW__
32 #include <vigra/windows.h>
33 #endif
34 #include <GL/gl.h>
35 #endif
36 
37 #include "panoinc.h"
38 #include "ViewState.h"
39 #include "MeshManager.h"
40 #include "ChoosyRemapper.h"
41 #include "LayoutRemapper.h"
42 #include <iostream>
43 
44 
45 // If we want to draw the outline of each face instead of shading it normally,
46 // uncomment this. Wireframe mode is for testing mesh quality.
47 // #define WIREFRAME
48 
49 const double MeshManager::PanosphereOverviewMeshInfo::scale_diff=1.5;
50 
MeshManager(HuginBase::Panorama * pano,VisualizationState * visualization_state)51 MeshManager::MeshManager(HuginBase::Panorama *pano, VisualizationState *visualization_state)
52     :   m_pano(pano),
53         visualization_state(visualization_state),
54         layout_mode_on(false)
55 {
56 }
57 
~MeshManager()58 MeshManager::~MeshManager()
59 {
60     for (std::vector<MeshInfo*>::iterator it = meshes.begin() ; it != meshes.end() ; ++it) {
61         delete (*it);
62     }
63     meshes.clear();
64 }
65 
CheckUpdate()66 void MeshManager::CheckUpdate()
67 {
68     unsigned int old_size = meshes.size();
69     // Resize to fit if images were removed
70     while (meshes.size() > m_pano->getNrOfImages())
71     {
72         delete (meshes[meshes.size()-1]);
73         meshes.pop_back();
74     }
75     // check each existing image individualy.
76     for (unsigned int i = 0; i < meshes.size(); i++)
77     {
78         if (visualization_state->RequireRecalculateMesh(i))
79         {
80             DEBUG_DEBUG("Update mesh for " << i);
81             meshes[i]->SetSrcImage(visualization_state->GetSrcImage(i));
82             meshes[i]->Update();
83         }
84     }
85     // add any new images.
86     for (unsigned int i = old_size; i < m_pano->getNrOfImages(); i++)
87     {
88         DEBUG_INFO("Making new mesh remapper for image " << i << ".");
89         //use the virtual method to get the right subclass for the MeshInfo
90         meshes.push_back(this->ObtainMeshInfo(visualization_state->GetSrcImage(i), layout_mode_on));
91     }
92 }
93 
RenderMesh(unsigned int image_number) const94 void MeshManager::RenderMesh(unsigned int image_number) const
95 {
96     meshes[image_number]->CallList();
97 }
98 
GetDisplayList(unsigned int image_number) const99 unsigned int MeshManager::GetDisplayList(unsigned int image_number) const
100 {
101     return meshes[image_number]->display_list_number;
102 }
103 
SetLayoutMode(bool state)104 void MeshManager::SetLayoutMode(bool state)
105 {
106     if (layout_mode_on == state) return;
107     layout_mode_on = state;
108     /* All meshes must be recalculated, since the layout mode uses meshes that
109      * do not resemble properly remapped images.
110      */
111     for (std::vector<MeshInfo*>::iterator it = meshes.begin() ; it != meshes.end() ; ++it) {
112         delete (*it);
113     }
114     meshes.clear();
115 }
116 
GetLayoutMode() const117 bool MeshManager::GetLayoutMode() const
118 {
119     return layout_mode_on;
120 }
121 
SetLayoutScale(double scale)122 void MeshManager::SetLayoutScale(double scale)
123 {
124     for(unsigned int i=0;i<meshes.size();i++)
125         meshes[i]->SetScaleFactor(scale);
126 };
127 
128 
MeshInfo(HuginBase::Panorama * m_pano_in,HuginBase::SrcPanoImage * image,VisualizationState * visualization_state_in,bool layout_mode_on_in)129 MeshManager::MeshInfo::MeshInfo(HuginBase::Panorama * m_pano_in,
130                                 HuginBase::SrcPanoImage * image,
131                                 VisualizationState * visualization_state_in,
132                                 bool layout_mode_on_in)
133     :   display_list_number(glGenLists(1)), // Find a free display list.
134         image(*image),
135         m_pano(m_pano_in),
136         scale_factor(3.0),
137         m_visualization_state(visualization_state_in),
138         remap(layout_mode_on_in ? (MeshRemapper *) new LayoutRemapper(m_pano, &(this->image), m_visualization_state)
139                                 : (MeshRemapper *) new ChoosyRemapper(m_pano, &(this->image), m_visualization_state)),
140         layout_mode_on(layout_mode_on_in)
141 {
142 }
143 
MeshInfo(const MeshInfo & source)144 MeshManager::MeshInfo::MeshInfo(const MeshInfo & source)
145     // copy remap object and display list, instead of references.
146     :   display_list_number(glGenLists(1)),
147     image(source.image),
148     m_pano(source.m_pano),
149     scale_factor(3.0),
150     m_visualization_state(source.m_visualization_state),
151     remap(source.layout_mode_on ? (MeshRemapper *) new LayoutRemapper(source.m_pano, (HuginBase::SrcPanoImage*) &(source.image), source.m_visualization_state)
152                                 : (MeshRemapper *) new ChoosyRemapper(source.m_pano, (HuginBase::SrcPanoImage*) &(source.image), source.m_visualization_state)),
153     layout_mode_on(source.layout_mode_on)
154 {
155 }
156 
157 
158 
~MeshInfo()159 MeshManager::MeshInfo::~MeshInfo()
160 {
161     glDeleteLists(display_list_number, 1);
162     delete remap;
163 }
164 
Update()165 void MeshManager::MeshInfo::Update()
166 {
167     if (layout_mode_on)
168     {
169         /** @todo Maybe we should find the scale once, instead of for each
170          * image, and find a more asthetic way to calculate it.
171          */
172         double scale = m_visualization_state->GetVisibleArea().width() /
173                        sqrt((double) m_pano->getNrOfImages()) / scale_factor;
174         MeshRemapper & remapper_ref = *remap;
175         LayoutRemapper &r = dynamic_cast<LayoutRemapper &>(remapper_ref);
176         r.setScale(scale);
177     }
178     this->CompileList();
179 }
180 
MeshCoords3D(const MeshRemapper::Coords & coords)181 MeshManager::MeshInfo::MeshCoords3D::MeshCoords3D(const MeshRemapper::Coords & coords)
182 {
183     for (int x = 0 ; x < 2 ; x++) {
184         for (int y = 0 ; y < 2 ; y++) {
185             tex_coords[x][y][0] = coords.tex_c[x][y][0];
186             tex_coords[x][y][1] = coords.tex_c[x][y][1];
187             vertex_coords[x][y][0] = coords.vertex_c[x][y][0];
188             vertex_coords[x][y][1] = coords.vertex_c[x][y][1];
189             vertex_coords[x][y][2] = 0;
190         }
191     }
192 }
193 
SetScaleFactor(double scale)194 void MeshManager::MeshInfo::SetScaleFactor(double scale)
195 {
196     scale_factor=scale;
197     Update();
198 };
199 
CallList() const200 void MeshManager::MeshInfo::CallList() const
201 {
202     glCallList(display_list_number);
203 }
204 
CompileList()205 void MeshManager::MeshInfo::CompileList()
206 {
207     // build the display list from the coordinates generated by the remapper
208 //    DEBUG_INFO("Preparing to compile a display list for overview for " << image_number
209 //              << ".");
210     DEBUG_ASSERT(remap);
211     bool multiTexture=m_visualization_state->getViewState()->GetSupportMultiTexture();
212     unsigned int number_of_faces = 0;
213 
214     DEBUG_DEBUG("mesh update compile pano");
215 
216     this->BeforeCompile();
217 
218     glNewList(display_list_number, GL_COMPILE);
219 
220         remap->UpdateAndResetIndex();
221         DEBUG_INFO("Specifying faces in display list.");
222 
223         glPushMatrix();
224 
225         this->Transform();
226 
227         #ifndef WIREFRAME
228         glBegin(GL_QUADS);
229         #endif
230             // get each face's coordinates from the remapper
231             MeshRemapper::Coords coords;
232             while (remap->GetNextFaceCoordinates(&coords))
233             {
234                 MeshCoords3D coords3d = m_visualization_state->GetMeshManager()->GetMeshCoords3D(coords);
235 //                DEBUG_DEBUG("mesh update " << coords3d.vertex_coords[0][0][0] << " " << coords3d.vertex_coords[0][0][1] << " " << coords3d.vertex_coords[0][0][2]);
236                 number_of_faces++;
237                 // go in an anticlockwise direction
238                 #ifdef WIREFRAME
239                 glBegin(GL_LINE_LOOP);
240                 #endif
241                 if(multiTexture)
242                 {
243                     glMultiTexCoord2dv(GL_TEXTURE0,coords3d.tex_coords[0][0]);
244                     glMultiTexCoord2dv(GL_TEXTURE1,coords3d.tex_coords[0][0]);
245                 }
246                 else
247                     glTexCoord2dv(coords3d.tex_coords[0][0]);
248                 glVertex3dv(coords3d.vertex_coords[0][0]);
249                 if(multiTexture)
250                 {
251                     glMultiTexCoord2dv(GL_TEXTURE0,coords3d.tex_coords[0][1]);
252                     glMultiTexCoord2dv(GL_TEXTURE1,coords3d.tex_coords[0][1]);
253                 }
254                 else
255                     glTexCoord2dv(coords3d.tex_coords[0][1]);
256                 glVertex3dv(coords3d.vertex_coords[0][1]);
257                 if(multiTexture)
258                 {
259                     glMultiTexCoord2dv(GL_TEXTURE0,coords3d.tex_coords[1][1]);
260                     glMultiTexCoord2dv(GL_TEXTURE1,coords3d.tex_coords[1][1]);
261                 }
262                 else
263                     glTexCoord2dv(coords3d.tex_coords[1][1]);
264                 glVertex3dv(coords3d.vertex_coords[1][1]);
265                  if(multiTexture)
266                 {
267                     glMultiTexCoord2dv(GL_TEXTURE0,coords3d.tex_coords[1][0]);
268                     glMultiTexCoord2dv(GL_TEXTURE1,coords3d.tex_coords[1][0]);
269                 }
270                 else
271                    glTexCoord2dv(coords3d.tex_coords[1][0]);
272                 glVertex3dv(coords3d.vertex_coords[1][0]);
273                 #ifdef WIREFRAME
274                 glEnd();
275                 #endif
276             }
277         #ifndef WIREFRAME
278         glEnd();
279         #endif
280 
281         glPopMatrix();
282 
283     glEndList();
284 
285 
286     this->AfterCompile();
287 //    DEBUG_INFO("Prepared a display list for " << image_number << ", using "
288 //              << number_of_faces << " face(s).");
289     DEBUG_DEBUG("after compile mesh");
290 }
291 
Convert(double & x,double & y,double & z,double th,double ph,double r)292 void MeshManager::PanosphereOverviewMeshInfo::Convert(double &x, double &y, double &z, double th, double ph, double r)
293 {
294     th /= 180.0;
295     th *= M_PI;
296     ph /= 180.0;
297     ph *= M_PI;
298 
299     x = r * sin(th) * cos(ph);
300     y = r * sin(ph);
301     z = r * cos(th) * cos(ph);
302 }
303 
BeforeCompile()304 void MeshManager::PanosphereOverviewMeshInfo::BeforeCompile()
305 {
306     yaw = image.getYaw();
307     pitch = image.getPitch();
308 
309     image.setYaw(0);
310     image.setPitch(0);
311 }
312 
Transform()313 void MeshManager::PanosphereOverviewMeshInfo::Transform()
314 {
315 
316     glRotated(yaw, 0,-1,0);
317     glRotated(pitch, -1,0,0);
318 
319 }
320 
AfterCompile()321 void MeshManager::PanosphereOverviewMeshInfo::AfterCompile()
322 {
323     image.setYaw(yaw);
324     image.setPitch(pitch);
325 }
326 
GetCoord3D(hugin_utils::FDiff2D & coord,VisualizationState * state)327 MeshManager::MeshInfo::Coord3D MeshManager::PanosphereOverviewMeshInfo::GetCoord3D(hugin_utils::FDiff2D & coord, VisualizationState * state)
328 {
329     double width, height, hfov, vfov;
330     HuginBase::PanoramaOptions * opts = state->GetOptions();
331     width = opts->getWidth();
332     height = opts->getHeight();
333 
334     hfov = 360;
335     vfov = 180;
336 
337     MeshManager::MeshInfo::Coord3D res;
338 
339     double r = static_cast<PanosphereOverviewVisualizationState*>(state)->getSphereRadius();
340     double th, ph;
341     th = ((coord.x / width) * hfov - hfov / 2.0);
342     ph = ((coord.y / height) * vfov - vfov / 2.0);
343 
344     Convert(
345         res.x,
346         res.y,
347         res.z,
348         -th,-ph,r);
349 
350     return res;
351 }
352 
GetMeshCoords3D(MeshRemapper::Coords & coords,VisualizationState * state)353 MeshManager::MeshInfo::MeshCoords3D MeshManager::PanosphereOverviewMeshInfo::GetMeshCoords3D(MeshRemapper::Coords &coords, VisualizationState * state)
354 {
355     double width, height, hfov, vfov;
356     HuginBase::PanoramaOptions * opts = state->GetOptions();
357     width = opts->getWidth();
358     height = opts->getHeight();
359 
360     hfov = 360;
361     vfov = 180;
362 
363     double r = static_cast<PanosphereOverviewVisualizationState*>(state)->getSphereRadius();
364 
365     MeshCoords3D res;
366     for (int x = 0 ; x < 2 ; x++) {
367         for (int y = 0 ; y < 2 ; y++) {
368 
369 
370             res.tex_coords[x][y][0] = coords.tex_c[x][y][0];
371             res.tex_coords[x][y][1] = coords.tex_c[x][y][1];
372 
373             double th, ph;
374             th = ((coords.vertex_c[x][y][0] / width) * hfov - hfov / 2.0);
375             ph = ((coords.vertex_c[x][y][1] / height) * vfov - vfov / 2.0);
376 
377             Convert(
378                 res.vertex_coords[x][y][0],
379                 res.vertex_coords[x][y][1],
380                 res.vertex_coords[x][y][2],
381                 -th,-ph,r);
382 
383 //            DEBUG_DEBUG("pano get " << res.vertex_coords[x][y][0] << " " << res.vertex_coords[x][y][1] << " " << res.vertex_coords[x][y][2]);
384 //            DEBUG_DEBUG("pano get " << coords.vertex_c[x][y][0] << " " << coords.vertex_c[x][y][1]);
385 
386         }
387     }
388     return res;
389 }
390 
391 
392 const double MeshManager::PlaneOverviewMeshInfo::scale = 100;
393 
GetCoord3D(hugin_utils::FDiff2D & coord,VisualizationState * state)394 MeshManager::MeshInfo::Coord3D MeshManager::PlaneOverviewMeshInfo::GetCoord3D(hugin_utils::FDiff2D &coord, VisualizationState * state)
395 {
396     double width, height;
397     HuginBase::PanoramaOptions * opts = state->GetOptions();
398     width = opts->getWidth();
399     height = opts->getHeight();
400 
401     Coord3D res;
402     res.x = (coord.x - width / 2.0) * scale / width;
403     res.y = (coord.y - height / 2.0) * (-scale) / width;
404     res.z = 0;
405     return res;
406 }
407 
GetMeshCoords3D(MeshRemapper::Coords & coords,VisualizationState * state)408 MeshManager::MeshInfo::MeshCoords3D MeshManager::PlaneOverviewMeshInfo::GetMeshCoords3D(MeshRemapper::Coords &coords, VisualizationState * state)
409 {
410     double width, height;
411     HuginBase::PanoramaOptions * opts = state->GetOptions();
412     width = opts->getWidth();
413     height = opts->getHeight();
414 
415     MeshCoords3D res;
416     for (int x = 0 ; x < 2 ; x++) {
417         for (int y = 0 ; y < 2 ; y++) {
418             res.tex_coords[x][y][0] = coords.tex_c[x][y][0];
419             res.tex_coords[x][y][1] = coords.tex_c[x][y][1];
420 
421             res.vertex_coords[x][y][0] = (coords.vertex_c[x][y][0] - width / 2.0) * scale / width;
422             res.vertex_coords[x][y][1] = (coords.vertex_c[x][y][1] - height / 2.0) * (-scale) / width;
423             res.vertex_coords[x][y][2] = 0;
424         }
425     }
426     return res;
427 
428 }
429 
ObtainMeshInfo(HuginBase::SrcPanoImage * src,bool layout_mode_on)430 MeshManager::MeshInfo * PanosphereOverviewMeshManager::ObtainMeshInfo(HuginBase::SrcPanoImage * src, bool layout_mode_on)
431 {
432     return new MeshManager::PanosphereOverviewMeshInfo(m_pano, src, visualization_state, layout_mode_on);
433 }
434 
ObtainMeshInfo(HuginBase::SrcPanoImage * src,bool layout_mode_on)435 MeshManager::MeshInfo * PlaneOverviewMeshManager::ObtainMeshInfo(HuginBase::SrcPanoImage * src, bool layout_mode_on)
436 {
437     return new MeshManager::PlaneOverviewMeshInfo(m_pano, src, visualization_state, layout_mode_on);
438 }
439 
ObtainMeshInfo(HuginBase::SrcPanoImage * src,bool layout_mode_on)440 MeshManager::MeshInfo * PreviewMeshManager::ObtainMeshInfo(HuginBase::SrcPanoImage * src, bool layout_mode_on)
441 {
442     return new MeshManager::PreviewMeshInfo(m_pano, src, visualization_state, layout_mode_on);
443 }
444 
445 
446 
447