Blame src/window.c

Ivan Mahonin 3f9996
Ivan Mahonin a20939
#include <time.h>
Ivan Mahonin b6ebe9
#include <limits.h>
Ivan Mahonin a20939
Ivan Mahonin f63775
#include <SDL.h>
Ivan Mahonin 3f9996
Ivan Mahonin 3f9996
#include "private.h"
Ivan Mahonin 3e7c5f
#include "drawing.h"
Ivan Mahonin d7d433
#include "window.h"
Ivan Mahonin 3f9996
Ivan Mahonin 3f9996
Ivan Mahonin a20939
static int sdlInitialized = 0;
Ivan Mahonin 87fe10
static SDL_Window *window;
Ivan Mahonin 87fe10
static SDL_GLContext context;
Ivan Mahonin 1015c5
Ivan Mahonin 3f9996
static int started;
Ivan Mahonin 3f9996
static int stopped;
Ivan Mahonin 8bc1f1
static int firstFrame = TRUE;
Ivan Mahonin 3f9996
static unsigned long long frameCount;
Ivan Mahonin a20939
static unsigned long long elapsedTimeUs;
Ivan Mahonin a20939
static unsigned long long elapsedTimeSinceLastFrameUs;
Ivan Mahonin a20939
static unsigned int prevFrameTimeMs;
Ivan Mahonin 3f9996
Ivan Mahonin df4105
static unsigned long long monotonicMs;
Ivan Mahonin df4105
static unsigned int prevMonotonicMs;
Ivan Mahonin df4105
Ivan Mahonin 534343
HeliDialog dialog;
Ivan Mahonin 534343
Ivan Mahonin 3f9996
static Callback initCallback;
Ivan Mahonin 3f9996
static Callback drawCallback;
Ivan Mahonin 1015c5
static Callback deinitCallback;
Ivan Mahonin 3f9996
Ivan Mahonin 534343
static const int minWidth = 200;
Ivan Mahonin 534343
static const int minHeight = 200;
Ivan Mahonin 534343
Ivan Mahonin ba9f06
static int width = 512;
Ivan Mahonin ba9f06
static int height = 512;
Ivan Mahonin 8eb855
static int resizable;
Ivan Mahonin 8eb855
static char title[1000];
Ivan Mahonin 8eb855
static int titleSize = (int)(sizeof(title)/sizeof(*title));
Ivan Mahonin dba3fc
static double minFPS = HELI_DEFAULT_FPS;
Ivan Mahonin dba3fc
static double maxFPS = HELI_DEFAULT_FPS;
Ivan Mahonin dba3fc
static double frameTime = 1.0/HELI_DEFAULT_FPS;
Ivan Mahonin 3f9996
Ivan Mahonin 1015c5
static HeliArray keyEvents[6];
Ivan Mahonin 1015c5
static int keyEventsCount = (int)(sizeof(keyEvents)/sizeof(*keyEvents));
Ivan Mahonin 3f9996
Ivan Mahonin b6ebe9
static int textInputActive;
Ivan Mahonin b6ebe9
static char *textInput;
Ivan Mahonin b6ebe9
static int textInputSize;
Ivan Mahonin b6ebe9
Ivan Mahonin 3f9996
static int mouseMovedInFrame;
Ivan Mahonin 3f9996
static double _mouseX;
Ivan Mahonin 3f9996
static double _mouseY;
Ivan Mahonin 3f9996
bw aaf750
static int _mouseScrolledX;
bw aaf750
static int _mouseScrolledY;
bw aaf750
Ivan Mahonin 3f9996
Ivan Mahonin 519bc5
static const char* keyAliases[][2] = {
Ivan Mahonin 519bc5
	// as user asked  | as internally stored //
Ivan Mahonin 519bc5
	{ "enter"         , "return"              },
Ivan Mahonin 519bc5
	{ "any enter"     , "any return"          },
Ivan Mahonin 519bc5
	{ "keypad return" , "keypad enter"        } };
Ivan Mahonin 519bc5
static int keyAliasesCount = (int)(sizeof(keyAliases)/sizeof(*keyAliases));
Ivan Mahonin 519bc5
static const char* keyGroups[][2] = {
Ivan Mahonin 519bc5
	// as SDL passed  | as internally stored //
Ivan Mahonin 519bc5
	{ "left shift"    , "any shift"           },
Ivan Mahonin 519bc5
	{ "left ctrl"     , "any ctrl"            },
Ivan Mahonin 519bc5
	{ "left alt"      , "any alt"             },
Ivan Mahonin 519bc5
	{ "left gui"      , "any gui"             },
Ivan Mahonin 519bc5
	{ "right shift"   , "any shift"           },
Ivan Mahonin 519bc5
	{ "right ctrl"    , "any ctrl"            },
Ivan Mahonin 519bc5
	{ "right alt"     , "any alt"             },
Ivan Mahonin 519bc5
	{ "right gui"     , "any gui"             },
Ivan Mahonin 519bc5
	{ "0"             , "any 0"               },
Ivan Mahonin 519bc5
	{ "1"             , "any 1"               },
Ivan Mahonin 519bc5
	{ "2"             , "any 2"               },
Ivan Mahonin 519bc5
	{ "3"             , "any 3"               },
Ivan Mahonin 519bc5
	{ "4"             , "any 4"               },
Ivan Mahonin 519bc5
	{ "5"             , "any 5"               },
Ivan Mahonin 519bc5
	{ "6"             , "any 6"               },
Ivan Mahonin 519bc5
	{ "7"             , "any 7"               },
Ivan Mahonin 519bc5
	{ "8"             , "any 8"               },
Ivan Mahonin 519bc5
	{ "9"             , "any 9"               },
Ivan Mahonin 519bc5
	{ "/"             , "any /"               },
Ivan Mahonin 519bc5
	{ "*"             , "any *"               },
Ivan Mahonin 519bc5
	{ "-"             , "any -"               },
Ivan Mahonin 519bc5
	{ "+"             , "any +"               },
Ivan Mahonin 519bc5
	{ "return"        , "any return"          },
Ivan Mahonin 519bc5
	{ "keypad 0"      , "any 0"               },
Ivan Mahonin 519bc5
	{ "keypad 1"      , "any 1"               },
Ivan Mahonin 519bc5
	{ "keypad 2"      , "any 2"               },
Ivan Mahonin 519bc5
	{ "keypad 3"      , "any 3"               },
Ivan Mahonin 519bc5
	{ "keypad 4"      , "any 4"               },
Ivan Mahonin 519bc5
	{ "keypad 5"      , "any 5"               },
Ivan Mahonin 519bc5
	{ "keypad 6"      , "any 6"               },
Ivan Mahonin 519bc5
	{ "keypad 7"      , "any 7"               },
Ivan Mahonin 519bc5
	{ "keypad 8"      , "any 8"               },
Ivan Mahonin 519bc5
	{ "keypad 9"      , "any 9"               },
Ivan Mahonin 519bc5
	{ "keypad 9"      , "any 9"               },
Ivan Mahonin 519bc5
	{ "keypad /"      , "any /"               },
Ivan Mahonin 519bc5
	{ "keypad *"      , "any *"               },
Ivan Mahonin 519bc5
	{ "keypad -"      , "any -"               },
Ivan Mahonin 519bc5
	{ "keypad +"      , "any +"               },
Ivan Mahonin 519bc5
	{ "keypad enter"  , "any return"          } };
Ivan Mahonin 519bc5
static int keyGroupsCount = (int)(sizeof(keyGroups)/sizeof(*keyGroups));
Ivan Mahonin 519bc5
Ivan Mahonin 519bc5
Ivan Mahonin 3f9996
Ivan Mahonin 1015c5
int keyEventGetCount(KeyEvent mode)
Ivan Mahonin 1015c5
	{ return (int)mode >= 0 && (int)mode <= keyEventsCount ? keyEvents[mode].count : 0; }
Ivan Mahonin 1015c5
const char *keyEventGet(KeyEvent mode, int i)
Ivan Mahonin 1015c5
	{ return (int)mode >= 0 && (int)mode <= keyEventsCount ? heliArrayGetValue(&keyEvents[mode], i) : NULL; }
Ivan Mahonin 1015c5
Ivan Mahonin 1015c5
static int keyEventCheck(KeyEvent mode, const char *code) {
Ivan Mahonin 1015c5
	int count = keyEventGetCount(mode);
Ivan Mahonin 1015c5
	for(int i = 0; i < count; ++i)
Ivan Mahonin bcaca0
		if (heliStringCompareCi(keyEventGet(mode, i), code) == 0)
Ivan Mahonin 1015c5
			return TRUE;
Ivan Mahonin 1015c5
	return FALSE;
Ivan Mahonin 1015c5
}
Ivan Mahonin 1015c5
Ivan Mahonin 519bc5
static int keyEventAliasesCheck(KeyEvent mode, const char *code) {
Ivan Mahonin 519bc5
	if (keyEventCheck(mode, code)) return TRUE;
Ivan Mahonin 519bc5
	for(int i = 0; i < keyAliasesCount; ++i)
Ivan Mahonin bcaca0
		if (heliStringCompareCi(code, keyAliases[i][0]) == 0)
Ivan Mahonin 519bc5
			if (keyEventCheck(mode, keyAliases[i][1])) return TRUE;
Ivan Mahonin 519bc5
	return FALSE;
Ivan Mahonin 519bc5
}
Ivan Mahonin 519bc5
Ivan Mahonin 519bc5
static int keyEventAdd(KeyEvent mode, const char *code) {
Ivan Mahonin 519bc5
	if ((int)mode >= 0 && mode <= (int)keyEventsCount && !keyEventCheck(mode, code)) {
Ivan Mahonin bcaca0
		heliArrayInsert(&keyEvents[mode], -1, heliStringCopyLower(code), &free);
Ivan Mahonin 519bc5
		return TRUE;
Ivan Mahonin 519bc5
	}
Ivan Mahonin 519bc5
	return FALSE;
Ivan Mahonin 1015c5
}
Ivan Mahonin 1015c5
Ivan Mahonin 519bc5
static int keyEventRemove(KeyEvent mode, const char *code) {
Ivan Mahonin 519bc5
	int removed = FALSE;
Ivan Mahonin 1015c5
	if ((int)mode >= 0 && mode <= (int)keyEventsCount)
Ivan Mahonin 1015c5
		for(int i = keyEvents[mode].count-1; i >= 0; --i)
Ivan Mahonin bcaca0
			if (heliStringCompareCi(keyEvents[mode].items[i].value, code) == 0)
Ivan Mahonin 519bc5
				{ heliArrayRemove(&keyEvents[mode], i); removed = TRUE; }
Ivan Mahonin 519bc5
	return removed;
Ivan Mahonin 1015c5
}
Ivan Mahonin 3f9996
Ivan Mahonin 519bc5
static void pressKey(int mouse, const char *code) {
Ivan Mahonin 519bc5
	keyEventAdd(mouse ? KEYEVENT_MOUSE_DOWN : KEYEVENT_KEY_DOWN, code);
Ivan Mahonin 519bc5
	keyEventAdd(mouse ? KEYEVENT_MOUSE_WENTDOWN : KEYEVENT_KEY_WENTDOWN, code);
Ivan Mahonin 519bc5
	if (!mouse) {
Ivan Mahonin 519bc5
		for(int i = 0; i < keyGroupsCount; ++i) {
Ivan Mahonin bcaca0
			if (heliStringCompareCi(code, keyGroups[i][0]) == 0) {
Ivan Mahonin 519bc5
				keyEventAdd(KEYEVENT_KEY_DOWN, keyGroups[i][1]);
Ivan Mahonin 519bc5
				keyEventAdd(KEYEVENT_KEY_WENTDOWN, keyGroups[i][1]);
Ivan Mahonin 519bc5
			}
Ivan Mahonin 519bc5
		}
Ivan Mahonin 519bc5
	}
Ivan Mahonin 519bc5
}
Ivan Mahonin 519bc5
Ivan Mahonin 519bc5
static void releaseKey(int mouse, const char *code) {
Ivan Mahonin 519bc5
	if (!keyEventRemove(mouse ? KEYEVENT_MOUSE_DOWN : KEYEVENT_KEY_DOWN, code))
Ivan Mahonin 519bc5
		return;
Ivan Mahonin 519bc5
	keyEventAdd(mouse ? KEYEVENT_MOUSE_WENTUP : KEYEVENT_KEY_WENTUP, code);
Ivan Mahonin 519bc5
	if (mouse)
Ivan Mahonin 519bc5
		return;
Ivan Mahonin 519bc5
	for(int i = 0; i < keyGroupsCount; ++i) {
Ivan Mahonin bcaca0
		if (heliStringCompareCi(code, keyGroups[i][0]) != 0) continue;
Ivan Mahonin 519bc5
		int allRemoved = TRUE;
Ivan Mahonin 519bc5
		for(int j = 0; j < keyGroupsCount; ++j)
Ivan Mahonin bcaca0
			if ( heliStringCompareCi(keyGroups[i][1], keyGroups[j][1]) == 0
Ivan Mahonin bcaca0
			  && keyEventCheck(KEYEVENT_KEY_DOWN, keyGroups[j][0]))
Ivan Mahonin 519bc5
				{ allRemoved = FALSE; break; }
Ivan Mahonin 519bc5
		if (allRemoved)
Ivan Mahonin 519bc5
			if (keyEventRemove(KEYEVENT_KEY_DOWN, keyGroups[i][1]))
Ivan Mahonin 519bc5
				keyEventAdd(KEYEVENT_KEY_WENTUP, keyGroups[i][1]);
Ivan Mahonin 519bc5
	}
Ivan Mahonin 519bc5
}
Ivan Mahonin 519bc5
Ivan Mahonin 519bc5
static void releaseAllKeys() {
Ivan Mahonin 519bc5
	int count = keyEventGetCount(KEYEVENT_KEY_DOWN);
Ivan Mahonin 519bc5
	for(int i = count-1; i >= 0; --i)
Ivan Mahonin 519bc5
		keyEventAdd(KEYEVENT_KEY_WENTUP, keyEventGet(KEYEVENT_KEY_DOWN, i));
Ivan Mahonin 519bc5
	heliArrayClear(&keyEvents[KEYEVENT_KEY_DOWN]);
Ivan Mahonin 1015c5
	
Ivan Mahonin 519bc5
	count = keyEventGetCount(KEYEVENT_MOUSE_DOWN);
Ivan Mahonin 519bc5
	for(int i = count-1; i >= 0; --i)
Ivan Mahonin 519bc5
		keyEventAdd(KEYEVENT_MOUSE_WENTUP, keyEventGet(KEYEVENT_MOUSE_DOWN, i));
Ivan Mahonin 519bc5
	heliArrayClear(&keyEvents[KEYEVENT_MOUSE_DOWN]);
Ivan Mahonin 519bc5
}
Ivan Mahonin 519bc5
Ivan Mahonin 519bc5
Ivan Mahonin 519bc5
Ivan Mahonin 8535a3
int keyDown(const char *code)
Ivan Mahonin 519bc5
	{ return keyEventAliasesCheck(KEYEVENT_KEY_DOWN, code); }
Ivan Mahonin 07b70f
int keyWentDown(const char *code)
Ivan Mahonin 519bc5
	{ return keyEventAliasesCheck(KEYEVENT_KEY_WENTDOWN, code); }
Ivan Mahonin 07b70f
int keyWentUp(const char *code)
Ivan Mahonin 519bc5
	{ return keyEventAliasesCheck(KEYEVENT_KEY_WENTUP, code); }
Ivan Mahonin 3f9996
Ivan Mahonin b6ebe9
Ivan Mahonin b6ebe9
const char* textInputGet()
Ivan Mahonin b6ebe9
	{ return textInput ? textInput : ""; }
Ivan Mahonin b6ebe9
void textInputClear()
Ivan Mahonin b6ebe9
	{ if (textInput) *textInput = 0; }
Ivan Mahonin b6ebe9
void textInputBegin()
Ivan Mahonin b6ebe9
	{ if (!textInputActive) { SDL_StartTextInput(); textInputActive = TRUE; } }
Ivan Mahonin b6ebe9
void textInputEnd()
Ivan Mahonin b6ebe9
	{ if (textInputActive) { SDL_StopTextInput(); textInputActive = FALSE; } }
Ivan Mahonin b6ebe9
Ivan Mahonin b6ebe9
Ivan Mahonin 3f9996
int mouseDidMove()
Ivan Mahonin 3f9996
	{ return mouseMovedInFrame; }
Ivan Mahonin 8535a3
int mouseDown(const char *code)
Ivan Mahonin 1015c5
	{ return keyEventCheck(KEYEVENT_MOUSE_DOWN, code); }
Ivan Mahonin 8535a3
int mouseWentDown(const char *code)
Ivan Mahonin 1015c5
	{ return keyEventCheck(KEYEVENT_MOUSE_WENTDOWN, code); }
Ivan Mahonin 8535a3
int mouseWentUp(const char *code)
Ivan Mahonin 1015c5
	{ return keyEventCheck(KEYEVENT_MOUSE_WENTUP, code); }
bw aaf750
int mouseScrolledX()
bw aaf750
	{ return _mouseScrolledX; }
bw aaf750
int mouseScrolledY()
bw aaf750
	{ return _mouseScrolledY; }
Ivan Mahonin 3f9996
double mouseX()
Ivan Mahonin 3f9996
	{ return _mouseX; }
Ivan Mahonin 3f9996
double mouseY()
Ivan Mahonin 3f9996
	{ return _mouseY; }
Ivan Mahonin 3f9996
Ivan Mahonin d7d433
double mouseTransformedX() {
Ivan Mahonin 8bc1f1
	double x = mouseX(), y = mouseY();
Ivan Mahonin 8bc1f1
	heliGLBackTransform(&x, &y);
Ivan Mahonin 8bc1f1
	return x;
Ivan Mahonin 8bc1f1
}
Ivan Mahonin 8bc1f1
Ivan Mahonin d7d433
double mouseTransformedY() {
Ivan Mahonin 8bc1f1
	double x = mouseX(), y = mouseY();
Ivan Mahonin 8bc1f1
	heliGLBackTransform(&x, &y);
Ivan Mahonin 8bc1f1
	return y;
Ivan Mahonin 8bc1f1
}
Ivan Mahonin 8bc1f1
Ivan Mahonin 981405
static void resize(int w, int h) {
Ivan Mahonin 534343
	w = w > minWidth ? w : minWidth;
Ivan Mahonin 534343
	h = h > minHeight ? h : minHeight;
Ivan Mahonin 59dae5
	if (width != w || height != h) {
Ivan Mahonin a20939
		width = w;
Ivan Mahonin a20939
		height = h;
Ivan Mahonin a20939
		if (started && !stopped && window)
Ivan Mahonin a20939
			SDL_SetWindowSize(window, width, height);
Ivan Mahonin 981405
	}
Ivan Mahonin 981405
}
Ivan Mahonin 8bc1f1
Ivan Mahonin b6ebe9
Ivan Mahonin b6ebe9
const char* windowGetClipboardText()
Ivan Mahonin b6ebe9
	{ const char *t = SDL_GetClipboardText(); return t ? t : ""; }
Ivan Mahonin b6ebe9
void windowSetClipboardText(const char *text)
Ivan Mahonin b6ebe9
	{ SDL_SetClipboardText(text); }
Ivan Mahonin b6ebe9
void windowSetClipboardTextEx(const char *text, int len) {
Ivan Mahonin b6ebe9
	if (len <= 0) return;
Ivan Mahonin b6ebe9
	char *t = malloc(len + 1);
Ivan Mahonin b6ebe9
	memcpy(t, text, len);
Ivan Mahonin b6ebe9
	t[len] = 0;
Ivan Mahonin b6ebe9
	windowSetClipboardText(t);
Ivan Mahonin b6ebe9
	free(t);
Ivan Mahonin b6ebe9
}
Ivan Mahonin b6ebe9
Ivan Mahonin d7d433
int windowGetWidth()
Ivan Mahonin 3f9996
	{ return width; }
Ivan Mahonin d7d433
void windowSetWidth(int w)
Ivan Mahonin 981405
	{ resize(w, height); }
Ivan Mahonin 3f9996
Ivan Mahonin d7d433
int windowGetHeight()
Ivan Mahonin 3f9996
	{ return height; }
Ivan Mahonin d7d433
void windowSetHeight(int h)
Ivan Mahonin 981405
	{ resize(width, h); }
Ivan Mahonin 3f9996
Ivan Mahonin d7d433
void windowSetSize(int w, int h)
Ivan Mahonin ca6bde
	{ resize(w, h); }
Ivan Mahonin ca6bde
Ivan Mahonin d7d433
int windowGetResizable()
Ivan Mahonin 8eb855
	{ return resizable; }
Ivan Mahonin d7d433
void windowSetResizable(int r) {
Ivan Mahonin 8eb855
	if (resizable == r) return;
Ivan Mahonin 8eb855
	resizable = r ? TRUE : FALSE;
Ivan Mahonin 8eb855
	if (started && !stopped && window)
Ivan Mahonin a20939
		SDL_SetWindowResizable(window, resizable);
Ivan Mahonin 8eb855
}
Ivan Mahonin 8eb855
Ivan Mahonin d7d433
const char* windowGetTitle()
Ivan Mahonin 8eb855
	{ return title; }
Ivan Mahonin d7d433
void windowSetTitle(const char *t) {
Ivan Mahonin 8eb855
	int changed = FALSE;
Ivan Mahonin 8eb855
	for(int i = 0; i < titleSize-1; ++i) {
Ivan Mahonin 8eb855
		if (title[i] != t[i]) changed = TRUE;
Ivan Mahonin 8eb855
		title[i] = t[i];
Ivan Mahonin 8eb855
		if (!t[i]) break;
Ivan Mahonin 8eb855
	}
Ivan Mahonin 8eb855
	if (changed && started && !stopped && window)
Ivan Mahonin a20939
		SDL_SetWindowTitle(window, title);
Ivan Mahonin 8eb855
}
Ivan Mahonin 8eb855
Ivan Mahonin d7d433
double windowGetMinFrameRate()
Ivan Mahonin 8bc1f1
	{ return minFPS; }
Ivan Mahonin d7d433
double windowGetMaxFrameRate()
Ivan Mahonin 8bc1f1
	{ return minFPS; }
Ivan Mahonin d7d433
void windowSetFrameRateEx(double minFrameRate, double maxFrameRate) {
Ivan Mahonin dba3fc
	if (!(minFrameRate > HELI_MIN_FPS)) minFrameRate = HELI_MIN_FPS;
Ivan Mahonin dba3fc
	if (!(minFrameRate < HELI_MAX_FPS)) minFrameRate = HELI_MAX_FPS;
Ivan Mahonin dba3fc
	if (!(maxFrameRate > HELI_MIN_FPS)) maxFrameRate = HELI_MIN_FPS;
Ivan Mahonin dba3fc
	if (!(maxFrameRate < HELI_MAX_FPS)) maxFrameRate = HELI_MAX_FPS;
Ivan Mahonin 8bc1f1
	if (minFrameRate > maxFrameRate) minFrameRate = maxFrameRate;
Ivan Mahonin 8bc1f1
	minFPS = minFrameRate;
Ivan Mahonin 8bc1f1
	maxFPS = maxFrameRate;
Ivan Mahonin 3f9996
}
Ivan Mahonin d7d433
void windowSetFrameRate(double frameRate)
Ivan Mahonin d7d433
	{ windowSetFrameRateEx(frameRate, frameRate); }
Ivan Mahonin d7d433
void windowSetVariableFrameRate()
Ivan Mahonin d7d433
	{ windowSetFrameRateEx(HELI_MIN_FPS, HELI_MAX_FPS); }
Ivan Mahonin 8bc1f1
Ivan Mahonin d7d433
double windowGetFrameTime()
Ivan Mahonin 8bc1f1
	{ return frameTime; }
Ivan Mahonin 8bc1f1
Ivan Mahonin d7d433
int windowGetFrameCount()
Ivan Mahonin 3f9996
	{ return (int)frameCount; }
Ivan Mahonin d7d433
double windowGetSeconds()
Ivan Mahonin a20939
	{ return started ? elapsedTimeUs*1e-6 : 0.0; }
Ivan Mahonin 3f9996
Ivan Mahonin df4105
unsigned long long windowGetMonotonicMilliseconds() {
Ivan Mahonin df4105
	unsigned int ms = SDL_GetTicks();
Ivan Mahonin df4105
	monotonicMs += ms - prevMonotonicMs;
Ivan Mahonin df4105
	prevMonotonicMs = ms;
Ivan Mahonin df4105
	return monotonicMs;
Ivan Mahonin df4105
}
Ivan Mahonin df4105
Ivan Mahonin df4105
double windowGetMonotonicSeconds()
Ivan Mahonin df4105
	{ return started ? monotonicMs*1e-3 : 0.0; }
Ivan Mahonin df4105
Ivan Mahonin d7d433
void windowSetInit(Callback init)
Ivan Mahonin 3f9996
	{ initCallback = init; }
Ivan Mahonin d7d433
void windowSetDraw(Callback draw)
Ivan Mahonin 3f9996
	{ drawCallback = draw; }
Ivan Mahonin d7d433
void windowSetDeinit(Callback deinit)
Ivan Mahonin 1015c5
	{ deinitCallback = deinit; }
Ivan Mahonin d7d433
void windowStop()
Ivan Mahonin 3f9996
	{ if (started) stopped = TRUE; }
Ivan Mahonin 3f9996
Ivan Mahonin 3f9996
Ivan Mahonin 3954ba
void messageBox(const char *message) {
Ivan Mahonin 3954ba
	SDL_ShowSimpleMessageBox(
Ivan Mahonin 3954ba
		SDL_MESSAGEBOX_INFORMATION,
Ivan Mahonin 3954ba
		title,
Ivan Mahonin 3954ba
		message,
Ivan Mahonin 3954ba
		window );
Ivan Mahonin 534343
	prevFrameTimeMs = SDL_GetTicks();
Ivan Mahonin 534343
}
Ivan Mahonin 534343
Ivan Mahonin f8dca4
int questionBox(const char *question, const char *answer0, const char *answer1) {
Ivan Mahonin f8dca4
	SDL_MessageBoxButtonData buttons[2] = {};
Ivan Mahonin f8dca4
	
Ivan Mahonin f8dca4
	buttons[0].buttonid = 1;
Ivan Mahonin f8dca4
	buttons[0].flags = SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT;
Ivan Mahonin f8dca4
	buttons[0].text = answer1;
Ivan Mahonin f8dca4
Ivan Mahonin f8dca4
	buttons[1].buttonid = 0;
Ivan Mahonin f8dca4
	buttons[1].flags = SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT;
Ivan Mahonin f8dca4
	buttons[1].text = answer0;
Ivan Mahonin f8dca4
	
Ivan Mahonin f8dca4
	SDL_MessageBoxData data = {};
Ivan Mahonin f8dca4
	data.flags = SDL_MESSAGEBOX_INFORMATION;
Ivan Mahonin f8dca4
	data.window = window;
Ivan Mahonin f8dca4
	data.title = title;
Ivan Mahonin f8dca4
	data.message = question;
Ivan Mahonin f8dca4
	data.buttons = buttons;
Ivan Mahonin f8dca4
	data.numbuttons = 2;
Ivan Mahonin f8dca4
	
Ivan Mahonin f8dca4
	int buttonid = 0;;
Ivan Mahonin f8dca4
	SDL_ShowMessageBox(&data, &buttonid);
Ivan Mahonin f8dca4
	prevFrameTimeMs = SDL_GetTicks();
Ivan Mahonin f8dca4
	
Ivan Mahonin f8dca4
	return buttonid;
Ivan Mahonin f8dca4
}
Ivan Mahonin f8dca4
Ivan Mahonin f8dca4
int questionBox3(const char* question, const char* answer0, const char* answer1, const char* answer2) {
Ivan Mahonin f8dca4
	SDL_MessageBoxButtonData buttons[3] = {};
Ivan Mahonin f8dca4
	
Ivan Mahonin f8dca4
	buttons[0].buttonid = 2;
Ivan Mahonin f8dca4
	buttons[0].flags = SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT;
Ivan Mahonin f8dca4
	buttons[0].text = answer2;
Ivan Mahonin f8dca4
	
Ivan Mahonin f8dca4
	buttons[1].buttonid = 1;
Ivan Mahonin f8dca4
	buttons[1].text = answer1;
Ivan Mahonin f8dca4
Ivan Mahonin f8dca4
	buttons[2].buttonid = 0;
Ivan Mahonin f8dca4
	buttons[2].flags = SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT;
Ivan Mahonin f8dca4
	buttons[2].text = answer0;
Ivan Mahonin f8dca4
	
Ivan Mahonin f8dca4
	SDL_MessageBoxData data = {};
Ivan Mahonin f8dca4
	data.flags = SDL_MESSAGEBOX_INFORMATION;
Ivan Mahonin f8dca4
	data.window = window;
Ivan Mahonin f8dca4
	data.title = title;
Ivan Mahonin f8dca4
	data.message = question;
Ivan Mahonin f8dca4
	data.buttons = buttons;
Ivan Mahonin f8dca4
	data.numbuttons = 3;
Ivan Mahonin f8dca4
	
Ivan Mahonin f8dca4
	int buttonid = 0;;
Ivan Mahonin f8dca4
	SDL_ShowMessageBox(&data, &buttonid);
Ivan Mahonin f8dca4
	prevFrameTimeMs = SDL_GetTicks();
Ivan Mahonin f8dca4
	
Ivan Mahonin f8dca4
	return buttonid;
Ivan Mahonin f8dca4
}
Ivan Mahonin f8dca4
Ivan Mahonin dba3fc
int askText(const char *question, char *answer, int maxAnswerSize)
Ivan Mahonin dba3fc
	{ return askTextEx(question, answer, maxAnswerSize, FALSE, FALSE); }
Ivan Mahonin 534343
Ivan Mahonin 7ebc4f
int askTextf(const char *question, const char *format, ...) {
Ivan Mahonin 7ebc4f
	char buf[2048] = {};
Ivan Mahonin 7ebc4f
	if (!askText(question, buf, sizeof(buf)))
Ivan Mahonin 7ebc4f
		return EOF;
Ivan Mahonin 7ebc4f
	va_list args;
Ivan Mahonin 7ebc4f
	va_start(args, format);
Ivan Mahonin 7ebc4f
	int result = vsscanf(buf, format, args);
Ivan Mahonin 7ebc4f
	va_end(args);
Ivan Mahonin 7ebc4f
	return result;
Ivan Mahonin 7ebc4f
}
Ivan Mahonin 7ebc4f
Ivan Mahonin 534343
Ivan Mahonin 534343
static void resetEvents() {
bw aaf750
	_mouseScrolledX = _mouseScrolledY = 0;
Ivan Mahonin 534343
	heliArrayClear(&keyEvents[KEYEVENT_KEY_WENTDOWN]);
Ivan Mahonin 534343
	heliArrayClear(&keyEvents[KEYEVENT_KEY_WENTUP]);
Ivan Mahonin 534343
	heliArrayClear(&keyEvents[KEYEVENT_MOUSE_WENTDOWN]);
Ivan Mahonin 534343
	heliArrayClear(&keyEvents[KEYEVENT_MOUSE_WENTUP]);
Ivan Mahonin 3954ba
}
Ivan Mahonin 3954ba
Ivan Mahonin 3954ba
Ivan Mahonin a20939
static void draw() {
Ivan Mahonin 5df077
	// touch monotonic timer to not skip the moment of overflow
Ivan Mahonin 5df077
	windowGetMonotonicMilliseconds();
Ivan Mahonin 5df077
	
Ivan Mahonin a20939
	unsigned int currentFrameTimeMs = SDL_GetTicks();
Ivan Mahonin 8bc1f1
	unsigned long long deltaUs = firstFrame ? 0 : (currentFrameTimeMs - prevFrameTimeMs)*1000ull;
Ivan Mahonin a20939
	prevFrameTimeMs = currentFrameTimeMs;
Ivan Mahonin d1f083
	
Ivan Mahonin 8bc1f1
	double actualMinFPS = minFPS, actualMaxFPS = maxFPS;
Ivan Mahonin 8bc1f1
	if (dialog.shown) { actualMinFPS = 1, actualMaxFPS = 100; }
Ivan Mahonin 8bc1f1
	
Ivan Mahonin 8bc1f1
	unsigned long long minTimeStepUs = (unsigned long long)round(1e6/actualMaxFPS);
Ivan Mahonin 8bc1f1
	unsigned long long maxTimeStepUs = (unsigned long long)round(1e6/actualMinFPS);
Ivan Mahonin 8bc1f1
	elapsedTimeSinceLastFrameUs += deltaUs;
Ivan Mahonin 8bc1f1
	if (elapsedTimeSinceLastFrameUs > 2000000)
Ivan Mahonin 8bc1f1
		elapsedTimeSinceLastFrameUs = 2000000;
Ivan Mahonin 8bc1f1
	if (firstFrame || elapsedTimeSinceLastFrameUs >= minTimeStepUs) {
Ivan Mahonin 8bc1f1
		unsigned long long encountedTimeUs = elapsedTimeSinceLastFrameUs;
Ivan Mahonin 8bc1f1
		if (encountedTimeUs > maxTimeStepUs) encountedTimeUs = maxTimeStepUs;
Ivan Mahonin 8bc1f1
		double dt = encountedTimeUs*1e-6;
Ivan Mahonin 8bc1f1
		
Ivan Mahonin 8bc1f1
		if (!firstFrame) elapsedTimeSinceLastFrameUs -= encountedTimeUs;
Ivan Mahonin 8bc1f1
		
Ivan Mahonin 8bc1f1
		if (!dialog.shown) {
Ivan Mahonin 8bc1f1
			elapsedTimeUs += encountedTimeUs;
Ivan Mahonin 8bc1f1
			++frameCount;
Ivan Mahonin 8bc1f1
			frameTime = firstFrame ? 1/maxFPS : dt;
Ivan Mahonin dba3fc
			heliAnimationUpdate(dt);
Ivan Mahonin 8bc1f1
			heliSpriteUpdate(dt);
Ivan Mahonin 8bc1f1
		}
Ivan Mahonin 09c823
		heliSoundUpdate();
Ivan Mahonin 650f35
		
Ivan Mahonin 8bc1f1
		firstFrame = FALSE;
Ivan Mahonin 8bc1f1
		
Ivan Mahonin 1d641c
		viewportByWindow();
Ivan Mahonin 1d641c
		projectionByViewport();
Ivan Mahonin a20939
		
Ivan Mahonin a20939
		heliDrawingPrepareFrame();
Ivan Mahonin 8bc1f1
		if (dialog.shown) {
Ivan Mahonin 8bc1f1
			heliDialogDraw(&dialog);
Ivan Mahonin 8bc1f1
		} else {
Ivan Mahonin 8bc1f1
		if (drawCallback) 
Ivan Mahonin 8bc1f1
			drawCallback();
Ivan Mahonin 8bc1f1
		}
Ivan Mahonin 650f35
		
Ivan Mahonin 534343
		resetEvents();
Ivan Mahonin a20939
		SDL_GL_SwapWindow(window);
Ivan Mahonin 8bc1f1
	}
Ivan Mahonin 8bc1f1
	
Ivan Mahonin 8bc1f1
	unsigned long long addUs = elapsedTimeSinceLastFrameUs + (SDL_GetTicks() - prevFrameTimeMs)*1000ull;
Ivan Mahonin 8bc1f1
	if (addUs < minTimeStepUs) {
Ivan Mahonin 8bc1f1
		unsigned long long waitUs = minTimeStepUs - addUs;
Ivan Mahonin 8bc1f1
		if (waitUs > 2000)
Ivan Mahonin 8bc1f1
			SDL_Delay( (unsigned int)((waitUs + 500)/1000ull) );
Ivan Mahonin 650f35
	}
Ivan Mahonin a20939
}
Ivan Mahonin a20939
Ivan Mahonin a20939
Ivan Mahonin a20939
static void deinit() {
Ivan Mahonin df4105
	monotonicMs = 0;
Ivan Mahonin df4105
	prevMonotonicMs = 0;
Ivan Mahonin df4105
	
Ivan Mahonin 1d641c
	heliGLStencilOpSeparatePtr = NULL;
Ivan Mahonin 87fe10
	
Ivan Mahonin a20939
	if (context) SDL_GL_DeleteContext(context);
Ivan Mahonin a20939
	context = NULL;
Ivan Mahonin 650f35
	
Ivan Mahonin a20939
	if (window) SDL_DestroyWindow(window);
Ivan Mahonin a20939
	window = NULL;
Ivan Mahonin 650f35
	
Ivan Mahonin a20939
	if (sdlInitialized) SDL_Quit();
Ivan Mahonin a20939
	sdlInitialized = FALSE;
Ivan Mahonin a20939
}
Ivan Mahonin a20939
Ivan Mahonin a20939
Ivan Mahonin a20939
static int init() {
Ivan Mahonin a20939
	if (SDL_Init(SDL_INIT_EVERYTHING) < 0) {
Ivan Mahonin 3954ba
		fprintf(stderr, "helianthus: SDL_Init failed\n");
Ivan Mahonin a20939
		deinit();
Ivan Mahonin a20939
		return FALSE;
Ivan Mahonin a20939
	}
Ivan Mahonin a20939
	sdlInitialized = TRUE;
Ivan Mahonin a20939
	
Ivan Mahonin a20939
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
Ivan Mahonin a20939
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
Ivan Mahonin b9c036
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
Ivan Mahonin ba9f06
	SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
Ivan Mahonin a20939
	SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
Ivan Mahonin a20939
	SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 8);
Ivan Mahonin a20939
	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
Ivan Mahonin a20939
	SDL_GL_SetSwapInterval(1);
Ivan Mahonin a20939
	
Ivan Mahonin a20939
	unsigned int flags = SDL_WINDOW_OPENGL;
Ivan Mahonin a20939
	if (resizable) flags |= SDL_WINDOW_RESIZABLE;
bw 354283
	
Ivan Mahonin a20939
	window = SDL_CreateWindow(
bw 354283
		title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
bw 354283
		width, height, flags );
bw 354283
	
bw 354283
	if (!window) {
bw 354283
		// try to create window without multisampling
bw 354283
		SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0);
bw 354283
		SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0);
bw 354283
		window = SDL_CreateWindow(
bw 354283
			title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
bw 354283
			width, height, flags );
bw 354283
	}
bw 354283
	
Ivan Mahonin a20939
	
Ivan Mahonin a20939
	if (!window) {
Ivan Mahonin 3954ba
		fprintf(stderr, "helianthus: cannot create window: %s\n", SDL_GetError());
Ivan Mahonin a20939
		SDL_ClearError();
Ivan Mahonin a20939
		deinit();
Ivan Mahonin a20939
		return FALSE;
Ivan Mahonin a20939
	}
Ivan Mahonin a20939
	
Ivan Mahonin 534343
	SDL_SetWindowMinimumSize(window, minWidth, minHeight);
Ivan Mahonin 534343
	
Ivan Mahonin a20939
	context = SDL_GL_CreateContext(window);
Ivan Mahonin a20939
	if (!context) {
Ivan Mahonin 3954ba
		fprintf(stderr, "helianthus: cannot create OpenGL context: %s\n", SDL_GetError());
Ivan Mahonin a20939
		SDL_ClearError();
Ivan Mahonin a20939
		deinit();
Ivan Mahonin a20939
		return FALSE;
Ivan Mahonin e034e4
	}
Ivan Mahonin 650f35
	
Ivan Mahonin 1d641c
	heliGLBlendFuncSeparatePtr       = SDL_GL_GetProcAddress("glBlendFuncSeparate");
Ivan Mahonin 1d641c
	heliGLStencilOpSeparatePtr       = SDL_GL_GetProcAddress("glStencilOpSeparate");
Ivan Mahonin 1d641c
	heliGLTexImage2DMultisamplePtr   = SDL_GL_GetProcAddress("glTexImage2DMultisample");
Ivan Mahonin 1d641c
	heliGLGenFramebuffersPtr         = SDL_GL_GetProcAddress("glGenFramebuffers");
Ivan Mahonin 1d641c
	heliGLDeleteFramebuffersPtr      = SDL_GL_GetProcAddress("glDeleteFramebuffers");
Ivan Mahonin 1d641c
	heliGLBindFramebufferPtr         = SDL_GL_GetProcAddress("glBindFramebuffer");
Ivan Mahonin 1d641c
	heliGLBlitFramebufferPtr         = SDL_GL_GetProcAddress("glBlitFramebuffer");
Ivan Mahonin 1d641c
	heliGLFramebufferRenderbufferPtr = SDL_GL_GetProcAddress("glFramebufferRenderbuffer");
Ivan Mahonin 1d641c
	heliGLFramebufferTexture2DPtr    = SDL_GL_GetProcAddress("glFramebufferTexture2D");
Ivan Mahonin 909bc2
	heliGLCheckFramebufferStatusPtr  = SDL_GL_GetProcAddress("glCheckFramebufferStatus");
Ivan Mahonin 1d641c
	heliGLGenRenderbuffersPtr        = SDL_GL_GetProcAddress("glGenRenderbuffers");
Ivan Mahonin 1d641c
	heliGLDeleteRenderbuffersPtr     = SDL_GL_GetProcAddress("glDeleteRenderbuffers");
Ivan Mahonin 1d641c
	heliGLBindRenderbufferPtr        = SDL_GL_GetProcAddress("glBindRenderbuffer");
Ivan Mahonin 1d641c
	heliGLRenderbufferStoragePtr     = SDL_GL_GetProcAddress("glRenderbufferStorage");
Ivan Mahonin 1d641c
	heliGLRenderbufferStorageMultisamplePtr = SDL_GL_GetProcAddress("glRenderbufferStorageMultisample");
Ivan Mahonin 1d641c
	glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, (int*)&heliGLWindowFramebufferReadId);
Ivan Mahonin 1d641c
	glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, (int*)&heliGLWindowFramebufferDrawId);
Ivan Mahonin 87fe10
	
Ivan Mahonin df4105
	monotonicMs = 0;
Ivan Mahonin df4105
	prevMonotonicMs = SDL_GetTicks();
Ivan Mahonin df4105
	
Ivan Mahonin 3f9996
	return TRUE;
Ivan Mahonin 3f9996
}
Ivan Mahonin 3f9996
Ivan Mahonin a20939
Ivan Mahonin a20939
static void handleEvent(SDL_Event *e) {
Ivan Mahonin a20939
	if (e->type == SDL_QUIT) {
Ivan Mahonin a20939
		stopped = TRUE;
Ivan Mahonin a20939
	} else
Ivan Mahonin a20939
	if (e->type == SDL_WINDOWEVENT) {
Ivan Mahonin a20939
		if (e->window.event == SDL_WINDOWEVENT_CLOSE) {
Ivan Mahonin a20939
			stopped = TRUE;
Ivan Mahonin a20939
		} else
Ivan Mahonin a20939
		if (e->window.event == SDL_WINDOWEVENT_RESIZED) {
Ivan Mahonin a20939
			width = e->window.data1;
Ivan Mahonin a20939
			height = e->window.data2;
Ivan Mahonin a20939
		} else
Ivan Mahonin a20939
		if (e->window.event == SDL_WINDOWEVENT_FOCUS_LOST) {
Ivan Mahonin 519bc5
			releaseAllKeys();
Ivan Mahonin 1015c5
		}
Ivan Mahonin a20939
	} else
Ivan Mahonin a20939
	if (e->type == SDL_KEYDOWN || e->type == SDL_KEYUP) {
Ivan Mahonin bcaca0
		const char *keyname = SDL_GetKeyName(e->key.keysym.sym);
Ivan Mahonin bcaca0
		if (keyname && *keyname) {
Ivan Mahonin 519bc5
			if (e->type == SDL_KEYDOWN)
Ivan Mahonin 519bc5
				pressKey(FALSE, keyname); else releaseKey(FALSE, keyname);
Ivan Mahonin a20939
		}
Ivan Mahonin a20939
	} else
Ivan Mahonin a20939
	if (e->type == SDL_MOUSEBUTTONDOWN || e->type == SDL_MOUSEBUTTONUP) {
Ivan Mahonin a20939
		char *button = NULL;
Ivan Mahonin a20939
		switch(e->button.button) {
Ivan Mahonin a20939
			case SDL_BUTTON_LEFT:   button = "left";   break;
Ivan Mahonin a20939
			case SDL_BUTTON_MIDDLE: button = "middle"; break;
Ivan Mahonin a20939
			case SDL_BUTTON_RIGHT:  button = "right";  break;
Ivan Mahonin a20939
			default: break;
Ivan Mahonin a20939
		}
Ivan Mahonin a20939
		if (button) {
Ivan Mahonin 519bc5
			if (e->type == SDL_MOUSEBUTTONDOWN)
Ivan Mahonin 519bc5
				pressKey(TRUE, button); else releaseKey(TRUE, button);
Ivan Mahonin a20939
		}
Ivan Mahonin a20939
		_mouseX = e->button.x;
Ivan Mahonin a20939
		_mouseY = e->button.y;
Ivan Mahonin a20939
	} else
Ivan Mahonin a20939
	if (e->type == SDL_MOUSEMOTION) {
Ivan Mahonin a20939
		_mouseX = e->motion.x;
Ivan Mahonin a20939
		_mouseY = e->motion.y;
Ivan Mahonin 534343
	} else
bw aaf750
	if (e->type == SDL_MOUSEWHEEL) {
bw aaf750
		_mouseScrolledX += e->wheel.x;
bw aaf750
		_mouseScrolledY += e->wheel.y;
bw aaf750
	} else
Ivan Mahonin 534343
	if (e->type == SDL_TEXTINPUT) {
Ivan Mahonin b6ebe9
		if (*e->text.text) {
Ivan Mahonin b6ebe9
			int oldlen = textInput ? strlen(textInput) : 0;
Ivan Mahonin 534343
			int newlen = strlen(e->text.text);
Ivan Mahonin b6ebe9
			int size = oldlen + newlen + 1;
Ivan Mahonin b6ebe9
			if (size > 0) {
Ivan Mahonin b6ebe9
				if (size > textInputSize) {
Ivan Mahonin b6ebe9
					int newsize = ((size + size/16 - 1)/1024 + 1)*1024;
Ivan Mahonin b6ebe9
					if (newsize < 0) newsize = INT_MAX;
Ivan Mahonin b6ebe9
					if (newsize > textInputSize) {
Ivan Mahonin b6ebe9
						textInput = realloc(textInput, newsize);
Ivan Mahonin b6ebe9
						textInputSize = newsize;
Ivan Mahonin b6ebe9
						textInput[textInputSize - 1] = 0;
Ivan Mahonin b6ebe9
					}
Ivan Mahonin b6ebe9
				}
Ivan Mahonin b6ebe9
				if (size <= textInputSize) {
Ivan Mahonin b6ebe9
					memcpy(textInput + oldlen, e->text.text, newlen);
Ivan Mahonin b6ebe9
					textInput[oldlen + newlen] = 0;
Ivan Mahonin b6ebe9
				}
Ivan Mahonin 534343
			}
Ivan Mahonin 534343
		}
Ivan Mahonin 534343
	}
Ivan Mahonin 534343
}
Ivan Mahonin 534343
Ivan Mahonin 534343
Ivan Mahonin dba3fc
int askTextEx(const char *question, char *answer, int maxAnswerSize, int multiline, int password) {
Ivan Mahonin 534343
	if (maxAnswerSize < 0 || !answer) maxAnswerSize = 0;
Ivan Mahonin 534343
	
Ivan Mahonin 534343
	memset(&dialog, 0, sizeof(dialog));
Ivan Mahonin 534343
	dialog.shown = TRUE;
Ivan Mahonin 534343
	dialog.question = question ? question : "";
Ivan Mahonin 534343
	dialog.answer = calloc(1, maxAnswerSize + 1);
Ivan Mahonin 97fe4e
	dialog.passwordText = calloc(1, maxAnswerSize*4 + 1);
Ivan Mahonin 534343
	dialog.maxAnswerSize = maxAnswerSize - 1;
Ivan Mahonin 534343
	if (maxAnswerSize > 0) memcpy(dialog.answer, answer, maxAnswerSize);
Ivan Mahonin 97fe4e
	dialog.multiline = multiline != 0 && password == 0;
Ivan Mahonin 534343
	dialog.password = password != 0;
Ivan Mahonin 534343
	dialog.pos = dialog.selPos = strlen(dialog.answer);
Ivan Mahonin 534343
	dialog.success = FALSE;
Ivan Mahonin 534343
	
Ivan Mahonin b6ebe9
	int tiActive = textInputActive;
Ivan Mahonin b6ebe9
	textInputBegin();
Ivan Mahonin 534343
	while(dialog.shown && !stopped) {
Ivan Mahonin 534343
		SDL_Event event;
Ivan Mahonin 534343
		while (SDL_PollEvent(&event))
Ivan Mahonin 534343
			handleEvent(&event);
Ivan Mahonin 534343
		draw();
Ivan Mahonin 3f9996
	}
Ivan Mahonin b6ebe9
	if (!tiActive) textInputEnd();
Ivan Mahonin 534343
	
Ivan Mahonin dba3fc
	int success = dialog.success;
Ivan Mahonin 534343
	if (dialog.success && maxAnswerSize > 0) strcpy(answer, dialog.answer);
Ivan Mahonin 534343
	free(dialog.answer);
Ivan Mahonin 97fe4e
	free(dialog.passwordText);
Ivan Mahonin 534343
	memset(&dialog, 0, sizeof(dialog));
Ivan Mahonin 534343
	
Ivan Mahonin 534343
	resetEvents();
Ivan Mahonin 534343
	heliArrayClear(&keyEvents[KEYEVENT_KEY_DOWN]);
Ivan Mahonin 534343
	heliArrayClear(&keyEvents[KEYEVENT_MOUSE_DOWN]);
Ivan Mahonin a20939
	
Ivan Mahonin 534343
	prevFrameTimeMs = SDL_GetTicks();
Ivan Mahonin 534343
	heliDrawingPrepareFrame();
Ivan Mahonin dba3fc
	
Ivan Mahonin dba3fc
	return success;
Ivan Mahonin 3f9996
}
Ivan Mahonin 3f9996
Ivan Mahonin a20939
Ivan Mahonin a20939
static void run() {
Ivan Mahonin a20939
	while(!stopped) {
Ivan Mahonin a20939
		SDL_Event event;
Ivan Mahonin a20939
		while (SDL_PollEvent(&event))
Ivan Mahonin a20939
			handleEvent(&event);
Ivan Mahonin a20939
		draw();
Ivan Mahonin a20939
	}
Ivan Mahonin 3f9996
}
Ivan Mahonin 3f9996
Ivan Mahonin a20939
Ivan Mahonin d7d433
void windowRun() {
Ivan Mahonin 3f9996
	if (started) return;
Ivan Mahonin 3f9996
	started = TRUE;
Ivan Mahonin 3f9996
	stopped = FALSE;
Ivan Mahonin a20939
	
Ivan Mahonin 8bc1f1
	firstFrame = TRUE;
Ivan Mahonin 3f9996
	frameCount = 0;
Ivan Mahonin a20939
	elapsedTimeUs = 0;
Ivan Mahonin a20939
	elapsedTimeSinceLastFrameUs = 0;
Ivan Mahonin 3f9996
	srand(time(NULL));
Ivan Mahonin 1015c5
	
Ivan Mahonin a20939
	if (init()) {
Ivan Mahonin a20939
		heliInitialized = TRUE;
Ivan Mahonin a20939
		
Ivan Mahonin 3e7c5f
		resetState();
Ivan Mahonin da4619
		heliDoTests();
Ivan Mahonin da4619
		
bw aaf750
		viewportByWindow();
bw aaf750
		projectionByViewport();
bw aaf750
		heliDrawingPrepareFrame();
bw aaf750
		
bw aaf750
		if (initCallback) initCallback();
Ivan Mahonin a20939
		run();
Ivan Mahonin a20939
		if (deinitCallback) deinitCallback();
Ivan Mahonin a20939
		
Ivan Mahonin a20939
		heliArrayClear(&heliObjectsSet);
Ivan Mahonin a20939
		heliSpriteFinish();
Ivan Mahonin a20939
		heliDrawingFinish();
Ivan Mahonin a20939
		heliFontFinish();
Ivan Mahonin a20939
		heliAnimationFinish();
Ivan Mahonin a20939
		heliSoundFinish();
Ivan Mahonin a20939
		heliArrayDestroy(&heliObjectsSet);
Ivan Mahonin a20939
		
Ivan Mahonin b6ebe9
		free(textInput);
Ivan Mahonin b6ebe9
		textInputSize = 0;
Ivan Mahonin b6ebe9
		
Ivan Mahonin a20939
		heliInitialized = FALSE;
Ivan Mahonin a20939
		
Ivan Mahonin a20939
		deinit();
Ivan Mahonin a20939
		
bw aaf750
		_mouseScrolledX = _mouseScrolledY = 0;
Ivan Mahonin a20939
		for(int i = 0; i < keyEventsCount; ++i)
Ivan Mahonin a20939
			heliArrayDestroy(&keyEvents[i]);
Ivan Mahonin a20939
	}
Ivan Mahonin 3f9996
	
Ivan Mahonin 3f9996
	started = FALSE;
Ivan Mahonin 3f9996
}