Sfoglia il codice sorgente

Add some code for Android touch input

Panagiotis Christopoulos Charitos 4 anni fa
parent
commit
79a1bf36bd

+ 2 - 3
AnKi/Core/App.cpp

@@ -293,7 +293,7 @@ void App::cleanup()
 	m_threadHive = nullptr;
 	GrManager::deleteInstance(m_gr);
 	m_gr = nullptr;
-	m_heapAlloc.deleteInstance(m_input);
+	Input::deleteInstance(m_input);
 	m_input = nullptr;
 	m_heapAlloc.deleteInstance(m_window);
 	m_window = nullptr;
@@ -401,8 +401,7 @@ Error App::initInternal(const ConfigSet& config_, AllocAlignedCallback allocCb,
 	//
 	// Input
 	//
-	m_input = m_heapAlloc.newInstance<Input>();
-	ANKI_CHECK(m_input->init(m_window));
+	ANKI_CHECK(Input::newInstance(m_allocCb, m_allocCbData, m_window, m_input));
 
 	//
 	// ThreadPool

+ 1 - 1
AnKi/Input/CMakeLists.txt

@@ -1,4 +1,4 @@
-set(SOURCES Input.cpp)
+set(SOURCES "")
 
 if(SDL)
 	set(SOURCES ${SOURCES} InputSdl.cpp)

+ 0 - 22
AnKi/Input/Input.cpp

@@ -1,22 +0,0 @@
-// Copyright (C) 2009-2021, Panagiotis Christopoulos Charitos and contributors.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#include <AnKi/Input/Input.h>
-#include <cstring>
-
-namespace anki
-{
-
-void Input::reset()
-{
-	zeroMemory(m_keys);
-	zeroMemory(m_mouseBtns);
-	m_mousePosNdc = Vec2(-1.0f);
-	m_mousePosWin = UVec2(0u);
-	zeroMemory(m_events);
-	zeroMemory(m_textInput);
-}
-
-} // end namespace anki

+ 50 - 34
AnKi/Input/Input.h

@@ -31,22 +31,10 @@ enum class InputEvent : U8
 class Input
 {
 public:
-	Input()
-	{
-	}
+	static ANKI_USE_RESULT Error newInstance(AllocAlignedCallback allocCallback, void* allocCallbackUserData,
+											 NativeWindow* nativeWindow, Input*& input);
 
-	~Input()
-	{
-		destroy();
-		ANKI_ASSERT(m_impl == nullptr);
-		ANKI_ASSERT(m_nativeWindow == nullptr);
-	}
-
-	ANKI_USE_RESULT Error init(NativeWindow* nativeWindow)
-	{
-		reset();
-		return initInternal(nativeWindow);
-	}
+	static void deleteInstance(Input* input);
 
 	U32 getKey(KeyCode i) const
 	{
@@ -69,13 +57,24 @@ public:
 	}
 
 	/// Get the times an event was triggered and resets the counter
-	U getEvent(InputEvent eventId) const
+	U32 getEvent(InputEvent eventId) const
 	{
-		return m_events[static_cast<U>(eventId)];
+		return m_events[eventId];
 	}
 
 	/// Reset the keys and mouse buttons
-	void reset();
+	void reset()
+	{
+		zeroMemory(m_keys);
+		zeroMemory(m_mouseBtns);
+		m_mousePosNdc = Vec2(-1.0f);
+		m_mousePosWin = UVec2(0u);
+		zeroMemory(m_events);
+		zeroMemory(m_textInput);
+		zeroMemory(m_touchPointers);
+		zeroMemory(m_touchPointerPosNdc);
+		zeroMemory(m_touchPointerPosWin);
+	}
 
 	/// Populate the key and button with the new state
 	ANKI_USE_RESULT Error handleEvents();
@@ -96,7 +95,7 @@ public:
 	/// Add a new event
 	void addEvent(InputEvent eventId)
 	{
-		++m_events[static_cast<U>(eventId)];
+		++m_events[eventId];
 	}
 
 	template<typename TFunc>
@@ -117,38 +116,55 @@ public:
 		return &m_textInput[0];
 	}
 
-private:
-	InputImpl* m_impl = nullptr;
-	NativeWindow* m_nativeWindow = nullptr;
+	U32 getTouchPointer(TouchPointer p) const
+	{
+		return m_touchPointers[p];
+	}
 
-	/// @name Keys and btns
-	/// @{
+	Vec2 getTouchPointerNdcPosition(TouchPointer p) const
+	{
+		return m_touchPointerPosNdc[p];
+	}
+
+	UVec2 getTouchPointerWindowPosition(TouchPointer p) const
+	{
+		return m_touchPointerPosWin[p];
+	}
+
+protected:
+	NativeWindow* m_nativeWindow = nullptr;
+	HeapAllocator<U8> m_alloc;
 
 	/// Shows the current key state
 	/// - 0 times: unpressed
 	/// - 1 times: pressed once
 	/// - >1 times: Kept pressed 'n' times continuously
-	Array<U32, static_cast<U>(KeyCode::COUNT)> m_keys;
+	Array<U32, U(KeyCode::COUNT)> m_keys;
 
 	/// Mouse btns. Supporting 3 btns & wheel. @see keys
 	Array<U32, U(MouseButton::COUNT)> m_mouseBtns;
-	/// @}
+	Vec2 m_mousePosNdc;
+	UVec2 m_mousePosWin;
 
-	Vec2 m_mousePosNdc = Vec2(2.0); ///< The coords are in the NDC space
-	UVec2 m_mousePosWin = UVec2(0u);
+	Array<U32, U(TouchPointer::COUNT)> m_touchPointers;
+	Array<Vec2, U(TouchPointer::COUNT)> m_touchPointerPosNdc;
+	Array<UVec2, U(TouchPointer::COUNT)> m_touchPointerPosWin;
 
-	Array<U8, static_cast<U>(InputEvent::COUNT)> m_events;
+	Array<U8, U(InputEvent::COUNT)> m_events;
 
 	/// The keybord input as ascii.
-	Array<char, static_cast<U>(KeyCode::COUNT)> m_textInput;
+	Array<char, U(KeyCode::COUNT)> m_textInput;
 
 	Bool m_lockCurs = false;
 
-	/// Initialize the platform's input system
-	ANKI_USE_RESULT Error initInternal(NativeWindow* nativeWindow);
+	Input()
+	{
+		reset();
+	}
 
-	/// Destroy the platform specific input system
-	void destroy();
+	~Input()
+	{
+	}
 };
 
 } // end namespace anki

+ 125 - 26
AnKi/Input/InputAndroid.cpp

@@ -3,28 +3,49 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#include <AnKi/Input/Input.h>
+#include <AnKi/Input/InputAndroid.h>
 #include <AnKi/Core/NativeWindowAndroid.h>
 #include <AnKi/Util/Logger.h>
-#include <AnKi/Core/App.h>
-#if ANKI_OS_ANDROID
-#	include <android_native_app_glue.h>
-#endif
 
 namespace anki
 {
 
-static void handleAndroidEvents(android_app* app, int32_t cmd)
+Error Input::newInstance(AllocAlignedCallback allocCallback, void* allocCallbackUserData, NativeWindow* nativeWindow,
+						 Input*& input)
 {
-	Input* input = static_cast<Input*>(app->userData);
-	ANKI_ASSERT(input != nullptr);
+	ANKI_ASSERT(allocCallback && nativeWindow);
 
-	switch(cmd)
+	HeapAllocator<U8> alloc(allocCallback, allocCallbackUserData);
+	InputAndroid* ainput =
+		static_cast<InputAndroid*>(alloc.getMemoryPool().allocate(sizeof(InputAndroid), alignof(InputAndroid)));
+	::new(ainput) InputAndroid();
+
+	ainput->m_alloc = alloc;
+	ainput->m_nativeWindow = nativeWindow;
+
+	const Error err = ainput->init();
+	if(err)
 	{
-	case APP_CMD_TERM_WINDOW:
-	case APP_CMD_LOST_FOCUS:
-		input->addEvent(InputEvent::WINDOW_CLOSED);
-		break;
+		ainput->~InputAndroid();
+		alloc.getMemoryPool().free(ainput);
+		input = nullptr;
+		return err;
+	}
+	else
+	{
+		input = ainput;
+		return Error::NONE;
+	}
+}
+
+void Input::deleteInstance(Input* input)
+{
+	if(input)
+	{
+		InputAndroid* self = static_cast<InputAndroid*>(input);
+		HeapAllocator<U8> alloc = self->m_alloc;
+		self->~InputAndroid();
+		alloc.getMemoryPool().free(self);
 	}
 }
 
@@ -45,30 +66,108 @@ Error Input::handleEvents()
 	return Error::NONE;
 }
 
-Error Input::initInternal(NativeWindow* window)
+void Input::moveCursor(const Vec2& posNdc)
 {
-	ANKI_ASSERT(window);
-	g_androidApp->userData = this;
-	g_androidApp->onAppCmd = handleAndroidEvents;
-	m_nativeWindow = window;
+	m_mousePosNdc = posNdc;
+	m_mousePosWin =
+		UVec2((posNdc * 0.5f + 0.5f) * Vec2(F32(m_nativeWindow->getWidth()), F32(m_nativeWindow->getHeight())));
+}
 
-	return Error::NONE;
+void Input::hideCursor(Bool hide)
+{
+	// do nothing
 }
 
-void Input::destroy()
+Error InputAndroid::init()
 {
+	ANKI_ASSERT(m_nativeWindow);
+	g_androidApp->userData = this;
+
+	g_androidApp->onAppCmd = [](android_app* app, int32_t cmd) {
+		InputAndroid* self = static_cast<InputAndroid*>(app->userData);
+		self->handleAndroidEvents(app, cmd);
+	};
+
+	g_androidApp->onInputEvent = [](android_app* app, AInputEvent* event) -> int {
+		InputAndroid* self = static_cast<InputAndroid*>(app->userData);
+		return self->handleAndroidInput(app, event);
+	};
+
+	return Error::NONE;
 }
 
-void Input::moveCursor(const Vec2& posNdc)
+void InputAndroid::handleAndroidEvents(android_app* app, int32_t cmd)
 {
-	m_mousePosNdc = posNdc;
-	m_mousePosWin =
-		UVec2((posNdc * 0.5f + 0.5f) * Vec2(F32(m_nativeWindow->getWidth()), F32(m_nativeWindow->getHeight())));
+	switch(cmd)
+	{
+	case APP_CMD_TERM_WINDOW:
+	case APP_CMD_LOST_FOCUS:
+		addEvent(InputEvent::WINDOW_CLOSED);
+		break;
+	}
 }
 
-void Input::hideCursor(Bool hide)
+int InputAndroid::handleAndroidInput(android_app* app, AInputEvent* event)
 {
-	// do nothing
+	const I32 type = AInputEvent_getType(event);
+	const I32 source = AInputEvent_getSource(event);
+	I32 handled = 0;
+
+	switch(type)
+	{
+	case AINPUT_EVENT_TYPE_KEY:
+		// TODO
+		break;
+
+	case AINPUT_EVENT_TYPE_MOTION:
+	{
+		const I32 pointer = AMotionEvent_getAction(event);
+		const I32 action = pointer & AMOTION_EVENT_ACTION_MASK;
+		const I32 index =
+			(pointer & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
+
+		if(source & AINPUT_SOURCE_JOYSTICK)
+		{
+			// TODO
+		}
+		else if(source & AINPUT_SOURCE_TOUCHSCREEN)
+		{
+			switch(action)
+			{
+			case AMOTION_EVENT_ACTION_DOWN:
+			case AMOTION_EVENT_ACTION_POINTER_DOWN:
+			{
+				F32 x = AMotionEvent_getX(event, index);
+				F32 y = AMotionEvent_getY(event, index);
+				int id = AMotionEvent_getPointerId(event, index);
+
+				ANKI_LOGI("Pointer down %f %f %d", x, y, id);
+				break;
+			}
+
+			case AMOTION_EVENT_ACTION_MOVE:
+			{
+				break;
+			}
+
+			case AMOTION_EVENT_ACTION_UP:
+			case AMOTION_EVENT_ACTION_POINTER_UP:
+			{
+				break;
+			}
+
+			default:
+				break;
+			}
+		}
+		break;
+	}
+
+	default:
+		break;
+	}
+
+	return handled;
 }
 
 } // end namespace anki

+ 25 - 0
AnKi/Input/InputAndroid.h

@@ -0,0 +1,25 @@
+// Copyright (C) 2009-2021, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma once
+
+#include <AnKi/Input.h>
+#include <AnKi/Input/KeyCode.h>
+#include <android_native_app_glue.h>
+
+namespace anki
+{
+
+/// Android input implementation
+class InputAndroid : public Input
+{
+public:
+	ANKI_USE_RESULT Error init();
+
+	void handleAndroidEvents(android_app* app, int32_t cmd);
+	int handleAndroidInput(android_app* app, AInputEvent* event);
+};
+
+} // end namespace anki

+ 72 - 44
AnKi/Input/InputSdl.cpp

@@ -32,18 +32,80 @@ static MouseButton sdlMouseButtonToAnKi(const U32 sdl)
 	return out;
 }
 
-Error Input::initInternal(NativeWindow* nativeWindow)
+Error Input::newInstance(AllocAlignedCallback allocCallback, void* allocCallbackUserData, NativeWindow* nativeWindow,
+						 Input*& input)
 {
-	ANKI_ASSERT(nativeWindow);
-	m_nativeWindow = nativeWindow;
+	ANKI_ASSERT(allocCallback && nativeWindow);
 
-	// Init native
-	HeapAllocator<std::pair<const SDL_Keycode, KeyCode>> alloc = m_nativeWindow->getAllocator();
+	HeapAllocator<U8> alloc(allocCallback, allocCallbackUserData);
+	InputSdl* sdlinput = static_cast<InputSdl*>(alloc.getMemoryPool().allocate(sizeof(InputSdl), alignof(InputSdl)));
+	::new(sdlinput) InputSdl(alloc);
 
-	m_impl = m_nativeWindow->getAllocator().newInstance<InputImpl>(alloc);
+	sdlinput->m_alloc = alloc;
+	sdlinput->m_nativeWindow = nativeWindow;
+
+	const Error err = sdlinput->init();
+	if(err)
+	{
+		sdlinput->~InputSdl();
+		alloc.getMemoryPool().free(sdlinput);
+		input = nullptr;
+		return err;
+	}
+	else
+	{
+		input = sdlinput;
+		return Error::NONE;
+	}
+}
+
+void Input::deleteInstance(Input* input)
+{
+	if(input)
+	{
+		InputSdl* self = static_cast<InputSdl*>(input);
+		HeapAllocator<U8> alloc = self->m_alloc;
+		self->~InputSdl();
+		alloc.getMemoryPool().free(self);
+	}
+}
+
+Error Input::handleEvents()
+{
+	InputSdl* self = static_cast<InputSdl*>(this);
+	return self->handleEventsInternal();
+}
+
+void Input::moveCursor(const Vec2& pos)
+{
+	if(pos != m_mousePosNdc)
+	{
+		const I32 x = I32(F32(m_nativeWindow->getWidth()) * (pos.x() * 0.5f + 0.5f));
+		const I32 y = I32(F32(m_nativeWindow->getHeight()) * (-pos.y() * 0.5f + 0.5f));
+
+		SDL_WarpMouseInWindow(m_nativeWindow->getNative().m_window, x, y);
+
+		// SDL doesn't generate a SDL_MOUSEMOTION event if the cursor is outside the window. Push that event
+		SDL_Event event;
+		event.type = SDL_MOUSEMOTION;
+		event.button.x = x;
+		event.button.y = y;
+
+		SDL_PushEvent(&event);
+	}
+}
+
+void Input::hideCursor(Bool hide)
+{
+	SDL_ShowCursor(!hide);
+}
+
+Error InputSdl::init()
+{
+	ANKI_ASSERT(m_nativeWindow);
 
 // impl
-#define MAP(sdl, ak) m_impl->m_sdlToAnki[sdl] = KeyCode::ak
+#define MAP(sdl, ak) m_sdlToAnki[sdl] = KeyCode::ak
 
 	MAP(SDLK_RETURN, RETURN);
 	MAP(SDLK_ESCAPE, ESCAPE);
@@ -287,17 +349,7 @@ Error Input::initInternal(NativeWindow* nativeWindow)
 	return handleEvents();
 }
 
-void Input::destroy()
-{
-	if(m_impl != nullptr)
-	{
-		m_nativeWindow->getAllocator().deleteInstance(m_impl);
-		m_impl = nullptr;
-	}
-	m_nativeWindow = nullptr;
-}
-
-Error Input::handleEvents()
+Error InputSdl::handleEventsInternal()
 {
 	ANKI_ASSERT(m_nativeWindow != nullptr);
 
@@ -327,11 +379,11 @@ Error Input::handleEvents()
 		switch(event.type)
 		{
 		case SDL_KEYDOWN:
-			akkey = m_impl->m_sdlToAnki[event.key.keysym.sym];
+			akkey = m_sdlToAnki[event.key.keysym.sym];
 			m_keys[akkey] = 1;
 			break;
 		case SDL_KEYUP:
-			akkey = m_impl->m_sdlToAnki[event.key.keysym.sym];
+			akkey = m_sdlToAnki[event.key.keysym.sym];
 			m_keys[akkey] = 0;
 			break;
 		case SDL_MOUSEBUTTONDOWN:
@@ -380,28 +432,4 @@ Error Input::handleEvents()
 	return Error::NONE;
 }
 
-void Input::moveCursor(const Vec2& pos)
-{
-	if(pos != m_mousePosNdc)
-	{
-		const I32 x = I32(F32(m_nativeWindow->getWidth()) * (pos.x() * 0.5f + 0.5f));
-		const I32 y = I32(F32(m_nativeWindow->getHeight()) * (-pos.y() * 0.5f + 0.5f));
-
-		SDL_WarpMouseInWindow(m_nativeWindow->getNative().m_window, x, y);
-
-		// SDL doesn't generate a SDL_MOUSEMOTION event if the cursor is outside the window. Push that event
-		SDL_Event event;
-		event.type = SDL_MOUSEMOTION;
-		event.button.x = x;
-		event.button.y = y;
-
-		SDL_PushEvent(&event);
-	}
-}
-
-void Input::hideCursor(Bool hide)
-{
-	SDL_ShowCursor(!hide);
-}
-
 } // end namespace anki

+ 6 - 2
AnKi/Input/InputSdl.h

@@ -5,6 +5,7 @@
 
 #pragma once
 
+#include <AnKi/Input.h>
 #include <AnKi/Input/KeyCode.h>
 #include <SDL_keycode.h>
 #include <unordered_map>
@@ -13,17 +14,20 @@ namespace anki
 {
 
 /// SDL input implementation
-class InputImpl
+class InputSdl : public Input
 {
 public:
 	std::unordered_map<SDL_Keycode, KeyCode, std::hash<SDL_Keycode>, std::equal_to<SDL_Keycode>,
 					   HeapAllocator<std::pair<const SDL_Keycode, KeyCode>>>
 		m_sdlToAnki;
 
-	InputImpl(HeapAllocator<std::pair<const SDL_Keycode, KeyCode>>& alloc)
+	InputSdl(HeapAllocator<std::pair<const SDL_Keycode, KeyCode>> alloc)
 		: m_sdlToAnki(10, std::hash<SDL_Keycode>(), std::equal_to<SDL_Keycode>(), alloc)
 	{
 	}
+
+	Error init();
+	Error handleEventsInternal();
 };
 
 } // end namespace anki

+ 24 - 1
AnKi/Input/KeyCode.h

@@ -268,7 +268,7 @@ enum class KeyCode
 };
 ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(KeyCode)
 
-enum class MouseButton
+enum class MouseButton : U8
 {
 	LEFT,
 	MIDDLE,
@@ -280,4 +280,27 @@ enum class MouseButton
 };
 ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(MouseButton)
 
+enum class TouchPointer : U8
+{
+	_0,
+	_1,
+	_2,
+	_3,
+	_4,
+	_5,
+	_6,
+	_7,
+	_8,
+	_9,
+	_10,
+	_11,
+	_12,
+	_13,
+	_14,
+	_15,
+
+	COUNT
+};
+ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(TouchPointer)
+
 } // end namespace anki

+ 1 - 4
AnKi/Util/ThreadHive.h

@@ -95,7 +95,7 @@ public:
 	}
 
 	/// Create a new semaphore with some initial value.
-	/// @param initialValue  Can't be zero.
+	/// @param initialValue Can't be zero.
 	ThreadHiveSemaphore* newSemaphore(const U32 initialValue)
 	{
 		ANKI_ASSERT(initialValue > 0);
@@ -159,9 +159,6 @@ private:
 
 	/// Get new work from the queue.
 	Task* getNewTask();
-
-	/// Complete a task.
-	void completeTask(U32 taskId);
 };
 /// @}
 

+ 2 - 3
Tests/Gr/Gr.cpp

@@ -265,8 +265,7 @@ static Input* input = nullptr;
 	cfg.set("gr_rayTracing", true); \
 	cfg.set("gr_debugMarkers", true); \
 	win = createWindow(cfg); \
-	input = new Input(); \
-	ANKI_TEST_EXPECT_NO_ERR(input->init(win)); \
+	ANKI_TEST_EXPECT_NO_ERR(Input::newInstance(allocAligned, nullptr, win, input)); \
 	gr = createGrManager(cfg, win); \
 	ANKI_TEST_EXPECT_NO_ERR(stagingMem->init(gr, cfg)); \
 	TransferGpuAllocator* transfAlloc = new TransferGpuAllocator(); \
@@ -281,7 +280,7 @@ static Input* input = nullptr;
 	delete transfAlloc; \
 	delete stagingMem; \
 	GrManager::deleteInstance(gr); \
-	delete input; \
+	Input::deleteInstance(input); \
 	delete win; \
 	win = nullptr; \
 	gr = nullptr; \

+ 3 - 4
Tests/Ui/Ui.cpp

@@ -63,15 +63,14 @@ ANKI_TEST(Ui, Ui)
 	cfg.set("rsrc_dataPaths", "EngineAssets");
 
 	NativeWindow* win = createWindow(cfg);
-	Input* in = new Input();
+	Input* in;
+	ANKI_TEST_EXPECT_NO_ERR(Input::newInstance(allocAligned, nullptr, win, in));
 	GrManager* gr = createGrManager(cfg, win);
 	PhysicsWorld* physics;
 	ResourceFilesystem* fs;
 	ResourceManager* resource = createResourceManager(cfg, gr, physics, fs);
 	UiManager* ui = new UiManager();
 
-	ANKI_TEST_EXPECT_NO_ERR(in->init(win));
-
 	StagingGpuMemoryManager* stagingMem = new StagingGpuMemoryManager();
 	ANKI_TEST_EXPECT_NO_ERR(stagingMem->init(gr, cfg));
 
@@ -153,7 +152,7 @@ ANKI_TEST(Ui, Ui)
 	delete physics;
 	delete fs;
 	GrManager::deleteInstance(gr);
-	delete in;
+	Input::deleteInstance(in);
 	delete win;
 }