Ver Fonte

Merge branch 'master' of github.com:taylor001/crown

Daniele Bartolini há 10 anos atrás
pai
commit
967ab9d5e9

+ 1 - 1
genie/toolchain.lua

@@ -234,7 +234,7 @@ function toolchain(build_dir, lib_dir)
 		}
 
 	configuration { "vs*" }
-		includedirs { CROWN_DIR .. "engine/core/compat/msvc" }
+		includedirs { CROWN_DIR .. "src/core/compat/msvc" }
 		defines {
 			"WIN32",
 			"_WIN32",

+ 4 - 0
src/config.h

@@ -82,6 +82,10 @@
 	#define CROWN_DATA_DIRECTORY "data"
 #endif // CROWN_DATA_DIRECTORY
 
+#ifndef CROWN_MAX_JOYPADS
+	#define CROWN_MAX_JOYPADS 4
+#endif // CROWN_MAX_JOYPADS
+
 #ifndef CE_MAX_SOUND_INSTANCES
 	#define CE_MAX_SOUND_INSTANCES 64 // Per world
 #endif // CE_MAX

+ 0 - 43
src/core/filesystem/filesystem.h

@@ -17,49 +17,6 @@ namespace crown
 /// Provides a platform-independent way to access files and directories
 /// on the host filesystem.
 ///
-/// Accessing files:
-/// Every file and every directory must be accessed through the Filesystem.
-/// Not a single C/C++ std file io call or other similar facilities
-/// should be used in any other part of the engine in order to maintain
-/// absolute platform independence.
-///
-/// Filesystem maintains a root path which acts as base directory for every
-/// file operation; access to files outside the root path is not allowed. If
-/// you really need it, instantiate another filesystem whith the appropriate
-/// root path (e.g.)
-///
-/// Filesystem fs("/home/foo"); // fs will use "/home/foo" as root path
-///
-/// fs.is_file("bar.txt");      // file "bar.txt" is relative to the root path,
-///                             // so it refers to "/home/foo/bar.txt"
-///
-/// The filesystem will take care of the necessary path conversions.
-/// The root path must be an absolute path for the underlying operating system.
-/// Examples of valid root paths:
-///
-/// 1) "/home/foo"
-/// 2) "C:\Users\Phil"
-///
-/// The relative paths, used to access files, must follow some strict rules:
-///
-/// a) Only unix-like pathnames (i.e. case sensitive and using '/' as separator)
-///    are allowed.
-/// b) Only relative paths are allowed: the filesystem is responsible for
-///    the creation of its absolute platform-specific counterpart.
-/// c) Filesystem forbids pathnames containing '.' and '..' to prevent access to
-///    files outside the filesystem's root path.
-/// d) Platform specific characters like '/', '\\' and ':' are forbidden as well.
-/// e) Symlinks, on platforms which support them, are _not_ resolved for the same
-///    reason of c)
-/// f) Although mixed-case pathnames are allowed, it is generally safer to use
-///    only lower-case ones for maximum compatibility.
-///
-/// Examples of valid relative paths.
-///
-/// 1) data/textures/grass.texture
-/// 2) grass.texture
-/// 3) foo/bar
-///
 /// @ingroup Filesystem
 class Filesystem
 {

+ 1 - 1
src/core/filesystem/os_file.h

@@ -49,7 +49,7 @@ public:
 		CE_ASSERT(_file != NULL, "Unable to open file: %s", path);
 #elif CROWN_PLATFORM_WINDOWS
 		_file = CreateFile(path
-			, mode == FOM_READ ? GENERIC_READ : GENERIC_WRITE,
+			, mode == FOM_READ ? GENERIC_READ : GENERIC_WRITE
 			, 0
 			, NULL
 			, OPEN_ALWAYS

+ 1 - 2
src/core/memory/memory.h

@@ -29,13 +29,12 @@ namespace memory
 		CE_ASSERT(align % 2 == 0 || align == 1, "Alignment must be a power of two");
 
 		uintptr_t ptr = (uintptr_t)p;
-
 		const uint32_t mod = ptr % align;
 
 		if (mod)
 			ptr += align - mod;
 
-		return (void*) ptr;
+		return (void*)ptr;
 	}
 
 	/// Respects standard behaviour when calling on NULL @a ptr

+ 60 - 1
src/core/os_event_queue.h

@@ -67,6 +67,26 @@ struct OsTouchEvent
 	bool pressed;
 };
 
+/// Represents an event fired by joystick
+struct OsJoypadEvent
+{
+	enum Enum
+	{
+		BUTTON,
+		AXIS,
+		CONNECTED
+	};
+
+	OsJoypadEvent::Enum type;
+	uint8_t index;
+	bool connected;
+	uint8_t button;
+	bool pressed;
+	float x;
+	float y;
+	float z;
+};
+
 /// Represents an event fired by accelerometer.
 struct OsAccelerometerEvent
 {
@@ -85,6 +105,7 @@ struct OsEvent
 		KEYBOARD,
 		MOUSE,
 		TOUCH,
+		JOYPAD,
 		ACCELEROMETER,
 
 		METRICS,
@@ -102,11 +123,12 @@ struct OsEvent
 		OsMouseEvent mouse;
 		OsKeyboardEvent keyboard;
 		OsTouchEvent touch;
+		OsJoypadEvent joypad;
 		OsAccelerometerEvent accelerometer;
 	};
 };
 
-#define MAX_OS_EVENTS 64
+#define MAX_OS_EVENTS 4096
 
 /// Single Producer Single Consumer event queue.
 /// Used only to pass events from os thread to main thread.
@@ -176,6 +198,43 @@ struct OsEventQueue
 		push_event(ev);
 	}
 
+	void push_joypad_event(uint8_t i, bool connected)
+	{
+		OsEvent ev;
+		ev.type = OsEvent::JOYPAD;
+		ev.joypad.type = OsJoypadEvent::CONNECTED;
+		ev.joypad.index = i;
+		ev.joypad.connected = connected;
+
+		push_event(ev);
+	}
+
+	void push_joypad_event(uint8_t i, uint8_t button, bool pressed)
+	{
+		OsEvent ev;
+		ev.type = OsEvent::JOYPAD;
+		ev.joypad.type = OsJoypadEvent::BUTTON;
+		ev.joypad.index = i;
+		ev.joypad.button = button;
+		ev.joypad.pressed = pressed;
+
+		push_event(ev);
+	}
+
+	void push_joypad_event(uint8_t i, uint8_t axis, float x, float y, float z)
+	{
+		OsEvent ev;
+		ev.type = OsEvent::JOYPAD;
+		ev.joypad.type = OsJoypadEvent::AXIS;
+		ev.joypad.index = i;
+		ev.joypad.button = axis;
+		ev.joypad.x = x;
+		ev.joypad.y = y;
+		ev.joypad.z = z;
+
+		push_event(ev);
+	}
+
 	void push_touch_event(int16_t x, int16_t y, uint8_t pointer_id, bool pressed)
 	{
 		OsEvent ev;

+ 17 - 28
src/core/settings/float_setting.cpp

@@ -5,25 +5,26 @@
 
 #include "float_setting.h"
 #include "string_utils.h"
+#include "math_utils.h"
 
 namespace crown
 {
 
 static FloatSetting* g_float_settings_head = NULL;
 
-FloatSetting::FloatSetting(const char* name, const char* synopsis, float value, float min, float max) :
-	m_name(name),
-	m_synopsis(synopsis),
-	m_value(0),
-	m_min(min),
-	m_max(max),
-	m_next(NULL)
+FloatSetting::FloatSetting(const char* name, const char* synopsis, float value, float min, float max)
+	: _name(name)
+	, _synopsis(synopsis)
+	, _value(0)
+	, _min(min)
+	, _max(max)
+	, _next(NULL)
 {
 	*this = value;
 
 	if (g_float_settings_head != NULL)
 	{
-		m_next = g_float_settings_head;
+		_next = g_float_settings_head;
 	}
 
 	g_float_settings_head = this;
@@ -31,49 +32,37 @@ FloatSetting::FloatSetting(const char* name, const char* synopsis, float value,
 
 const char* FloatSetting::name() const
 {
-	return m_name;
+	return _name;
 }
 
 const char* FloatSetting::synopsis() const
 {
-	return m_synopsis;
+	return _synopsis;
 }
 
 float FloatSetting::value() const
 {
-	return m_value;
+	return _value;
 }
 
 float FloatSetting::min() const
 {
-	return m_min;
+	return _min;
 }
 
 float FloatSetting::max() const
 {
-	return m_max;
+	return _max;
 }
 
 FloatSetting::operator float()
 {
-	return m_value;
+	return _value;
 }
 
 FloatSetting& FloatSetting::operator=(const float value)
 {
-	if (value > m_max)
-	{
-		m_value = m_max;
-	}
-	else if (value < m_min)
-	{
-		m_value = m_min;
-	}
-	else
-	{
-		m_value = value;
-	}
-
+	_value = clamp(_min, _max, value);
 	return *this;
 }
 
@@ -88,7 +77,7 @@ FloatSetting* FloatSetting::find_setting(const char* name)
 			return head;
 		}
 
-		head = head->m_next;
+		head = head->_next;
 	}
 
 	return NULL;

+ 15 - 16
src/core/settings/float_setting.h

@@ -15,34 +15,33 @@ class FloatSetting
 {
 public:
 
-							FloatSetting(const char* name, const char* synopsis, float value, float min, float max);
+	FloatSetting(const char* name, const char* synopsis, float value, float min, float max);
 
-	const char*				name() const;
-	const char*				synopsis() const;
+	const char* name() const;
+	const char* synopsis() const;
 
-	float					value() const;
-	float					min() const;
-	float					max() const;
+	float value() const;
+	float min() const;
+	float max() const;
 
-							operator float();
-
-	FloatSetting&			operator=(const float value);
+	operator float();
+	FloatSetting& operator=(const float value);
 
 public:
 
 	/// Returns the setting @name or NULL if not found.
-	static FloatSetting*	find_setting(const char* name);
+	static FloatSetting* find_setting(const char* name);
 
 private:
 
-	const char*				m_name;
-	const char*				m_synopsis;
+	const char* _name;
+	const char* _synopsis;
 
-	float					m_value;
-	float					m_min;
-	float					m_max;
+	float _value;
+	float _min;
+	float _max;
 
-	FloatSetting*			m_next;
+	FloatSetting* _next;
 };
 
 } // namespace crown

+ 17 - 28
src/core/settings/int_setting.cpp

@@ -5,25 +5,26 @@
 
 #include "int_setting.h"
 #include "string_utils.h"
+#include "math_utils.h"
 
 namespace crown
 {
 
 static IntSetting* g_int_settings_head = NULL;
 
-IntSetting::IntSetting(const char* name, const char* synopsis, int32_t value, int32_t min, int32_t max) :
-	m_name(name),
-	m_synopsis(synopsis),
-	m_value(0),
-	m_min(min),
-	m_max(max),
-	m_next(NULL)
+IntSetting::IntSetting(const char* name, const char* synopsis, int32_t value, int32_t min, int32_t max)
+	: _name(name)
+	, _synopsis(synopsis)
+	, _value(0)
+	, _min(min)
+	, _max(max)
+	, _next(NULL)
 {
 	*this = value;
 
 	if (g_int_settings_head != NULL)
 	{
-		m_next = g_int_settings_head;
+		_next = g_int_settings_head;
 	}
 
 	g_int_settings_head = this;
@@ -31,49 +32,37 @@ IntSetting::IntSetting(const char* name, const char* synopsis, int32_t value, in
 
 const char* IntSetting::name() const
 {
-	return m_name;
+	return _name;
 }
 
 const char* IntSetting::synopsis() const
 {
-	return m_synopsis;
+	return _synopsis;
 }
 
 int32_t IntSetting::value() const
 {
-	return m_value;
+	return _value;
 }
 
 int32_t IntSetting::min() const
 {
-	return m_min;
+	return _min;
 }
 
 int32_t IntSetting::max() const
 {
-	return m_max;
+	return _max;
 }
 
 IntSetting::operator int()
 {
-	return m_value;
+	return _value;
 }
 
 IntSetting& IntSetting::operator=(const int32_t value)
 {
-	if (value > m_max)
-	{
-		m_value = m_max;
-	}
-	else if (value < m_min)
-	{
-		m_value = m_min;
-	}
-	else
-	{
-		m_value = value;
-	}
-
+	_value = clamp(_min, _max, value);
 	return *this;
 }
 
@@ -88,7 +77,7 @@ IntSetting*	IntSetting::find_setting(const char* name)
 			return head;
 		}
 
-		head = head->m_next;
+		head = head->_next;
 	}
 
 	return NULL;

+ 15 - 15
src/core/settings/int_setting.h

@@ -15,34 +15,34 @@ class IntSetting
 {
 public:
 
-						IntSetting(const char* name, const char* synopsis, int32_t value, int32_t min, int32_t max);
+	IntSetting(const char* name, const char* synopsis, int32_t value, int32_t min, int32_t max);
 
-	const char*			name() const;
-	const char*			synopsis() const;
+	const char* name() const;
+	const char* synopsis() const;
 
-	int32_t				value() const;
-	int32_t				min() const;
-	int32_t				max() const;
+	int32_t value() const;
+	int32_t min() const;
+	int32_t max() const;
 
-						operator int();
+	operator int();
 
-	IntSetting&			operator=(const int32_t value);
+	IntSetting& operator=(const int32_t value);
 
 public:
 
 	/// Returns the setting @name or NULL if not found.
-	static IntSetting*	find_setting(const char* name);
+	static IntSetting* find_setting(const char* name);
 
 private:
 
-	const char*			m_name;
-	const char*			m_synopsis;
+	const char* _name;
+	const char* _synopsis;
 
-	int32_t				m_value;
-	int32_t				m_min;
-	int32_t				m_max;
+	int32_t _value;
+	int32_t _min;
+	int32_t _max;
 
-	IntSetting*			m_next;
+	IntSetting* _next;
 };
 
 } // namespace crown

+ 11 - 12
src/core/settings/string_setting.cpp

@@ -11,17 +11,17 @@ namespace crown
 
 static StringSetting* g_string_settings_head = NULL;
 
-StringSetting::StringSetting(const char* name, const char* synopsis, const char* value) :
-	m_name(name),
-	m_synopsis(synopsis),
-	m_value(value),
-	m_next(NULL)
+StringSetting::StringSetting(const char* name, const char* synopsis, const char* value)
+	: _name(name)
+	, _synopsis(synopsis)
+	, _value(value)
+	, _next(NULL)
 {
 	*this = value;
 
 	if (g_string_settings_head != NULL)
 	{
-		m_next = g_string_settings_head;
+		_next = g_string_settings_head;
 	}
 
 	g_string_settings_head = this;
@@ -29,23 +29,22 @@ StringSetting::StringSetting(const char* name, const char* synopsis, const char*
 
 const char* StringSetting::name() const
 {
-	return m_name;
+	return _name;
 }
 
 const char* StringSetting::synopsis() const
 {
-	return m_synopsis;
+	return _synopsis;
 }
 
 const char*	StringSetting::value() const
 {
-	return m_value;
+	return _value;
 }
 
 StringSetting& StringSetting::operator=(const char* value)
 {
-	m_value = value;
-
+	_value = value;
 	return *this;
 }
 
@@ -60,7 +59,7 @@ StringSetting* StringSetting::find_setting(const char* name)
 			return head;
 		}
 
-		head = head->m_next;
+		head = head->_next;
 	}
 
 	return NULL;

+ 9 - 9
src/core/settings/string_setting.h

@@ -15,14 +15,14 @@ class StringSetting
 {
 public:
 
-							StringSetting(const char* name, const char* synopsis, const char* value);
+	StringSetting(const char* name, const char* synopsis, const char* value);
 
-	const char*				name() const;
-	const char*				synopsis() const;
+	const char* name() const;
+	const char* synopsis() const;
 
-	const char*				value() const;
+	const char* value() const;
 
-	StringSetting&			operator=(const char* value);
+	StringSetting& operator=(const char* value);
 
 public:
 
@@ -31,11 +31,11 @@ public:
 
 private:
 
-	const char*				m_name;
-	const char*				m_synopsis;
-	const char*				m_value;
+	const char* _name;
+	const char* _synopsis;
+	const char* _value;
 
-	StringSetting*			m_next;
+	StringSetting* _next;
 };
 
 } // namespace crown

+ 0 - 2
src/crown.cpp

@@ -63,7 +63,6 @@ bool init(const DeviceOptions& opts, Filesystem& fs)
 	physics_globals::init();
 	bgfx::init();
 	device_globals::init(opts, fs);
-	device()->init();
 	return true;
 }
 
@@ -81,7 +80,6 @@ void update()
 
 void shutdown()
 {
-	device()->shutdown();
 	device_globals::shutdown();
 	bgfx::shutdown();
 	physics_globals::shutdown();

+ 2 - 0
src/device.cpp

@@ -277,10 +277,12 @@ namespace device_globals
 	{
 		CE_ASSERT(_device == NULL, "Crown already initialized");
 		_device = new (_buffer) Device(opts, fs);
+		_device->init();
 	}
 
 	void shutdown()
 	{
+		_device->shutdown();
 		_device->~Device();
 		_device = NULL;
 	}

+ 10 - 0
src/input/input_device.cpp

@@ -15,6 +15,11 @@ const char* InputDevice::name() const
 	return _name;
 }
 
+bool InputDevice::connected() const
+{
+	return _connected;
+}
+
 uint8_t InputDevice::num_buttons() const
 {
 	return _num_buttons;
@@ -53,6 +58,11 @@ Vector3 InputDevice::axis(uint8_t i) const
 	return _axis[i];
 }
 
+void InputDevice::set_connected(bool connected)
+{
+	_connected = connected;
+}
+
 void InputDevice::set_button_state(uint8_t i, bool state)
 {
 	CE_ASSERT(i < _num_buttons, "Index out of bounds");

+ 6 - 0
src/input/input_device.h

@@ -16,6 +16,9 @@ struct InputDevice
 	/// Returns the name of the input device.
 	const char* name() const;
 
+	/// Returns whether the input device is connected and functioning.
+	bool connected() const;
+
 	/// Returns the number of buttons of the input device.
 	uint8_t num_buttons() const;
 
@@ -37,12 +40,15 @@ struct InputDevice
 	/// Returns the value of the axis @a i.
 	Vector3 axis(uint8_t i) const;
 
+	void set_connected(bool connected);
+
 	void set_button_state(uint8_t i, bool state);
 
 	void set_axis(uint8_t i, const Vector3& value);
 
 	void update();
 
+	bool _connected;
 	uint8_t _num_buttons;
 	uint8_t _num_axes;
 	uint8_t _last_button;

+ 20 - 0
src/input/input_manager.cpp

@@ -20,10 +20,20 @@ InputManager::InputManager()
 	_keyboard = create_input_device("Keyboard", KeyboardButton::COUNT, 0);
 	_mouse = create_input_device("Mouse", MouseButton::COUNT, 2);
 	_touch = create_input_device("Touch", TouchButton::COUNT, TouchButton::COUNT);
+
+	for (uint8_t i = 0; i < CROWN_MAX_JOYPADS; ++i)
+		_joypad[i] = create_input_device("Joypad", JoypadButton::COUNT, JoypadAxis::COUNT);
+
+	_keyboard->set_connected(true);
+	_mouse->set_connected(true);
+	_touch->set_connected(true);
 }
 
 InputManager::~InputManager()
 {
+	for (uint8_t i = 0; i < CROWN_MAX_JOYPADS; ++i)
+		default_allocator().deallocate(_joypad[i]);
+
 	default_allocator().deallocate(_touch);
 	default_allocator().deallocate(_mouse);
 	default_allocator().deallocate(_keyboard);
@@ -39,6 +49,7 @@ InputDevice* InputManager::create_input_device(const char* name, uint8_t num_but
 
 	InputDevice* id = (InputDevice*)default_allocator().allocate(size);
 
+	id->_connected = false;
 	id->_num_buttons = num_buttons;
 	id->_num_axes = num_axes;
 	id->_last_button = 0;
@@ -71,11 +82,20 @@ InputDevice* InputManager::touch()
 	return _touch;
 }
 
+InputDevice* InputManager::joypad(uint8_t i)
+{
+	CE_ASSERT(i < CROWN_MAX_JOYPADS, "Index out of bounds");
+	return _joypad[i];
+}
+
 void InputManager::update()
 {
 	_keyboard->update();
 	_mouse->update();
 	_touch->update();
+
+	for (uint8_t i = 0; i < CROWN_MAX_JOYPADS; ++i)
+		_joypad[i]->update();
 }
 
 } // namespace crown

+ 4 - 0
src/input/input_manager.h

@@ -30,6 +30,9 @@ public:
 	/// Returns the default touch input device.
 	InputDevice* touch();
 
+	/// Returns the joypad @a i.
+	InputDevice* joypad(uint8_t i);
+
 	/// Updates the input devices
 	void update();
 
@@ -38,6 +41,7 @@ private:
 	InputDevice* _keyboard;
 	InputDevice* _mouse;
 	InputDevice* _touch;
+	InputDevice* _joypad[CROWN_MAX_JOYPADS];
 };
 
 } // namespace crown

+ 43 - 0
src/input/input_types.h

@@ -8,6 +8,8 @@
 namespace crown
 {
 
+/// @defgroup Input Input
+
 class InputManager;
 struct InputDevice;
 
@@ -136,6 +138,8 @@ struct MouseButton
 };
 
 /// Enumerates touch panel buttons
+///
+/// @ingroup Input
 struct TouchButton
 {
 	enum Enum
@@ -148,4 +152,43 @@ struct TouchButton
 	};
 };
 
+/// Enumerates joypad buttons.
+///
+/// @ingroup Input
+struct JoypadButton
+{
+	enum Enum
+	{
+		UP,
+		DOWN,
+		LEFT,
+		RIGHT,
+		START,
+		BACK,
+		GUIDE,
+		LEFT_THUMB,
+		RIGHT_THUMB,
+		LEFT_SHOULDER,
+		RIGHT_SHOULDER,
+		A,
+		B,
+		X,
+		Y,
+		COUNT
+	};
+};
+
+/// Enumerates joypad axes.
+///
+/// @ingroup Input
+struct JoypadAxis
+{
+	enum Enum
+	{
+		LEFT,
+		RIGHT,
+		COUNT
+	};
+};
+
 } // namespace crown

+ 336 - 0
src/lua/lua_input.cpp

@@ -0,0 +1,336 @@
+/*
+ * Copyright (c) 2012-2015 Daniele Bartolini and individual contributors.
+ * License: https://github.com/taylor001/crown/blob/master/LICENSE
+ */
+
+#include "lua_stack.h"
+#include "lua_environment.h"
+#include "device.h"
+#include "input_manager.h"
+#include "input_device.h"
+
+namespace crown
+{
+
+static int input_device_name(lua_State* L, InputDevice& id)
+{
+	LuaStack stack(L);
+	stack.push_string(id.name());
+	return 1;
+}
+
+static int input_device_connected(lua_State* L, InputDevice& id)
+{
+	LuaStack stack(L);
+	stack.push_bool(id.connected());
+	return 1;
+}
+
+static int input_device_num_buttons(lua_State* L, InputDevice& id)
+{
+	LuaStack stack(L);
+	stack.push_uint32(id.num_buttons());
+	return 1;
+}
+
+static int input_device_num_axes(lua_State* L, InputDevice& id)
+{
+	LuaStack stack(L);
+	stack.push_uint32(id.num_axes());
+	return 1;
+}
+
+static int input_device_pressed(lua_State* L, InputDevice& id)
+{
+	LuaStack stack(L);
+	stack.push_bool(id.pressed(stack.get_int(1)));
+	return 1;
+}
+
+static int input_device_released(lua_State* L, InputDevice& id)
+{
+	LuaStack stack(L);
+	stack.push_bool(id.released(stack.get_int(1)));
+	return 1;
+}
+
+static int input_device_any_pressed(lua_State* L, InputDevice& id)
+{
+	LuaStack stack(L);
+	stack.push_bool(id.any_pressed());
+	return 1;
+}
+
+static int input_device_any_released(lua_State* L, InputDevice& id)
+{
+	LuaStack stack(L);
+	stack.push_bool(id.any_released());
+	return 1;
+}
+
+static int input_device_axis(lua_State* L, InputDevice& id)
+{
+	LuaStack stack(L);
+	stack.push_vector3(id.axis(stack.get_int(1)));
+	return 1;
+}
+
+#define KEYBOARD_FN(name) keyboard_##name
+#define MOUSE_FN(name) mouse_##name
+#define TOUCH_FN(name) touch_##name
+#define JOYPAD_FN(index, name) joypad_##name##index
+
+#define KEYBOARD(name) static int KEYBOARD_FN(name)(lua_State* L)\
+	{ return input_device_##name(L, *device()->input_manager()->keyboard()); }
+#define MOUSE(name) static int MOUSE_FN(name)(lua_State* L)\
+	{ return input_device_##name(L, *device()->input_manager()->mouse()); }
+#define TOUCH(name) static int TOUCH_FN(name)(lua_State* L)\
+	{ return input_device_##name(L, *device()->input_manager()->touch()); }
+#define JOYPAD(index, name) static int JOYPAD_FN(index, name)(lua_State* L)\
+	{ return input_device_##name(L, *device()->input_manager()->joypad(index)); }
+
+KEYBOARD(name)
+KEYBOARD(connected)
+KEYBOARD(num_buttons)
+KEYBOARD(num_axes)
+KEYBOARD(pressed)
+KEYBOARD(released)
+KEYBOARD(any_pressed)
+KEYBOARD(any_released)
+// KEYBOARD(axis) // Keyboard has no axis
+
+MOUSE(name)
+MOUSE(connected)
+MOUSE(num_buttons)
+MOUSE(num_axes)
+MOUSE(pressed)
+MOUSE(released)
+MOUSE(any_pressed)
+MOUSE(any_released)
+MOUSE(axis)
+
+TOUCH(name)
+TOUCH(connected)
+TOUCH(num_buttons)
+TOUCH(num_axes)
+TOUCH(pressed)
+TOUCH(released)
+TOUCH(any_pressed)
+TOUCH(any_released)
+TOUCH(axis)
+
+JOYPAD(0, name)
+JOYPAD(0, connected)
+JOYPAD(0, num_buttons)
+JOYPAD(0, num_axes)
+JOYPAD(0, pressed)
+JOYPAD(0, released)
+JOYPAD(0, any_pressed)
+JOYPAD(0, any_released)
+JOYPAD(0, axis)
+
+JOYPAD(1, name)
+JOYPAD(1, connected)
+JOYPAD(1, num_buttons)
+JOYPAD(1, num_axes)
+JOYPAD(1, pressed)
+JOYPAD(1, released)
+JOYPAD(1, any_pressed)
+JOYPAD(1, any_released)
+JOYPAD(1, axis)
+
+JOYPAD(2, name)
+JOYPAD(2, connected)
+JOYPAD(2, num_buttons)
+JOYPAD(2, num_axes)
+JOYPAD(2, pressed)
+JOYPAD(2, released)
+JOYPAD(2, any_pressed)
+JOYPAD(2, any_released)
+JOYPAD(2, axis)
+
+JOYPAD(3, name)
+JOYPAD(3, connected)
+JOYPAD(3, num_buttons)
+JOYPAD(3, num_axes)
+JOYPAD(3, pressed)
+JOYPAD(3, released)
+JOYPAD(3, any_pressed)
+JOYPAD(3, any_released)
+JOYPAD(3, axis)
+
+void load_input(LuaEnvironment& env)
+{
+	env.load_module_function("Keyboard", "name",         KEYBOARD_FN(name));
+	env.load_module_function("Keyboard", "connected",    KEYBOARD_FN(connected));
+	env.load_module_function("Keyboard", "num_buttons",  KEYBOARD_FN(num_buttons));
+	env.load_module_function("Keyboard", "num_axes",     KEYBOARD_FN(num_axes));
+	env.load_module_function("Keyboard", "pressed",      KEYBOARD_FN(pressed));
+	env.load_module_function("Keyboard", "released",     KEYBOARD_FN(released));
+	env.load_module_function("Keyboard", "any_pressed",  KEYBOARD_FN(any_pressed));
+	env.load_module_function("Keyboard", "any_released", KEYBOARD_FN(any_released));
+
+	env.load_module_enum("Keyboard", "TAB",       KeyboardButton::TAB);
+	env.load_module_enum("Keyboard", "ENTER",     KeyboardButton::ENTER);
+	env.load_module_enum("Keyboard", "ESCAPE",    KeyboardButton::ESCAPE);
+	env.load_module_enum("Keyboard", "SPACE",     KeyboardButton::SPACE);
+	env.load_module_enum("Keyboard", "BACKSPACE", KeyboardButton::BACKSPACE);
+	env.load_module_enum("Keyboard", "KP_0",      KeyboardButton::KP_0);
+	env.load_module_enum("Keyboard", "KP_1",      KeyboardButton::KP_1);
+	env.load_module_enum("Keyboard", "KP_2",      KeyboardButton::KP_2);
+	env.load_module_enum("Keyboard", "KP_3",      KeyboardButton::KP_3);
+	env.load_module_enum("Keyboard", "KP_4",      KeyboardButton::KP_4);
+	env.load_module_enum("Keyboard", "KP_5",      KeyboardButton::KP_5);
+	env.load_module_enum("Keyboard", "KP_6",      KeyboardButton::KP_6);
+	env.load_module_enum("Keyboard", "KP_7",      KeyboardButton::KP_7);
+	env.load_module_enum("Keyboard", "KP_8",      KeyboardButton::KP_8);
+	env.load_module_enum("Keyboard", "KP_9",      KeyboardButton::KP_9);
+	env.load_module_enum("Keyboard", "F1",        KeyboardButton::F1);
+	env.load_module_enum("Keyboard", "F2",        KeyboardButton::F2);
+	env.load_module_enum("Keyboard", "F3",        KeyboardButton::F3);
+	env.load_module_enum("Keyboard", "F4",        KeyboardButton::F4);
+	env.load_module_enum("Keyboard", "F5",        KeyboardButton::F5);
+	env.load_module_enum("Keyboard", "F6",        KeyboardButton::F6);
+	env.load_module_enum("Keyboard", "F7",        KeyboardButton::F7);
+	env.load_module_enum("Keyboard", "F8",        KeyboardButton::F8);
+	env.load_module_enum("Keyboard", "F9",        KeyboardButton::F9);
+	env.load_module_enum("Keyboard", "F10",       KeyboardButton::F10);
+	env.load_module_enum("Keyboard", "F11",       KeyboardButton::F11);
+	env.load_module_enum("Keyboard", "F12",       KeyboardButton::F12);
+	env.load_module_enum("Keyboard", "HOME",      KeyboardButton::HOME);
+	env.load_module_enum("Keyboard", "LEFT",      KeyboardButton::LEFT);
+	env.load_module_enum("Keyboard", "UP",        KeyboardButton::UP);
+	env.load_module_enum("Keyboard", "RIGHT",     KeyboardButton::RIGHT);
+	env.load_module_enum("Keyboard", "DOWN",      KeyboardButton::DOWN);
+	env.load_module_enum("Keyboard", "PAGE_UP",   KeyboardButton::PAGE_UP);
+	env.load_module_enum("Keyboard", "PAGE_DOWN", KeyboardButton::PAGE_DOWN);
+	env.load_module_enum("Keyboard", "LCONTROL",  KeyboardButton::LCONTROL);
+	env.load_module_enum("Keyboard", "RCONTROL",  KeyboardButton::RCONTROL);
+	env.load_module_enum("Keyboard", "LSHIFT",    KeyboardButton::LSHIFT);
+	env.load_module_enum("Keyboard", "RSHIFT",    KeyboardButton::RSHIFT);
+	env.load_module_enum("Keyboard", "CAPS_LOCK", KeyboardButton::CAPS_LOCK);
+	env.load_module_enum("Keyboard", "LALT",      KeyboardButton::LALT);
+	env.load_module_enum("Keyboard", "RALT",      KeyboardButton::RALT);
+	env.load_module_enum("Keyboard", "LSUPER",    KeyboardButton::LSUPER);
+	env.load_module_enum("Keyboard", "RSUPER",    KeyboardButton::RSUPER);
+	env.load_module_enum("Keyboard", "NUM_0",     KeyboardButton::NUM_0);
+	env.load_module_enum("Keyboard", "NUM_1",     KeyboardButton::NUM_1);
+	env.load_module_enum("Keyboard", "NUM_2",     KeyboardButton::NUM_2);
+	env.load_module_enum("Keyboard", "NUM_3",     KeyboardButton::NUM_3);
+	env.load_module_enum("Keyboard", "NUM_4",     KeyboardButton::NUM_4);
+	env.load_module_enum("Keyboard", "NUM_5",     KeyboardButton::NUM_5);
+	env.load_module_enum("Keyboard", "NUM_6",     KeyboardButton::NUM_6);
+	env.load_module_enum("Keyboard", "NUM_7",     KeyboardButton::NUM_7);
+	env.load_module_enum("Keyboard", "NUM_8",     KeyboardButton::NUM_8);
+	env.load_module_enum("Keyboard", "NUM_9",     KeyboardButton::NUM_9);
+	env.load_module_enum("Keyboard", "A",         KeyboardButton::A);
+	env.load_module_enum("Keyboard", "B",         KeyboardButton::B);
+	env.load_module_enum("Keyboard", "C",         KeyboardButton::C);
+	env.load_module_enum("Keyboard", "D",         KeyboardButton::D);
+	env.load_module_enum("Keyboard", "E",         KeyboardButton::E);
+	env.load_module_enum("Keyboard", "F",         KeyboardButton::F);
+	env.load_module_enum("Keyboard", "G",         KeyboardButton::G);
+	env.load_module_enum("Keyboard", "H",         KeyboardButton::H);
+	env.load_module_enum("Keyboard", "I",         KeyboardButton::I);
+	env.load_module_enum("Keyboard", "J",         KeyboardButton::J);
+	env.load_module_enum("Keyboard", "K",         KeyboardButton::K);
+	env.load_module_enum("Keyboard", "L",         KeyboardButton::L);
+	env.load_module_enum("Keyboard", "M",         KeyboardButton::M);
+	env.load_module_enum("Keyboard", "N",         KeyboardButton::N);
+	env.load_module_enum("Keyboard", "O",         KeyboardButton::O);
+	env.load_module_enum("Keyboard", "P",         KeyboardButton::P);
+	env.load_module_enum("Keyboard", "Q",         KeyboardButton::Q);
+	env.load_module_enum("Keyboard", "R",         KeyboardButton::R);
+	env.load_module_enum("Keyboard", "S",         KeyboardButton::S);
+	env.load_module_enum("Keyboard", "T",         KeyboardButton::T);
+	env.load_module_enum("Keyboard", "U",         KeyboardButton::U);
+	env.load_module_enum("Keyboard", "V",         KeyboardButton::V);
+	env.load_module_enum("Keyboard", "W",         KeyboardButton::W);
+	env.load_module_enum("Keyboard", "X",         KeyboardButton::X);
+	env.load_module_enum("Keyboard", "Y",         KeyboardButton::Y);
+	env.load_module_enum("Keyboard", "Z",         KeyboardButton::Z);
+
+	env.load_module_function("Mouse", "name",         MOUSE_FN(name));
+	env.load_module_function("Mouse", "connected",    MOUSE_FN(connected));
+	env.load_module_function("Mouse", "num_buttons",  MOUSE_FN(num_buttons));
+	env.load_module_function("Mouse", "num_axes",     MOUSE_FN(num_axes));
+	env.load_module_function("Mouse", "pressed",      MOUSE_FN(pressed));
+	env.load_module_function("Mouse", "released",     MOUSE_FN(released));
+	env.load_module_function("Mouse", "any_pressed",  MOUSE_FN(any_pressed));
+	env.load_module_function("Mouse", "any_released", MOUSE_FN(any_released));
+	env.load_module_function("Mouse", "axis",         MOUSE_FN(axis));
+
+	env.load_module_enum("Mouse", "LEFT",   MouseButton::LEFT);
+	env.load_module_enum("Mouse", "MIDDLE", MouseButton::MIDDLE);
+	env.load_module_enum("Mouse", "RIGHT",  MouseButton::RIGHT);
+
+	env.load_module_function("Touch", "name",         TOUCH_FN(name));
+	env.load_module_function("Touch", "connected",    TOUCH_FN(connected));
+	env.load_module_function("Touch", "num_buttons",  TOUCH_FN(num_buttons));
+	env.load_module_function("Touch", "num_axes",     TOUCH_FN(num_axes));
+	env.load_module_function("Touch", "pressed",      TOUCH_FN(pressed));
+	env.load_module_function("Touch", "released",     TOUCH_FN(released));
+	env.load_module_function("Touch", "any_pressed",  TOUCH_FN(any_pressed));
+	env.load_module_function("Touch", "any_released", TOUCH_FN(any_released));
+	env.load_module_function("Touch", "axis",         TOUCH_FN(axis));
+
+	env.load_module_function("Pad1", "name",         JOYPAD_FN(0, name));
+	env.load_module_function("Pad1", "connected",    JOYPAD_FN(0, connected));
+	env.load_module_function("Pad1", "num_buttons",  JOYPAD_FN(0, num_buttons));
+	env.load_module_function("Pad1", "num_axes",     JOYPAD_FN(0, num_axes));
+	env.load_module_function("Pad1", "pressed",      JOYPAD_FN(0, pressed));
+	env.load_module_function("Pad1", "released",     JOYPAD_FN(0, released));
+	env.load_module_function("Pad1", "any_pressed",  JOYPAD_FN(0, any_pressed));
+	env.load_module_function("Pad1", "any_released", JOYPAD_FN(0, any_released));
+	env.load_module_function("Pad1", "axis",         JOYPAD_FN(0, axis));
+
+	env.load_module_function("Pad2", "name",         JOYPAD_FN(1, name));
+	env.load_module_function("Pad2", "connected",    JOYPAD_FN(1, connected));
+	env.load_module_function("Pad2", "num_buttons",  JOYPAD_FN(1, num_buttons));
+	env.load_module_function("Pad2", "num_axes",     JOYPAD_FN(1, num_axes));
+	env.load_module_function("Pad2", "pressed",      JOYPAD_FN(1, pressed));
+	env.load_module_function("Pad2", "released",     JOYPAD_FN(1, released));
+	env.load_module_function("Pad2", "any_pressed",  JOYPAD_FN(1, any_pressed));
+	env.load_module_function("Pad2", "any_released", JOYPAD_FN(1, any_released));
+	env.load_module_function("Pad2", "axis",         JOYPAD_FN(1, axis));
+
+	env.load_module_function("Pad3", "name",         JOYPAD_FN(2, name));
+	env.load_module_function("Pad3", "connected",    JOYPAD_FN(2, connected));
+	env.load_module_function("Pad3", "num_buttons",  JOYPAD_FN(2, num_buttons));
+	env.load_module_function("Pad3", "num_axes",     JOYPAD_FN(2, num_axes));
+	env.load_module_function("Pad3", "pressed",      JOYPAD_FN(2, pressed));
+	env.load_module_function("Pad3", "released",     JOYPAD_FN(2, released));
+	env.load_module_function("Pad3", "any_pressed",  JOYPAD_FN(2, any_pressed));
+	env.load_module_function("Pad3", "any_released", JOYPAD_FN(2, any_released));
+	env.load_module_function("Pad3", "axis",         JOYPAD_FN(2, axis));
+
+	env.load_module_function("Pad4", "name",         JOYPAD_FN(3, name));
+	env.load_module_function("Pad4", "connected",    JOYPAD_FN(3, connected));
+	env.load_module_function("Pad4", "num_buttons",  JOYPAD_FN(3, num_buttons));
+	env.load_module_function("Pad4", "num_axes",     JOYPAD_FN(3, num_axes));
+	env.load_module_function("Pad4", "pressed",      JOYPAD_FN(3, pressed));
+	env.load_module_function("Pad4", "released",     JOYPAD_FN(3, released));
+	env.load_module_function("Pad4", "any_pressed",  JOYPAD_FN(3, any_pressed));
+	env.load_module_function("Pad4", "any_released", JOYPAD_FN(3, any_released));
+	env.load_module_function("Pad4", "axis",         JOYPAD_FN(3, axis));
+
+	env.load_module_enum("JoypadButton", "UP",             JoypadButton::UP);
+	env.load_module_enum("JoypadButton", "DOWN",           JoypadButton::DOWN);
+	env.load_module_enum("JoypadButton", "LEFT",           JoypadButton::LEFT);
+	env.load_module_enum("JoypadButton", "RIGHT",          JoypadButton::RIGHT);
+	env.load_module_enum("JoypadButton", "START",          JoypadButton::START);
+	env.load_module_enum("JoypadButton", "BACK",           JoypadButton::BACK);
+	env.load_module_enum("JoypadButton", "LEFT_THUMB",     JoypadButton::LEFT_THUMB);
+	env.load_module_enum("JoypadButton", "RIGHT_THUMB",    JoypadButton::RIGHT_THUMB);
+	env.load_module_enum("JoypadButton", "LEFT_SHOULDER",  JoypadButton::LEFT_SHOULDER);
+	env.load_module_enum("JoypadButton", "RIGHT_SHOULDER", JoypadButton::RIGHT_SHOULDER);
+	env.load_module_enum("JoypadButton", "A",              JoypadButton::A);
+	env.load_module_enum("JoypadButton", "B",              JoypadButton::B);
+	env.load_module_enum("JoypadButton", "X",              JoypadButton::X);
+	env.load_module_enum("JoypadButton", "Y",              JoypadButton::Y);
+
+	env.load_module_enum("JoypadAxis", "LEFT",  JoypadAxis::LEFT);
+	env.load_module_enum("JoypadAxis", "RIGHT", JoypadAxis::RIGHT);
+}
+
+} // namespace crown

+ 2 - 1
src/lua/lua_stack.h

@@ -42,7 +42,8 @@
 	#define CHECKSTRING(stack, i) luaL_checkstring(stack, i)
 
 	#define LUA_ASSERT(condition, stack, msg, ...) do { if (!(condition)) {\
-		stack.push_fstring("\nLua assertion failed: %s\n\t" msg "\n", #condition, ##__VA_ARGS__); lua_error(stack.state()); }} while (0);
+		stack.push_fstring("\nLua assertion failed: %s\n\t" msg "\n", #condition, ##__VA_ARGS__);\
+		lua_error(stack.state()); }} while (0);
 #else
 	#define CHECKUDATA(stack, i, expected) lua_touserdata(stack, i)
 	#define CHECKLIGHTDATA(stack, i, cf, expected) lua_touserdata(stack, i)

+ 22 - 2
src/main/main.cpp

@@ -39,7 +39,7 @@ bool process_events()
 						im->touch()->set_axis(ev.pointer_id, vector3(ev.x, ev.y, 0.0f));
 						break;
 					default:
-						CE_FATAL("Oops, unknown touch event type");
+						CE_FATAL("Unknown touch event type");
 						break;
 				}
 				break;
@@ -59,7 +59,7 @@ bool process_events()
 						im->mouse()->set_axis(1, vector3(ev.wheel, 0.0f, 0.0f));
 						break;
 					default:
-						CE_FATAL("Oops, unknown mouse event type");
+						CE_FATAL("Unknown mouse event type");
 						break;
 				}
 				break;
@@ -70,6 +70,26 @@ bool process_events()
 				im->keyboard()->set_button_state(ev.button, ev.pressed);
 				break;
 			}
+			case OsEvent::JOYPAD:
+			{
+				const OsJoypadEvent& ev = event.joypad;
+				switch (ev.type)
+				{
+					case OsJoypadEvent::CONNECTED:
+						im->joypad(ev.index)->set_connected(ev.connected);
+						break;
+					case OsJoypadEvent::BUTTON:
+						im->joypad(ev.index)->set_button_state(ev.button, ev.pressed);
+						break;
+					case OsJoypadEvent::AXIS:
+						im->joypad(ev.index)->set_axis(ev.button, vector3(ev.x, ev.y, ev.z));
+						break;
+					default:
+						CE_FATAL("Unknown joypad event");
+						break;
+				}
+				break;
+			}
 			case OsEvent::METRICS:
 			{
 				const OsMetricsEvent& ev = event.metrics;

+ 18 - 23
src/main/main_windows.cpp

@@ -117,13 +117,13 @@ static bool s_exit = false;
 struct MainThreadArgs
 {
 	Filesystem* fs;
-	ConfigSettings* cs;
+	DeviceOptions* opts;
 };
 
 int32_t func(void* data)
 {
 	MainThreadArgs* args = (MainThreadArgs*)data;
-	crown::init(*args->fs, *args->cs);
+	crown::init(*args->opts, *args->fs);
 	crown::update();
 	crown::shutdown();
 	s_exit = true;
@@ -138,7 +138,7 @@ struct WindowsDevice
 	{
 	}
 
-	int32_t	run(Filesystem* fs, ConfigSettings* cs)
+	int32_t	run(Filesystem* fs, DeviceOptions* opts)
 	{
 		HINSTANCE instance = (HINSTANCE)GetModuleHandle(NULL);
 		WNDCLASSEX wnd;
@@ -156,10 +156,10 @@ struct WindowsDevice
 		_hwnd = CreateWindowA("crown"
 			, "Crown"
 			, WS_OVERLAPPEDWINDOW | WS_VISIBLE
-			, 0
-			, 0
-			, cs->window_width
-			, cs->window_height
+			, opts->window_x()
+			, opts->window_y()
+			, opts->window_width()
+			, opts->window_height()
 			, 0
 			, NULL
 			, instance
@@ -170,7 +170,7 @@ struct WindowsDevice
 
 		MainThreadArgs mta;
 		mta.fs = fs;
-		mta.cs = cs;
+		mta.opts = opts;
 
 		Thread main_thread;
 		main_thread.start(func, &mta);
@@ -313,6 +313,7 @@ bool next_event(OsEvent& ev)
 int main(int argc, char** argv)
 {
 	using namespace crown;
+	memory_globals::init();
 
 	WSADATA dummy;
 	int err = WSAStartup(MAKEWORD(2, 2), &dummy);
@@ -320,34 +321,28 @@ int main(int argc, char** argv)
 	CE_UNUSED(dummy);
 	CE_UNUSED(err);
 
-	ConfigSettings cs;
-	parse_command_line(argc, argv, cs);
-
-	memory_globals::init();
-	{
-		DiskFilesystem fs(cs.source_dir);
-		parse_config_file(fs, cs);
-	}
-
-	console_server_globals::init(cs.console_port, cs.wait_console);
+	DeviceOptions opts(argc, argv);
 
-	bundle_compiler_globals::init(cs.source_dir, cs.bundle_dir);
+	console_server_globals::init(opts.console_port(), opts.wait_console());
+	bundle_compiler_globals::init(opts.source_dir(), opts.bundle_dir());
 
 	bool do_continue = true;
 	int exitcode = EXIT_SUCCESS;
 
-	do_continue = bundle_compiler::main(cs.do_compile, cs.do_continue, cs.platform);
+	do_continue = bundle_compiler::main(opts.do_compile(), opts.do_continue(), opts.platform());
 
 	if (do_continue)
 	{
-		DiskFilesystem dst_fs(cs.bundle_dir);
-		exitcode = crown::s_wdvc.run(&dst_fs, &cs);
+		DiskFilesystem dst_fs(opts.bundle_dir());
+		exitcode = crown::s_wdvc.run(&dst_fs, &opts);
 	}
 
 	bundle_compiler_globals::shutdown();
 	console_server_globals::shutdown();
-	memory_globals::shutdown();
+
 	WSACleanup();
+
+	memory_globals::shutdown();
 	return exitcode;
 }