1 // -*- c-basic-offset: 4 -*-
2
3 /** @file hugin_utils/utils.cpp
4 *
5 * @author Pablo d'Angelo <pablo.dangelo@web.de>
6 *
7 * $Id$
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
13 *
14 * This software is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public
20 * License along with this software. If not, see
21 * <http://www.gnu.org/licenses/>.
22 *
23 */
24
25 #include "utils.h"
26 #include "hugin_version.h"
27 #include "hugin_config.h"
28
29 #ifdef _WIN32
30 #define NOMINMAX
31 #include <sys/utime.h>
32 #include <shlobj.h>
33 #else
34 #include <sys/time.h>
35 #include <cstdlib>
36 #include <unistd.h>
37 #include <sys/types.h>
38 #include <pwd.h>
39 #endif
40 #include <time.h>
41 #include <fstream>
42 #include <stdio.h>
43 #include <cstdio>
44 #ifdef _WIN32
45 #define NOMINMAX
46 #include <windows.h>
47 #else
48 #include <hugin_config.h>
49 #endif
50 #include <algorithm>
51 #include <hugin_utils/filesystem.h>
52 #include <lcms2.h>
53
54 #ifdef __APPLE__
55 #include <mach-o/dyld.h> /* _NSGetExecutablePath */
56 #include <limits.h> /* PATH_MAX */
57 #include <libgen.h> /* dirname */
58 #endif
59
60 #include <GL/glew.h>
61 #ifdef _WIN32
62 #include <GL/wglew.h>
63 #elif defined __APPLE__
64 #include <GLUT/glut.h>
65 #endif
66
67 namespace hugin_utils {
68
69 #ifdef UNIX_LIKE
GetCurrentTimeString()70 std::string GetCurrentTimeString()
71 {
72 char tmp[100];
73 struct tm t;
74 struct timeval tv;
75 gettimeofday(&tv,NULL);
76 localtime_r((time_t*)&tv.tv_sec, &t); // is the casting safe?
77 strftime(tmp,99,"%H:%M:%S",&t);
78 sprintf(tmp+8,".%06ld", (long)tv.tv_usec);
79 return tmp;
80 }
81 #else
82 std::string GetCurrentTimeString()
83 {
84 // FIXME implement for Win
85 return "";
86 }
87 #endif
88
89
getExtension(const std::string & basename2)90 std::string getExtension(const std::string & basename2)
91 {
92 std::string::size_type idx = basename2.rfind('.');
93 // check if the dot is not followed by a \ or a /
94 // to avoid cutting pathes.
95 if (idx == std::string::npos) {
96 // no dot found
97 return std::string("");
98 }
99 #ifdef UNIX_LIKE
100 // check for slashes after dot
101 std::string::size_type slashidx = basename2.find('/', idx);
102 if ( slashidx == std::string::npos)
103 {
104 return basename2.substr(idx+1);
105 } else {
106 return std::string("");
107 }
108 #else
109 // check for slashes after dot
110 std::string::size_type slashidx = basename2.find('/', idx);
111 std::string::size_type backslashidx = basename2.find('\\', idx);
112 if ( slashidx == std::string::npos && backslashidx == std::string::npos)
113 {
114 return basename2.substr(idx+1);
115 } else {
116 return std::string("");
117 }
118 #endif
119 }
120
stripExtension(const std::string & basename2)121 std::string stripExtension(const std::string & basename2)
122 {
123 std::string::size_type idx = basename2.rfind('.');
124 // check if the dot is not followed by a \ or a /
125 // to avoid cutting pathes.
126 if (idx == std::string::npos) {
127 // no dot found
128 return basename2;
129 }
130 #ifdef UNIX_LIKE
131 std::string::size_type slashidx = basename2.find('/', idx);
132 if ( slashidx == std::string::npos)
133 {
134 return basename2.substr(0, idx);
135 } else {
136 return basename2;
137 }
138 #else
139 // check for slashes after dot
140 std::string::size_type slashidx = basename2.find('/', idx);
141 std::string::size_type backslashidx = basename2.find('\\', idx);
142 if ( slashidx == std::string::npos && backslashidx == std::string::npos)
143 {
144 return basename2.substr(0, idx);
145 } else {
146 return basename2;
147 }
148 #endif
149 }
150
stripPath(const std::string & filename)151 std::string stripPath(const std::string & filename)
152 {
153 #ifdef UNIX_LIKE
154 std::string::size_type idx = filename.rfind('/');
155 #else
156 std::string::size_type idx1 = filename.rfind('\\');
157 std::string::size_type idx2 = filename.rfind('/');
158 std::string::size_type idx;
159 if (idx1 == std::string::npos) {
160 idx = idx2;
161 } else if (idx2 == std::string::npos) {
162 idx = idx1;
163 } else {
164 idx = std::max(idx1, idx2);
165 }
166 #endif
167 if (idx != std::string::npos) {
168 // DEBUG_DEBUG("returning substring: " << filename.substr(idx + 1));
169 return filename.substr(idx + 1);
170 } else {
171 return filename;
172 }
173 }
174
getPathPrefix(const std::string & filename)175 std::string getPathPrefix(const std::string & filename)
176 {
177 #ifdef UNIX_LIKE
178 std::string::size_type idx = filename.rfind('/');
179 #else
180 std::string::size_type idx1 = filename.rfind('\\');
181 std::string::size_type idx2 = filename.rfind('/');
182 std::string::size_type idx;
183 if (idx1 == std::string::npos) {
184 idx = idx2;
185 } else if (idx2 == std::string::npos) {
186 idx = idx1;
187 } else {
188 idx = std::max(idx1, idx2);
189 }
190 #endif
191 if (idx != std::string::npos) {
192 // DEBUG_DEBUG("returning substring: " << filename.substr(idx + 1));
193 return filename.substr(0, idx+1);
194 } else {
195 return "";
196 }
197 }
198
StrTrim(const std::string & str)199 std::string StrTrim(const std::string& str)
200 {
201 std::string s(str);
202 std::string::size_type pos = s.find_last_not_of(" \t");
203 if (pos != std::string::npos)
204 {
205 s.erase(pos + 1);
206 pos = s.find_first_not_of(" \t");
207 if (pos != std::string::npos)
208 {
209 s.erase(0, pos);
210 };
211 }
212 else
213 {
214 s.erase(s.begin(), s.end());
215 };
216 return s;
217 }
218
doubleToString(double d,int digits)219 std::string doubleToString(double d, int digits)
220 {
221 char fmt[10];
222 if (digits < 0) {
223 strcpy(fmt,"%f");
224 } else {
225 // max. 16 digits to prevent overflow
226 std::sprintf(fmt, "%%.%df", std::min(digits, 16));
227 }
228 char c[1024];
229 c[1023] = 0;
230 #ifdef _MSC_VER
231 _snprintf (c, 1023, fmt, d);
232 #else
233 snprintf (c, 1023, fmt, d);
234 #endif
235
236 std::string number (c);
237
238 int l = (int)number.length()-1;
239
240 while ( l != 0 && number[l] == '0' ) {
241 number.erase (l);
242 l--;
243 }
244 if ( number[l] == ',' ) {
245 number.erase (l);
246 l--;
247 }
248 if ( number[l] == '.' ) {
249 number.erase (l);
250 l--;
251 }
252 return number;
253 }
254
stringToInt(const std::string & s,int & val)255 bool stringToInt(const std::string& s, int& val)
256 {
257 if (StrTrim(s) == "0")
258 {
259 val = 0;
260 return true;
261 };
262 int x = atoi(s.c_str());
263 if (x != 0)
264 {
265 val = x;
266 return true;
267 };
268 return false;
269 };
270
stringToUInt(const std::string & s,unsigned int & val)271 bool stringToUInt(const std::string&s, unsigned int& val)
272 {
273 int x;
274 if (stringToInt(s, x))
275 {
276 if (x >= 0)
277 {
278 val = static_cast<unsigned int>(x);
279 return true;
280 };
281 };
282 return false;
283 };
284
SplitString(const std::string & s,const std::string & sep)285 std::vector<std::string> SplitString(const std::string& s, const std::string& sep)
286 {
287 std::vector<std::string> result;
288 std::size_t pos = s.find_first_of(sep, 0);
289 std::size_t pos2 = 0;
290 while (pos != std::string::npos)
291 {
292 if (pos - pos2 > 0)
293 {
294 std::string t(s.substr(pos2, pos - pos2));
295 t=StrTrim(t);
296 if (!t.empty())
297 {
298 result.push_back(t);
299 };
300 };
301 pos2 = pos + 1;
302 pos = s.find_first_of(sep, pos2);
303 }
304 if (pos2 < s.length())
305 {
306 std::string t(s.substr(pos2));
307 t = StrTrim(t);
308 if (!t.empty())
309 {
310 result.push_back(t);
311 };
312 };
313 return result;
314 };
315
ReplaceAll(std::string & s,const std::string & oldChar,char newChar)316 void ReplaceAll(std::string& s, const std::string& oldChar, char newChar)
317 {
318 std::size_t found = s.find_first_of(oldChar);
319 while (found != std::string::npos)
320 {
321 s[found] = newChar;
322 found = s.find_first_of(oldChar, found + 1);
323 };
324 };
325
ControlPointErrorColour(const double cperr,double & r,double & g,double & b)326 void ControlPointErrorColour(const double cperr,
327 double &r,double &g, double &b)
328 {
329 //Colour change points
330 #define XP1 5.0f
331 #define XP2 10.0f
332
333 if ( cperr<= XP1)
334 {
335 //low error
336 r = cperr / XP1;
337 g = 0.75;
338 }
339 else
340 {
341 r = 1.0;
342 g = 0.75 * ((1.0 - std::min<double>(cperr - XP1, XP2 - XP1) / (XP2 - XP1)));
343 }
344 b = 0.0;
345 }
346
FileExists(const std::string & filename)347 bool FileExists(const std::string& filename)
348 {
349 std::ifstream ifile(filename.c_str());
350 return !ifile.fail();
351 }
352
GetAbsoluteFilename(const std::string & filename)353 std::string GetAbsoluteFilename(const std::string& filename)
354 {
355 #ifdef _WIN32
356 char fullpath[_MAX_PATH];
357 _fullpath(fullpath,filename.c_str(),_MAX_PATH);
358 return std::string(fullpath);
359 #else
360 //realpath works only with existing files
361 //so as work around we create the file first, call then realpath
362 //and delete the temp file
363 /** @TODO replace realpath with function with works without this hack */
364 bool tempFileCreated=false;
365 if(!FileExists(filename))
366 {
367 tempFileCreated=true;
368 std::ofstream os(filename.c_str());
369 os.close();
370 };
371 char *real_path = realpath(filename.c_str(), NULL);
372 std::string absPath;
373 if(real_path!=NULL)
374 {
375 absPath=std::string(real_path);
376 free(real_path);
377 }
378 else
379 {
380 absPath=filename;
381 };
382 if(tempFileCreated)
383 {
384 remove(filename.c_str());
385 };
386 return absPath;
387 #endif
388 };
389
IsFileTypeSupported(const std::string & filename)390 bool IsFileTypeSupported(const std::string& filename)
391 {
392 const std::string extension = getExtension(filename);
393 return (vigra::impexListExtensions().find(extension) != std::string::npos);
394 };
395
EnforceExtension(std::string & filename,const std::string & defaultExtension)396 void EnforceExtension(std::string& filename, const std::string& defaultExtension)
397 {
398 const std::string extension = getExtension(filename);
399 if (extension.empty())
400 {
401 filename = stripExtension(filename) + "." + defaultExtension;
402 };
403 };
404
GetDataDir()405 std::string GetDataDir()
406 {
407 #ifdef _WIN32
408 char buffer[MAX_PATH];//always use MAX_PATH for filepaths
409 GetModuleFileName(NULL,buffer,sizeof(buffer));
410 fs::path data_path(buffer);
411 data_path.remove_filename();
412 if (data_path.has_parent_path())
413 {
414 return (data_path.parent_path() / "share/hugin/data").string() + "\\";
415 };
416 return std::string();
417 #elif defined MAC_SELF_CONTAINED_BUNDLE
418 char path[PATH_MAX + 1];
419 uint32_t size = sizeof(path);
420 std::string data_path("");
421 if (_NSGetExecutablePath(path, &size) == 0)
422 {
423 data_path=dirname(path);
424 data_path.append("/../Resources/xrc/");
425 }
426 return data_path;
427 #elif defined UNIX_SELF_CONTAINED_BUNDLE
428 fs::path data_path = fs::read_symlink("/proc/self/exe");
429 data_path.remove_filename();
430 if (data_path.has_parent_path())
431 {
432 return (data_path.parent_path() / "share/hugin/data").string() + "/";
433 };
434 return std::string();
435 #else
436 return std::string(INSTALL_DATA_DIR);
437 #endif
438 };
439
440 #ifndef _WIN32
GetHomeDir()441 std::string GetHomeDir()
442 {
443 char *homedir = getenv("HOME");
444 struct passwd *pw;
445 if (homedir == NULL)
446 {
447 pw = getpwuid(getuid());
448 if (pw != NULL)
449 {
450 homedir = pw->pw_dir;
451 };
452 };
453 if (homedir == NULL)
454 {
455 return std::string();
456 };
457 return std::string(homedir);
458 }
459 #endif
460
GetUserAppDataDir()461 std::string GetUserAppDataDir()
462 {
463 fs::path path;
464 #ifdef _WIN32
465 char fullpath[_MAX_PATH];
466 if(SHGetFolderPath(NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, fullpath)!=S_OK)
467 {
468 return std::string();
469 };
470 path = fs::path(fullpath);
471 path /= "hugin";
472 #else
473 #ifdef USE_XDG_DIRS
474 char *xdgDataDir = getenv("XDG_DATA_HOME");
475 if (strlen(xdgDataDir) == 0)
476 {
477 // no XDG_DATA_HOME enviroment variable set
478 // use $HOME/.local/share instead
479 const std::string homeDir = GetHomeDir();
480 if (homeDir.empty())
481 {
482 return std::string();
483 };
484 path = fs::path(homeDir);
485 path /= ".local/share/hugin";
486 }
487 else
488 {
489 // XDG_DATA_HOME set, use hugindata sub directory
490 path = fs::path(xdgDataDir);
491 path /= "hugin";
492 };
493 #else
494 // old behaviour, save in users home directory, sub-directory .hugindata
495 const std::string homeDir = GetHomeDir();
496 if (homeDir.empty())
497 {
498 return std::string();
499 };
500 path = fs::path(homeDir);
501 // we have already a file with name ".hugin" for our wxWidgets settings
502 // therefore we use directory ".hugindata" in homedir
503 path /= ".hugindata";
504 #endif
505 #endif
506 if (!fs::exists(path))
507 {
508 if (!fs::create_directories(path))
509 {
510 std::cerr << "ERROR: Could not create destination directory: " << path.string() << std::endl
511 << "Maybe you have not sufficient rights to create this directory." << std::endl;
512 return std::string();
513 };
514 };
515 return path.string();
516 };
517
518 // initialization and wrapup of GPU for GPU remapping
519 #ifdef _WIN32
520 struct ContextSettings
521 {
522 HWND window;
523 HDC dc;
524 HGLRC renderingContext;
525
ContextSettingshugin_utils::ContextSettings526 ContextSettings()
527 {
528 window = NULL;
529 dc = NULL;
530 renderingContext = NULL;
531 }
532 };
533 static ContextSettings context;
534
535 // create context, return false if failed
CreateContext(int * argcp,char ** argv)536 bool CreateContext(int *argcp, char **argv)
537 {
538 WNDCLASS windowClass;
539 /* register window class */
540 ZeroMemory(&windowClass, sizeof(WNDCLASS));
541 windowClass.hInstance = GetModuleHandle(NULL);
542 windowClass.lpfnWndProc = DefWindowProc;
543 windowClass.lpszClassName = "Hugin";
544 if (RegisterClass(&windowClass) == 0)
545 {
546 return false;
547 };
548 /* create window */
549 context.window = CreateWindow("Hugin", "Hugin", 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
550 CW_USEDEFAULT, NULL, NULL, GetModuleHandle(NULL), NULL);
551 if (context.window == NULL)
552 {
553 return false;
554 };
555 /* get the device context */
556 context.dc = GetDC(context.window);
557 if (context.dc == NULL)
558 {
559 return false;
560 };
561 /* find pixel format */
562 PIXELFORMATDESCRIPTOR pixelFormatDesc;
563 ZeroMemory(&pixelFormatDesc, sizeof(PIXELFORMATDESCRIPTOR));
564 pixelFormatDesc.nSize = sizeof(PIXELFORMATDESCRIPTOR);
565 pixelFormatDesc.nVersion = 1;
566 pixelFormatDesc.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
567 int pixelFormat = ChoosePixelFormat(context.dc, &pixelFormatDesc);
568 if (pixelFormat == 0)
569 {
570 return false;
571 }
572 /* set the pixel format for the dc */
573 if (SetPixelFormat(context.dc, pixelFormat, &pixelFormatDesc) == FALSE)
574 {
575 return false;
576 };
577 /* create rendering context */
578 context.renderingContext = wglCreateContext(context.dc);
579 if (context.renderingContext == NULL)
580 {
581 return false;
582 };
583 if (wglMakeCurrent(context.dc, context.renderingContext) == FALSE)
584 {
585 return false;
586 };
587 return true;
588 }
589
DestroyContext()590 void DestroyContext()
591 {
592 if (context.renderingContext != NULL)
593 {
594 wglMakeCurrent(NULL, NULL);
595 wglDeleteContext(context.renderingContext);
596 }
597 if (context.window != NULL && context.dc != NULL)
598 {
599 ReleaseDC(context.window, context.dc);
600 };
601 if (context.window != NULL)
602 {
603 DestroyWindow(context.window);
604 };
605 UnregisterClass("Hugin", GetModuleHandle(NULL));
606 }
607
608 #elif defined __APPLE__
609 static GLuint GlutWindowHandle;
CreateContext(int * argcp,char ** argv)610 bool CreateContext(int *argcp, char **argv)
611 {
612 // GLUT changes the working directory to the ressource path of the bundle
613 // so we store the old working directory and restore it at the end
614 char workingDir[FILENAME_MAX];
615 getcwd(workingDir, FILENAME_MAX);
616 glutInit(argcp, argv);
617 glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA | GLUT_ALPHA);
618 GlutWindowHandle = glutCreateWindow("Hugin");
619 // restore working dir, as GLUT changes it the ressource path
620 chdir(workingDir);
621 return true;
622 }
623
DestroyContext()624 void DestroyContext()
625 {
626 glutDestroyWindow(GlutWindowHandle);
627 }
628
629 #else
630 #if defined HAVE_EGL && HAVE_EGL
631 #include <EGL/egl.h>
632
633 struct ContextSettings
634 {
635 EGLDisplay m_display;
636 EGLContext m_context;
637 };
638
639 static ContextSettings context;
640
641 static const EGLint configAttribs[] = {
642 EGL_BLUE_SIZE, 8,
643 EGL_GREEN_SIZE, 8,
644 EGL_RED_SIZE, 8,
645 EGL_ALPHA_SIZE, 8,
646 EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
647 EGL_CONFORMANT, EGL_OPENGL_BIT,
648 EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER,
649 EGL_NONE
650 };
651
CreateContext(int * argcp,char ** argv)652 bool CreateContext(int *argcp, char **argv)
653 {
654 // get display connection
655 context.m_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
656 if (context.m_display == EGL_NO_DISPLAY)
657 {
658 std::cerr << "Could not connect to EGL_DEFAULT_DISPLAY" << std::endl;
659 return false;
660 };
661 // initialize egl
662 EGLint major, minor;
663 if (eglInitialize(context.m_display, &major, &minor) != EGL_TRUE)
664 {
665 std::cerr << "Could not initialize EGL" << std::endl
666 << "Error: 0x" << std::hex << eglGetError() << std::endl;
667 return false;
668 };
669 std::cout << "Init OpenGL ES " << major << "." << minor << std::endl;
670 std::cout << "Client API: " << eglQueryString(context.m_display, EGL_CLIENT_APIS) << std::endl
671 << "Vendor: " << eglQueryString(context.m_display, EGL_VENDOR) << std::endl
672 << "Version: " << eglQueryString(context.m_display, EGL_VERSION) << std::endl
673 << "EGL Extensions: " << eglQueryString(context.m_display, EGL_EXTENSIONS) << std::endl;
674 // bind OpenGL API (not OpenGL ES)
675 if (!eglBindAPI(EGL_OPENGL_API))
676 {
677 std::cerr << "Could not bind OpenGL API" << std::endl
678 << "Error: 0x" << std::hex << eglGetError() << std::endl;
679 return false;
680 };
681 // choose config
682 EGLint numConfigs;
683 EGLConfig egl_config;
684 if (eglChooseConfig(context.m_display, configAttribs, &egl_config, 1, &numConfigs) != EGL_TRUE)
685 {
686 std::cerr << "Cound not set egl config" << std::endl
687 << "Error: 0x" << std::hex << eglGetError() << std::endl;
688 return false;
689 };
690 // create surface
691 // create context and make it current
692 context.m_context = eglCreateContext(context.m_display, egl_config, EGL_NO_CONTEXT, NULL);
693 if (context.m_context == EGL_NO_CONTEXT)
694 {
695 std::cerr << "Cound not create context" << std::endl
696 << "Error: 0x" << std::hex << eglGetError() << std::endl;
697 return false;
698 };
699 if (eglMakeCurrent(context.m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, context.m_context) != EGL_TRUE)
700 {
701 std::cerr << "Could not make current context" << std::endl
702 << "Error: 0x" << std::hex << eglGetError() << std::endl;
703 return false;
704 };
705 return true;
706 }
707
DestroyContext()708 void DestroyContext()
709 {
710 // terminate egl at end
711 eglTerminate(context.m_display);
712 };
713
714 #else
715 #include <X11/Xlib.h>
716 #include <X11/Xutil.h>
717 #include <GL/glx.h>
718
719 struct ContextSettings
720 {
721 Display* display;
722 XVisualInfo* visualInfo;
723 GLXContext context;
724 Window window;
725 Colormap colormap;
726
ContextSettingshugin_utils::ContextSettings727 ContextSettings()
728 {
729 display=NULL;
730 visualInfo=NULL;
731 context=NULL;
732 window=0;
733 colormap=0;
734 };
735 };
736
737 static ContextSettings context;
738
CreateContext(int * argcp,char ** argv)739 bool CreateContext(int *argcp, char **argv)
740 {
741 /* open display */
742 context.display = XOpenDisplay(NULL);
743 if (context.display == NULL)
744 {
745 return false;
746 };
747 /* query for glx */
748 int erb, evb;
749 if (!glXQueryExtension(context.display, &erb, &evb))
750 {
751 return false;
752 };
753 /* choose visual */
754 int attrib[] = { GLX_RGBA, None };
755 context.visualInfo = glXChooseVisual(context.display, DefaultScreen(context.display), attrib);
756 if (context.visualInfo == NULL)
757 {
758 return false;
759 };
760 /* create context */
761 context.context = glXCreateContext(context.display, context.visualInfo, None, True);
762 if (context.context == NULL)
763 {
764 return false;
765 };
766 /* create window */
767 context.colormap = XCreateColormap(context.display, RootWindow(context.display, context.visualInfo->screen), context.visualInfo->visual, AllocNone);
768 XSetWindowAttributes swa;
769 swa.border_pixel = 0;
770 swa.colormap = context.colormap;
771 context.window = XCreateWindow(context.display, RootWindow(context.display, context.visualInfo->screen),
772 0, 0, 1, 1, 0, context.visualInfo->depth, InputOutput, context.visualInfo->visual,
773 CWBorderPixel | CWColormap, &swa);
774 /* make context current */
775 if (!glXMakeCurrent(context.display, context.window, context.context))
776 {
777 return false;
778 };
779 return true;
780 };
781
DestroyContext()782 void DestroyContext()
783 {
784 if (context.display != NULL && context.context != NULL)
785 {
786 glXDestroyContext(context.display, context.context);
787 }
788 if (context.display != NULL && context.window != 0)
789 {
790 XDestroyWindow(context.display, context.window);
791 };
792 if (context.display != NULL && context.colormap != 0)
793 {
794 XFreeColormap(context.display, context.colormap);
795 };
796 if (context.visualInfo != NULL)
797 {
798 XFree(context.visualInfo);
799 };
800 if (context.display != NULL)
801 {
802 XCloseDisplay(context.display);
803 };
804 };
805 #endif
806 #endif
807
initGPU(int * argcp,char ** argv)808 bool initGPU(int *argcp, char **argv)
809 {
810 if (!CreateContext(argcp, argv))
811 {
812 return false;
813 };
814 int err = glewInit();
815 if (err != GLEW_OK)
816 {
817 std::cerr << argv[0] << ": an error occurred while setting up the GPU:" << std::endl;
818 std::cerr << glewGetErrorString(err) << std::endl;
819 std::cerr << argv[0] << ": Switching to CPU calculation." << std::endl;
820 DestroyContext();
821 return false;
822 }
823
824 std::cout << hugin_utils::stripPath(argv[0]) << ": using graphics card: " << glGetString(GL_VENDOR) << " " << glGetString(GL_RENDERER) << std::endl;
825
826 const GLboolean has_arb_fragment_shader = glewGetExtension("GL_ARB_fragment_shader");
827 const GLboolean has_arb_vertex_shader = glewGetExtension("GL_ARB_vertex_shader");
828 const GLboolean has_arb_shader_objects = glewGetExtension("GL_ARB_shader_objects");
829 const GLboolean has_arb_shading_language = glewGetExtension("GL_ARB_shading_language_100");
830 const GLboolean has_ext_framebuffer = glewGetExtension("GL_EXT_framebuffer_object");
831 const GLboolean has_arb_texture_rectangle = glewGetExtension("GL_ARB_texture_rectangle");
832 const GLboolean has_arb_texture_border_clamp = glewGetExtension("GL_ARB_texture_border_clamp");
833 const GLboolean has_arb_texture_float = glewGetExtension("GL_ARB_texture_float");
834
835 if (!(has_arb_fragment_shader && has_arb_vertex_shader && has_arb_shader_objects && has_arb_shading_language && has_ext_framebuffer && has_arb_texture_rectangle && has_arb_texture_border_clamp && has_arb_texture_float)) {
836 const char * msg[] = {"false", "true"};
837 std::cerr << argv[0] << ": extension GL_ARB_fragment_shader = " << msg[has_arb_fragment_shader] << std::endl;
838 std::cerr << argv[0] << ": extension GL_ARB_vertex_shader = " << msg[has_arb_vertex_shader] << std::endl;
839 std::cerr << argv[0] << ": extension GL_ARB_shader_objects = " << msg[has_arb_shader_objects] << std::endl;
840 std::cerr << argv[0] << ": extension GL_ARB_shading_language_100 = " << msg[has_arb_shading_language] << std::endl;
841 std::cerr << argv[0] << ": extension GL_EXT_framebuffer_object = " << msg[has_ext_framebuffer] << std::endl;
842 std::cerr << argv[0] << ": extension GL_ARB_texture_rectangle = " << msg[has_arb_texture_rectangle] << std::endl;
843 std::cerr << argv[0] << ": extension GL_ARB_texture_border_clamp = " << msg[has_arb_texture_border_clamp] << std::endl;
844 std::cerr << argv[0] << ": extension GL_ARB_texture_float = " << msg[has_arb_texture_float] << std::endl;
845 std::cerr << argv[0] << ": This graphics system lacks the necessary extensions for -g." << std::endl;
846 std::cerr << argv[0] << ": Switching to CPU calculation." << std::endl;
847 DestroyContext();
848 return false;
849 }
850
851 return true;
852 }
853
wrapupGPU()854 bool wrapupGPU()
855 {
856 DestroyContext();
857 return true;
858 }
859
GetHuginVersion()860 std::string GetHuginVersion()
861 {
862 return std::string(DISPLAY_VERSION);
863 };
864
GetICCDesc(const vigra::ImageImportInfo::ICCProfile & iccProfile)865 std::string GetICCDesc(const vigra::ImageImportInfo::ICCProfile& iccProfile)
866 {
867 if (iccProfile.empty())
868 {
869 // no profile
870 return std::string();
871 };
872 cmsHPROFILE profile = cmsOpenProfileFromMem(iccProfile.data(), iccProfile.size());
873 if (profile == NULL)
874 {
875 // invalid profile
876 return std::string();
877 };
878 const std::string name=GetICCDesc(profile);
879 cmsCloseProfile(profile);
880 return name;
881 };
882
GetICCDesc(const cmsHPROFILE & profile)883 std::string GetICCDesc(const cmsHPROFILE& profile)
884 {
885 const size_t size = cmsGetProfileInfoASCII(profile, cmsInfoDescription, cmsNoLanguage, cmsNoCountry, nullptr, 0);
886 std::string information(size, '\000');
887 cmsGetProfileInfoASCII(profile, cmsInfoDescription, cmsNoLanguage, cmsNoCountry, &information[0], size);
888 StrTrim(information);
889 return information;
890 }
891 } //namespace
892