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