aboutsummaryrefslogtreecommitdiff
path: root/platform/windows/os_windows.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'platform/windows/os_windows.cpp')
-rw-r--r--platform/windows/os_windows.cpp1732
1 files changed, 1732 insertions, 0 deletions
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
new file mode 100644
index 000000000..efeb813a2
--- /dev/null
+++ b/platform/windows/os_windows.cpp
@@ -0,0 +1,1732 @@
+/*************************************************************************/
+/* os_windows.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 "drivers/gles2/rasterizer_gles2.h"
+#include "drivers/gles1/rasterizer_gles1.h"
+#include "os_windows.h"
+#include "drivers/nedmalloc/memory_pool_static_nedmalloc.h"
+#include "drivers/unix/memory_pool_static_malloc.h"
+#include "os/memory_pool_dynamic_static.h"
+#include "drivers/windows/thread_windows.h"
+#include "drivers/windows/semaphore_windows.h"
+#include "drivers/windows/mutex_windows.h"
+#include "main/main.h"
+#include "drivers/windows/file_access_windows.h"
+#include "drivers/windows/dir_access_windows.h"
+
+
+#include "servers/visual/visual_server_raster.h"
+#include "servers/audio/audio_server_sw.h"
+#include "servers/visual/visual_server_wrap_mt.h"
+
+#include "tcp_server_winsock.h"
+#include "stream_peer_winsock.h"
+#include "os/pc_joystick_map.h"
+#include "lang_table.h"
+#include "os/memory_pool_dynamic_prealloc.h"
+#include "globals.h"
+#include "io/marshalls.h"
+static const WORD MAX_CONSOLE_LINES = 1500;
+
+//#define STDOUT_FILE
+
+extern HINSTANCE godot_hinstance;
+
+void RedirectIOToConsole() {
+
+ int hConHandle;
+
+ intptr_t lStdHandle;
+
+ CONSOLE_SCREEN_BUFFER_INFO coninfo;
+
+ FILE *fp;
+
+ // allocate a console for this app
+
+ AllocConsole();
+
+ // set the screen buffer to be big enough to let us scroll text
+
+ GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE),
+
+ &coninfo);
+
+ coninfo.dwSize.Y = MAX_CONSOLE_LINES;
+
+ SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE),
+
+ coninfo.dwSize);
+
+ // redirect unbuffered STDOUT to the console
+
+ lStdHandle = (intptr_t)GetStdHandle(STD_OUTPUT_HANDLE);
+
+ hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
+
+ fp = _fdopen( hConHandle, "w" );
+
+ *stdout = *fp;
+
+ setvbuf( stdout, NULL, _IONBF, 0 );
+
+ // redirect unbuffered STDIN to the console
+
+ lStdHandle = (intptr_t)GetStdHandle(STD_INPUT_HANDLE);
+
+ hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
+
+ fp = _fdopen( hConHandle, "r" );
+
+ *stdin = *fp;
+
+ setvbuf( stdin, NULL, _IONBF, 0 );
+
+ // redirect unbuffered STDERR to the console
+
+ lStdHandle = (intptr_t)GetStdHandle(STD_ERROR_HANDLE);
+
+ hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
+
+ fp = _fdopen( hConHandle, "w" );
+
+ *stderr = *fp;
+
+ setvbuf( stderr, NULL, _IONBF, 0 );
+
+ // make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog
+
+ // point to console as well
+}
+
+int OS_Windows::get_video_driver_count() const {
+
+ return 2;
+}
+const char * OS_Windows::get_video_driver_name(int p_driver) const {
+
+ return p_driver==0?"GLES2":"GLES1";
+}
+
+OS::VideoMode OS_Windows::get_default_video_mode() const {
+
+ return VideoMode(800,600,false);
+}
+
+int OS_Windows::get_audio_driver_count() const {
+
+ return AudioDriverManagerSW::get_driver_count();
+}
+const char * OS_Windows::get_audio_driver_name(int p_driver) const {
+
+ AudioDriverSW* driver = AudioDriverManagerSW::get_driver(p_driver);
+ ERR_FAIL_COND_V( !driver, "" );
+ return AudioDriverManagerSW::get_driver(p_driver)->get_name();
+}
+
+static MemoryPoolStatic *mempool_static=NULL;
+static MemoryPoolDynamic *mempool_dynamic=NULL;
+
+void OS_Windows::initialize_core() {
+
+
+ last_button_state=0;
+
+ //RedirectIOToConsole();
+
+ ThreadWindows::make_default();
+ SemaphoreWindows::make_default();
+ MutexWindows::make_default();
+
+ FileAccess::make_default<FileAccessWindows>(FileAccess::ACCESS_RESOURCES);
+ FileAccess::make_default<FileAccessWindows>(FileAccess::ACCESS_USERDATA);
+ FileAccess::make_default<FileAccessWindows>(FileAccess::ACCESS_FILESYSTEM);
+ //FileAccessBufferedFA<FileAccessWindows>::make_default();
+ DirAccess::make_default<DirAccessWindows>(DirAccess::ACCESS_RESOURCES);
+ DirAccess::make_default<DirAccessWindows>(DirAccess::ACCESS_USERDATA);
+ DirAccess::make_default<DirAccessWindows>(DirAccess::ACCESS_FILESYSTEM);
+
+ TCPServerWinsock::make_default();
+ StreamPeerWinsock::make_default();
+
+ mempool_static = new MemoryPoolStaticMalloc;
+#if 1
+ mempool_dynamic = memnew( MemoryPoolDynamicStatic );
+#else
+#define DYNPOOL_SIZE 4*1024*1024
+ void * buffer = malloc( DYNPOOL_SIZE );
+ mempool_dynamic = memnew( MemoryPoolDynamicPrealloc(buffer,DYNPOOL_SIZE) );
+
+#endif
+
+ // We need to know how often the clock is updated
+ if( !QueryPerformanceFrequency((LARGE_INTEGER *)&ticks_per_second) )
+ ticks_per_second = 1000;
+ // If timeAtGameStart is 0 then we get the time since
+ // the start of the computer when we call GetGameTime()
+ ticks_start = 0;
+ ticks_start = get_ticks_usec();
+
+ process_map = memnew((Map<ProcessID, ProcessInfo>));
+
+ IP_Unix::make_default();
+
+ cursor_shape=CURSOR_ARROW;
+
+
+}
+
+bool OS_Windows::can_draw() const {
+
+ return !minimized;
+};
+
+
+LRESULT OS_Windows::WndProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam) {
+
+
+ switch (uMsg) // Check For Windows Messages
+ {
+ case WM_ACTIVATE: // Watch For Window Activate Message
+ {
+ minimized = HIWORD(wParam) != 0;
+ if (!main_loop) {
+ return 0;
+ };
+ if (LOWORD(wParam) == WA_ACTIVE || LOWORD(wParam) == WA_CLICKACTIVE) {
+
+ main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_IN);
+ alt_mem=false;
+ control_mem=false;
+ shift_mem=false;
+ if (mouse_mode==MOUSE_MODE_CAPTURED) {
+ RECT clipRect;
+ GetClientRect(hWnd, &clipRect);
+ ClientToScreen(hWnd, (POINT*) &clipRect.left);
+ ClientToScreen(hWnd, (POINT*) &clipRect.right);
+ ClipCursor(&clipRect);
+ SetCapture(hWnd);
+
+ }
+ } else {
+ main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_OUT);
+ alt_mem=false;
+
+ };
+
+ return 0; // Return To The Message Loop
+ }
+
+ case WM_PAINT:
+
+ Main::force_redraw();
+ break;
+
+ case WM_SYSCOMMAND: // Intercept System Commands
+ {
+ switch (wParam) // Check System Calls
+ {
+ case SC_SCREENSAVE: // Screensaver Trying To Start?
+ case SC_MONITORPOWER: // Monitor Trying To Enter Powersave?
+ return 0; // Prevent From Happening
+ case SC_KEYMENU:
+ if ((lParam>>16)<=0)
+ return 0;
+ }
+ break; // Exit
+ }
+
+ case WM_CLOSE: // Did We Receive A Close Message?
+ {
+ if (main_loop)
+ main_loop->notification(MainLoop::NOTIFICATION_WM_QUIT_REQUEST);
+ //force_quit=true;
+ return 0; // Jump Back
+ }
+ case WM_MOUSELEAVE: {
+
+ old_invalid=true;
+ outside=true;
+
+ } break;
+ case WM_MOUSEMOVE: {
+
+ if (outside) {
+
+ CursorShape c=cursor_shape;
+ cursor_shape=CURSOR_MAX;
+ set_cursor_shape(c);
+ outside=false;
+
+ //Once-Off notification, must call again....
+ TRACKMOUSEEVENT tme;
+ tme.cbSize=sizeof(TRACKMOUSEEVENT);
+ tme.dwFlags=TME_LEAVE;
+ tme.hwndTrack=hWnd;
+ tme.dwHoverTime=HOVER_DEFAULT;
+ TrackMouseEvent(&tme);
+
+ }
+ InputEvent event;
+ event.type=InputEvent::MOUSE_MOTION;
+ event.ID=++last_id;
+ InputEventMouseMotion &mm=event.mouse_motion;
+
+ mm.mod.control=(wParam&MK_CONTROL)!=0;
+ mm.mod.shift=(wParam&MK_SHIFT)!=0;
+ mm.mod.alt=alt_mem;
+
+ mm.button_mask|=(wParam&MK_LBUTTON)?(1<<0):0;
+ mm.button_mask|=(wParam&MK_RBUTTON)?(1<<1):0;
+ mm.button_mask|=(wParam&MK_MBUTTON)?(1<<2):0;
+ last_button_state=mm.button_mask;
+ /*mm.button_mask|=(wParam&MK_XBUTTON1)?(1<<5):0;
+ mm.button_mask|=(wParam&MK_XBUTTON2)?(1<<6):0;*/
+ mm.x=GET_X_LPARAM(lParam);
+ mm.y=GET_Y_LPARAM(lParam);
+
+ if (mouse_mode==MOUSE_MODE_CAPTURED) {
+
+ Point2i c(video_mode.width/2,video_mode.height/2);
+ if (Point2i(mm.x,mm.y)==c) {
+ center=c;
+ return 0;
+ }
+
+ Point2i ncenter(mm.x,mm.y);
+ mm.x = old_x + (mm.x-center.x);
+ mm.y = old_y + (mm.y-center.y);
+ center=ncenter;
+ POINT pos = { (int) c.x, (int) c.y };
+ ClientToScreen(hWnd, &pos);
+ SetCursorPos(pos.x, pos.y);
+
+ }
+
+ input->set_mouse_pos(Point2(mm.x,mm.y));
+ mm.speed_x=input->get_mouse_speed().x;
+ mm.speed_y=input->get_mouse_speed().y;
+
+ if (old_invalid) {
+
+ old_x=mm.x;
+ old_y=mm.y;
+ old_invalid=false;
+ }
+
+ mm.relative_x=mm.x-old_x;
+ mm.relative_y=mm.y-old_y;
+ old_x=mm.x;
+ old_y=mm.y;
+ if (main_loop)
+ input->parse_input_event(event);
+
+
+
+ } break;
+ case WM_LBUTTONDOWN:
+ case WM_LBUTTONUP:
+ case WM_MBUTTONDOWN:
+ case WM_MBUTTONUP:
+ case WM_RBUTTONDOWN:
+ case WM_RBUTTONUP:
+ case WM_MOUSEWHEEL:
+ case WM_LBUTTONDBLCLK:
+ /*case WM_XBUTTONDOWN:
+ case WM_XBUTTONUP: */{
+
+ InputEvent event;
+ event.type=InputEvent::MOUSE_BUTTON;
+ event.ID=++last_id;
+ InputEventMouseButton &mb=event.mouse_button;
+
+ switch (uMsg) {
+ case WM_LBUTTONDOWN: {
+ mb.pressed=true;
+ mb.button_index=1;
+ } break;
+ case WM_LBUTTONUP: {
+ mb.pressed=false;
+ mb.button_index=1;
+ } break;
+ case WM_MBUTTONDOWN: {
+ mb.pressed=true;
+ mb.button_index=3;
+
+ } break;
+ case WM_MBUTTONUP: {
+ mb.pressed=false;
+ mb.button_index=3;
+ } break;
+ case WM_RBUTTONDOWN: {
+ mb.pressed=true;
+ mb.button_index=2;
+ } break;
+ case WM_RBUTTONUP: {
+ mb.pressed=false;
+ mb.button_index=2;
+ } break;
+ case WM_LBUTTONDBLCLK: {
+
+ mb.pressed=true;
+ mb.button_index=1;
+ mb.doubleclick = true;
+ } break;
+ case WM_MOUSEWHEEL: {
+
+ mb.pressed=true;
+ int motion = (short)HIWORD(wParam);
+ if (!motion)
+ return 0;
+
+
+ if (motion>0)
+ mb.button_index=4;
+ else
+ mb.button_index=5;
+
+
+ } break;
+ /*
+ case WM_XBUTTONDOWN: {
+ mb.pressed=true;
+ mb.button_index=(HIWORD(wParam)==XBUTTON1)?6:7;
+ } break;
+ case WM_XBUTTONUP:
+ mb.pressed=true;
+ mb.button_index=(HIWORD(wParam)==XBUTTON1)?6:7;
+ } break;*/
+ default: { return 0; }
+ }
+
+
+ mb.mod.control=(wParam&MK_CONTROL)!=0;
+ mb.mod.shift=(wParam&MK_SHIFT)!=0;
+ mb.mod.alt=alt_mem;
+ //mb.mod.alt=(wParam&MK_MENU)!=0;
+ mb.button_mask|=(wParam&MK_LBUTTON)?(1<<0):0;
+ mb.button_mask|=(wParam&MK_RBUTTON)?(1<<1):0;
+ mb.button_mask|=(wParam&MK_MBUTTON)?(1<<2):0;
+
+ last_button_state=mb.button_mask;
+ /*
+ mb.button_mask|=(wParam&MK_XBUTTON1)?(1<<5):0;
+ mb.button_mask|=(wParam&MK_XBUTTON2)?(1<<6):0;*/
+ mb.x=GET_X_LPARAM(lParam);
+ mb.y=GET_Y_LPARAM(lParam);
+
+ if (mouse_mode==MOUSE_MODE_CAPTURED) {
+
+ mb.x=old_x;
+ mb.y=old_y;
+ }
+
+ mb.global_x=mb.x;
+ mb.global_y=mb.y;
+
+
+ if (uMsg != WM_MOUSEWHEEL) {
+ if (mb.pressed) {
+
+ if (++pressrc>0)
+ SetCapture(hWnd);
+ } else {
+
+
+ if (--pressrc<=0) {
+ ReleaseCapture();
+ pressrc=0;
+ }
+
+ }
+ } else if (mouse_mode!=MOUSE_MODE_CAPTURED) {
+ // for reasons unknown to mankind, wheel comes in screen cordinates
+ RECT rect;
+ GetWindowRect(hWnd,&rect);
+ mb.x-=rect.left;
+ mb.y-=rect.top;
+
+ }
+
+ if (main_loop) {
+ input->parse_input_event(event);
+ if (mb.pressed && mb.button_index>3) {
+ //send release for mouse wheel
+ mb.pressed=false;
+ event.ID=++last_id;
+ input->parse_input_event(event);
+
+ }
+ }
+
+
+
+ } break;
+
+ case WM_SIZE: {
+ video_mode.width=LOWORD(lParam);
+ video_mode.height=HIWORD(lParam);
+ //return 0; // Jump Back
+ } break;
+ case WM_SYSKEYDOWN:
+ case WM_SYSKEYUP:
+ case WM_KEYUP:
+ case WM_KEYDOWN: {
+
+
+ if (wParam==VK_SHIFT)
+ shift_mem=uMsg==WM_KEYDOWN;
+ if (wParam==VK_CONTROL)
+ control_mem=uMsg==WM_KEYDOWN;
+ if (wParam==VK_MENU) {
+ alt_mem=(uMsg==WM_KEYDOWN || uMsg==WM_SYSKEYDOWN);
+ if (lParam&(1<<24))
+ gr_mem=alt_mem;
+ }
+
+ //if (wParam==VK_WIN) TODO wtf is this?
+ // meta_mem=uMsg==WM_KEYDOWN;
+
+
+ } //fallthrough
+ case WM_CHAR: {
+
+ ERR_BREAK(key_event_pos >= KEY_EVENT_BUFFER_SIZE);
+
+ KeyEvent ke;
+ ke.mod_state.shift=shift_mem;
+ ke.mod_state.alt=alt_mem;
+ ke.mod_state.control=control_mem;
+ ke.mod_state.meta=meta_mem;
+ ke.uMsg=uMsg;
+
+ if (ke.uMsg==WM_SYSKEYDOWN)
+ ke.uMsg=WM_KEYDOWN;
+ if (ke.uMsg==WM_SYSKEYUP)
+ ke.uMsg=WM_KEYUP;
+
+
+ /*if (ke.uMsg==WM_KEYDOWN && alt_mem && uMsg!=WM_SYSKEYDOWN) {
+ //altgr hack for intl keyboards, not sure how good it is
+ //windows is weeeeird
+ ke.mod_state.alt=false;
+ ke.mod_state.control=false;
+ print_line("")
+ }*/
+
+
+ ke.wParam=wParam;
+ ke.lParam=lParam;
+ key_event_buffer[key_event_pos++]=ke;
+
+ } break;
+ case WM_INPUTLANGCHANGEREQUEST: {
+
+ print_line("input lang change");
+ } break;
+ default: {
+
+ if (user_proc) {
+
+ return CallWindowProcW(user_proc, hWnd, uMsg, wParam, lParam);
+ };
+ };
+ }
+
+ return DefWindowProcW(hWnd,uMsg,wParam,lParam);
+
+}
+
+LRESULT CALLBACK WndProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam) {
+
+ OS_Windows *os_win = static_cast<OS_Windows*>(OS::get_singleton());
+ if (os_win)
+ return os_win->WndProc(hWnd,uMsg,wParam,lParam);
+ else
+ return DefWindowProcW(hWnd,uMsg,wParam,lParam);
+
+}
+
+void OS_Windows::probe_joysticks() {
+
+ int device_count = joyGetNumDevs();
+
+ JOYINFOEX jinfo;
+ jinfo.dwSize = sizeof(JOYINFOEX);
+ jinfo.dwFlags = JOY_RETURNALL;
+
+ for (int i=0; i<JOYSTICKS_MAX; i++) {
+
+ joysticks[i].attached = (device_count > 0) && (joyGetPosEx(JOYSTICKID1 + i, &jinfo) == JOYERR_NOERROR);
+
+ if (!joysticks[i].attached) {
+
+ continue;
+ };
+
+ joysticks[i].last_buttons = jinfo.dwButtons;
+
+ joysticks[i].last_axis[0] = jinfo.dwXpos;
+ joysticks[i].last_axis[1] = jinfo.dwYpos;
+ joysticks[i].last_axis[2] = jinfo.dwZpos;
+ joysticks[i].last_axis[3] = jinfo.dwRpos;
+ joysticks[i].last_axis[4] = jinfo.dwUpos;
+ joysticks[i].last_axis[5] = jinfo.dwVpos;
+ };
+};
+
+void OS_Windows::process_key_events() {
+
+ for(int i=0;i<key_event_pos;i++) {
+
+ KeyEvent &ke = key_event_buffer[i];
+ switch(ke.uMsg) {
+
+ case WM_CHAR: {
+
+ //do nothing
+ } break;
+ case WM_KEYUP:
+ case WM_KEYDOWN: {
+
+
+ InputEvent event;
+ event.type=InputEvent::KEY;
+ event.ID=++last_id;
+ InputEventKey &k=event.key;
+
+
+ k.mod=ke.mod_state;
+ k.pressed=(ke.uMsg==WM_KEYDOWN);
+
+ k.scancode=KeyMappingWindows::get_keysym(ke.wParam);
+ if (i+1 < key_event_pos && key_event_buffer[i+1].uMsg==WM_CHAR)
+ k.unicode=key_event_buffer[i+1].wParam;
+ if (k.unicode && gr_mem) {
+ k.mod.alt=false;
+ k.mod.control=false;
+ }
+
+ if (k.unicode<32)
+ k.unicode=0;
+
+
+
+ k.echo=(ke.uMsg==WM_KEYDOWN && (ke.lParam&(1<<30)));
+
+ input->parse_input_event(event);
+
+
+ } break;
+ }
+ }
+
+ key_event_pos=0;
+}
+
+void OS_Windows::_post_dpad(DWORD p_dpad, int p_device, bool p_pressed) {
+
+ InputEvent ievent;
+ ievent.device = p_device;
+ ievent.type = InputEvent::JOYSTICK_BUTTON;
+ ievent.joy_button.pressed = p_pressed;
+ ievent.joy_button.pressure = p_pressed ? 1.0 : 0.0;
+
+ if (p_dpad == 0) {
+
+ ievent.joy_button.button_index = JOY_DPAD_UP;
+ ievent.ID = ++last_id;
+ input->parse_input_event(ievent);
+
+ } else if (p_dpad == 4500) {
+
+ ievent.joy_button.button_index = JOY_DPAD_UP;
+ ievent.ID = ++last_id;
+ input->parse_input_event(ievent);
+
+ ievent.joy_button.button_index = JOY_DPAD_RIGHT;
+ ievent.ID = ++last_id;
+ input->parse_input_event(ievent);
+
+ } else if (p_dpad == 9000) {
+
+ ievent.joy_button.button_index = JOY_DPAD_RIGHT;
+ ievent.ID = ++last_id;
+ input->parse_input_event(ievent);
+
+ } else if (p_dpad == 13500) {
+
+ ievent.joy_button.button_index = JOY_DPAD_RIGHT;
+ ievent.ID = ++last_id;
+ input->parse_input_event(ievent);
+
+ ievent.joy_button.button_index = JOY_DPAD_DOWN;
+ ievent.ID = ++last_id;
+ input->parse_input_event(ievent);
+
+ } else if (p_dpad == 18000) {
+
+ ievent.joy_button.button_index = JOY_DPAD_DOWN;
+ ievent.ID = ++last_id;
+ input->parse_input_event(ievent);
+
+ } else if (p_dpad == 22500) {
+
+ ievent.joy_button.button_index = JOY_DPAD_DOWN;
+ ievent.ID = ++last_id;
+ input->parse_input_event(ievent);
+
+ ievent.joy_button.button_index = JOY_DPAD_LEFT;
+ ievent.ID = ++last_id;
+ input->parse_input_event(ievent);
+
+ } else if (p_dpad == 27000) {
+
+ ievent.joy_button.button_index = JOY_DPAD_LEFT;
+ ievent.ID = ++last_id;
+ input->parse_input_event(ievent);
+
+ } else if (p_dpad == 31500) {
+
+ ievent.joy_button.button_index = JOY_DPAD_LEFT;
+ ievent.ID = ++last_id;
+ input->parse_input_event(ievent);
+
+ ievent.joy_button.button_index = JOY_DPAD_UP;
+ ievent.ID = ++last_id;
+ input->parse_input_event(ievent);
+ };
+};
+
+void OS_Windows::process_joysticks() {
+
+ if (!main_loop) {
+ return;
+ };
+
+ InputEvent ievent;
+
+ JOYINFOEX jinfo;
+ jinfo.dwSize = sizeof(JOYINFOEX);
+ jinfo.dwFlags = JOY_RETURNALL;
+
+ for (int i=0; i<JOYSTICKS_MAX; i++) {
+
+ if (!joysticks[i].attached) {
+ continue;
+ };
+
+ if (joyGetPosEx(JOYSTICKID1 + i, &jinfo) != JOYERR_NOERROR) {
+
+ continue;
+ };
+
+ ievent.device = i;
+
+ #define CHECK_AXIS(n, var) \
+ if (joysticks[i].last_axis[n] != var) {\
+ ievent.type = InputEvent::JOYSTICK_MOTION;\
+ ievent.ID = ++last_id;\
+ ievent.joy_motion.axis = n;\
+ ievent.joy_motion.axis_value = (float)((int)var - MAX_JOY_AXIS) / (float)MAX_JOY_AXIS;\
+ joysticks[i].last_axis[n] = var;\
+ input->parse_input_event(ievent);\
+ };
+
+ CHECK_AXIS(0, jinfo.dwXpos);
+ CHECK_AXIS(1, jinfo.dwYpos);
+ CHECK_AXIS(2, jinfo.dwZpos);
+ CHECK_AXIS(3, jinfo.dwRpos);
+ CHECK_AXIS(4, jinfo.dwUpos);
+ CHECK_AXIS(5, jinfo.dwVpos);
+
+ if (joysticks[i].last_pov != jinfo.dwPOV) {
+
+ if (joysticks[i].last_pov != JOY_POVCENTERED)
+ _post_dpad(joysticks[i].last_pov, i, false);
+
+ if (jinfo.dwPOV != JOY_POVCENTERED)
+ _post_dpad(jinfo.dwPOV, i, true);
+
+ joysticks[i].last_pov = jinfo.dwPOV;
+ };
+
+ if (joysticks[i].last_buttons == jinfo.dwButtons) {
+ continue;
+ };
+
+ ievent.type = InputEvent::JOYSTICK_BUTTON;
+ for (int j=0; j<32; j++) {
+
+ if ( (joysticks[i].last_buttons & (1<<j)) != (jinfo.dwButtons & (1<<j)) ) {
+
+ ievent.joy_button.button_index = _pc_joystick_get_native_button(j);
+ ievent.joy_button.pressed = jinfo.dwButtons & 1<<j;
+ ievent.ID = ++last_id;
+ input->parse_input_event(ievent);
+ };
+ };
+
+ joysticks[i].last_buttons = jinfo.dwButtons;
+ };
+};
+
+void OS_Windows::initialize(const VideoMode& p_desired,int p_video_driver,int p_audio_driver) {
+
+
+
+ main_loop=NULL;
+ outside=true;
+
+ WNDCLASSEXW wc;
+
+ video_mode=p_desired;
+ //printf("**************** desired %s, mode %s\n", p_desired.fullscreen?"true":"false", video_mode.fullscreen?"true":"false");
+ RECT WindowRect;
+
+ WindowRect.left=0;
+ WindowRect.right=video_mode.width;
+ WindowRect.top=0;
+ WindowRect.bottom=video_mode.height;
+
+ memset(&wc,0,sizeof(WNDCLASSEXW));
+ wc.cbSize=sizeof(WNDCLASSEXW);
+ wc.style= CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS;
+ wc.lpfnWndProc = (WNDPROC)::WndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra= 0;
+ //wc.hInstance = hInstance;
+ wc.hInstance = godot_hinstance ? godot_hinstance : GetModuleHandle(NULL);
+ wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
+ wc.hCursor = NULL;//LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = NULL;
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = L"Engine";
+
+ if (!RegisterClassExW(&wc)) {
+ MessageBox(NULL,"Failed To Register The Window Class.","ERROR",MB_OK|MB_ICONEXCLAMATION);
+ return; // Return
+ }
+
+
+ if (video_mode.fullscreen) {
+
+ DEVMODE current;
+ memset(&current,0,sizeof(current));
+ EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &current);
+
+ DEVMODE dmScreenSettings;
+ memset(&dmScreenSettings,0,sizeof(dmScreenSettings));
+ dmScreenSettings.dmSize=sizeof(dmScreenSettings);
+ dmScreenSettings.dmPelsWidth = video_mode.width;
+ dmScreenSettings.dmPelsHeight = video_mode.height;
+ dmScreenSettings.dmBitsPerPel = current.dmBitsPerPel;
+ dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
+
+ LONG err = ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN);
+ if (err!=DISP_CHANGE_SUCCESSFUL) {
+
+ video_mode.fullscreen=false;
+ }
+ }
+
+ DWORD dwExStyle;
+ DWORD dwStyle;
+
+ if (video_mode.fullscreen) {
+
+ dwExStyle=WS_EX_APPWINDOW;
+ dwStyle=WS_POPUP;
+
+ } else {
+ dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
+ dwStyle=WS_OVERLAPPEDWINDOW;
+ }
+
+ AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);
+
+
+ char* windowid = getenv("GODOT_WINDOWID");
+ if (windowid) {
+
+ // strtoull on mingw
+ #ifdef MINGW_ENABLED
+ hWnd = (HWND)strtoull(windowid, NULL, 0);
+ #else
+ hWnd = (HWND)_strtoui64(windowid, NULL, 0);
+ #endif
+ SetLastError(0);
+ user_proc = (WNDPROC)GetWindowLongPtr(hWnd, GWLP_WNDPROC);
+ SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)(WNDPROC)::WndProc);
+ DWORD le = GetLastError();
+ if (user_proc == 0 && le != 0) {
+
+ printf("Error setting WNDPROC: %li\n", le);
+ };
+ LONG_PTR proc = GetWindowLongPtr(hWnd, GWLP_WNDPROC);
+
+ RECT rect;
+ if (!GetClientRect(hWnd, &rect)) {
+ MessageBoxW(NULL,L"Window Creation Error.",L"ERROR",MB_OK|MB_ICONEXCLAMATION);
+ return; // Return FALSE
+ };
+ video_mode.width = rect.right;
+ video_mode.height = rect.bottom;
+ video_mode.fullscreen = false;
+ } else {
+
+ if (!(hWnd=CreateWindowExW(dwExStyle,L"Engine",L"", dwStyle|WS_CLIPSIBLINGS|WS_CLIPCHILDREN, 0, 0,WindowRect.right-WindowRect.left,WindowRect.bottom-WindowRect.top, NULL,NULL, hInstance,NULL))) {
+ MessageBoxW(NULL,L"Window Creation Error.",L"ERROR",MB_OK|MB_ICONEXCLAMATION);
+ return; // Return FALSE
+ }
+
+
+ };
+
+#if defined(OPENGL_ENABLED) || defined(GLES2_ENABLED) || defined(LEGACYGL_ENABLED)
+ gl_context = memnew( ContextGL_Win(hWnd,false) );
+ gl_context->initialize();
+ rasterizer = memnew( RasterizerGLES2 );
+#else
+ #ifdef DX9_ENABLED
+ rasterizer = memnew( RasterizerDX9(hWnd) );
+ #endif
+#endif
+
+ visual_server = memnew( VisualServerRaster(rasterizer) );
+ if (get_render_thread_mode()!=RENDER_THREAD_UNSAFE) {
+
+ visual_server =memnew(VisualServerWrapMT(visual_server,get_render_thread_mode()==RENDER_SEPARATE_THREAD));
+ }
+
+ //
+ physics_server = memnew( PhysicsServerSW );
+ physics_server->init();
+
+ physics_2d_server = memnew( Physics2DServerSW );
+ physics_2d_server->init();
+
+ if (!is_no_window_mode_enabled()) {
+ ShowWindow(hWnd,SW_SHOW); // Show The Window
+ SetForegroundWindow(hWnd); // Slightly Higher Priority
+ SetFocus(hWnd); // Sets Keyboard Focus To
+ }
+
+/*
+ DEVMODE dmScreenSettings; // Device Mode
+ memset(&dmScreenSettings,0,sizeof(dmScreenSettings)); // Makes Sure Memory's Cleared
+ dmScreenSettings.dmSize=sizeof(dmScreenSettings); // Size Of The Devmode Structure
+ dmScreenSettings.dmPelsWidth = width; // Selected Screen Width
+ dmScreenSettings.dmPelsHeight = height; // Selected Screen Height
+ dmScreenSettings.dmBitsPerPel = bits; // Selected Bits Per Pixel
+ dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
+ if (ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL)
+
+
+
+
+ */
+ visual_server->init();
+
+ input = memnew( InputDefault );
+
+ AudioDriverManagerSW::get_driver(p_audio_driver)->set_singleton();
+
+ if (AudioDriverManagerSW::get_driver(p_audio_driver)->init()!=OK) {
+
+ ERR_PRINT("Initializing audio failed.");
+ }
+
+ sample_manager = memnew( SampleManagerMallocSW );
+ audio_server = memnew( AudioServerSW(sample_manager) );
+
+ audio_server->init();
+
+ spatial_sound_server = memnew( SpatialSoundServerSW );
+ spatial_sound_server->init();
+ spatial_sound_2d_server = memnew( SpatialSound2DServerSW );
+ spatial_sound_2d_server->init();
+
+ probe_joysticks();
+
+ TRACKMOUSEEVENT tme;
+ tme.cbSize=sizeof(TRACKMOUSEEVENT);
+ tme.dwFlags=TME_LEAVE;
+ tme.hwndTrack=hWnd;
+ tme.dwHoverTime=HOVER_DEFAULT;
+ TrackMouseEvent(&tme);
+
+
+ _ensure_data_dir();
+
+
+}
+
+void OS_Windows::set_clipboard(const String& p_text) {
+
+ if (!OpenClipboard(hWnd)) {
+ ERR_EXPLAIN("Unable to open clipboard.");
+ ERR_FAIL();
+ };
+ EmptyClipboard();
+
+ HGLOBAL mem = GlobalAlloc(GMEM_MOVEABLE, (p_text.length() + 1) * sizeof(CharType));
+ if (mem == NULL) {
+ ERR_EXPLAIN("Unable to allocate memory for clipboard contents.");
+ ERR_FAIL();
+ };
+ LPWSTR lptstrCopy = (LPWSTR)GlobalLock(mem);
+ memcpy(lptstrCopy, p_text.c_str(), (p_text.length() + 1) * sizeof(CharType));
+ //memset((lptstrCopy + p_text.length()), 0, sizeof(CharType));
+ GlobalUnlock(mem);
+
+ SetClipboardData(CF_UNICODETEXT, mem);
+
+ // set the CF_TEXT version (not needed?)
+ CharString utf8 = p_text.utf8();
+ mem = GlobalAlloc(GMEM_MOVEABLE, utf8.length() + 1);
+ if (mem == NULL) {
+ ERR_EXPLAIN("Unable to allocate memory for clipboard contents.");
+ ERR_FAIL();
+ };
+ LPTSTR ptr = (LPTSTR)GlobalLock(mem);
+ memcpy(ptr, utf8.get_data(), utf8.length());
+ ptr[utf8.length()] = 0;
+ GlobalUnlock(mem);
+
+ SetClipboardData(CF_TEXT, mem);
+
+ CloseClipboard();
+};
+
+String OS_Windows::get_clipboard() const {
+
+ String ret;
+ if (!OpenClipboard(hWnd)) {
+ ERR_EXPLAIN("Unable to open clipboard.");
+ ERR_FAIL_V("");
+ };
+
+ if (IsClipboardFormatAvailable(CF_UNICODETEXT)) {
+
+ HGLOBAL mem = GetClipboardData(CF_UNICODETEXT);
+ if (mem != NULL) {
+
+ LPWSTR ptr = (LPWSTR)GlobalLock(mem);
+ if (ptr != NULL) {
+
+ ret = String((CharType*)ptr);
+ GlobalUnlock(mem);
+ };
+ };
+
+ } else if (IsClipboardFormatAvailable(CF_TEXT)) {
+
+ HGLOBAL mem = GetClipboardData(CF_UNICODETEXT);
+ if (mem != NULL) {
+
+ LPTSTR ptr = (LPTSTR)GlobalLock(mem);
+ if (ptr != NULL) {
+
+ ret.parse_utf8((const char*)ptr);
+ GlobalUnlock(mem);
+ };
+ };
+ };
+
+ CloseClipboard();
+
+ return ret;
+};
+
+
+void OS_Windows::delete_main_loop() {
+
+ if (main_loop)
+ memdelete(main_loop);
+ main_loop=NULL;
+}
+
+void OS_Windows::set_main_loop( MainLoop * p_main_loop ) {
+
+ input->set_main_loop(p_main_loop);
+ main_loop=p_main_loop;
+}
+
+void OS_Windows::finalize() {
+
+ if(main_loop)
+ memdelete(main_loop);
+
+ main_loop=NULL;
+
+ visual_server->finish();
+ memdelete(visual_server);
+#ifdef OPENGL_ENABLED
+ if (gl_context)
+ memdelete(gl_context);
+#endif
+ if (rasterizer)
+ memdelete(rasterizer);
+
+ if (user_proc) {
+ SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)user_proc);
+ };
+
+ spatial_sound_server->finish();
+ memdelete(spatial_sound_server);
+ spatial_sound_2d_server->finish();
+ memdelete(spatial_sound_2d_server);
+
+ //if (debugger_connection_console) {
+// memdelete(debugger_connection_console);
+//}
+
+ audio_server->finish();
+ memdelete(audio_server);
+ memdelete(sample_manager);
+
+ memdelete(input);
+
+ physics_server->finish();
+ memdelete(physics_server);
+
+ physics_2d_server->finish();
+ memdelete(physics_2d_server);
+
+}
+void OS_Windows::finalize_core() {
+
+ memdelete(process_map);
+
+ if (mempool_dynamic)
+ memdelete( mempool_dynamic );
+ if (mempool_static)
+ delete mempool_static;
+
+
+ TCPServerWinsock::cleanup();
+ StreamPeerWinsock::cleanup();
+}
+
+void OS_Windows::vprint(const char* p_format, va_list p_list, bool p_stderr) {
+
+ char buf[16384+1];
+ int len = vsnprintf(buf,16384,p_format,p_list);
+ if (len<=0)
+ return;
+ buf[len]=0;
+
+
+ int wlen = MultiByteToWideChar(CP_UTF8,0,buf,len,NULL,0);
+ if (wlen<0)
+ return;
+
+ wchar_t *wbuf = (wchar_t*)malloc((len+1)*sizeof(wchar_t));
+ MultiByteToWideChar(CP_UTF8,0,buf,len,wbuf,wlen);
+ wbuf[wlen]=0;
+
+ if (p_stderr)
+ fwprintf(stderr,L"%s",wbuf);
+ else
+ wprintf(L"%s",wbuf);
+
+#ifdef STDOUT_FILE
+ //vwfprintf(stdo,p_format,p_list);
+#endif
+ free(wbuf);
+
+ fflush(stdout);
+};
+
+void OS_Windows::alert(const String& p_alert,const String& p_title) {
+
+ if (!is_no_window_mode_enabled())
+ MessageBoxW(NULL,p_alert.c_str(),p_title.c_str(),MB_OK|MB_ICONEXCLAMATION);
+ else
+ print_line("ALERT: "+p_alert);
+}
+
+void OS_Windows::set_mouse_mode(MouseMode p_mode) {
+
+ if (mouse_mode==p_mode)
+ return;
+ ShowCursor(p_mode==MOUSE_MODE_VISIBLE);
+ mouse_mode=p_mode;
+ if (p_mode==MOUSE_MODE_CAPTURED) {
+ RECT clipRect;
+ GetClientRect(hWnd, &clipRect);
+ ClientToScreen(hWnd, (POINT*) &clipRect.left);
+ ClientToScreen(hWnd, (POINT*) &clipRect.right);
+ ClipCursor(&clipRect);
+ SetCapture(hWnd);
+ center=Point2i(video_mode.width/2,video_mode.height/2);
+ POINT pos = { (int) center.x, (int) center.y };
+ ClientToScreen(hWnd, &pos);
+ SetCursorPos(pos.x, pos.y);
+ } else {
+ ReleaseCapture();
+ ClipCursor(NULL);
+ }
+
+}
+
+OS_Windows::MouseMode OS_Windows::get_mouse_mode() const{
+
+ return mouse_mode;
+}
+
+
+
+Point2 OS_Windows::get_mouse_pos() const {
+
+ return Point2(old_x, old_y);
+}
+
+int OS_Windows::get_mouse_button_state() const {
+
+ return last_button_state;
+}
+
+void OS_Windows::set_window_title(const String& p_title) {
+
+ SetWindowTextW(hWnd,p_title.c_str());
+}
+
+void OS_Windows::set_video_mode(const VideoMode& p_video_mode,int p_screen) {
+
+
+}
+OS::VideoMode OS_Windows::get_video_mode(int p_screen) const {
+
+ return video_mode;
+}
+void OS_Windows::get_fullscreen_mode_list(List<VideoMode> *p_list,int p_screen) const {
+
+
+}
+
+void OS_Windows::print_error(const char* p_function,const char* p_file,int p_line,const char *p_code,const char*p_rationale,ErrorType p_type) {
+
+ HANDLE hCon=GetStdHandle(STD_OUTPUT_HANDLE);
+ if (!hCon || hCon==INVALID_HANDLE_VALUE) {
+ if (p_rationale && p_rationale[0]) {
+
+ print("\E[1;31;40mERROR: %s: \E[1;37;40m%s\n",p_function,p_rationale);
+ print("\E[0;31;40m At: %s:%i.\E[0;0;37m\n",p_file,p_line);
+
+ } else {
+ print("\E[1;31;40mERROR: %s: \E[1;37;40m%s\n",p_function,p_code);
+ print("\E[0;31;40m At: %s:%i.\E[0;0;37m\n",p_file,p_line);
+
+ }
+ } else {
+
+ CONSOLE_SCREEN_BUFFER_INFO sbi; //original
+ GetConsoleScreenBufferInfo(hCon,&sbi);
+
+ SetConsoleTextAttribute(hCon,sbi.wAttributes);
+
+
+
+ uint32_t basecol=0;
+ switch(p_type) {
+ case ERR_ERROR: basecol = FOREGROUND_RED; break;
+ case ERR_WARNING: basecol = FOREGROUND_RED|FOREGROUND_GREEN; break;
+ case ERR_SCRIPT: basecol = FOREGROUND_GREEN; break;
+ }
+
+ if (p_rationale && p_rationale[0]) {
+
+ SetConsoleTextAttribute(hCon,basecol|FOREGROUND_INTENSITY);
+
+
+ switch(p_type) {
+ case ERR_ERROR: print("ERROR: "); break;
+ case ERR_WARNING: print("WARNING: "); break;
+ case ERR_SCRIPT: print("SCRIPT ERROR: "); break;
+ }
+
+ SetConsoleTextAttribute(hCon,FOREGROUND_RED|FOREGROUND_BLUE|FOREGROUND_GREEN|FOREGROUND_INTENSITY);
+ print(" %s\n",p_rationale);
+ SetConsoleTextAttribute(hCon,basecol);
+ print("At: ");
+ SetConsoleTextAttribute(hCon,FOREGROUND_RED|FOREGROUND_BLUE|FOREGROUND_GREEN);
+ print(" %s:%i\n",p_file,p_line);
+
+
+ } else {
+ SetConsoleTextAttribute(hCon,basecol|FOREGROUND_INTENSITY);
+ switch(p_type) {
+ case ERR_ERROR: print("ERROR: %s: ",p_function); break;
+ case ERR_WARNING: print("WARNING: %s: ",p_function); break;
+ case ERR_SCRIPT: print("SCRIPT ERROR: %s: ",p_function); break;
+ }
+ SetConsoleTextAttribute(hCon,FOREGROUND_RED|FOREGROUND_BLUE|FOREGROUND_GREEN|FOREGROUND_INTENSITY);
+ print(" %s\n",p_code);
+ SetConsoleTextAttribute(hCon,basecol);
+ print("At: ");
+ SetConsoleTextAttribute(hCon,FOREGROUND_RED|FOREGROUND_BLUE|FOREGROUND_GREEN);
+ print(" %s:%i\n",p_file,p_line);
+ }
+
+ SetConsoleTextAttribute(hCon,sbi.wAttributes);
+ }
+
+}
+
+
+String OS_Windows::get_name() {
+
+ return "Windows";
+}
+
+OS::Date OS_Windows::get_date() const {
+
+ SYSTEMTIME systemtime;
+ GetSystemTime(&systemtime);
+ Date date;
+ date.day=systemtime.wDay;
+ date.month=Month(systemtime.wMonth);
+ date.weekday=Weekday(systemtime.wDayOfWeek);
+ date.year=systemtime.wYear;
+ date.dst=false;
+ return date;
+}
+OS::Time OS_Windows::get_time() const {
+
+ SYSTEMTIME systemtime;
+ GetSystemTime(&systemtime);
+
+ Time time;
+ time.hour=systemtime.wHour;
+ time.min=systemtime.wMinute;
+ time.sec=systemtime.wSecond;
+ return time;
+}
+
+uint64_t OS_Windows::get_unix_time() const {
+
+ FILETIME ft;
+ SYSTEMTIME st;
+ GetSystemTime(&st);
+ SystemTimeToFileTime(&st, &ft);
+
+ SYSTEMTIME ep;
+ ep.wYear = 1970;
+ ep.wMonth = 1;
+ ep.wDayOfWeek = 4;
+ ep.wDay = 1;
+ ep.wHour = 0;
+ ep.wMinute = 0;
+ ep.wSecond = 0;
+ ep.wMilliseconds = 0;
+ FILETIME fep;
+ SystemTimeToFileTime(&ep, &fep);
+
+ return (*(uint64_t*)&ft - *(uint64_t*)&fep) / 10000000;
+};
+
+void OS_Windows::delay_usec(uint32_t p_usec) const {
+
+ if (p_usec < 1000)
+ Sleep(1);
+ else
+ Sleep(p_usec / 1000);
+
+}
+uint64_t OS_Windows::get_ticks_usec() const {
+
+ uint64_t ticks;
+ uint64_t time;
+ // This is the number of clock ticks since start
+ if( !QueryPerformanceCounter((LARGE_INTEGER *)&ticks) )
+ ticks = (UINT64)timeGetTime();
+ // Divide by frequency to get the time in seconds
+ time = ticks * 1000000L / ticks_per_second;
+ // Subtract the time at game start to get
+ // the time since the game started
+ time -= ticks_start;
+ return time;
+}
+
+
+void OS_Windows::process_events() {
+
+ MSG msg;
+
+ process_joysticks();
+
+ while(PeekMessageW(&msg,NULL,0,0,PM_REMOVE)) {
+
+
+ TranslateMessage(&msg);
+ DispatchMessageW(&msg);
+
+ }
+
+ process_key_events();
+
+}
+
+void OS_Windows::set_cursor_shape(CursorShape p_shape) {
+
+ ERR_FAIL_INDEX(p_shape,CURSOR_MAX);
+
+ if (cursor_shape==p_shape)
+ return;
+
+ static const LPCTSTR win_cursors[CURSOR_MAX]={
+ IDC_ARROW,
+ IDC_IBEAM,
+ IDC_HAND,//finger
+ IDC_CROSS,
+ IDC_WAIT,
+ IDC_APPSTARTING,
+ IDC_ARROW,
+ IDC_ARROW,
+ IDC_NO,
+ IDC_SIZENS,
+ IDC_SIZEWE,
+ IDC_SIZENESW,
+ IDC_SIZENWSE,
+ IDC_SIZEALL,
+ IDC_SIZENS,
+ IDC_SIZEWE,
+ IDC_HELP
+ };
+
+ SetCursor(LoadCursor(hInstance,win_cursors[p_shape]));
+ cursor_shape=p_shape;
+}
+
+Error OS_Windows::execute(const String& p_path, const List<String>& p_arguments,bool p_blocking,ProcessID *r_child_id,String* r_pipe,int *r_exitcode) {
+
+ if (p_blocking && r_pipe) {
+
+
+ String argss;
+ argss="\"\""+p_path+"\"";
+
+ for(int i=0;i<p_arguments.size();i++) {
+
+ argss+=String(" \"")+p_arguments[i]+"\"";
+ }
+
+// print_line("ARGS: "+argss);
+ //argss+"\"";
+ //argss+=" 2>nul";
+
+ FILE* f=_wpopen(argss.c_str(),L"r");
+
+ ERR_FAIL_COND_V(!f,ERR_CANT_OPEN);
+
+ char buf[65535];
+ while(fgets(buf,65535,f)) {
+
+ (*r_pipe)+=buf;
+ }
+
+ int rv = _pclose(f);
+ if (r_exitcode)
+ *r_exitcode=rv;
+
+ return OK;
+ }
+
+ String cmdline = "\""+p_path+"\"";
+ const List<String>::Element* I = p_arguments.front();
+ while (I) {
+
+
+ cmdline += " \""+I->get() + "\"";
+
+ I = I->next();
+ };
+
+ //cmdline+="\"";
+
+ ProcessInfo pi;
+ ZeroMemory( &pi.si, sizeof(pi.si) );
+ pi.si.cb = sizeof(pi.si);
+ ZeroMemory( &pi.pi, sizeof(pi.pi) );
+
+ print_line("running cmdline: "+cmdline);
+
+ int ret = CreateProcess(NULL, (LPSTR)cmdline.utf8().get_data(), NULL, NULL, 0, NORMAL_PRIORITY_CLASS, NULL, NULL, &pi.si, &pi.pi);
+ ERR_FAIL_COND_V(ret == 0, ERR_CANT_FORK);
+
+ if (p_blocking) {
+
+ DWORD ret = WaitForSingleObject(pi.pi.hProcess, INFINITE);
+ if (r_exitcode)
+ *r_exitcode=ret;
+
+ } else {
+
+ ProcessID pid = pi.pi.dwProcessId;
+ if (r_child_id) {
+ *r_child_id = pid;
+ };
+ process_map->insert(pid, pi);
+ };
+ return OK;
+};
+
+Error OS_Windows::kill(const ProcessID& p_pid) {
+
+ HANDLE h;
+
+ if (process_map->has(p_pid)) {
+ h = (*process_map)[p_pid].pi.hProcess;
+ process_map->erase(p_pid);
+ } else {
+
+ ERR_FAIL_COND_V(!process_map->has(p_pid), FAILED);
+ };
+
+ int ret = TerminateProcess(h, 0);
+
+ return ret != 0?OK:FAILED;
+};
+
+Error OS_Windows::set_cwd(const String& p_cwd) {
+
+ if (_wchdir(p_cwd.c_str())!=0)
+ return ERR_CANT_OPEN;
+
+ return OK;
+}
+
+void OS_Windows::set_icon(const Image& p_icon) {
+
+
+ Image icon=p_icon;
+ if (icon.get_format()!=Image::FORMAT_RGBA)
+ icon.convert(Image::FORMAT_RGBA);
+ int w = icon.get_width();
+ int h = icon.get_height();
+
+ /* Create temporary bitmap buffer */
+ int icon_len = 40 + h * w * 4;
+ BYTE *icon_bmp = (BYTE*)alloca(icon_len);
+
+ encode_uint32(40,&icon_bmp[0]);
+ encode_uint32(w,&icon_bmp[4]);
+ encode_uint32(h*2,&icon_bmp[8]);
+ encode_uint16(1,&icon_bmp[12]);
+ encode_uint16(32,&icon_bmp[14]);
+ encode_uint32(BI_RGB,&icon_bmp[16]);
+ encode_uint32(w*h*4,&icon_bmp[20]);
+ encode_uint32(0,&icon_bmp[24]);
+ encode_uint32(0,&icon_bmp[28]);
+ encode_uint32(0,&icon_bmp[32]);
+ encode_uint32(0,&icon_bmp[36]);
+
+ uint8_t *wr=&icon_bmp[40];
+ DVector<uint8_t>::Read r= icon.get_data().read();
+
+ for(int i=0;i<h;i++) {
+
+ for(int j=0;j<w;j++) {
+
+ const uint8_t *rpx = &r[((h-i-1)*w+j)*4];
+ uint8_t *wpx = &wr[(i*w+j)*4];
+ wpx[0]=rpx[2];
+ wpx[1]=rpx[1];
+ wpx[2]=rpx[0];
+ wpx[3]=rpx[3];
+ }
+ }
+
+
+ HICON hicon = CreateIconFromResource(icon_bmp, icon_len, TRUE, 0x00030000);
+
+ /* Set the icon for the window */
+ SendMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM) hicon);
+
+ /* Set the icon in the task manager (should we do this?) */
+ SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM) hicon);
+}
+
+
+bool OS_Windows::has_environment(const String& p_var) const {
+
+ return getenv(p_var.utf8().get_data()) != NULL;
+};
+
+String OS_Windows::get_environment(const String& p_var) const {
+
+ return getenv(p_var.utf8().get_data());
+};
+
+String OS_Windows::get_stdin_string(bool p_block) {
+
+ if (p_block) {
+ char buff[1024];
+ return fgets(buff,1024,stdin);
+ };
+
+ return String();
+}
+
+
+void OS_Windows::move_window_to_foreground() {
+
+ SetForegroundWindow(hWnd);
+
+}
+
+String OS_Windows::get_locale() const {
+
+ const _WinLocale *wl = &_win_locales[0];
+
+ LANGID langid = GetUserDefaultUILanguage();
+ String neutral;
+ int lang = langid&((1<<9)-1);
+ int sublang = langid&~((1<<9)-1);
+
+ while(wl->locale) {
+
+ if (wl->main_lang==lang && wl->sublang==SUBLANG_NEUTRAL)
+ neutral=wl->locale;
+
+ if (lang==wl->main_lang && sublang==wl->sublang)
+ return wl->locale;
+
+
+ wl++;
+ }
+
+ if (neutral!="")
+ return neutral;
+
+ return "en";
+}
+
+void OS_Windows::release_rendering_thread() {
+
+ gl_context->release_current();
+
+}
+
+void OS_Windows::make_rendering_thread() {
+
+ gl_context->make_current();
+}
+
+void OS_Windows::swap_buffers() {
+
+ gl_context->swap_buffers();
+}
+
+
+void OS_Windows::run() {
+
+ if (!main_loop)
+ return;
+
+ main_loop->init();
+
+ uint64_t last_ticks=get_ticks_usec();
+
+ int frames=0;
+ uint64_t frame=0;
+
+ while (!force_quit) {
+
+ process_events(); // get rid of pending events
+ if (Main::iteration()==true)
+ break;
+ };
+
+ main_loop->finish();
+
+}
+
+
+
+MainLoop *OS_Windows::get_main_loop() const {
+
+ return main_loop;
+}
+
+
+String OS_Windows::get_data_dir() const {
+
+ String an = Globals::get_singleton()->get("application/name");
+ if (an!="") {
+
+ if (has_environment("APPDATA")) {
+
+ return OS::get_singleton()->get_environment("APPDATA")+"\\"+an;
+ }
+ }
+
+ return Globals::get_singleton()->get_resource_path();
+
+
+}
+
+
+OS_Windows::OS_Windows(HINSTANCE _hInstance) {
+
+ key_event_pos=0;
+ force_quit=false;
+ alt_mem=false;
+ gr_mem=false;
+ shift_mem=false;
+ control_mem=false;
+ meta_mem=false;
+ minimized = false;
+
+ hInstance=_hInstance;
+ pressrc=0;
+ old_invalid=true;
+ last_id=0;
+ mouse_mode=MOUSE_MODE_VISIBLE;
+#ifdef STDOUT_FILE
+ stdo=fopen("stdout.txt","wb");
+#endif
+ user_proc = NULL;
+
+#ifdef RTAUDIO_ENABLED
+ AudioDriverManagerSW::add_driver(&driver_rtaudio);
+#endif
+
+}
+
+
+OS_Windows::~OS_Windows()
+{
+#ifdef STDOUT_FILE
+ fclose(stdo);
+#endif
+}
+
+