// // Copyright (c) 2008-2013 the Urho3D project. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // #include "Precompiled.h" #include "Mutex.h" #include "ProcessUtils.h" #include "MathDefs.h" #include #include #ifdef __APPLE__ #include "TargetConditionals.h" #endif #if defined(IOS) #include #elif !defined(ANDROID) && !defined(RASPI) #include #endif #ifdef WIN32 #include #include #else #include #endif #if defined(_MSC_VER) #include #elif !defined(ANDROID) && !defined(IOS) && !defined(RASPI) // From http://stereopsis.com/FPU.html #define FPU_CW_PREC_MASK 0x0300 #define FPU_CW_PREC_SINGLE 0x0000 #define FPU_CW_PREC_DOUBLE 0x0200 #define FPU_CW_PREC_EXTENDED 0x0300 #define FPU_CW_ROUND_MASK 0x0c00 #define FPU_CW_ROUND_NEAR 0x0000 #define FPU_CW_ROUND_DOWN 0x0400 #define FPU_CW_ROUND_UP 0x0800 #define FPU_CW_ROUND_CHOP 0x0c00 inline unsigned GetFPUState() { unsigned control = 0; __asm__ __volatile__ ("fnstcw %0" : "=m" (control)); return control; } inline void SetFPUState(unsigned control) { __asm__ __volatile__ ("fldcw %0" : : "m" (control)); } #endif #include "DebugNew.h" namespace Urho3D { #ifdef WIN32 static bool consoleOpened = false; #endif static String currentLine; static Vector arguments; #if defined(IOS) void GetCPUData(host_basic_info_data_t* data) { mach_msg_type_number_t infoCount; infoCount = HOST_BASIC_INFO_COUNT; host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t)data, &infoCount); } #elif !defined(ANDROID) && !defined(RASPI) void GetCPUData(struct cpu_id_t* data) { if (cpu_identify(0, data) < 0) { data->num_logical_cpus = 1; data->num_cores = 1; } } #endif void InitFPU() { #if !defined(ANDROID) && !defined(IOS) && !defined(RASPI) && !defined(__x86_64__) && !defined(_M_AMD64) // Make sure FPU is in round-to-nearest, single precision mode // This ensures Direct3D and OpenGL behave similarly, and all threads behave similarly #ifdef _MSC_VER _controlfp(_RC_NEAR | _PC_24, _MCW_RC | _MCW_PC); #else unsigned control = GetFPUState(); control &= ~(FPU_CW_PREC_MASK | FPU_CW_ROUND_MASK); control |= (FPU_CW_PREC_SINGLE | FPU_CW_ROUND_NEAR); SetFPUState(control); #endif #endif } void ErrorDialog(const String& title, const String& message) { #ifdef WIN32 MessageBoxW(0, WString(message).CString(), WString(title).CString(), 0); #else PrintLine(message, true); #endif } void ErrorExit(const String& message, int exitCode) { if (!message.Empty()) PrintLine(message, true); exit(exitCode); } void OpenConsoleWindow() { #ifdef WIN32 if (consoleOpened) return; AllocConsole(); HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); int hCrt = _open_osfhandle((size_t)hOut, _O_TEXT); FILE* outFile = _fdopen(hCrt, "w"); setvbuf(outFile, NULL, _IONBF, 1); *stdout = *outFile; HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE); hCrt = _open_osfhandle((size_t)hIn, _O_TEXT); FILE* inFile = _fdopen(hCrt, "r"); setvbuf(inFile, NULL, _IONBF, 128); *stdin = *inFile; consoleOpened = true; #endif } void PrintUnicode(const String& str, bool error) { #if !defined(ANDROID) && !defined(IOS) #ifdef WIN32 HANDLE stream = GetStdHandle(error ? STD_ERROR_HANDLE : STD_OUTPUT_HANDLE); if (stream == INVALID_HANDLE_VALUE) return; WString strW(str); DWORD charsWritten; WriteConsoleW(stream, strW.CString(), strW.Length(), &charsWritten, 0); #else fprintf(error ? stderr : stdout, "%s", str.CString()); #endif #endif } void PrintUnicodeLine(const String& str, bool error) { PrintUnicode(str + '\n', error); } void PrintLine(const String& str, bool error) { #if !defined(ANDROID) && !defined(IOS) fprintf(error ? stderr: stdout, "%s\n", str.CString()); #endif } const Vector& ParseArguments(const String& cmdLine, bool skipFirstArgument) { arguments.Clear(); unsigned cmdStart = 0, cmdEnd = 0; bool inCmd = false; bool inQuote = false; for (unsigned i = 0; i < cmdLine.Length(); ++i) { if (cmdLine[i] == '\"') inQuote = !inQuote; if (cmdLine[i] == ' ' && !inQuote) { if (inCmd) { inCmd = false; cmdEnd = i; // Do not store the first argument (executable name) if (!skipFirstArgument) arguments.Push(cmdLine.Substring(cmdStart, cmdEnd - cmdStart)); skipFirstArgument = false; } } else { if (!inCmd) { inCmd = true; cmdStart = i; } } } if (inCmd) { cmdEnd = cmdLine.Length(); if (!skipFirstArgument) arguments.Push(cmdLine.Substring(cmdStart, cmdEnd - cmdStart)); } // Strip double quotes from the arguments for (unsigned i = 0; i < arguments.Size(); ++i) arguments[i].Replace("\"", ""); return arguments; } const Vector& ParseArguments(const char* cmdLine) { return ParseArguments(String(cmdLine)); } const Vector& ParseArguments(const WString& cmdLine) { return ParseArguments(String(cmdLine)); } const Vector& ParseArguments(const wchar_t* cmdLine) { return ParseArguments(String(cmdLine)); } const Vector& ParseArguments(int argc, char** argv) { String cmdLine; for (int i = 0; i < argc; ++i) cmdLine.AppendWithFormat("\"%s\" ", (const char*)argv[i]); return ParseArguments(cmdLine); } const Vector& GetArguments() { return arguments; } String GetConsoleInput() { String ret; #ifdef WIN32 HANDLE input = GetStdHandle(STD_INPUT_HANDLE); HANDLE output = GetStdHandle(STD_OUTPUT_HANDLE); if (input == INVALID_HANDLE_VALUE || output == INVALID_HANDLE_VALUE) return ret; // Use char-based input SetConsoleMode(input, ENABLE_PROCESSED_INPUT); INPUT_RECORD record; DWORD events = 0; DWORD readEvents = 0; if (!GetNumberOfConsoleInputEvents(input, &events)) return ret; while (events--) { ReadConsoleInputW(input, &record, 1, &readEvents); if (record.EventType == KEY_EVENT && record.Event.KeyEvent.bKeyDown) { unsigned c = record.Event.KeyEvent.uChar.UnicodeChar; if (c) { if (c == '\b') { PrintUnicode("\b \b"); int length = currentLine.LengthUTF8(); if (length) currentLine = currentLine.SubstringUTF8(0, length - 1); } else if (c == '\r') { PrintUnicode("\n"); ret = currentLine; currentLine.Clear(); return ret; } else { // We have disabled echo, so echo manually wchar_t out = c; DWORD charsWritten; WriteConsoleW(output, &out, 1, &charsWritten, 0); currentLine.AppendUTF8(c); } } } } #elif !defined(ANDROID) && !defined(IOS) int flags = fcntl(STDIN_FILENO, F_GETFL); fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK); for (;;) { int ch = fgetc(stdin); if (ch >= 0 && ch != '\n') ret += (char)ch; else break; } #endif return ret; } String GetPlatform() { #if defined(ANDROID) return "Android"; #elif defined(IOS) return "iOS"; #elif defined(WIN32) return "Windows"; #elif defined(__APPLE__) return "Mac OS X"; #elif defined(RASPI) return "Raspberry Pi"; #elif defined(__linux__) return "Linux"; #else return String::EMPTY; #endif } unsigned GetNumPhysicalCPUs() { #if defined(IOS) host_basic_info_data_t data; GetCPUData(&data); #if defined(TARGET_IPHONE_SIMULATOR) // Hardcoded to dual-core on simulator mode even if the host has more return Min(2, data.physical_cpu); #else return data.physical_cpu; #endif #elif !defined(ANDROID) && !defined(RASPI) struct cpu_id_t data; GetCPUData(&data); return data.num_cores; #else /// \todo Implement properly return 1; #endif } unsigned GetNumLogicalCPUs() { #if defined(IOS) host_basic_info_data_t data; GetCPUData(&data); #if defined(TARGET_IPHONE_SIMULATOR) return Min(2, data.logical_cpu); #else return data.logical_cpu; #endif #elif !defined(ANDROID) && !defined(RASPI) struct cpu_id_t data; GetCPUData(&data); return data.num_logical_cpus; #else /// \todo Implement properly return 1; #endif } }