]> git.lizzy.rs Git - minetest.git/blob - src/porting.cpp
Fix mapgen using unitialised height map values
[minetest.git] / src / porting.cpp
1 /*
2 Minetest
3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 /*
21         Random portability stuff
22
23         See comments in porting.h
24 */
25
26 #include "porting.h"
27
28 #if defined(__FreeBSD__)
29         #include <sys/types.h>
30         #include <sys/sysctl.h>
31 #elif defined(_WIN32)
32         #include <algorithm>
33 #endif
34 #if !defined(_WIN32)
35         #include <unistd.h>
36         #include <sys/utsname.h>
37 #endif
38
39 #if !defined(_WIN32) && !defined(__APPLE__) && \
40         !defined(__ANDROID__) && !defined(SERVER)
41         #define XORG_USED
42 #endif
43
44 #ifdef XORG_USED
45         #include <X11/Xlib.h>
46         #include <X11/Xutil.h>
47 #endif
48
49 #include "config.h"
50 #include "debug.h"
51 #include "filesys.h"
52 #include "log.h"
53 #include "util/string.h"
54 #include "main.h"
55 #include "settings.h"
56 #include <list>
57
58 namespace porting
59 {
60
61 /*
62         Signal handler (grabs Ctrl-C on POSIX systems)
63 */
64
65 bool g_killed = false;
66
67 bool * signal_handler_killstatus(void)
68 {
69         return &g_killed;
70 }
71
72 #if !defined(_WIN32) // POSIX
73         #include <signal.h>
74
75 void sigint_handler(int sig)
76 {
77         if(g_killed == false)
78         {
79                 dstream<<DTIME<<"INFO: sigint_handler(): "
80                                 <<"Ctrl-C pressed, shutting down."<<std::endl;
81
82                 // Comment out for less clutter when testing scripts
83                 /*dstream<<DTIME<<"INFO: sigint_handler(): "
84                                 <<"Printing debug stacks"<<std::endl;
85                 debug_stacks_print();*/
86
87                 g_killed = true;
88         }
89         else
90         {
91                 (void)signal(SIGINT, SIG_DFL);
92         }
93 }
94
95 void signal_handler_init(void)
96 {
97         (void)signal(SIGINT, sigint_handler);
98 }
99
100 #else // _WIN32
101         #include <signal.h>
102
103         BOOL WINAPI event_handler(DWORD sig)
104         {
105                 switch(sig)
106                 {
107                 case CTRL_C_EVENT:
108                 case CTRL_CLOSE_EVENT:
109                 case CTRL_LOGOFF_EVENT:
110                 case CTRL_SHUTDOWN_EVENT:
111
112                         if(g_killed == false)
113                         {
114                                 dstream<<DTIME<<"INFO: event_handler(): "
115                                                 <<"Ctrl+C, Close Event, Logoff Event or Shutdown Event, shutting down."<<std::endl;
116                                 // Comment out for less clutter when testing scripts
117                                 /*dstream<<DTIME<<"INFO: event_handler(): "
118                                                 <<"Printing debug stacks"<<std::endl;
119                                 debug_stacks_print();*/
120
121                                 g_killed = true;
122                         }
123                         else
124                         {
125                                 (void)signal(SIGINT, SIG_DFL);
126                         }
127
128                         break;
129                 case CTRL_BREAK_EVENT:
130                         break;
131                 }
132
133                 return TRUE;
134         }
135
136 void signal_handler_init(void)
137 {
138         SetConsoleCtrlHandler( (PHANDLER_ROUTINE)event_handler,TRUE);
139 }
140
141 #endif
142
143
144 /*
145         Multithreading support
146 */
147 int getNumberOfProcessors() {
148 #if defined(_SC_NPROCESSORS_ONLN)
149
150         return sysconf(_SC_NPROCESSORS_ONLN);
151
152 #elif defined(__FreeBSD__) || defined(__APPLE__)
153
154         unsigned int len, count;
155         len = sizeof(count);
156         return sysctlbyname("hw.ncpu", &count, &len, NULL, 0);
157
158 #elif defined(_GNU_SOURCE)
159
160         return get_nprocs();
161
162 #elif defined(_WIN32)
163
164         SYSTEM_INFO sysinfo;
165         GetSystemInfo(&sysinfo);
166         return sysinfo.dwNumberOfProcessors;
167
168 #elif defined(PTW32_VERSION) || defined(__hpux)
169
170         return pthread_num_processors_np();
171
172 #else
173
174         return 1;
175
176 #endif
177 }
178
179
180 #ifndef __ANDROID__
181 bool threadBindToProcessor(threadid_t tid, int pnumber) {
182 #if defined(_WIN32)
183
184         HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, 0, tid);
185         if (!hThread)
186                 return false;
187
188         bool success = SetThreadAffinityMask(hThread, 1 << pnumber) != 0;
189
190         CloseHandle(hThread);
191         return success;
192
193 #elif (defined(__FreeBSD__) && (__FreeBSD_version >= 702106)) \
194         || defined(__linux) || defined(linux)
195
196         cpu_set_t cpuset;
197
198         CPU_ZERO(&cpuset);
199         CPU_SET(pnumber, &cpuset);
200         return pthread_setaffinity_np(tid, sizeof(cpuset), &cpuset) == 0;
201
202 #elif defined(__sun) || defined(sun)
203
204         return processor_bind(P_LWPID, MAKE_LWPID_PTHREAD(tid),
205                                                 pnumber, NULL) == 0;
206
207 #elif defined(_AIX)
208
209         return bindprocessor(BINDTHREAD, (tid_t)tid, pnumber) == 0;
210
211 #elif defined(__hpux) || defined(hpux)
212
213         pthread_spu_t answer;
214
215         return pthread_processor_bind_np(PTHREAD_BIND_ADVISORY_NP,
216                                                                         &answer, pnumber, tid) == 0;
217
218 #elif defined(__APPLE__)
219
220         struct thread_affinity_policy tapol;
221
222         thread_port_t threadport = pthread_mach_thread_np(tid);
223         tapol.affinity_tag = pnumber + 1;
224         return thread_policy_set(threadport, THREAD_AFFINITY_POLICY,
225                         (thread_policy_t)&tapol, THREAD_AFFINITY_POLICY_COUNT) == KERN_SUCCESS;
226
227 #else
228
229         return false;
230
231 #endif
232 }
233 #endif
234
235 bool threadSetPriority(threadid_t tid, int prio) {
236 #if defined(_WIN32)
237
238         HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, 0, tid);
239         if (!hThread)
240                 return false;
241
242         bool success = SetThreadPriority(hThread, prio) != 0;
243
244         CloseHandle(hThread);
245         return success;
246
247 #else
248
249         struct sched_param sparam;
250         int policy;
251
252         if (pthread_getschedparam(tid, &policy, &sparam) != 0)
253                 return false;
254
255         int min = sched_get_priority_min(policy);
256         int max = sched_get_priority_max(policy);
257
258         sparam.sched_priority = min + prio * (max - min) / THREAD_PRIORITY_HIGHEST;
259         return pthread_setschedparam(tid, policy, &sparam) == 0;
260
261 #endif
262 }
263
264
265 /*
266         Path mangler
267 */
268
269 // Default to RUN_IN_PLACE style relative paths
270 std::string path_share = "..";
271 std::string path_user = "..";
272
273 std::string getDataPath(const char *subpath)
274 {
275         return path_share + DIR_DELIM + subpath;
276 }
277
278 void pathRemoveFile(char *path, char delim)
279 {
280         // Remove filename and path delimiter
281         int i;
282         for(i = strlen(path)-1; i>=0; i--)
283         {
284                 if(path[i] == delim)
285                         break;
286         }
287         path[i] = 0;
288 }
289
290 bool detectMSVCBuildDir(char *c_path)
291 {
292         std::string path(c_path);
293         const char *ends[] = {
294                 "bin\\Release",
295                 "bin\\Debug",
296                 "bin\\Build",
297                 NULL};
298         return (removeStringEnd(path, ends) != "");
299 }
300
301 std::string get_sysinfo()
302 {
303 #ifdef _WIN32
304         OSVERSIONINFO osvi;
305         std::ostringstream oss;
306         std::string tmp;
307         ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
308         osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
309         GetVersionEx(&osvi);
310         tmp = osvi.szCSDVersion;
311         std::replace(tmp.begin(), tmp.end(), ' ', '_');
312
313         oss << "Windows/" << osvi.dwMajorVersion << "."
314                 << osvi.dwMinorVersion;
315         if(osvi.szCSDVersion[0])
316                 oss << "-" << tmp;
317         oss << " ";
318         #ifdef _WIN64
319         oss << "x86_64";
320         #else
321         BOOL is64 = FALSE;
322         if(IsWow64Process(GetCurrentProcess(), &is64) && is64)
323                 oss << "x86_64"; // 32-bit app on 64-bit OS
324         else
325                 oss << "x86";
326         #endif
327
328         return oss.str();
329 #else
330         struct utsname osinfo;
331         uname(&osinfo);
332         return std::string(osinfo.sysname) + "/"
333                 + osinfo.release + " " + osinfo.machine;
334 #endif
335 }
336
337 void initializePaths()
338 {
339 #if RUN_IN_PLACE
340         /*
341                 Use relative paths if RUN_IN_PLACE
342         */
343
344         infostream<<"Using relative paths (RUN_IN_PLACE)"<<std::endl;
345
346         /*
347                 Windows
348         */
349         #if defined(_WIN32)
350
351         const DWORD buflen = 1000;
352         char buf[buflen];
353         DWORD len;
354
355         // Find path of executable and set path_share relative to it
356         len = GetModuleFileName(GetModuleHandle(NULL), buf, buflen);
357         assert(len < buflen);
358         pathRemoveFile(buf, '\\');
359
360         if(detectMSVCBuildDir(buf)){
361                 infostream<<"MSVC build directory detected"<<std::endl;
362                 path_share = std::string(buf) + "\\..\\..";
363                 path_user = std::string(buf) + "\\..\\..";
364         }
365         else{
366                 path_share = std::string(buf) + "\\..";
367                 path_user = std::string(buf) + "\\..";
368         }
369
370         /*
371                 Linux
372         */
373         #elif defined(linux)
374
375         char buf[BUFSIZ];
376         memset(buf, 0, BUFSIZ);
377         // Get path to executable
378         assert(readlink("/proc/self/exe", buf, BUFSIZ-1) != -1);
379
380         pathRemoveFile(buf, '/');
381
382         path_share = std::string(buf) + "/..";
383         path_user = std::string(buf) + "/..";
384
385         /*
386                 OS X
387         */
388         #elif defined(__APPLE__)
389
390         //https://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man3/dyld.3.html
391         //TODO: Test this code
392         char buf[BUFSIZ];
393         uint32_t len = sizeof(buf);
394         assert(_NSGetExecutablePath(buf, &len) != -1);
395
396         pathRemoveFile(buf, '/');
397
398         path_share = std::string(buf) + "/..";
399         path_user = std::string(buf) + "/..";
400
401         /*
402                 FreeBSD
403         */
404         #elif defined(__FreeBSD__)
405
406         int mib[4];
407         char buf[BUFSIZ];
408         size_t len = sizeof(buf);
409
410         mib[0] = CTL_KERN;
411         mib[1] = KERN_PROC;
412         mib[2] = KERN_PROC_PATHNAME;
413         mib[3] = -1;
414         assert(sysctl(mib, 4, buf, &len, NULL, 0) != -1);
415
416         pathRemoveFile(buf, '/');
417
418         path_share = std::string(buf) + "/..";
419         path_user = std::string(buf) + "/..";
420
421         #else
422
423         //TODO: Get path of executable. This assumes working directory is bin/
424         dstream<<"WARNING: Relative path not properly supported on this platform"
425                         <<std::endl;
426
427         /* scriptapi no longer allows paths that start with "..", so assuming that
428            the current working directory is bin/, strip off the last component. */
429         char *cwd = getcwd(NULL, 0);
430         pathRemoveFile(cwd, '/');
431         path_share = std::string(cwd);
432         path_user = std::string(cwd);
433
434         #endif
435
436 #else // RUN_IN_PLACE
437
438         /*
439                 Use platform-specific paths otherwise
440         */
441
442         infostream<<"Using system-wide paths (NOT RUN_IN_PLACE)"<<std::endl;
443
444         /*
445                 Windows
446         */
447         #if defined(_WIN32)
448
449         const DWORD buflen = 1000;
450         char buf[buflen];
451         DWORD len;
452
453         // Find path of executable and set path_share relative to it
454         len = GetModuleFileName(GetModuleHandle(NULL), buf, buflen);
455         assert(len < buflen);
456         pathRemoveFile(buf, '\\');
457
458         // Use ".\bin\.."
459         path_share = std::string(buf) + "\\..";
460
461         // Use "C:\Documents and Settings\user\Application Data\<PROJECT_NAME>"
462         len = GetEnvironmentVariable("APPDATA", buf, buflen);
463         assert(len < buflen);
464         path_user = std::string(buf) + DIR_DELIM + PROJECT_NAME;
465
466         /*
467                 Linux
468         */
469         #elif defined(linux)
470
471         // Get path to executable
472         std::string bindir = "";
473         {
474                 char buf[BUFSIZ];
475                 memset(buf, 0, BUFSIZ);
476                 if (readlink("/proc/self/exe", buf, BUFSIZ-1) == -1) {
477                         errorstream << "Unable to read bindir "<< std::endl;
478 #ifndef __ANDROID__
479                         assert("Unable to read bindir" == 0);
480 #endif
481                 } else {
482                         pathRemoveFile(buf, '/');
483                         bindir = buf;
484                 }
485         }
486
487         // Find share directory from these.
488         // It is identified by containing the subdirectory "builtin".
489         std::list<std::string> trylist;
490         std::string static_sharedir = STATIC_SHAREDIR;
491         if(static_sharedir != "" && static_sharedir != ".")
492                 trylist.push_back(static_sharedir);
493         trylist.push_back(
494                         bindir + DIR_DELIM + ".." + DIR_DELIM + "share" + DIR_DELIM + PROJECT_NAME);
495         trylist.push_back(bindir + DIR_DELIM + "..");
496 #ifdef __ANDROID__
497         trylist.push_back(path_user);
498 #endif
499
500         for(std::list<std::string>::const_iterator i = trylist.begin();
501                         i != trylist.end(); i++)
502         {
503                 const std::string &trypath = *i;
504                 if(!fs::PathExists(trypath) || !fs::PathExists(trypath + DIR_DELIM + "builtin")){
505                         dstream<<"WARNING: system-wide share not found at \""
506                                         <<trypath<<"\""<<std::endl;
507                         continue;
508                 }
509                 // Warn if was not the first alternative
510                 if(i != trylist.begin()){
511                         dstream<<"WARNING: system-wide share found at \""
512                                         <<trypath<<"\""<<std::endl;
513                 }
514                 path_share = trypath;
515                 break;
516         }
517 #ifndef __ANDROID__
518         path_user = std::string(getenv("HOME")) + DIR_DELIM + "." + PROJECT_NAME;
519 #endif
520
521         /*
522                 OS X
523         */
524         #elif defined(__APPLE__)
525
526         // Code based on
527         // http://stackoverflow.com/questions/516200/relative-paths-not-working-in-xcode-c
528         CFBundleRef main_bundle = CFBundleGetMainBundle();
529         CFURLRef resources_url = CFBundleCopyResourcesDirectoryURL(main_bundle);
530         char path[PATH_MAX];
531         if(CFURLGetFileSystemRepresentation(resources_url, TRUE, (UInt8 *)path, PATH_MAX))
532         {
533                 dstream<<"Bundle resource path: "<<path<<std::endl;
534                 //chdir(path);
535                 path_share = std::string(path) + DIR_DELIM + STATIC_SHAREDIR;
536         }
537         else
538         {
539                 // error!
540                 dstream<<"WARNING: Could not determine bundle resource path"<<std::endl;
541         }
542         CFRelease(resources_url);
543
544         path_user = std::string(getenv("HOME")) + "/Library/Application Support/" + PROJECT_NAME;
545
546         #else // FreeBSD, and probably many other POSIX-like systems.
547
548         path_share = STATIC_SHAREDIR;
549         path_user = std::string(getenv("HOME")) + DIR_DELIM + "." + PROJECT_NAME;
550
551         #endif
552
553 #endif // RUN_IN_PLACE
554 }
555
556 static irr::IrrlichtDevice *device;
557
558 void initIrrlicht(irr::IrrlichtDevice *device_)
559 {
560         device = device_;
561 }
562
563 void setXorgClassHint(const video::SExposedVideoData &video_data,
564         const std::string &name)
565 {
566 #ifdef XORG_USED
567         if (video_data.OpenGLLinux.X11Display == NULL)
568                 return;
569
570         XClassHint *classhint = XAllocClassHint();
571         classhint->res_name  = (char *)name.c_str();
572         classhint->res_class = (char *)name.c_str();
573
574         XSetClassHint((Display *)video_data.OpenGLLinux.X11Display,
575                 video_data.OpenGLLinux.X11Window, classhint);
576         XFree(classhint);
577 #endif
578 }
579
580 #ifndef SERVER
581 v2u32 getWindowSize()
582 {
583         return device->getVideoDriver()->getScreenSize();
584 }
585
586
587 std::vector<core::vector3d<u32> > getVideoModes()
588 {
589         std::vector<core::vector3d<u32> > mlist;
590         video::IVideoModeList *modelist = device->getVideoModeList();
591
592         u32 num_modes = modelist->getVideoModeCount();
593         for (u32 i = 0; i != num_modes; i++) {
594                 core::dimension2d<u32> mode_res = modelist->getVideoModeResolution(i);
595                 s32 mode_depth = modelist->getVideoModeDepth(i);
596                 mlist.push_back(core::vector3d<u32>(mode_res.Width, mode_res.Height, mode_depth));
597         }
598
599         return mlist;
600 }
601
602 std::vector<irr::video::E_DRIVER_TYPE> getSupportedVideoDrivers()
603 {
604         std::vector<irr::video::E_DRIVER_TYPE> drivers;
605
606         for (int i = 0; i != irr::video::EDT_COUNT; i++) {
607                 if (irr::IrrlichtDevice::isDriverSupported((irr::video::E_DRIVER_TYPE)i))
608                         drivers.push_back((irr::video::E_DRIVER_TYPE)i);
609         }
610
611         return drivers;
612 }
613
614 const char *getVideoDriverName(irr::video::E_DRIVER_TYPE type)
615 {
616         static const char *driver_ids[] = {
617                 "null",
618                 "software",
619                 "burningsvideo",
620                 "direct3d8",
621                 "direct3d9",
622                 "opengl",
623                 "ogles1",
624                 "ogles2",
625         };
626
627         return driver_ids[type];
628 }
629
630
631 const char *getVideoDriverFriendlyName(irr::video::E_DRIVER_TYPE type)
632 {
633         static const char *driver_names[] = {
634                 "NULL Driver",
635                 "Software Renderer",
636                 "Burning's Video",
637                 "Direct3D 8",
638                 "Direct3D 9",
639                 "OpenGL",
640                 "OpenGL ES1",
641                 "OpenGL ES2",
642         };
643
644         return driver_names[type];
645 }
646
647
648 #ifndef __ANDROID__
649 #ifdef XORG_USED
650
651 static float calcDisplayDensity()
652 {
653         const char* current_display = getenv("DISPLAY");
654
655         if (current_display != NULL) {
656                         Display * x11display = XOpenDisplay(current_display);
657
658                         if (x11display != NULL) {
659                                 /* try x direct */
660                                 float dpi_height =
661                                                 floor(DisplayHeight(x11display, 0) /
662                                                                 (DisplayHeightMM(x11display, 0) * 0.039370) + 0.5);
663                                 float dpi_width =
664                                                 floor(DisplayWidth(x11display, 0) /
665                                                                 (DisplayWidthMM(x11display, 0) * 0.039370) +0.5);
666
667                                 XCloseDisplay(x11display);
668
669                                 return std::max(dpi_height,dpi_width) / 96.0;
670                         }
671                 }
672
673         /* return manually specified dpi */
674         return g_settings->getFloat("screen_dpi")/96.0;
675 }
676
677
678 float getDisplayDensity()
679 {
680         static float cached_display_density = calcDisplayDensity();
681         return cached_display_density;
682 }
683
684
685 #else
686 float getDisplayDensity()
687 {
688         return g_settings->getFloat("screen_dpi")/96.0;
689 }
690 #endif
691
692 v2u32 getDisplaySize()
693 {
694         IrrlichtDevice *nulldevice = createDevice(video::EDT_NULL);
695
696         core::dimension2d<u32> deskres = nulldevice->getVideoModeList()->getDesktopResolution();
697         nulldevice -> drop();
698
699         return deskres;
700 }
701 #endif
702 #endif
703
704 } //namespace porting
705