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