#include <SDL2/SDL.h>
#include "video.h"
#include "wx-sdl2-video.h"
#include "wx-utils.h"
#include "ibm.h"
#include "wx-display.h"
#include "plat-keyboard.h"

#ifdef __WINDOWS__
#define BITMAP WINDOWS_BITMAP
#undef UNICODE
#include <windows.h>
#include <windowsx.h>
#undef BITMAP

HHOOK hKeyboardHook;
int modkeystate[255];

#endif

SDL_mutex *rendererMutex;
SDL_cond *rendererCond;
SDL_Thread *renderthread = NULL;

SDL_Window *window = NULL;

int rendering = 0;

int mousecapture = 0;

extern int pause;
extern int video_scale;
extern int take_screenshot;

void *ghwnd;
void *menu;

SDL_Rect remembered_rect;
int remembered_mouse_x = 0;
int remembered_mouse_y = 0;

int custom_resolution_width = 640;
int custom_resolution_height = 480;

int win_doresize = 0;
int winsizex = 640, winsizey = 480;

void renderer_start();
void renderer_stop(int timeout);

int trigger_fullscreen = 0;
int trigger_screenshot = 0;
int trigger_togglewindow = 0;
int trigger_inputrelease = 0;

extern void device_force_redraw();
extern void mouse_wheel_update(int);
extern void toggle_fullscreen();

void display_resize(int width, int height) {
	winsizex = width * (video_scale + 1) >> 1;
	winsizey = height * (video_scale + 1) >> 1;

	SDL_Rect rect;
	rect.x = rect.y = 0;
	rect.w = winsizex;
	rect.h = winsizey;
	sdl_scale(video_fullscreen_scale, rect, &rect, winsizex, winsizey);
	winsizex = rect.w;
	winsizey = rect.h;

	win_doresize = 1;
}

void releasemouse() {
	if (mousecapture) {
		SDL_SetWindowGrab(window, SDL_FALSE);
		SDL_SetRelativeMouseMode(SDL_FALSE);
		mousecapture = 0;
	}
}

int display_init() {
	if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0) {
		printf("SDL could not initialize! Error: %s\n", SDL_GetError());
		return 0;
	}

	SDL_version ver;
	SDL_GetVersion(&ver);
	printf("SDL %i.%i.%i initialized.\n", ver.major, ver.minor, ver.patch);
	return 1;
}

void display_close() {
	SDL_Quit();
}

void display_start(void *hwnd) {
	ghwnd = hwnd;
	menu = wx_getmenu(hwnd);
	atexit(releasemouse);
	rendererMutex = SDL_CreateMutex();
	rendererCond = SDL_CreateCond();
	renderer_start();
}

void display_stop() {
	renderer_stop(10 * 1000);

	SDL_DestroyMutex(rendererMutex);
	SDL_DestroyCond(rendererCond);
#if SDL_VERSION_ATLEAST(2, 0, 2)
	SDL_DetachThread(renderthread);
#endif
	releasemouse();
}

int is_fullscreen() {
	int flags = SDL_GetWindowFlags(window);
	return (flags & SDL_WINDOW_FULLSCREEN) || (flags & SDL_WINDOW_FULLSCREEN_DESKTOP);
}

void sdl_set_window_title(const char *title) {
	if (window && !is_fullscreen())
		SDL_SetWindowTitle(window, title);
}

int get_border_size(int *top, int *left, int *bottom, int *right) {
#if SDL_VERSION_ATLEAST(2, 0, 5)
	return SDL_GetWindowBordersSize(window, top, left, bottom, right);
#else
	if (top) *top = 0;
	if (left) *left = 0;
	if (bottom) *bottom = 0;
	if (right) *right = 0;
	return 0;
#endif
}

static const struct {
	SDL_Scancode sdl;
	int system;
} SDLScancodeToSystemScancode[] = {
	{SDL_SCANCODE_A, 0x1e},
	{SDL_SCANCODE_B, 0x30},
	{SDL_SCANCODE_C, 0x2e},
	{SDL_SCANCODE_D, 0x20},
	{SDL_SCANCODE_E, 0x12},
	{SDL_SCANCODE_F, 0x21},
	{SDL_SCANCODE_G, 0x22},
	{SDL_SCANCODE_H, 0x23},
	{SDL_SCANCODE_I, 0x17},
	{SDL_SCANCODE_J, 0x24},
	{SDL_SCANCODE_K, 0x25},
	{SDL_SCANCODE_L, 0x26},
	{SDL_SCANCODE_M, 0x32},
	{SDL_SCANCODE_N, 0x31},
	{SDL_SCANCODE_O, 0x18},
	{SDL_SCANCODE_P, 0x19},
	{SDL_SCANCODE_Q, 0x10},
	{SDL_SCANCODE_R, 0x13},
	{SDL_SCANCODE_S, 0x1f},
	{SDL_SCANCODE_T, 0x14},
	{SDL_SCANCODE_U, 0x16},
	{SDL_SCANCODE_V, 0x2f},
	{SDL_SCANCODE_W, 0x11},
	{SDL_SCANCODE_X, 0x2d},
	{SDL_SCANCODE_Y, 0x15},
	{SDL_SCANCODE_Z, 0x2c},
	{SDL_SCANCODE_0, 0x0B},
	{SDL_SCANCODE_1, 0x02},
	{SDL_SCANCODE_2, 0x03},
	{SDL_SCANCODE_3, 0x04},
	{SDL_SCANCODE_4, 0x05},
	{SDL_SCANCODE_5, 0x06},
	{SDL_SCANCODE_6, 0x07},
	{SDL_SCANCODE_7, 0x08},
	{SDL_SCANCODE_8, 0x09},
	{SDL_SCANCODE_9, 0x0A},
	{SDL_SCANCODE_GRAVE, 0x29},
	{SDL_SCANCODE_MINUS, 0x0c},
	{SDL_SCANCODE_EQUALS, 0x0d},
	{SDL_SCANCODE_NONUSBACKSLASH, 0x56},
	{SDL_SCANCODE_BACKSLASH, 0x2b},
	{SDL_SCANCODE_BACKSPACE, 0x0e},
	{SDL_SCANCODE_SPACE, 0x39},
	{SDL_SCANCODE_TAB, 0x0f},
	{SDL_SCANCODE_CAPSLOCK, 0x3a},
	{SDL_SCANCODE_LSHIFT, 0x2a},
	{SDL_SCANCODE_LCTRL, 0x1d},
	{SDL_SCANCODE_LGUI, 0xdb},
	{SDL_SCANCODE_LALT, 0x38},
	{SDL_SCANCODE_RSHIFT, 0x36},
	{SDL_SCANCODE_RCTRL, 0x9d},
	{SDL_SCANCODE_RGUI, 0xdc},
	{SDL_SCANCODE_RALT, 0xb8},
	{SDL_SCANCODE_SYSREQ, 0x54},
	{SDL_SCANCODE_APPLICATION, 0xdd},
	{SDL_SCANCODE_RETURN, 0x1c},
	{SDL_SCANCODE_ESCAPE, 0x01},
	{SDL_SCANCODE_F1, 0x3B},
	{SDL_SCANCODE_F2, 0x3C},
	{SDL_SCANCODE_F3, 0x3D},
	{SDL_SCANCODE_F4, 0x3e},
	{SDL_SCANCODE_F5, 0x3f},
	{SDL_SCANCODE_F6, 0x40},
	{SDL_SCANCODE_F7, 0x41},
	{SDL_SCANCODE_F8, 0x42},
	{SDL_SCANCODE_F9, 0x43},
	{SDL_SCANCODE_F10, 0x44},
	{SDL_SCANCODE_F11, 0x57},
	{SDL_SCANCODE_F12, 0x58},
	{SDL_SCANCODE_SCROLLLOCK, 0x46},
	{SDL_SCANCODE_LEFTBRACKET, 0x1a},
	{SDL_SCANCODE_RIGHTBRACKET, 0x1b},
	{SDL_SCANCODE_INSERT, 0xd2},
	{SDL_SCANCODE_HOME, 0xc7},
	{SDL_SCANCODE_PAGEUP, 0xc9},
	{SDL_SCANCODE_DELETE, 0xd3},
	{SDL_SCANCODE_END, 0xcf},
	{SDL_SCANCODE_PAGEDOWN, 0xd1},
	{SDL_SCANCODE_UP, 0xc8},
	{SDL_SCANCODE_LEFT, 0xcb},
	{SDL_SCANCODE_DOWN, 0xd0},
	{SDL_SCANCODE_RIGHT, 0xcd},
	{SDL_SCANCODE_NUMLOCKCLEAR, 0x45},
	{SDL_SCANCODE_KP_DIVIDE, 0xb5},
	{SDL_SCANCODE_KP_MULTIPLY, 0x37},
	{SDL_SCANCODE_KP_MINUS, 0x4a},
	{SDL_SCANCODE_KP_PLUS, 0x4e},
	{SDL_SCANCODE_KP_ENTER, 0x9c},
	{SDL_SCANCODE_KP_PERIOD, 0x53},
	{SDL_SCANCODE_KP_0, 0x52},
	{SDL_SCANCODE_KP_1, 0x4f},
	{SDL_SCANCODE_KP_2, 0x50},
	{SDL_SCANCODE_KP_3, 0x51},
	{SDL_SCANCODE_KP_4, 0x4b},
	{SDL_SCANCODE_KP_5, 0x4c},
	{SDL_SCANCODE_KP_6, 0x4d},
	{SDL_SCANCODE_KP_7, 0x47},
	{SDL_SCANCODE_KP_8, 0x48},
	{SDL_SCANCODE_KP_9, 0x49},
	{SDL_SCANCODE_SEMICOLON, 0x27},
	{SDL_SCANCODE_APOSTROPHE, 0x28},
	{SDL_SCANCODE_COMMA, 0x33},
	{SDL_SCANCODE_PERIOD, 0x34},
	{SDL_SCANCODE_SLASH, 0x35},
	{SDL_SCANCODE_PRINTSCREEN, 0xb7}
};

int sdl_scancode(SDL_Scancode scancode) {
	int i;
	for (i = 0; i < SDL_arraysize(SDLScancodeToSystemScancode); ++i) {
		if (SDLScancodeToSystemScancode[i].sdl == scancode) {
			return SDLScancodeToSystemScancode[i].system;
		}
	}
	return -1;
}

SDL_Event event;
SDL_Rect rect;
int border_x, border_y = 0;

uint64_t render_time = 0;
int render_fps = 0;
uint32_t render_frame_time = 0;
uint32_t render_frames = 0;

void window_setup() {
	SDL_SetHint(SDL_HINT_GRAB_KEYBOARD, "1");
#if SDL_VERSION_ATLEAST(2, 0, 5)
	SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1");
#endif

	if (start_in_fullscreen) {
		start_in_fullscreen = 0;
		window_dofullscreen = 1;
		window_doinputgrab = 1;
	}

	if (window_remember) {
		rect.x = window_x;
		rect.y = window_y;
		rect.w = window_w;
		rect.h = window_h;
	} else {
		rect.x = SDL_WINDOWPOS_CENTERED;
		rect.y = SDL_WINDOWPOS_CENTERED;
		rect.w = 640;
		rect.h = 480;
	}

	if (vid_resize == 2) {
		rect.w = custom_resolution_width;
		rect.h = custom_resolution_height;
	}
}

#ifdef __WINDOWS__
int sdl_winhook(int code) {
	switch (code) {
	case VK_LMENU:return SDL_SCANCODE_LALT;
	case VK_LCONTROL:return SDL_SCANCODE_LCTRL;
	case VK_LWIN:return SDL_SCANCODE_LGUI;
	case VK_LSHIFT:return SDL_SCANCODE_LSHIFT;
	case VK_RMENU:return SDL_SCANCODE_RALT;
	case VK_RCONTROL:return SDL_SCANCODE_RCTRL;
	case VK_RWIN:return SDL_SCANCODE_RGUI;
	case VK_RSHIFT:return SDL_SCANCODE_RSHIFT;
	}

	return -1;
}

LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) {
	KBDLLHOOKSTRUCT *p = (KBDLLHOOKSTRUCT *)lParam;

	int c = p->vkCode;

	int steal = 0;
	int s = sdl_winhook(c);
	if (s != -1) {
		int key_state = !(p->flags & LLKHF_UP);
		if (abs(modkeystate[c]) != key_state) {
			/* if mousecapture is 0, key_state should be negative */
			if (!mousecapture)
				key_state = -key_state;
			/* if key_state is 0 and modkeystate[c] is negative,
			 an sdl_event should not be generated */
			if (key_state > 0 || modkeystate[c] > 0) {
				steal = key_state != 0;
				SDL_Event event;
				event.key.keysym.scancode = s;
				event.key.timestamp = p->time;

				event.type = key_state ? SDL_KEYDOWN : SDL_KEYUP;
				SDL_PushEvent(&event);
			}
			modkeystate[c] = key_state;
		}
		if (steal)
			return 1;
	}

	return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
}
#endif

int window_create() {
	window = SDL_CreateWindow("PCem Display",
				  rect.x, rect.y, rect.w, rect.h,
				  requested_render_driver.sdl_window_params | (vid_resize == 1 ? SDL_WINDOW_RESIZABLE : 0));
	if (!window) {
		char message[200];
		sprintf(message,
			"SDL window could not be created! Error: %s\n",
			SDL_GetError());
		wx_messagebox(ghwnd, message, "SDL Error", WX_MB_OK);
		return 0;
	}

#ifdef __WINDOWS__
	memset(modkeystate, 0, sizeof(modkeystate));
	hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, GetModuleHandle(NULL), 0);
#endif

	render_time = 0;
	render_fps = 0;
	render_frame_time = SDL_GetTicks();
	render_frames = 0;
	return 1;
}

void window_close() {
#ifdef __WINDOWS__
	UnhookWindowsHookEx(hKeyboardHook);
#endif

	sdl_renderer_close();

	if (window) {
		SDL_GetWindowPosition(window, &rect.x, &rect.y);
		SDL_GetWindowSize(window, &rect.w, &rect.h);
		get_border_size(&border_y, &border_x, 0, 0);
		rect.x -= border_x;
		rect.y -= border_y;

		SDL_DestroyWindow(window);
	}
	window = NULL;
}

int render() {
	uint64_t start_time = timer_read();
	uint64_t end_time;

	if (window_dosetresize) {
		window_dosetresize = 0;
#if SDL_VERSION_ATLEAST(2, 0, 5)
		SDL_GetWindowSize(window, &rect.w, &rect.h);
		SDL_SetWindowResizable(window, vid_resize == 1);
		SDL_SetWindowSize(window, rect.w, rect.h);
#else
		window_doreset = 1;
#endif
		if (vid_resize == 2)
			SDL_SetWindowSize(window, custom_resolution_width, custom_resolution_height);

		device_force_redraw();
	}
	if (window_doreset) {
		pclog("window_doreset\n");
		window_doreset = 0;
		renderer_doreset = 0;
		return 0;
	}
	if (renderer_doreset) {
		pclog("renderer_doreset\n");
		renderer_doreset = 0;
		sdl_renderer_close();
		sdl_renderer_init(window);

		device_force_redraw();
		video_wait_for_blit();
	}
	while (SDL_PollEvent(&event)) {
		switch (event.type) {
		case SDL_MOUSEBUTTONUP:
			if (!mousecapture) {
				if (event.button.button == SDL_BUTTON_LEFT && !pause) {
					window_doinputgrab = 1;
					if (video_fullscreen)
						window_dofullscreen = 1;
				} else if (event.button.button == SDL_BUTTON_RIGHT)
					wx_popupmenu(ghwnd, menu, 0, 0);

			} else if (event.button.button == SDL_BUTTON_MIDDLE && !is_fullscreen())
				window_doinputrelease = 1;
			break;
		case SDL_MOUSEWHEEL:
			if (mousecapture)
				mouse_wheel_update(event.wheel.y);
			break;
		case SDL_WINDOWEVENT:
			if (event.window.event == SDL_WINDOWEVENT_CLOSE)
				wx_stop_emulation(ghwnd);
			if (event.window.event == SDL_WINDOWEVENT_RESIZED)
				device_force_redraw();
			if (event.window.event == SDL_WINDOWEVENT_FOCUS_LOST) {
				if (is_fullscreen())
					window_dowindowed = 1;
				window_doinputrelease = 1;
			}

			if (window_remember) {
				int flags = SDL_GetWindowFlags(window);
				if (!(flags & SDL_WINDOW_FULLSCREEN) && !(flags & SDL_WINDOW_FULLSCREEN_DESKTOP)) {
					if (event.window.event == SDL_WINDOWEVENT_MOVED) {
						get_border_size(&border_y, &border_x, 0, 0);
						window_x = event.window.data1 - border_x;
						window_y = event.window.data2 - border_y;
					} else if (event.window.event == SDL_WINDOWEVENT_RESIZED) {
						window_w = event.window.data1;
						window_h = event.window.data2;
					}
					//save_window_pos = 1;
				}
			}

			break;
		case SDL_KEYDOWN: {
#ifdef __WINDOWS__
			/* international keyboard workaround */
			if (event.key.keysym.scancode == SDL_SCANCODE_RALT &&
				(event.key.keysym.mod & KMOD_LCTRL) &&
				event.key.timestamp == rawinputkey[sdl_scancode(SDL_SCANCODE_LCTRL)])
				rawinputkey[sdl_scancode(SDL_SCANCODE_LCTRL)] = 0;
#endif
			int key_idx = sdl_scancode(event.key.keysym.scancode);
			if (key_idx != -1)
				rawinputkey[key_idx] = event.key.timestamp;
			break;
		}
		case SDL_KEYUP: {
			int key_idx = sdl_scancode(event.key.keysym.scancode);
			if (key_idx != -1)
				rawinputkey[key_idx] = 0;
			break;
		}
		}
	}
	if ((rawinputkey[sdl_scancode(SDL_SCANCODE_PAGEDOWN)] || rawinputkey[sdl_scancode(SDL_SCANCODE_KP_3)]) &&
		(rawinputkey[sdl_scancode(SDL_SCANCODE_LCTRL)] || rawinputkey[sdl_scancode(SDL_SCANCODE_RCTRL)]) &&
		(rawinputkey[sdl_scancode(SDL_SCANCODE_LALT)] || rawinputkey[sdl_scancode(SDL_SCANCODE_RALT)]))
		trigger_fullscreen = 1;
	else if (trigger_fullscreen) {
		trigger_fullscreen = 0;
		toggle_fullscreen();
	} else if ((rawinputkey[sdl_scancode(SDL_SCANCODE_PAGEUP)] || rawinputkey[sdl_scancode(SDL_SCANCODE_KP_9)]) &&
		(rawinputkey[sdl_scancode(SDL_SCANCODE_LCTRL)] || rawinputkey[sdl_scancode(SDL_SCANCODE_RCTRL)]) &&
		(rawinputkey[sdl_scancode(SDL_SCANCODE_LALT)] || rawinputkey[sdl_scancode(SDL_SCANCODE_RALT)]))
		trigger_screenshot = 1;
	else if (trigger_screenshot) {
		trigger_screenshot = 0;
		take_screenshot = 1;
	} else if ((rawinputkey[sdl_scancode(SDL_SCANCODE_END)] || rawinputkey[sdl_scancode(SDL_SCANCODE_KP_1)]) &&
		(rawinputkey[sdl_scancode(SDL_SCANCODE_LCTRL)] || rawinputkey[sdl_scancode(SDL_SCANCODE_RCTRL)]))
		trigger_inputrelease = 1;
	else if (trigger_inputrelease) {
		trigger_inputrelease = 0;
		if (!is_fullscreen())
			window_doinputrelease = 1;
	}
	if (window_doremember) {
		window_doremember = 0;
		SDL_GetWindowPosition(window, &window_x, &window_y);
		SDL_GetWindowSize(window, &window_w, &window_h);
		get_border_size(&border_y, &border_x, 0, 0);
		window_x -= border_x;
		window_y -= border_y;
		saveconfig(NULL);
	}

	if (window_dotogglefullscreen) {
		window_dotogglefullscreen = 0;
		if (SDL_GetWindowGrab(window) || is_fullscreen()) {
			window_doinputrelease = 1;
			if (is_fullscreen())
				window_dowindowed = 1;
		} else {
			window_doinputgrab = 1;
			window_dofullscreen = 1;
		}
	}

	if (window_dofullscreen) {
		window_dofullscreen = 0;
		video_wait_for_blit();
		SDL_RaiseWindow(window);
#if SDL_VERSION_ATLEAST(2, 0, 4)
		SDL_GetGlobalMouseState(&remembered_mouse_x, &remembered_mouse_y);
#endif
		SDL_GetWindowPosition(window, &remembered_rect.x, &remembered_rect.y);
		get_border_size(&border_y, &border_x, 0, 0);
		remembered_rect.x -= border_x;
		remembered_rect.y -= border_y;
		SDL_GetWindowSize(window, &remembered_rect.w, &remembered_rect.h);
		SDL_SetWindowFullscreen(window, video_fullscreen_mode == 0 ? SDL_WINDOW_FULLSCREEN_DESKTOP : SDL_WINDOW_FULLSCREEN);
		device_force_redraw();
	}
	if (window_doinputgrab) {
		window_doinputgrab = 0;
		mousecapture = 1;
		SDL_GetRelativeMouseState(0, 0);
		SDL_SetWindowGrab(window, SDL_TRUE);
		SDL_SetRelativeMouseMode(SDL_TRUE);
	}

	if (window_doinputrelease) {
		window_doinputrelease = 0;
		mousecapture = 0;
		SDL_SetWindowGrab(window, SDL_FALSE);
		SDL_SetRelativeMouseMode(SDL_FALSE);
	}
	if (window_dowindowed) {
		window_dowindowed = 0;
		SDL_SetWindowFullscreen(window, 0);
		SDL_SetWindowSize(window, remembered_rect.w, remembered_rect.h);
		SDL_SetWindowPosition(window, remembered_rect.x, remembered_rect.y);
#if SDL_VERSION_ATLEAST(2, 0, 4)
		SDL_WarpMouseGlobal(remembered_mouse_x, remembered_mouse_y);
#endif
		device_force_redraw();
	}

	if (win_doresize) {
		int flags = SDL_GetWindowFlags(window);

		win_doresize = 0;
		if (!vid_resize || (flags & SDL_WINDOW_FULLSCREEN)) {
			SDL_GetWindowSize(window, &rect.w, &rect.h);
			if (rect.w != winsizex || rect.h != winsizey) {
				SDL_GetWindowPosition(window, &rect.x, &rect.y);
				SDL_SetWindowSize(window, winsizex, winsizey);
				SDL_SetWindowPosition(window, rect.x, rect.y);
				device_force_redraw();
			}
		}
	}

	if (sdl_renderer_update(window))
		sdl_renderer_present(window);

	end_time = timer_read();
	render_time += end_time - start_time;

	++render_frames;
	uint32_t ticks = SDL_GetTicks();
	if (ticks - render_frame_time >= 1000) {
		render_fps = render_frames / ((ticks - render_frame_time) / 1000.0);
		render_frames = 0;
		render_frame_time = ticks;
	}

	return 1;
}

int renderer_thread(void *params) {
	int internal_rendering;

	SDL_LockMutex(rendererMutex);
	SDL_CondSignal(rendererCond);
	SDL_UnlockMutex(rendererMutex);

	window_setup();

	rendering = 1;
	while (rendering) {

		if (!window_create())
			rendering = 0;

		renderer_doreset = 1;
		internal_rendering = 1;
		while (rendering && internal_rendering) {
			if (!render())
				internal_rendering = 0;

			SDL_Delay(1);
		}
		window_close();
	}

	SDL_LockMutex(rendererMutex);
	SDL_CondSignal(rendererCond);
	SDL_UnlockMutex(rendererMutex);

	return SDL_TRUE;
}

void *timer = 0;

void render_timer() {
#ifdef PCEM_RENDER_TIMER_LOOP
	/* For some reason this while-loop works on OSX, which also fixes missing events. No idea why though. */
	renderer_thread(0);
#else
	if (rendering && !render()) {
		window_close();
		window_create();
		renderer_doreset = 1;
	}
#endif
}

void render_start_timer() {
#ifdef PCEM_RENDER_TIMER_LOOP
	timer = wx_createtimer(render_timer);
	wx_starttimer(timer, 500, 1);
#else
	window_setup();
	if (window_create()) {
		rendering = 1;
		renderer_doreset = 1;
		wx_starttimer(timer, 1, 0);
	}
#endif
}

void renderer_start() {
	if (!rendering) {
#ifdef PCEM_RENDER_WITH_TIMER
		render_start_timer();
#else
		SDL_LockMutex(rendererMutex);
		renderthread = SDL_CreateThread(renderer_thread, "SDL2 Thread", NULL);
		SDL_CondWait(rendererCond, rendererMutex);
		SDL_UnlockMutex(rendererMutex);
#endif
	}
}

void renderer_stop(int timeout) {
#if defined(PCEM_RENDER_WITH_TIMER) && !defined(PCEM_RENDER_TIMER_LOOP)
	rendering = 0;
	window_close();
	wx_destroytimer(timer);
#else
	if (rendering) {
		SDL_LockMutex(rendererMutex);
		rendering = 0;
		if (timeout)
			SDL_CondWaitTimeout(rendererCond, rendererMutex, timeout);
		else
			SDL_CondWait(rendererCond, rendererMutex);
		SDL_UnlockMutex(rendererMutex);
		renderthread = NULL;
	}
	if (timer)
		wx_destroytimer(timer);
#endif
}
