Ver Fonte

Added joystick support.
Cleaned up reading touch input.

Lasse Öörni há 13 anos atrás
pai
commit
4a463176ab

+ 1 - 1
Bin/Data/Scripts/NinjaSnowWar.as

@@ -793,7 +793,7 @@ void UpdateControls()
         {
             for (uint i = 0; i < input.numTouches; ++i)
             {
-                TouchState touch = input.touches[i];
+                TouchState@ touch = input.touches[i];
 
                 if (touch.touchID == rotateTouchID)
                 {

+ 26 - 1
Docs/ScriptAPI.dox

@@ -203,6 +203,11 @@
 - int KEY_RCTRL
 - int KEY_LALT
 - int KEY_RALT
+- int HAT_CENTER
+- int HAT_UP
+- int HAT_RIGHT
+- int HAT_DOWN
+- int HAT_LEFT
 - uint DD_DISABLED
 - uint DD_SOURCE
 - uint DD_TARGET
@@ -722,6 +727,7 @@ AttributeInfo
 
 Properties:<br>
 - String[]@ enumNames (readonly)
+- String name (readonly)
 - VariantType type
 - String name
 - Variant defaultValue
@@ -2380,8 +2386,24 @@ Properties:<br>
 - int pressure
 
 
+JoystickState
+
+Properties:<br>
+- uint numButtons (readonly)
+- uint numAxes (readonly)
+- uint numHats (readonly)
+- bool[] buttons (readonly)
+- float[] axes (readonly)
+- int[] hats (readonly)
+- String name
+
+
 Input
 
+Methods:<br>
+- bool OpenJoystick(uint)
+- bool CloseJoystick(uint)
+
 Properties:<br>
 - ShortStringHash type (readonly)
 - String typeName (readonly)
@@ -2398,7 +2420,10 @@ Properties:<br>
 - int mouseMoveY (readonly)
 - int mouseMoveWheel (readonly)
 - uint numTouches (readonly)
-- TouchState[] touches (readonly)
+- TouchState@[] touches (readonly)
+- uint numJoysticks (readonly)
+- String[] joystickNames (readonly)
+- JoystickState@[] joysticks (readonly)
 - bool active (readonly)
 - bool minimized (readonly)
 

+ 68 - 9
Engine/Engine/InputAPI.cpp

@@ -25,6 +25,9 @@
 #include "APITemplates.h"
 #include "Input.h"
 
+void FakeAddRef(void* ptr);
+void FakeReleaseRef(void* ptr);
+
 static void RegisterInputConstants(asIScriptEngine* engine)
 {
     engine->RegisterGlobalProperty("const int MOUSEB_LEFT", (void*)&MOUSEB_LEFT);
@@ -101,6 +104,11 @@ static void RegisterInputConstants(asIScriptEngine* engine)
     engine->RegisterGlobalProperty("const int KEY_RCTRL", (void*)&KEY_RCTRL);
     engine->RegisterGlobalProperty("const int KEY_LALT", (void*)&KEY_LALT);
     engine->RegisterGlobalProperty("const int KEY_RALT", (void*)&KEY_RALT);
+    engine->RegisterGlobalProperty("const int HAT_CENTER", (void*)&HAT_CENTER);
+    engine->RegisterGlobalProperty("const int HAT_UP", (void*)&HAT_UP);
+    engine->RegisterGlobalProperty("const int HAT_RIGHT", (void*)&HAT_RIGHT);
+    engine->RegisterGlobalProperty("const int HAT_DOWN", (void*)&HAT_DOWN);
+    engine->RegisterGlobalProperty("const int HAT_LEFT", (void*)&HAT_LEFT);
 }
 
 static Input* GetInput()
@@ -108,21 +116,69 @@ static Input* GetInput()
     return GetScriptContext()->GetSubsystem<Input>();
 }
 
-static void ConstructTouchState(TouchState* ptr)
+static unsigned JoystickStateGetNumButtons(JoystickState* ptr)
 {
-    new(ptr) TouchState();
+    return ptr->buttons_.Size();
+}
+
+static unsigned JoystickStateGetNumAxes(JoystickState* ptr)
+{
+    return ptr->axes_.Size();
+}
+
+static unsigned JoystickStateGetNumHats(JoystickState* ptr)
+{
+    return ptr->hats_.Size();
+}
+
+static bool JoystickStateGetButton(unsigned index, JoystickState* ptr)
+{
+    if (index < ptr->buttons_.Size())
+        return ptr->buttons_[index];
+    else
+        return false;
+}
+
+static float JoystickStateGetAxis(unsigned index, JoystickState* ptr)
+{
+    if (index < ptr->axes_.Size())
+        return ptr->axes_[index];
+    else
+        return 0.0f;
+}
+
+static int JoystickStateGetHat(unsigned index, JoystickState* ptr)
+{
+    if (index < ptr->hats_.Size())
+        return ptr->hats_[index];
+    else
+        return HAT_CENTER;
 }
 
 static void RegisterInput(asIScriptEngine* engine)
 {
-    engine->RegisterObjectType("TouchState", sizeof(TouchState), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS);
-    engine->RegisterObjectBehaviour("TouchState", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(ConstructTouchState), asCALL_CDECL_OBJLAST);
-    engine->RegisterObjectProperty("TouchState", "int touchID", offsetof(TouchState, touchID_));
-    engine->RegisterObjectProperty("TouchState", "IntVector2 position", offsetof(TouchState, position_));
-    engine->RegisterObjectProperty("TouchState", "IntVector2 delta", offsetof(TouchState, delta_));
-    engine->RegisterObjectProperty("TouchState", "int pressure", offsetof(TouchState, pressure_));
+    engine->RegisterObjectType("TouchState", 0, asOBJ_REF);
+    engine->RegisterObjectBehaviour("TouchState", asBEHAVE_ADDREF, "void f()", asFUNCTION(FakeAddRef), asCALL_CDECL_OBJLAST);
+    engine->RegisterObjectBehaviour("TouchState", asBEHAVE_RELEASE, "void f()", asFUNCTION(FakeReleaseRef), asCALL_CDECL_OBJLAST);
+    engine->RegisterObjectProperty("TouchState", "const int touchID", offsetof(TouchState, touchID_));
+    engine->RegisterObjectProperty("TouchState", "const IntVector2 position", offsetof(TouchState, position_));
+    engine->RegisterObjectProperty("TouchState", "const IntVector2 delta", offsetof(TouchState, delta_));
+    engine->RegisterObjectProperty("TouchState", "const int pressure", offsetof(TouchState, pressure_));
+    
+    engine->RegisterObjectType("JoystickState", 0, asOBJ_REF);
+    engine->RegisterObjectBehaviour("JoystickState", asBEHAVE_ADDREF, "void f()", asFUNCTION(FakeAddRef), asCALL_CDECL_OBJLAST);
+    engine->RegisterObjectBehaviour("JoystickState", asBEHAVE_RELEASE, "void f()", asFUNCTION(FakeReleaseRef), asCALL_CDECL_OBJLAST);
+    engine->RegisterObjectProperty("JoystickState", "const String name", offsetof(JoystickState, name_));
+    engine->RegisterObjectMethod("JoystickState", "uint get_numButtons() const", asFUNCTION(JoystickStateGetNumButtons), asCALL_CDECL_OBJLAST);
+    engine->RegisterObjectMethod("JoystickState", "uint get_numAxes() const", asFUNCTION(JoystickStateGetNumAxes), asCALL_CDECL_OBJLAST);
+    engine->RegisterObjectMethod("JoystickState", "uint get_numHats() const", asFUNCTION(JoystickStateGetNumHats), asCALL_CDECL_OBJLAST);
+    engine->RegisterObjectMethod("JoystickState", "bool get_buttons(uint) const", asFUNCTION(JoystickStateGetButton), asCALL_CDECL_OBJLAST);
+    engine->RegisterObjectMethod("JoystickState", "float get_axes(uint) const", asFUNCTION(JoystickStateGetAxis), asCALL_CDECL_OBJLAST);
+    engine->RegisterObjectMethod("JoystickState", "int get_hats(uint) const", asFUNCTION(JoystickStateGetHat), asCALL_CDECL_OBJLAST);
     
     RegisterObject<Input>(engine, "Input");
+    engine->RegisterObjectMethod("Input", "bool OpenJoystick(uint)", asMETHOD(Input, OpenJoystick), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Input", "bool CloseJoystick(uint)", asMETHOD(Input, CloseJoystick), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "void set_toggleFullscreen(bool)", asMETHOD(Input, SetToggleFullscreen), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "bool get_toggleFullscreen() const", asMETHOD(Input, GetToggleFullscreen), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "bool get_keyDown(int) const", asMETHOD(Input, GetKeyDown), asCALL_THISCALL);
@@ -137,7 +193,10 @@ static void RegisterInput(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Input", "int get_mouseMoveY() const", asMETHOD(Input, GetMouseMoveY), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "int get_mouseMoveWheel() const", asMETHOD(Input, GetMouseMoveWheel), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "uint get_numTouches() const", asMETHOD(Input, GetNumTouches), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Input", "TouchState get_touches(uint) const", asMETHOD(Input, GetTouch), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Input", "TouchState@+ get_touches(uint) const", asMETHOD(Input, GetTouch), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Input", "uint get_numJoysticks() const", asMETHOD(Input, GetNumJoysticks), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Input", "String get_joystickNames(uint) const", asMETHOD(Input, GetJoystickName), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Input", "JoystickState@+ get_joysticks(uint) const", asMETHOD(Input, GetJoystick), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "bool get_active() const", asMETHOD(Input, IsActive), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "bool get_minimized() const", asMETHOD(Input, IsMinimized), asCALL_THISCALL);
     engine->RegisterGlobalFunction("Input@+ get_input()", asFUNCTION(GetInput), asCALL_CDECL);

+ 1 - 1
Engine/Graphics/Direct3D9/D3D9Graphics.cpp

@@ -190,7 +190,7 @@ Graphics::Graphics(Context* context) :
         MutexLock lock(GetStaticMutex());
         
         if (!numInstances)
-            SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_NOPARACHUTE);
+            SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK | SDL_INIT_NOPARACHUTE);
         ++numInstances;
     }
 }

+ 1 - 1
Engine/Graphics/OpenGL/OGLGraphics.cpp

@@ -160,7 +160,7 @@ Graphics::Graphics(Context* context_) :
         MutexLock lock(GetStaticMutex());
         
         if (!numInstances)
-            SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_NOPARACHUTE);
+            SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK | SDL_INIT_NOPARACHUTE);
         ++numInstances;
     }
 }

+ 117 - 4
Engine/Input/Input.cpp

@@ -189,6 +189,49 @@ void Input::SetToggleFullscreen(bool enable)
     toggleFullscreen_ = enable;
 }
 
+bool Input::OpenJoystick(unsigned index)
+{
+    MutexLock lock(GetStaticMutex());
+    
+    SDL_Joystick* joystick = SDL_JoystickOpen(index);
+    if (joystick)
+    {
+        if (index <= joysticks_.Size())
+            joysticks_.Resize(index + 1);
+        
+        JoystickState& state = joysticks_[index];
+        state.joystick_ = joystick;
+        state.buttons_.Resize(SDL_JoystickNumButtons(joystick));
+        state.axes_.Resize(SDL_JoystickNumAxes(joystick));
+        state.hats_.Resize(SDL_JoystickNumHats(joystick));
+        for (unsigned i = 0; i < state.buttons_.Size(); ++i)
+            state.buttons_[i] = false;
+        for (unsigned i = 0; i < state.axes_.Size(); ++i)
+            state.axes_[i] = 0;
+        for (unsigned i = 0; i < state.hats_.Size(); ++i)
+            state.hats_[i] = HAT_CENTER;
+        
+        return true;
+    }
+    else
+        return false;
+}
+
+void Input::CloseJoystick(unsigned index)
+{
+    MutexLock lock(GetStaticMutex());
+    
+    if (index < joysticks_.Size() && joysticks_[index].joystick_)
+    {
+        JoystickState& state = joysticks_[index];
+        SDL_JoystickClose(state.joystick_);
+        state.joystick_ = 0;
+        state.buttons_.Clear();
+        state.axes_.Clear();
+        state.hats_.Clear();
+    }
+}
+
 bool Input::GetKeyDown(int key) const
 {
     return keyDown_.Contains(key);
@@ -245,19 +288,39 @@ int Input::GetQualifiers() const
     return ret;
 }
 
-TouchState Input::GetTouch(unsigned index) const
+TouchState* Input::GetTouch(unsigned index) const
 {
     unsigned cmpIndex = 0;
     for (Map<int, TouchState>::ConstIterator i = touches_.Begin(); i != touches_.End(); ++i)
     {
-        /// \todo Do not make a value copy
         if (cmpIndex == index)
-            return i->second_;
+            return const_cast<TouchState*>(&i->second_);
         else
             ++cmpIndex;
     }
     
-    return TouchState();
+    return 0;
+}
+
+unsigned Input::GetNumJoysticks() const
+{
+    return SDL_NumJoysticks();
+}
+
+String Input::GetJoystickName(unsigned index) const
+{
+    if (index < GetNumJoysticks())
+        return String(SDL_JoystickName(index));
+    else
+        return String();
+}
+
+JoystickState* Input::GetJoystick(unsigned index) const
+{
+    if (index < joysticks_.Size())
+        return const_cast<JoystickState*>(&joysticks_[index]);
+    else
+        return 0;
 }
 
 bool Input::IsMinimized() const
@@ -330,6 +393,15 @@ void Input::ResetState()
     keyDown_.Clear();
     keyPress_.Clear();
     
+    /// \todo Check if this is necessary
+    for (Vector<JoystickState>::Iterator i = joysticks_.Begin(); i != joysticks_.End(); ++i)
+    {
+        for (unsigned j = 0; j < i->buttons_.Size(); ++j)
+            i->buttons_[j] = false;
+        for (unsigned j = 0; j < i->hats_.Size(); ++j)
+            i->hats_[j] = HAT_CENTER;
+    }
+    
     // When clearing touch states, send the corresponding touch end events
     for (Map<int, TouchState>::Iterator i = touches_.Begin(); i != touches_.End(); ++i)
     {
@@ -607,6 +679,47 @@ void Input::HandleSDLEvent(void* sdlEvent)
         }
         break;
         
+    case SDL_JOYBUTTONDOWN:
+        // Joystick events are not targeted at a window. Check all input instances which have opened the joystick
+        for (HashMap<unsigned, Input*>::Iterator i = inputInstances.Begin(); i != inputInstances.End(); ++i)
+        {
+            input = i->second_;
+            if (evt.jbutton.which < input->joysticks_.Size() && evt.jbutton.button <
+                input->joysticks_[evt.jbutton.which].buttons_.Size())
+                input->joysticks_[evt.jbutton.which].buttons_[evt.jbutton.button] = true;
+        }
+        break;
+        
+    case SDL_JOYBUTTONUP:
+        for (HashMap<unsigned, Input*>::Iterator i = inputInstances.Begin(); i != inputInstances.End(); ++i)
+        {
+            input = i->second_;
+            if (evt.jbutton.which < input->joysticks_.Size() && evt.jbutton.button <
+                input->joysticks_[evt.jbutton.which].buttons_.Size())
+                input->joysticks_[evt.jbutton.which].buttons_[evt.jbutton.button] = false;
+        }
+        break;
+        
+    case SDL_JOYAXISMOTION:
+        for (HashMap<unsigned, Input*>::Iterator i = inputInstances.Begin(); i != inputInstances.End(); ++i)
+        {
+            input = i->second_;
+            if (evt.jaxis.which < input->joysticks_.Size() && evt.jaxis.axis <
+                input->joysticks_[evt.jaxis.which].axes_.Size())
+                input->joysticks_[evt.jaxis.which].axes_[evt.jaxis.axis] = Clamp((float)evt.jaxis.value / 32767.0f, -1.0f, 1.0f);
+        }
+        break;
+        
+    case SDL_JOYHATMOTION:
+        for (HashMap<unsigned, Input*>::Iterator i = inputInstances.Begin(); i != inputInstances.End(); ++i)
+        {
+            input = i->second_;
+            if (evt.jhat.which < input->joysticks_.Size() && evt.jhat.hat <
+                input->joysticks_[evt.jhat.which].hats_.Size())
+                input->joysticks_[evt.jhat.which].hats_[evt.jhat.hat] = evt.jhat.value;
+        }
+        break;
+        
     case SDL_WINDOWEVENT:
         input = GetInputInstance(evt.window.windowID);
         if (input)

+ 34 - 1
Engine/Input/Input.h

@@ -45,6 +45,27 @@ struct TouchState
     int pressure_;
 };
 
+/// Structure for a connected joystick.
+struct JoystickState
+{
+    /// Construct with defaults.
+    JoystickState() :
+        joystick_(0)
+    {
+    }
+    
+    /// SDL joystick.
+    SDL_Joystick* joystick_;
+    /// Joystick name.
+    String name_;
+    /// Button state.
+    PODVector<bool> buttons_;
+    /// Axis position from -1 to 1.
+    PODVector<float> axes_;
+    /// POV hat bits.
+    PODVector<int> hats_;
+};
+
 /// %Input subsystem. Converts operating system window messages to input state and events.
 class Input : public Object
 {
@@ -60,6 +81,10 @@ public:
     void Update();
     /// %Set whether ALT-ENTER fullscreen toggle is enabled.
     void SetToggleFullscreen(bool enable);
+    /// Open a joystick. Return true if successful.
+    bool OpenJoystick(unsigned index);
+    /// Close a joystick.
+    void CloseJoystick(unsigned index);
     
     /// Check if a key is held down.
     bool GetKeyDown(int key) const;
@@ -86,7 +111,13 @@ public:
     /// Return number of active finger touches.
     unsigned GetNumTouches() const { return touches_.Size(); }
     /// Return active finger touch by index.
-    TouchState GetTouch(unsigned index) const;
+    TouchState* GetTouch(unsigned index) const;
+    /// Return number of connected joysticks.
+    unsigned GetNumJoysticks() const;
+    /// Return joystick name by index.
+    String GetJoystickName(unsigned index) const;
+    /// Return joystick state by index.
+    JoystickState* GetJoystick(unsigned index) const;
     /// Return whether fullscreen toggle is enabled.
     bool GetToggleFullscreen() const { return toggleFullscreen_; }
     /// Return whether application window is active.
@@ -130,6 +161,8 @@ private:
     HashSet<int> keyPress_;
     /// Active finger touches.
     Map<int, TouchState> touches_;
+    /// Opened joysticks.
+    Vector<JoystickState> joysticks_;
     /// Mouse buttons' down state.
     unsigned mouseButtonDown_;
     /// Mouse buttons' pressed state.

+ 7 - 0
Engine/Input/InputEvents.h

@@ -25,6 +25,7 @@
 
 #include "Object.h"
 
+#include <SDL_joystick.h>
 #include <SDL_keycode.h>
 
 /// Mouse button pressed.
@@ -201,3 +202,9 @@ static const int KEY_LCTRL = SDLK_LCTRL;
 static const int KEY_RCTRL = SDLK_RCTRL;
 static const int KEY_LALT = SDLK_LALT;
 static const int KEY_RALT = SDLK_RALT;
+
+static const int HAT_CENTER = SDL_HAT_CENTERED;
+static const int HAT_UP = SDL_HAT_UP;
+static const int HAT_RIGHT = SDL_HAT_RIGHT;
+static const int HAT_DOWN = SDL_HAT_DOWN;
+static const int HAT_LEFT = SDL_HAT_LEFT;

+ 3 - 3
Engine/UI/UI.cpp

@@ -217,10 +217,10 @@ void UI::Update(float timeStep)
         unsigned numTouches = input->GetNumTouches();
         for (unsigned i = 0; i < numTouches; ++i)
         {
-            TouchState touch = input->GetTouch(i);
-            WeakPtr<UIElement> element(GetElementAt(touch.position_));
+            TouchState* touch = input->GetTouch(i);
+            WeakPtr<UIElement> element(GetElementAt(touch->position_));
             if (element)
-                element->OnHover(element->ScreenToElement(touch.position_), touch.position_, MOUSEB_LEFT, 0, 0);
+                element->OnHover(element->ScreenToElement(touch->position_), touch->position_, MOUSEB_LEFT, 0, 0);
         }
     }