Browse Source

Move the AngelScript API registration to the Script library and inverted the Script <-> Engine library dependency.
Move object factory registration into the subsystems where possible.

Lasse Öörni 12 years ago
parent
commit
1fdf228359

+ 3 - 5
Docs/GettingStarted.dox

@@ -302,13 +302,11 @@ The libraries are the following:
 - Physics. Provides physics simulation.
 - Navigation. Provides navigation mesh generation and pathfinding.
 - %Script. Provides scripting support using the AngelScript language.
-- %Engine. Instantiates the subsystems from the libraries above, and manages the main loop iteration.
+- %Engine. Instantiates the subsystems from the libraries above and manages the main loop iteration.
 
-Urho3D.exe uses the Engine & Script libraries to start up the subsystems and to load the script file specified on the command line; however all of the libraries above get automatically linked as Engine library depends on all of them.
+Urho3D.exe uses the Engine & Script libraries to start up the subsystems and to load the script file specified on the command line. It is also possible to use the engine through C++ only: when the scripting library is not used, the resulting executable will be significantly smaller.
 
-Although Urho3D.exe itself is geared towards running a scripted application, it is also possible to use the engine through C++ only. When the scripting subsystem initialization is completely skipped, the resulting executable will also be significantly smaller.
-
-The third-party libraries are used for the following functionality:
+Third-party libraries are used for the following functionality:
 
 - AngelScript: scripting language implementation
 - Bullet: physics simulation implementation

+ 8 - 2
Docs/Reference.dox

@@ -66,7 +66,7 @@ The following subsystems are optional, so GetSubsystem() may return null if they
 - Profiler: Provides hierarchical function execution time measurement using the operating system performance counter. Exists if profiling has been compiled in (configurable from the root CMakeLists.txt)
 - Graphics: Manages the application window, the rendering context and resources. Exists if not in headless mode.
 - Renderer: Renders scenes in 3D and manages rendering quality settings. Exists if not in headless mode.
-- Script: Provides the AngelScript execution environment. Created by calling \ref Engine::InitializeScripting "InitializeScripting()".
+- Script: Provides the AngelScript execution environment. Needs to be created and registered manually.
 - Console: provides an interactive AngelScript console and log display. Created by calling \ref Engine::CreateConsole "CreateConsole()".
 - DebugHud: displays rendering mode information and statistics and profiling data. Created by calling \ref Engine::CreateDebugHud "CreateDebugHud()".
 
@@ -86,7 +86,7 @@ When subscribing to an event, a handler function must be specified. In C++ these
 SubscribeToEvent(E_UPDATE, HANDLER(MyClass, MyEventHandler));
 \endcode
 
-In script events are identified by their string names instead of name hashes (though these are internally converted to hashes.) Script event handlers can either have the same signature as in C++, or a simplified signature void HandleEvent() when event type and parameters are not required. The same event subscription would look like:
+In script events are identified by their string names instead of name hashes (though these are internally converted to hashes.) %Script event handlers can either have the same signature as in C++, or a simplified signature void HandleEvent() when event type and parameters are not required. The same event subscription would look like:
 
 \code
 SubscribeToEvent("Update", "MyEventHandler");
@@ -286,6 +286,12 @@ Memory budgets can be set per resource type: if resources consume more memory th
 
 \page Scripting Scripting
 
+To enable AngelScript scripting support, the Script subsystem needs to be created and registered after initializing the Engine. This is accomplished by the following code, seen eg. in Urho3D/Urho3D.cpp:
+
+\code
+context_->RegisterSubsystem(new Script(context_));
+\endcode
+
 There are three ways the AngelScript language can be interacted with in Urho3D:
 
 \section Scripting_Immediate Immediate execution

+ 5 - 2
Engine/Audio/Audio.cpp

@@ -55,10 +55,13 @@ Audio::Audio(Context* context) :
     sampleSize_(0),
     playing_(false)
 {
-    SubscribeToEvent(E_RENDERUPDATE, HANDLER(Audio, HandleRenderUpdate));
-    
     for (unsigned i = 0; i < MAX_SOUND_TYPES; ++i)
         masterGain_[i] = 1.0f;
+    
+    // Register Audio library object factories
+    RegisterAudioLibrary(context_);
+    
+    SubscribeToEvent(E_RENDERUPDATE, HANDLER(Audio, HandleRenderUpdate));
 }
 
 Audio::~Audio()

+ 1 - 1
Engine/Audio/Audio.h

@@ -124,7 +124,7 @@ private:
     WeakPtr<SoundListener> listener_;
 };
 
-/// Register Sound library objects.
+/// Register Audio library objects.
 void RegisterAudioLibrary(Context* context);
 
 }

+ 2 - 2
Engine/Engine/CMakeLists.txt

@@ -8,8 +8,8 @@ set (SOURCE_FILES ${CPP_FILES} ${H_FILES})
 
 # Define dependency libs
 set (LIBS ../Audio ../Container ../Core ../Graphics ../Input ../IO ../Math ../Navigation ../Network ../Physics ../Resource 
-    ../Scene ../Script ../UI)
-set (INCLUDE_DIRS_ONLY ../../ThirdParty/AngelScript/include ../../ThirdParty/Bullet/src ../../ThirdParty/kNet/include)
+    ../Scene ../UI)
+set (INCLUDE_DIRS_ONLY ../../ThirdParty/Bullet/src ../../ThirdParty/kNet/include)
 
 # Setup target
 enable_pch ()

+ 7 - 4
Engine/Engine/Console.cpp

@@ -23,6 +23,7 @@
 #include "Precompiled.h"
 #include "Console.h"
 #include "Context.h"
+#include "EngineEvents.h"
 #include "Font.h"
 #include "Graphics.h"
 #include "GraphicsEvents.h"
@@ -31,7 +32,6 @@
 #include "LineEdit.h"
 #include "Log.h"
 #include "ResourceCache.h"
-#include "Script.h"
 #include "Text.h"
 #include "UI.h"
 #include "UIEvents.h"
@@ -176,9 +176,12 @@ void Console::HandleTextFinished(StringHash eventType, VariantMap& eventData)
     String line = lineEdit_->GetText();
     if (!line.Empty())
     {
-        Script* script = GetSubsystem<Script>();
-        if (script)
-            script->Execute(line);
+        // Send the command as an event for script subsystem
+        using namespace ConsoleCommand;
+
+        VariantMap eventData;
+        eventData[P_COMMAND] = line;
+        SendEvent(E_CONSOLECOMMAND, eventData);
 
         // Store to history, then clear the lineedit
         history_.Push(line);

+ 21 - 56
Engine/Engine/Engine.cpp

@@ -41,8 +41,6 @@
 #include "ResourceCache.h"
 #include "Scene.h"
 #include "SceneEvents.h"
-#include "Script.h"
-#include "ScriptAPI.h"
 #include "StringUtils.h"
 #include "UI.h"
 #include "WorkQueue.h"
@@ -112,8 +110,7 @@ bool Engine::Initialize(const VariantMap& parameters)
     // Set headless mode
     headless_ = GetParameter(parameters, "Headless", false).GetBool();
     
-    // Register object factories and attributes first, then subsystems
-    RegisterObjects();
+    // Register subsystems and object factories
     RegisterSubsystems();
     
     PROFILE(InitEngine);
@@ -249,38 +246,6 @@ bool Engine::Initialize(const VariantMap& parameters)
     return true;
 }
 
-bool Engine::InitializeScripting()
-{
-    // Check if scripting already initialized
-    if (GetSubsystem<Script>())
-        return true;
-    
-    RegisterScriptLibrary(context_);
-    context_->RegisterSubsystem(new Script(context_));
-   
-    {
-        PROFILE(RegisterScriptAPI);
-        
-        asIScriptEngine* engine = GetSubsystem<Script>()->GetScriptEngine();
-        RegisterMathAPI(engine);
-        RegisterCoreAPI(engine);
-        RegisterIOAPI(engine);
-        RegisterResourceAPI(engine);
-        RegisterSceneAPI(engine);
-        RegisterGraphicsAPI(engine);
-        RegisterInputAPI(engine);
-        RegisterAudioAPI(engine);
-        RegisterUIAPI(engine);
-        RegisterNetworkAPI(engine);
-        RegisterPhysicsAPI(engine);
-        RegisterNavigationAPI(engine);
-        RegisterScriptAPI(engine);
-        RegisterEngineAPI(engine);
-    }
-    
-    return true;
-}
-
 void Engine::RunFrame()
 {
     assert(initialized_ && !exiting_);
@@ -641,31 +606,12 @@ const Variant& Engine::GetParameter(const VariantMap& parameters, const String&
     return i != parameters.End() ? i->second_ : defaultValue;
 }
 
-void Engine::RegisterObjects()
-{
-    RegisterResourceLibrary(context_);
-    RegisterSceneLibrary(context_);
-    RegisterNetworkLibrary(context_);
-    RegisterGraphicsLibrary(context_);
-    RegisterAudioLibrary(context_);
-    RegisterUILibrary(context_);
-    RegisterPhysicsLibrary(context_);
-    RegisterNavigationLibrary(context_);
-    
-    // In debug mode, check that all factory created objects can be created without crashing
-    #ifdef _DEBUG
-    const HashMap<ShortStringHash, SharedPtr<ObjectFactory> >& factories = context_->GetObjectFactories();
-    for (HashMap<ShortStringHash, SharedPtr<ObjectFactory> >::ConstIterator i = factories.Begin(); i != factories.End(); ++i)
-        SharedPtr<Object> object = i->second_->CreateObject();
-    #endif
-}
-
 void Engine::RegisterSubsystems()
 {
     // Register self as a subsystem
     context_->RegisterSubsystem(this);
     
-    // Create and register the rest of the subsystems
+    // Create and register the rest of the subsystems. They will register object factories for their own libraries
     context_->RegisterSubsystem(new Time(context_));
     context_->RegisterSubsystem(new WorkQueue(context_));
     #ifdef ENABLE_PROFILING
@@ -680,6 +626,12 @@ void Engine::RegisterSubsystems()
         context_->RegisterSubsystem(new Graphics(context_));
         context_->RegisterSubsystem(new Renderer(context_));
     }
+    else
+    {
+        // Register Graphics library object factories also in headless mode; the objects will function without allocating
+        // actual GPU resources
+        RegisterGraphicsLibrary(context_);
+    }
     
     context_->RegisterSubsystem(new Input(context_));
     context_->RegisterSubsystem(new UI(context_));
@@ -687,6 +639,19 @@ void Engine::RegisterSubsystems()
     #ifdef ENABLE_LOGGING
     context_->RegisterSubsystem(new Log(context_));
     #endif
+    
+    // Scene, Physics & Navigation libraries do not have a corresponding subsystem which would register their object factories.
+    // Register manually now
+    RegisterSceneLibrary(context_);
+    RegisterPhysicsLibrary(context_);
+    RegisterNavigationLibrary(context_);
+    
+    // In debug mode, check that all factory created objects can be created without crashing
+    #ifdef _DEBUG
+    const HashMap<ShortStringHash, SharedPtr<ObjectFactory> >& factories = context_->GetObjectFactories();
+    for (HashMap<ShortStringHash, SharedPtr<ObjectFactory> >::ConstIterator i = factories.Begin(); i != factories.End(); ++i)
+        SharedPtr<Object> object = i->second_->CreateObject();
+    #endif
 }
 
 }

+ 0 - 4
Engine/Engine/Engine.h

@@ -44,8 +44,6 @@ public:
     
     /// Initialize engine using parameters given and show the application window. Return true if successful.
     bool Initialize(const VariantMap& parameters);
-    /// Initialize script subsystem and register the script API. Return true if successful (engine must be initialized first.)
-    bool InitializeScripting();
     /// Run one frame.
     void RunFrame();
     /// Create the console and return it. May return null if engine configuration does not allow creation (headless mode.)
@@ -99,8 +97,6 @@ public:
     static const Variant& GetParameter(const VariantMap& parameters, const String& parameter, const Variant& defaultValue = Variant::EMPTY);
     
 private:
-    /// Register object factories and attributes.
-    void RegisterObjects();
     /// Create and register subsystems. In headless mode graphics, input & UI are not created.
     void RegisterSubsystems();
     

+ 36 - 0
Engine/Engine/EngineEvents.h

@@ -0,0 +1,36 @@
+//
+// Copyright (c) 2008-2013 the Urho3D project.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#pragma once
+
+#include "Object.h"
+
+namespace Urho3D
+{
+
+/// A command has been entered on the console
+EVENT(E_CONSOLECOMMAND, ConsoleCommand)
+{
+    PARAM(P_COMMAND, Command);              // String
+}
+
+}

+ 3 - 0
Engine/Graphics/Direct3D9/D3D9Graphics.cpp

@@ -208,6 +208,9 @@ Graphics::Graphics(Context* context) :
             SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK | SDL_INIT_NOPARACHUTE);
         ++numInstances;
     }
+    
+    // Register Graphics library object factories
+    RegisterGraphicsLibrary(context_);
 }
 
 Graphics::~Graphics()

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

@@ -191,6 +191,9 @@ Graphics::Graphics(Context* context_) :
             SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK | SDL_INIT_NOPARACHUTE);
         ++numInstances;
     }
+    
+    // Register Graphics library object factories
+    RegisterGraphicsLibrary(context_);
 }
 
 Graphics::~Graphics()

+ 3 - 0
Engine/Network/Network.cpp

@@ -53,6 +53,9 @@ Network::Network(Context* context) :
 {
     network_ = new kNet::Network();
     
+    // Register Network library object factories
+    RegisterNetworkLibrary(context_);
+    
     SubscribeToEvent(E_BEGINFRAME, HANDLER(Network, HandleBeginFrame));
     SubscribeToEvent(E_RENDERUPDATE, HANDLER(Network, HandleRenderUpdate));
 }

+ 2 - 0
Engine/Resource/ResourceCache.cpp

@@ -64,6 +64,8 @@ ResourceCache::ResourceCache(Context* context) :
     Object(context),
     autoReloadResources_(false)
 {
+    // Register Resource library object factories
+    RegisterResourceLibrary(context_);
 }
 
 ResourceCache::~ResourceCache()

+ 0 - 0
Engine/Engine/APITemplates.h → Engine/Script/APITemplates.h


+ 0 - 0
Engine/Engine/AudioAPI.cpp → Engine/Script/AudioAPI.cpp


+ 3 - 2
Engine/Script/CMakeLists.txt

@@ -7,8 +7,9 @@ file (GLOB H_FILES *.h)
 set (SOURCE_FILES ${CPP_FILES} ${H_FILES})
 
 # Define dependency libs
-set (LIBS ../Container ../Core ../IO ../Math ../Physics ../Resource ../Scene ../../ThirdParty/AngelScript/include)
-set (INCLUDE_DIRS_ONLY ../../ThirdParty/Bullet/src)
+set (LIBS ../Audio ../Container ../Core ../Engine ../Graphics ../Input ../IO ../Math ../Navigation ../Network ../Physics
+    ../Resource ../Scene ../UI ../../ThirdParty/AngelScript/include)
+set (INCLUDE_DIRS_ONLY ../../ThirdParty/Bullet/src ../../ThirdParty/kNet/include)
 
 # Setup target
 enable_pch ()

+ 0 - 0
Engine/Engine/CoreAPI.cpp → Engine/Script/CoreAPI.cpp


+ 0 - 0
Engine/Engine/EngineAPI.cpp → Engine/Script/EngineAPI.cpp


+ 0 - 0
Engine/Engine/GraphicsAPI.cpp → Engine/Script/GraphicsAPI.cpp


+ 0 - 0
Engine/Engine/IOAPI.cpp → Engine/Script/IOAPI.cpp


+ 0 - 0
Engine/Engine/InputAPI.cpp → Engine/Script/InputAPI.cpp


+ 0 - 0
Engine/Engine/MathAPI.cpp → Engine/Script/MathAPI.cpp


+ 0 - 0
Engine/Engine/NavigationAPI.cpp → Engine/Script/NavigationAPI.cpp


+ 0 - 0
Engine/Engine/NetworkAPI.cpp → Engine/Script/NetworkAPI.cpp


+ 0 - 0
Engine/Engine/PhysicsAPI.cpp → Engine/Script/PhysicsAPI.cpp


+ 0 - 0
Engine/Engine/ResourceAPI.cpp → Engine/Script/ResourceAPI.cpp


+ 0 - 0
Engine/Engine/SceneAPI.cpp → Engine/Script/SceneAPI.cpp


+ 32 - 1
Engine/Script/Script.cpp

@@ -23,10 +23,12 @@
 #include "Precompiled.h"
 #include "Addons.h"
 #include "Context.h"
+#include "EngineEvents.h"
 #include "Log.h"
 #include "Profiler.h"
 #include "Scene.h"
 #include "Script.h"
+#include "ScriptAPI.h"
 #include "ScriptFile.h"
 #include "ScriptInstance.h"
 
@@ -156,9 +158,31 @@ Script::Script(Context* context) :
     immediateContext_ = scriptEngine_->CreateContext();
     immediateContext_->SetExceptionCallback(asMETHOD(Script, ExceptionCallback), this, asCALL_THISCALL);
 
-    // Register the Array & String types
+    // Register Script library object factories
+    RegisterScriptLibrary(context_);
+
+    // Register the Array & String API
     RegisterArray(scriptEngine_);
     RegisterString(scriptEngine_);
+
+    // Register the rest of the script API
+    RegisterMathAPI(scriptEngine_);
+    RegisterCoreAPI(scriptEngine_);
+    RegisterIOAPI(scriptEngine_);
+    RegisterResourceAPI(scriptEngine_);
+    RegisterSceneAPI(scriptEngine_);
+    RegisterGraphicsAPI(scriptEngine_);
+    RegisterInputAPI(scriptEngine_);
+    RegisterAudioAPI(scriptEngine_);
+    RegisterUIAPI(scriptEngine_);
+    RegisterNetworkAPI(scriptEngine_);
+    RegisterPhysicsAPI(scriptEngine_);
+    RegisterNavigationAPI(scriptEngine_);
+    RegisterScriptAPI(scriptEngine_);
+    RegisterEngineAPI(scriptEngine_);
+    
+    // Subscribe to console commands
+    SubscribeToEvent(E_CONSOLECOMMAND, HANDLER(Script, HandleConsoleCommand));
 }
 
 Script::~Script()
@@ -475,6 +499,13 @@ void Script::OutputAPIRow(const String& row, bool removeReference)
     Log::WriteRaw("- " + out + "\n");
 }
 
+void Script::HandleConsoleCommand(StringHash eventType, VariantMap& eventData)
+{
+    using namespace ConsoleCommand;
+    
+    Execute(eventData[P_COMMAND].GetString());
+}
+
 void RegisterScriptLibrary(Context* context)
 {
     ScriptFile::RegisterObject(context);

+ 3 - 1
Engine/Script/Script.h

@@ -107,7 +107,9 @@ private:
     asIScriptContext* GetScriptFileContext();
     /// Output a sanitated row of script API. No-ops when ENABLE_LOGGING not defined.
     void OutputAPIRow(const String& row, bool removeReference = false);
-
+    /// Handle a console command event.
+    void HandleConsoleCommand(StringHash eventType, VariantMap& eventData);
+    
     /// AngelScript engine.
     asIScriptEngine* scriptEngine_;
     /// Immediate execution script context.

+ 0 - 0
Engine/Engine/ScriptAPI.cpp → Engine/Script/ScriptAPI.cpp


+ 0 - 0
Engine/Engine/ScriptAPI.h → Engine/Script/ScriptAPI.h


+ 0 - 0
Engine/Engine/UIAPI.cpp → Engine/Script/UIAPI.cpp


+ 4 - 1
Engine/UI/UI.cpp

@@ -83,7 +83,10 @@ UI::UI(Context* context) :
 {
     rootElement_->SetTraversalMode(TM_DEPTH_FIRST);
     rootModalElement_->SetTraversalMode(TM_DEPTH_FIRST);
-
+    
+    // Register UI library object factories
+    RegisterUILibrary(context_);
+    
     SubscribeToEvent(E_SCREENMODE, HANDLER(UI, HandleScreenMode));
     SubscribeToEvent(E_MOUSEBUTTONDOWN, HANDLER(UI, HandleMouseButtonDown));
     SubscribeToEvent(E_MOUSEBUTTONUP, HANDLER(UI, HandleMouseButtonUp));

+ 3 - 3
Tools/AssetImporter/AssetImporter.cpp

@@ -207,12 +207,12 @@ void Run(const Vector<String>& arguments)
         );
     }
     
-    RegisterSceneLibrary(context_);
-    RegisterGraphicsLibrary(context_);
-    RegisterPhysicsLibrary(context_);
     context_->RegisterSubsystem(new FileSystem(context_));
     context_->RegisterSubsystem(new ResourceCache(context_));
     context_->RegisterSubsystem(new WorkQueue(context_));
+    RegisterSceneLibrary(context_);
+    RegisterGraphicsLibrary(context_);
+    RegisterPhysicsLibrary(context_);
     
     String command = arguments[0].ToLower();
     String rootNodeName;

+ 2 - 3
Tools/ScriptCompiler/ScriptCompiler.cpp

@@ -67,7 +67,9 @@ int main(int argc, char** argv)
     }
     
     SharedPtr<Context> context(new Context());
+    
     SharedPtr<Engine> engine(new Engine(context));
+    context->RegisterSubsystem(new Script(context));
     context->RegisterSubsystem(new FileSystem(context));
     context->RegisterSubsystem(new ResourceCache(context));
     context->RegisterSubsystem(new Log(context));
@@ -76,9 +78,6 @@ int main(int argc, char** argv)
     log->SetLevel(LOG_WARNING);
     log->SetTimeStamp(false);
     
-    if (!engine->InitializeScripting())
-        ErrorExit("Unable to initialize script engine. The application will now exit.");
-    
     if (!dumpApiMode)
     {
         String path, file, extension;

+ 4 - 1
Urho3D/Urho3D.cpp

@@ -28,6 +28,7 @@
 #include "ProcessUtils.h"
 #include "ResourceCache.h"
 #include "ResourceEvents.h"
+#include "Script.h"
 #include "ScriptFile.h"
 
 #include <exception>
@@ -133,8 +134,10 @@ int Application::Run()
     SharedPtr<Engine> engine(new Engine(context_));
     if (engine->Initialize(Engine::ParseParameters(arguments)))
     {
+        // Instantiate and register the script subsystem
+        context_->RegisterSubsystem(new Script(context_));
+        
         // Hold a shared pointer to the script file to make sure it is not unloaded during runtime
-        engine->InitializeScripting();
         SharedPtr<ScriptFile> scriptFile(context_->GetSubsystem<ResourceCache>()->GetResource<ScriptFile>(scriptFileName));
         
         // If script loading is successful, execute engine loop