浏览代码

Added possibility to remove subsystems in explicit order.
Call SDL_Init() & SDL_Quit() from the Graphics subsystem.
Direct SDL events to the proper Input instance based on the window ID.

Lasse Öörni 13 年之前
父节点
当前提交
d3e302f197

+ 1 - 23
Engine/Audio/Audio.cpp

@@ -55,8 +55,6 @@ static const int MAX_MIXRATE = 48000;
 static const int AUDIO_FPS = 100;
 
 #ifdef USE_OPENGL
-static unsigned numInstances = 0;
-
 static void SDLAudioCallback(void *userdata, Uint8 *stream, int len);
 #else
 /// DirectSound audio output stream.
@@ -268,33 +266,13 @@ Audio::Audio(Context* context) :
     
     for (unsigned i = 0; i < MAX_SOUND_TYPES; ++i)
         masterGain_[i] = 1.0f;
-    
-    // Initialize SDL audio under static mutex in case this is the first instance
-    #ifdef USE_OPENGL
-    {
-        MutexLock lock(GetStaticMutex());
-        
-        if (!numInstances)
-            SDL_InitSubSystem(SDL_INIT_AUDIO);
-        ++numInstances;
-    }
-    #endif
 }
 
 Audio::~Audio()
 {
     Release();
     
-    // Uninitialize SDL audio under static mutex in case this is the last instance
-    #ifdef USE_OPENGL
-    {
-        MutexLock lock(GetStaticMutex());
-        
-        --numInstances;
-        if (!numInstances)
-            SDL_QuitSubSystem(SDL_INIT_AUDIO);
-    }
-    #else
+    #ifndef USE_OPENGL
     delete (AudioStream*)stream_;
     stream_ = 0;
     #endif

+ 7 - 0
Engine/Core/Context.cpp

@@ -86,6 +86,13 @@ void Context::RegisterSubsystem(Object* object)
     subsystems_[object->GetType()] = object;
 }
 
+void Context::RemoveSubsystem(ShortStringHash objectType)
+{
+    HashMap<ShortStringHash, SharedPtr<Object> >::Iterator i = subsystems_.Find(objectType);
+    if (i != subsystems_.End())
+        subsystems_.Erase(i);
+}
+
 void Context::RegisterAttribute(ShortStringHash objectType, const AttributeInfo& attr)
 {
     // None or Pointer types can not be supported

+ 9 - 4
Engine/Core/Context.h

@@ -41,10 +41,12 @@ public:
     
     /// Create an object by type hash. Return pointer to it or null if no factory found.
     SharedPtr<Object> CreateObject(ShortStringHash objectType);
-    /// Register a factory for an object type. If exists already, will not be replaced.
+    /// Register a factory for an object type.
     void RegisterFactory(ObjectFactory* factory);
-    /// Register a subsystem. If exists already, will not be replaced.
+    /// Register a subsystem.
     void RegisterSubsystem(Object* subsystem);
+    /// Remove a subsystem.
+    void RemoveSubsystem(ShortStringHash objectType);
     /// Register object attribute.
     void RegisterAttribute(ShortStringHash objectType, const AttributeInfo& attr);
     /// Remove object attribute.
@@ -53,10 +55,12 @@ public:
     void CopyBaseAttributes(ShortStringHash baseType, ShortStringHash derivedType);
     /// Template version of registering an object factory.
     template <class T> void RegisterFactory();
+    /// Template version of removing a subsystem.
+    template <class T> void RemoveSubsystem();
     /// Template version of registering an object attribute.
     template <class T> void RegisterAttribute(const AttributeInfo& attr);
     /// Template version of removing an object attribute.
-    template <class T> void RemoveAttribute(const char* name);
+    template <class T> void RemoveAttribute(const String& name);
     /// Template version of copying base class attributes to derived class.
     template <class T, class U> void CopyBaseAttributes();
     
@@ -146,7 +150,8 @@ private:
 };
 
 template <class T> void Context::RegisterFactory() { RegisterFactory(new ObjectFactoryImpl<T>(this)); }
+template <class T> void Context::RemoveSubsystem() { RemoveSubsystem(T::GetTypeStatic()); }
 template <class T> void Context::RegisterAttribute(const AttributeInfo& attr) { RegisterAttribute(T::GetTypeStatic(), attr); }
-template <class T> void Context::RemoveAttribute(const char* name) { RemoveAttribute(T::GetTypeStatic(), name); }
+template <class T> void Context::RemoveAttribute(const String& name) { RemoveAttribute(T::GetTypeStatic(), name); }
 template <class T, class U> void Context::CopyBaseAttributes() { CopyBaseAttributes(T::GetTypeStatic(), U::GetTypeStatic()); }
 template <class T> T* Context::GetSubsystem() const { return static_cast<T*>(GetSubsystem(T::GetTypeStatic())); }

+ 6 - 0
Engine/Engine/Engine.cpp

@@ -65,6 +65,12 @@ Engine::Engine(Context* context) :
 
 Engine::~Engine()
 {
+    // Remove subsystems that use SDL (OpenGL mode only) in reverse order of construction
+    context_->RemoveSubsystem<Audio>();
+    context_->RemoveSubsystem<UI>();
+    context_->RemoveSubsystem<Input>();
+    context_->RemoveSubsystem<Renderer>();
+    context_->RemoveSubsystem<Graphics>();
 }
 
 bool Engine::Initialize(const String& windowTitle, const String& logName, const Vector<String>& arguments)

+ 6 - 3
Engine/Graphics/OpenGL/OGLGraphics.cpp

@@ -129,11 +129,13 @@ Graphics::Graphics(Context* context_) :
     ResetCachedState();
     SetTextureUnitMappings();
     
+    // If first instance in this process, initialize SDL under static mutex. Note that Graphics subsystem will also be in charge
+    // of shutting down SDL as a whole, so it should be the last SDL-using subsystem (Audio and Input also use SDL) alive
     {
         MutexLock lock(GetStaticMutex());
-        if (!numInstances)
-            SDL_InitSubSystem(SDL_INIT_VIDEO);
         
+        if (!numInstances)
+            SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_NOPARACHUTE);
         ++numInstances;
     }
 }
@@ -145,12 +147,13 @@ Graphics::~Graphics()
     delete impl_;
     impl_ = 0;
     
+    // If last instance in this process, shut down SDL under static mutex
     {
         MutexLock lock(GetStaticMutex());
         
         --numInstances;
         if (!numInstances)
-            SDL_QuitSubSystem(SDL_INIT_VIDEO);
+            SDL_Quit();
     }
 }
 

+ 74 - 22
Engine/Input/Input.cpp

@@ -27,20 +27,30 @@
 #include "GraphicsEvents.h"
 #include "Input.h"
 #include "Log.h"
+#include "Mutex.h"
+#include "ProcessUtils.h"
 #include "Profiler.h"
 #include "StringUtils.h"
 
 #include <cstring>
 
-#ifndef USE_OPENGL
-#include <windows.h>
-#else
+#ifdef USE_OPENGL
 #include <GraphicsImpl.h>
+#else
+#include <windows.h>
 #endif
 
 #include "DebugNew.h"
 
-#ifndef USE_OPENGL
+#ifdef USE_OPENGL
+static HashMap<unsigned, Input*> inputInstances;
+
+/// Return the Input subsystem instance corresponding to an SDL window ID.
+Input* GetInputInstance(unsigned windowID)
+{
+    return windowID ? inputInstances[windowID] : 0;
+}
+#else
 /// Convert the virtual key code & scan code if necessary. Return non-zero if key should be posted
 int ConvertKeyCode(unsigned wParam, unsigned lParam)
 {
@@ -92,7 +102,11 @@ OBJECTTYPESTATIC(Input);
 
 Input::Input(Context* context) :
     Object(context),
+    #ifdef USE_OPENGL
+    windowID_(0),
+    #else
     showCursor_(true),
+    #endif
     toggleFullscreen_(true),
     active_(false),
     minimized_(false),
@@ -117,6 +131,15 @@ Input::Input(Context* context) :
 
 Input::~Input()
 {
+    #ifdef USE_OPENGL
+    // Remove input instance mapping
+    if (initialized_)
+    {
+        MutexLock lock(GetStaticMutex());
+        
+        inputInstances.Erase(windowID_);
+    }
+    #endif
 }
 
 void Input::Update()
@@ -141,11 +164,15 @@ void Input::Update()
         DispatchMessageW(&msg);
     }
     #else
-    // Pump SDL events
-    SDL_Event evt;
-    SDL_PumpEvents();
-    while (SDL_PollEvent(&evt))
-        HandleSDLEvent(&evt);
+    {
+        MutexLock lock(GetStaticMutex());
+        
+        // Pump SDL events
+        SDL_Event evt;
+        SDL_PumpEvents();
+        while (SDL_PollEvent(&evt))
+            HandleSDLEvent(&evt);
+    }
     
     // Poll SDL window activation state
     SDL_Window* window = graphics_->GetImpl()->GetWindow();
@@ -275,6 +302,16 @@ void Input::Initialize()
     activated_ = true;
     initialized_ = true;
     
+    #ifdef USE_OPENGL
+    {
+        MutexLock lock(GetStaticMutex());
+        
+        // Store window ID to direct SDL events to the correct instance
+        windowID_ = SDL_GetWindowID(graphics_->GetImpl()->GetWindow());
+        inputInstances[windowID_] = this;
+    }
+    #endif
+    
     LOGINFO("Initialized input");
 }
 
@@ -618,22 +655,27 @@ void Input::HandleWindowMessage(StringHash eventType, VariantMap& eventData)
 #else
 void Input::HandleSDLEvent(void* sdlEvent)
 {
-    /// \todo Multiple windows are not differentiated
     SDL_Event& evt = *static_cast<SDL_Event*>(sdlEvent);
+    Input* input = 0;
     
     switch (evt.type)
     {
     case SDL_KEYDOWN:
         // Convert to uppercase to match Win32 virtual key codes
-        SetKey(SDL_toupper(evt.key.keysym.sym), true);
+        input = GetInputInstance(evt.key.windowID);
+        if (input)
+            input->SetKey(SDL_toupper(evt.key.keysym.sym), true);
         break;
         
     case SDL_KEYUP:
-        SetKey(SDL_toupper(evt.key.keysym.sym), false);
+        input = GetInputInstance(evt.key.windowID);
+        if (input)
+            input->SetKey(SDL_toupper(evt.key.keysym.sym), false);
         break;
         
     case SDL_TEXTINPUT:
-        if (evt.text.text[0])
+        input = GetInputInstance(evt.text.windowID);
+        if (input && evt.text.text[0])
         {
             String text(&evt.text.text[0]);
             unsigned unicode = text.AtUTF8(0);
@@ -644,28 +686,38 @@ void Input::HandleSDLEvent(void* sdlEvent)
                 VariantMap keyEventData;
                 
                 keyEventData[P_CHAR] = unicode;
-                keyEventData[P_BUTTONS] = mouseButtonDown_;
-                keyEventData[P_QUALIFIERS] = GetQualifiers();
-                SendEvent(E_CHAR, keyEventData);
+                keyEventData[P_BUTTONS] = input->mouseButtonDown_;
+                keyEventData[P_QUALIFIERS] = input->GetQualifiers();
+                input->SendEvent(E_CHAR, keyEventData);
             }
         }
         break;
         
     case SDL_MOUSEBUTTONDOWN:
-        SetMouseButton(1 << (evt.button.button - 1), true);
+        input = GetInputInstance(evt.button.windowID);
+        if (input)
+            input->SetMouseButton(1 << (evt.button.button - 1), true);
         break;
         
     case SDL_MOUSEBUTTONUP:
-        SetMouseButton(1 << (evt.button.button - 1), false);
+        input = GetInputInstance(evt.button.windowID);
+        if (input)
+            input->SetMouseButton(1 << (evt.button.button - 1), false);
         break;
         
     case SDL_MOUSEWHEEL:
-        SetMouseWheel(evt.wheel.y);
+        input = GetInputInstance(evt.wheel.windowID);
+        if (input)
+            input->SetMouseWheel(evt.wheel.y);
         break;
         
-    case SDL_QUIT:
-        if (graphics_)
-            graphics_->Close();
+    case SDL_WINDOWEVENT:
+        if (evt.window.event == SDL_WINDOWEVENT_CLOSE)
+        {
+            input = GetInputInstance(evt.window.windowID);
+            if (input)
+                input->GetSubsystem<Graphics>()->Close();
+        }
         break;
     }
 }

+ 10 - 3
Engine/Input/Input.h

@@ -100,15 +100,17 @@ private:
     void SetCursorVisible(bool enable);
     /// Handle window message event.
     void HandleWindowMessage(StringHash eventType, VariantMap& eventData);
-    #else
-    /// Handle SDL event.
-    void HandleSDLEvent(void* sdlEvent);
     #endif
     /// Handle screen mode event.
     void HandleScreenMode(StringHash eventType, VariantMap& eventData);
     /// Handle frame start event.
     void HandleBeginFrame(StringHash eventType, VariantMap& eventData);
     
+    #ifdef USE_OPENGL
+    /// Handle SDL event.
+    static void HandleSDLEvent(void* sdlEvent);
+    #endif
+    
     /// Graphics subsystem.
     WeakPtr<Graphics> graphics_;
     /// Key down state.
@@ -125,8 +127,13 @@ private:
     IntVector2 mouseMove_;
     /// Mouse wheel movement since last frame.
     int mouseMoveWheel_;
+    #ifdef USE_OPENGL
+    /// SDL window ID.
+    unsigned windowID_;
+    #else
     /// Mouse cursor show/hide flag.
     bool showCursor_;
+    #endif
     /// Fullscreen toggle flag.
     bool toggleFullscreen_;
     /// Active flag.