Browse Source

Working on prefabs, new editor can run as player

Josh Engebretson 10 years ago
parent
commit
a206d02545

+ 16 - 4
Data/AtomicEditor/Resources/EditorData/AtomicEditor/typescript/ui/MainFrame.ts

@@ -90,9 +90,7 @@ class MainFrame extends ScriptWidget {
             if (refid == "quit")
                 Atomic.getEngine().exit();
 
-        }
-
-        if (target.id == "menu edit popup") {
+        } else if (target.id == "menu edit popup") {
 
             if (refid == "edit play") {
 
@@ -103,10 +101,24 @@ class MainFrame extends ScriptWidget {
 
             return false;
 
+        } else if (target.id == "menu file popup") {
+
+            if (refid == "file save file") {
+
+               //TODO: this is horrible
+                if (this.resourceframe.currentResourceEditor)
+                  this.resourceframe.currentResourceEditor.save();
+
+                return true;
+
+            }
+
+            return false;
         }
+
     }
 
-    handleResourceEditorChanged(data):void {
+    handleResourceEditorChanged(data): void {
 
         var editor = <Editor.ResourceEditor> data.editor;
 

+ 18 - 0
Data/AtomicEditor/Resources/EditorData/AtomicEditor/typescript/ui/MainFrameMenu.ts

@@ -36,10 +36,23 @@ var editItems = {
 
 };
 
+var fileItems = {
+
+  "New Project": ["file new project"],
+  "Open Project": ["file open project"],
+  "Save Project": ["file save project"],
+  "-1": null,
+  "Close Project": ["file close project"],
+  "-2": null,
+  "Save File": ["file save file"],
+  "Close File": ["file close file"]
+}
+
 var srcLookup = {};
 
 srcLookup["menu atomic editor"] = createMenuItemSource(editorItems);
 srcLookup["menu edit"] = createMenuItemSource(editItems);
+srcLookup["menu file"] = createMenuItemSource(fileItems);
 
 export function getMenuItemSource(id: string): Atomic.UIMenuItemSource {
     return srcLookup[id];
@@ -63,6 +76,11 @@ function createMenuItemSource(items: any): Atomic.UIMenuItemSource {
 
                 src.addItem(new UIMenuItem(key));
 
+            }
+            else if (typeof value === 'object' && value.length == 1) {
+
+                src.addItem(new UIMenuItem(key, value[0]));
+
             } else if (typeof value === 'object' && value.length == 2) {
 
                 src.addItem(new UIMenuItem(key, value[0], strings.EditorString.GetString(value[1])));

+ 7 - 0
Data/AtomicEditor/Resources/EditorData/AtomicEditor/typescript/ui/inspector/ComponentInspector.ts

@@ -99,6 +99,13 @@ class ComponentInspector extends Atomic.UISection {
 
         }
 
+        for (var i in this.bindings)
+        {
+            this.bindings[i].setWidgetValueFromObject();
+            this.bindings[i].objectLocked = false;
+        }
+
+
     }
 
     bindings:Array<DataBinding> = new Array();

+ 188 - 12
Data/AtomicEditor/Resources/EditorData/AtomicEditor/typescript/ui/inspector/DataBinding.ts

@@ -24,19 +24,46 @@ class DataBinding {
         }
         else if (attrInfo.type == Atomic.VAR_INT) {
 
-          if (attrInfo.enumNames.length) {
+            if (attrInfo.enumNames.length) {
+
+                var button = new Atomic.UIButton();
+                button.fontDescription = fd;
+                button.text = "Enum Value!";
+                var lp = new Atomic.UILayoutParams();
+                lp.width = 140;
+                button.layoutParams = lp;
+
+                widget = button;
+
+            } else {
+
+                var field = new Atomic.UIEditField();
+                field.textAlign = Atomic.UI_TEXT_ALIGN_CENTER;
+                field.fontDescription = fd;
+                field.skinBg = "TBAttrEditorField";
+
+                var lp = new Atomic.UILayoutParams();
+                lp.width = 140;
+                field.layoutParams = lp;
+
+                widget = field;
+            }
+
+        } else if (attrInfo.type == Atomic.VAR_FLOAT) {
+
+            var field = new Atomic.UIEditField();
+            field.textAlign = Atomic.UI_TEXT_ALIGN_CENTER;
+            field.fontDescription = fd;
+            field.skinBg = "TBAttrEditorField";
 
-            var button = new Atomic.UIButton();
-            button.fontDescription = fd;
-            button.text = "Enum Value!";
             var lp = new Atomic.UILayoutParams();
             lp.width = 140;
-            button.layoutParams = lp;
+            field.layoutParams = lp;
 
-            widget = button;
-          }
+            widget = field;
 
-        } else if (attrInfo.type == Atomic.VAR_STRING) {
+        }
+        else if (attrInfo.type == Atomic.VAR_STRING) {
 
             var field = new Atomic.UIEditField();
             field.textAlign = Atomic.UI_TEXT_ALIGN_LEFT;
@@ -69,6 +96,23 @@ class DataBinding {
                 layout.addChild(select);
             }
 
+        } else if (attrInfo.type == Atomic.VAR_COLOR) {
+            var layout = new Atomic.UILayout();
+            widget = layout;
+            layout.spacing = 0;
+
+            var lp = new Atomic.UILayoutParams();
+            lp.width = 70;
+
+            for (var i = 0; i < 4; i++) {
+                var select = new Atomic.UIInlineSelect();
+                select.id = String(i + 1);
+                select.fontDescription = fd;
+                select.setLimits(-10000000, 10000000);
+                select.layoutParams = lp;
+                layout.addChild(select);
+            }
+
         }
 
         if (widget) {
@@ -82,6 +126,79 @@ class DataBinding {
 
     }
 
+    setWidgetValueFromObject() {
+        if (this.widgetLocked)
+            return;
+
+        this.widgetLocked = true;
+
+        var attrInfo = this.attrInfo;
+        var object = this.object;
+        var widget = this.widget;
+
+        if (attrInfo.type == Atomic.VAR_BOOL) {
+            var value = object.getAttribute(attrInfo.name);
+            widget.value = (value ? 1 : 0);
+        }
+        else if (attrInfo.type == Atomic.VAR_VECTOR3) {
+
+            var value = object.getAttribute(attrInfo.name);
+
+            for (var i = 0; i < 3; i++) {
+
+                var select = widget.getWidget((i + 1).toString());
+                if (select)
+                    select.value = value[i];
+            }
+
+        }
+        else if (attrInfo.type == Atomic.VAR_QUATERNION) {
+
+            var value = object.getAttribute(attrInfo.name);
+
+            for (var i = 0; i < 3; i++) {
+
+                var select = widget.getWidget((i + 1).toString());
+                if (select)
+                    select.value = value[i];
+            }
+
+        }
+        else if (attrInfo.type == Atomic.VAR_STRING) {
+            var value = object.getAttribute(attrInfo.name);
+            widget.text = value;
+        }
+        else if (attrInfo.type == Atomic.VAR_FLOAT) {
+            var value = object.getAttribute(attrInfo.name);
+            widget.text = value.toString();
+        }
+        else if (attrInfo.type == Atomic.VAR_INT) {
+            var value = object.getAttribute(attrInfo.name);
+
+            if (attrInfo.enumNames.length) {
+                widget.text = attrInfo.enumNames[value];
+            }
+            else {
+                widget.text = value.toString();
+            }
+        }
+        else if (attrInfo.type == Atomic.VAR_COLOR) {
+
+            var value = object.getAttribute(attrInfo.name);
+
+            for (var i = 0; i < 4; i++) {
+
+                var select = widget.getWidget((i + 1).toString());
+                if (select)
+                    select.value = value[i];
+            }
+
+        }
+
+        this.widgetLocked = false;
+
+    }
+
     setObjectValueFromWidget(srcWidget: Atomic.UIWidget) {
 
         if (this.objectLocked)
@@ -89,11 +206,69 @@ class DataBinding {
 
         this.objectLocked = true;
 
-        var type = this.attrInfo.type;
+        var widget = this.widget;
+        var object = this.object;
+        var attrInfo = this.attrInfo;
+        var type = attrInfo.type;
 
         if (type == Atomic.VAR_BOOL) {
-            var box = <Atomic.UICheckBox> this.widget;
-            this.object.setAttribute(this.attrInfo.name, box.value ? true : false);
+
+            object.setAttribute(attrInfo.name, widget.value ? true : false);
+
+        } else if (type == Atomic.VAR_INT) {
+
+            object.setAttribute(attrInfo.name, Number(widget.text));
+
+        }
+        else if (type == Atomic.VAR_FLOAT) {
+
+            object.setAttribute(attrInfo.name, Number(widget.text));
+
+        }
+        else if (type == Atomic.VAR_STRING) {
+
+            object.setAttribute(attrInfo.name, widget.text);
+
+        } else if (type == Atomic.VAR_VECTOR3 && srcWidget) {
+
+            var value = object.getAttribute(attrInfo.name);
+
+            if (srcWidget.id == "1")
+                value[0] = srcWidget.value;
+            else if (srcWidget.id == "2")
+                value[1] = srcWidget.value;
+            else if (srcWidget.id == "3")
+                value[2] = srcWidget.value;
+
+            object.setAttribute(attrInfo.name, value);
+
+        } else if (type == Atomic.VAR_QUATERNION && srcWidget) {
+
+            var value = object.getAttribute(attrInfo.name);
+
+            if (srcWidget.id == "1")
+                value[0] = srcWidget.value;
+            else if (srcWidget.id == "2")
+                value[1] = srcWidget.value;
+            else if (srcWidget.id == "3")
+                value[2] = srcWidget.value;
+
+            object.setAttribute(attrInfo.name, value);
+
+        } else if (type == Atomic.VAR_COLOR && srcWidget) {
+
+            var value = object.getAttribute(attrInfo.name);
+
+            if (srcWidget.id == "1")
+                value[0] = srcWidget.value;
+            else if (srcWidget.id == "2")
+                value[1] = srcWidget.value;
+            else if (srcWidget.id == "3")
+                value[2] = srcWidget.value;
+            else if (srcWidget.id == "4")
+                value[3] = srcWidget.value;
+
+            object.setAttribute(attrInfo.name, value);
         }
 
         this.objectLocked = false;
@@ -117,7 +292,8 @@ class DataBinding {
     }
 
     object: Atomic.Serializable;
-    objectLocked: boolean = false;
+    objectLocked: boolean = true;
+    widgetLocked: boolean = false;
     attrInfo: Atomic.AttributeInfo;
     widget: Atomic.UIWidget;
 

+ 6 - 0
Data/AtomicEditor/Resources/EditorData/AtomicEditor/typescript/ui/inspector/NodeInspector.ts

@@ -133,6 +133,12 @@ class NodeInspector extends ScriptWidget {
 
         nodeLayout.addChild(button);
 
+        for (var i in this.bindings)
+        {
+            this.bindings[i].setWidgetValueFromObject();
+            this.bindings[i].objectLocked = false;
+        }
+
     }
 
     bindings:Array<DataBinding> = new Array();

+ 261 - 10
Source/AtomicEditorWork/Application/AEPlayerApp.cpp

@@ -1,39 +1,290 @@
-// Copyright (c) 2014-2015, THUNDERBEAST GAMES LLC All rights reserved
-// Please see LICENSE.md in repository root for license information
-// https://github.com/AtomicGameEngine/AtomicGameEngine
+//
+// Copyright (c) 2008-2014 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.
+//
 
+#include <Atomic/Atomic.h>
 #include <Atomic/Engine/Engine.h>
+#include <Atomic/IO/FileSystem.h>
+#include <Atomic/IO/Log.h>
+#include <Atomic/IO/IOEvents.h>
+#include <Atomic/Core/Main.h>
+#include <Atomic/Core/ProcessUtils.h>
+#include <Atomic/Resource/ResourceCache.h>
+#include <Atomic/Resource/ResourceEvents.h>
 
-#include <ToolCore/ToolSystem.h>
-#include <ToolCore/ToolEnvironment.h>
+#include <Atomic/IPC/IPC.h>
+#include <Atomic/IPC/IPCEvents.h>
+#include <Atomic/IPC/IPCWorker.h>
+
+// Move me
+#include <Atomic/Environment/Environment.h>
+
+#include <AtomicJS/Javascript/Javascript.h>
 
 #include "AEPlayerApp.h"
 
-using namespace ToolCore;
+#include <Atomic/DebugNew.h>
+
+#include <Atomic/UI/UI.h>
+
+#ifdef __APPLE__
+#include <unistd.h>
+#endif
 
 namespace AtomicEditor
 {
 
-AEPlayerApp::AEPlayerApp(Context* context) :
+// fixme
+static JSVM* vm = NULL;
+static Javascript* javascript = NULL;
+
+AEPlayerApplication::AEPlayerApplication(Context* context) :
     Application(context)
 {
+    fd_[0] = INVALID_IPCHANDLE_VALUE;
+    fd_[1] = INVALID_IPCHANDLE_VALUE;
+
+#ifdef ATOMIC_3D
+    RegisterEnvironmentLibrary(context_);
+#endif
 
 }
 
-void AEPlayerApp::Start()
+void AEPlayerApplication::Setup()
 {
+    FileSystem* filesystem = GetSubsystem<FileSystem>();
+
+    engineParameters_["WindowTitle"] = "AtomicPlayer";
+
+#if (ATOMIC_PLATFORM_ANDROID)
+    engineParameters_["FullScreen"] = true;
+    engineParameters_["ResourcePaths"] = "CoreData;AtomicResources";
+#elif ATOMIC_PLATFORM_WEB
+    engineParameters_["FullScreen"] = false;
+    engineParameters_["ResourcePaths"] = "AtomicResources";
+    // engineParameters_["WindowWidth"] = 1280;
+    // engineParameters_["WindowHeight"] = 720;
+#elif ATOMIC_PLATFORM_IOS
+    engineParameters_["FullScreen"] = false;
+    engineParameters_["ResourcePaths"] = "AtomicResources";
+#else
+    engineParameters_["FullScreen"] = false;
+    engineParameters_["WindowWidth"] = 1280;
+    engineParameters_["WindowHeight"] = 720;
+#endif
+
+#if ATOMIC_PLATFORM_WINDOWS
+    engineParameters_["WindowIcon"] = "Images/AtomicLogo32.png";
+    engineParameters_["ResourcePrefixPath"] = "AtomicPlayer_Resources";
+#elif ATOMIC_PLATFORM_ANDROID
+    //engineParameters_["ResourcePrefixPath"] = "assets";
+#elif ATOMIC_PLATFORM_OSX
+    engineParameters_["ResourcePrefixPath"] = "../Resources";
+#endif
+
+    const Vector<String>& arguments = GetArguments();
+
+    for (unsigned i = 0; i < arguments.Size(); ++i)
+    {
+        if (arguments[i].Length() > 1)
+        {
+            String argument = arguments[i].ToLower();
+            String value = i + 1 < arguments.Size() ? arguments[i + 1] : String::EMPTY;
+
+            if (argument == "--log-std")
+            {
+                SubscribeToEvent(E_LOGMESSAGE, HANDLER(AEPlayerApplication, HandleLogMessage));
+            }
+
+            if (argument.StartsWith("--ipc-server=") || argument.StartsWith("--ipc-client="))
+            {
+                LOGINFOF("Starting IPCWorker %s", argument.CString());
+
+                Vector<String> ipc = argument.Split(argument.CString(), '=');
 
+                if (ipc.Size() == 2)
+                {
+                    if (argument.StartsWith("--ipc-server="))
+                    {
+#ifdef ATOMIC_PLATFORM_WINDOWS
+                        WString wipc(ipc[1]);
+                        HANDLE pipe = reinterpret_cast<HANDLE>(_wtoi64(wipc.CString()));
+                        fd_[0] = pipe;
+#else
+                        int fd = ToInt(ipc[1].CString());
+                        fd_[0] = fd;
+#endif
+                    }
+                    else
+                    {
+#ifdef ATOMIC_PLATFORM_WINDOWS
+                        WString wipc(ipc[1]);
+                        HANDLE pipe = reinterpret_cast<HANDLE>(_wtoi64(wipc.CString()));
+                        fd_[1] = pipe;
+#else
+                        int fd = ToInt(ipc[1].CString());
+                        fd_[1] = fd;
+#endif
+                    }
+
+                }
+
+            }
+            else if (argument == "--project" && value.Length())
+            {
+                engineParameters_["ResourcePrefixPath"] = "";
+
+                // This works for a local dev build, --editor-resource-paths command below is for
+                // launching from AtomicEditor (IPC)
+
+                String resourcePaths = ToString("%s/Data/AtomicPlayer/Resources/CoreData;%s/Data/AtomicPlayer/Resources/PlayerData;%s/;%s/Resources",
+                         ATOMIC_ROOT_SOURCE_DIR, ATOMIC_ROOT_SOURCE_DIR, value.CString(), value.CString());
+
+                LOGINFOF("Adding ResourcePaths: %s", resourcePaths.CString());
+
+                engineParameters_["ResourcePaths"] = resourcePaths;
+
+            }
+            else if (argument == "--editor-resource-paths" && value.Length())
+            {
+                // "/Users/josh/Dev/atomic/AtomicGameEngine/Data/AtomicPlayer/Resources/CoreData!/Users/josh/Dev/atomic/AtomicGameEngine/Data/AtomicPlayer/Resources/PlayerData!/Users/josh/Dev/atomic/AtomicExamples/NewSpaceGame/Resources"
+                engineParameters_["ResourcePrefixPath"] = "";
+                value.Replace("!", ";");
+                engineParameters_["ResourcePaths"] = value;
+            }
+        }
+    }
+
+    // Use the script file name as the base name for the log file
+    engineParameters_["LogName"] = filesystem->GetAppPreferencesDir("AtomicPlayer", "Logs") + "AtomicPlayer.log";
+}
+
+void AEPlayerApplication::HandleHelloFromBroker(StringHash eventType, VariantMap& eventData)
+{
+    assert(eventData[HelloFromBroker::P_HELLO].GetString() == "Hello");
+    assert(eventData[HelloFromBroker::P_LIFETHEUNIVERSEANDEVERYTHING].GetInt() == 42);
+
+    LOGERROR("Passed Test!");
 }
 
-void AEPlayerApp::Setup()
+void AEPlayerApplication::Start()
 {
+    SubscribeToEvent(E_IPCHELLOFROMBROKER, HANDLER(AEPlayerApplication, HandleHelloFromBroker));
+    SubscribeToEvent(E_JSERROR, HANDLER(AEPlayerApplication, HandleJSError));
+
 
+#ifdef ATOMIC_PLATFORM_WINDOWS
+    if (fd_[0] != INVALID_IPCHANDLE_VALUE)
+    {
+        //::CloseHandle(fd_[0]);
+        fd_[0] = INVALID_IPCHANDLE_VALUE;
+    }
 
+    if (fd_[1] != INVALID_IPCHANDLE_VALUE)
+    {
+        IPC* ipc = new IPC(context_);
+        context_->RegisterSubsystem(ipc);
+        //ipc->InitWorker(fd_[0], fd_[1]);
+    }
+#else
+    if (fd_[0] != INVALID_IPCHANDLE_VALUE && fd_[1] != INVALID_IPCHANDLE_VALUE)
+    {
+        IPC* ipc = new IPC(context_);
+        context_->RegisterSubsystem(ipc);
+        ipc->InitWorker(fd_[0], fd_[1]);
+    }
+#endif
+
+    // Instantiate and register the Javascript subsystem
+    javascript = new Javascript(context_);
+    context_->RegisterSubsystem(javascript);
+
+    vm = javascript->InstantiateVM("MainVM");
+    vm->InitJSContext();
+
+    vm->SetModuleSearchPaths("Modules");
+
+    if (!vm->ExecuteMain())
+    {
+        ErrorExit("Error executing Scripts/main.js");
+    }
+
+    return;
+}
+
+void AEPlayerApplication::Stop()
+{
+    context_->RemoveSubsystem<Javascript>();
+}
+
+void AEPlayerApplication::HandleScriptReloadStarted(StringHash eventType, VariantMap& eventData)
+{
+}
+
+void AEPlayerApplication::HandleScriptReloadFinished(StringHash eventType, VariantMap& eventData)
+{
+}
+
+void AEPlayerApplication::HandleScriptReloadFailed(StringHash eventType, VariantMap& eventData)
+{
+    ErrorExit();
 }
 
-void AEPlayerApp::Stop()
+void AEPlayerApplication::HandleLogMessage(StringHash eventType, VariantMap& eventData)
 {
+    using namespace LogMessage;
+
+    int level = eventData[P_LEVEL].GetInt();
+    // The message may be multi-line, so split to rows in that case
+    Vector<String> rows = eventData[P_MESSAGE].GetString().Split('\n');
+
+    for (unsigned i = 0; i < rows.Size(); ++i)
+    {
+        if (level == LOG_ERROR)
+        {
+            fprintf(stderr, "%s\n", rows[i].CString());
+        }
+        else
+        {
+            fprintf(stdout, "%s\n", rows[i].CString());
+        }
+    }
 
 }
 
+void AEPlayerApplication::HandleJSError(StringHash eventType, VariantMap& eventData)
+{
+    using namespace JSError;
+    //String errName = eventData[P_ERRORNAME].GetString();
+    String errMessage = eventData[P_ERRORMESSAGE].GetString();
+    String errFilename = eventData[P_ERRORFILENAME].GetString();
+    //String errStack = eventData[P_ERRORSTACK].GetString();
+    int errLineNumber = eventData[P_ERRORLINENUMBER].GetInt();
+
+    String errorString = ToString("%s - %s - Line: %i",
+                                  errFilename.CString(), errMessage.CString(), errLineNumber);
+
+    ErrorExit(errorString);
+
+}
+
+
 }

+ 39 - 3
Source/AtomicEditorWork/Application/AEPlayerApp.h

@@ -1,6 +1,28 @@
+//
+// Copyright (c) 2008-2014 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 <Atomic/IPC/IPCTypes.h>
 #include <Atomic/Engine/Application.h>
 
 using namespace Atomic;
@@ -8,13 +30,13 @@ using namespace Atomic;
 namespace AtomicEditor
 {
 
-class AEPlayerApp : public Application
+class AEPlayerApplication : public Application
 {
-    OBJECT(AEPlayerApp);
+    OBJECT(AEPlayerApplication);
 
 public:
     /// Construct.
-    AEPlayerApp(Context* context);
+    AEPlayerApplication(Context* context);
 
     /// Setup before engine initialization. Verify that a script file has been specified.
     virtual void Setup();
@@ -24,7 +46,21 @@ public:
     virtual void Stop();
 
 private:
+    /// Handle reload start of the script file.
+    void HandleScriptReloadStarted(StringHash eventType, VariantMap& eventData);
+    /// Handle reload success of the script file.
+    void HandleScriptReloadFinished(StringHash eventType, VariantMap& eventData);
+    /// Handle reload failure of the script file.
+    void HandleScriptReloadFailed(StringHash eventType, VariantMap& eventData);
 
+    void HandleJSError(StringHash eventType, VariantMap& eventData);
+
+    void HandleLogMessage(StringHash eventType, VariantMap& eventData);
+
+
+    void HandleHelloFromBroker(StringHash eventType, VariantMap& eventData);
+
+    IPCHandle fd_[2];
 };
 
 }

+ 1 - 1
Source/AtomicEditorWork/Application/Main.cpp

@@ -25,7 +25,7 @@ static int RunEditorApplication()
 static int RunPlayerApplication()
 {
     Atomic::SharedPtr<Atomic::Context> context(new Atomic::Context());
-    Atomic::SharedPtr<AEPlayerApp> application(new AEPlayerApp(context));
+    Atomic::SharedPtr<AEPlayerApplication> application(new AEPlayerApplication(context));
     return application->Run();
 }
 

+ 2 - 0
Source/AtomicEditorWork/Editors/ResourceEditor.h

@@ -43,6 +43,8 @@ public:
 
     const String& GetFullPath() { return fullpath_; }
 
+    virtual bool Save() { return true; }
+
     UIWidget* GetRootContentWidget() { return rootContentWidget_; }
 
 protected:

+ 16 - 0
Source/AtomicEditorWork/Editors/SceneEditor3D/SceneEditor3D.cpp

@@ -23,8 +23,13 @@
 #include <Atomic/Input/Input.h>
 #include <Atomic/UI/UI.h>
 
+#include <ToolCore/Assets/AssetDatabase.h>
+#include <ToolCore/Assets/Asset.h>
+
 #include "SceneEditor3D.h"
 
+using namespace ToolCore;
+
 namespace AtomicEditor
 {
 
@@ -177,7 +182,18 @@ void SceneEditor3D::HandlePlayStopped(StringHash eventType, VariantMap& eventDat
     sceneView_->Enable();
 }
 
+bool SceneEditor3D::Save()
+{
+    File file(context_);
 
+    if (file.Open(fullpath_, FILE_WRITE))
+    {
+        scene_->SaveXML(file);
+        file.Close();
+    }
+
+    return true;
 
+}
 
 }

+ 1 - 0
Source/AtomicEditorWork/Editors/SceneEditor3D/SceneEditor3D.h

@@ -48,6 +48,7 @@ public:
 
     virtual bool RequiresInspector() { return true; }
 
+    bool Save();
 
 private:
 

+ 0 - 9
Source/AtomicEditorWork/Editors/SceneEditor3D/SceneView3D.cpp

@@ -482,15 +482,6 @@ void SceneView3D::HandleDragEnterWidget(StringHash eventType, VariantMap& eventD
             dragNode_->LoadXML(xml->GetRoot());
             dragNode_->SetName(asset->GetName());
 
-            AnimationController* controller = dragNode_->GetComponent<AnimationController>();
-            if (controller)
-            {
-                controller->PlayExclusive("Idle", 0, true);
-
-                dragNode_->GetScene()->SetUpdateEnabled(true);
-            }
-
-
             /*
             dragNode_ = scene_->CreateChild(asset->GetName());            
             preloadResourceScene_ = new Scene(context_);

+ 74 - 3
Source/AtomicJS/Javascript/JSAPI.cpp

@@ -237,6 +237,53 @@ void js_to_variant(duk_context* ctx, int variantIdx, Variant &v)
         v = (RefCounted*) duk_get_pointer(ctx, variantIdx);
         return;
     }
+
+    if (duk_is_array(ctx, variantIdx))
+    {
+        if (duk_get_length(ctx, variantIdx) == 2)
+        {
+            Vector2 v2;
+            duk_get_prop_index(ctx, variantIdx, 0);
+            v2.x_ = duk_to_number(ctx, -1);
+            duk_get_prop_index(ctx, variantIdx, 1);
+            v2.y_ = duk_to_number(ctx, -1);
+            duk_pop_n(ctx, 2);
+            v = v2;
+            return;
+        }
+        else if (duk_get_length(ctx, variantIdx) == 3)
+        {
+            Vector3 v3;
+            duk_get_prop_index(ctx, variantIdx, 0);
+            v3.x_ = duk_to_number(ctx, -1);
+            duk_get_prop_index(ctx, variantIdx, 1);
+            v3.y_ = duk_to_number(ctx, -1);
+            duk_get_prop_index(ctx, variantIdx, 2);
+            v3.z_ = duk_to_number(ctx, -1);
+            duk_pop_n(ctx, 3);
+            v = v3;
+            return;
+        }
+        else if (duk_get_length(ctx, variantIdx) == 4)
+        {
+            Vector4 v4;
+            duk_get_prop_index(ctx, variantIdx, 0);
+            v4.x_ = duk_to_number(ctx, -1);
+            duk_get_prop_index(ctx, variantIdx, 1);
+            v4.y_ = duk_to_number(ctx, -1);
+            duk_get_prop_index(ctx, variantIdx, 2);
+            v4.z_ = duk_to_number(ctx, -1);
+            duk_get_prop_index(ctx, variantIdx, 2);
+            v4.w_ = duk_to_number(ctx, -1);
+            duk_pop_n(ctx, 4);
+            v = v4;
+            return;
+        }
+
+
+        return;
+    }
+
 }
 
 void js_push_variant(duk_context *ctx, const Variant& v)
@@ -244,9 +291,11 @@ void js_push_variant(duk_context *ctx, const Variant& v)
     VariantType type = v.GetType();
     RefCounted* ref;
     Object* object;
-    Vector2& vector2 = (Vector2&) Vector2::ZERO;
-    Vector3& vector3 = (Vector3&) Vector3::ZERO;
-    Vector4& vector4 = (Vector4&) Vector3::ZERO;
+    Vector2 vector2 = Vector2::ZERO;
+    Vector3 vector3 = Vector3::ZERO;
+    Vector4 vector4 = Vector4::ZERO;
+    Color color = Color::BLACK;
+
     void* uniqueClassID = NULL;
     const char* package = NULL;
 
@@ -324,6 +373,28 @@ void js_push_variant(duk_context *ctx, const Variant& v)
         duk_push_number(ctx, vector3.z_);
         duk_put_prop_index(ctx, -2, 2);
         break;
+    case VAR_QUATERNION:
+        vector3 = v.GetQuaternion().EulerAngles();
+        duk_push_array(ctx);
+        duk_push_number(ctx, vector3.x_);
+        duk_put_prop_index(ctx, -2, 0);
+        duk_push_number(ctx, vector3.y_);
+        duk_put_prop_index(ctx, -2, 1);
+        duk_push_number(ctx, vector3.z_);
+        duk_put_prop_index(ctx, -2, 2);
+        break;
+    case VAR_COLOR:
+        color = v.GetColor();
+        duk_push_array(ctx);
+        duk_push_number(ctx, color.r_);
+        duk_put_prop_index(ctx, -2, 0);
+        duk_push_number(ctx, color.g_);
+        duk_put_prop_index(ctx, -2, 1);
+        duk_push_number(ctx, color.b_);
+        duk_put_prop_index(ctx, -2, 2);
+        duk_push_number(ctx, color.a_);
+        duk_put_prop_index(ctx, -2, 3);
+        break;
     case VAR_VECTOR4:
         vector4 = v.GetVector4();
         duk_push_array(ctx);

+ 48 - 0
Source/AtomicJS/Javascript/JSSceneSerializable.cpp

@@ -43,11 +43,54 @@ static int Serializable_SetAttribute(duk_context* ctx)
     duk_push_this(ctx);
     Serializable* serial = js_to_class_instance<Serializable>(ctx, -1, 0);
 
+    const Vector<AttributeInfo>* attributes = serial->GetAttributes();
+
+    for (unsigned i = 0; i < attributes->Size(); i++)
+    {
+        const AttributeInfo* attr = &attributes->At(i);
+
+        if (attr->name_ == name)
+        {
+            if (attr->type_ == VAR_QUATERNION)
+            {
+                Vector3 v3 = v.GetVector3();
+                Quaternion q;
+                q.FromEulerAngles(v3.x_, v3.y_, v3.z_);
+                v = q;
+            }
+
+            else if (attr->type_ == VAR_COLOR)
+            {
+                Vector4 v4 = v.GetVector4();
+                Color c(v4.x_, v4.y_, v4.z_, v4.w_ );
+                v = c;
+            }
+            else if (attr->type_ == VAR_INT)
+            {
+                v = (int) v.GetFloat();
+            }
+
+            break;
+        }
+    }
+
     serial->SetAttribute(name, v);
 
     return 0;
 }
 
+static int Serializable_GetAttribute(duk_context* ctx)
+{
+    const char* name = duk_to_string(ctx, 0);
+
+    duk_push_this(ctx);
+    Serializable* serial = js_to_class_instance<Serializable>(ctx, -1, 0);
+    js_push_variant(ctx,  serial->GetAttribute(name));
+
+    return 1;
+}
+
+
 static int Serializable_GetAttributes(duk_context* ctx)
 {
     duk_push_this(ctx);
@@ -74,6 +117,9 @@ static int Serializable_GetAttributes(duk_context* ctx)
     {
         const AttributeInfo* attr = &attrs->At(i);
 
+        if (attr->mode_ & AM_NOEDIT)
+            continue;
+
         duk_push_object(ctx);
 
         duk_push_number(ctx, (double) attr->type_);
@@ -123,6 +169,8 @@ void jsapi_init_scene_serializable(JSVM* vm)
     js_class_get_prototype(ctx, "Atomic", "Serializable");
     duk_push_c_function(ctx, Serializable_GetAttributes, 0);
     duk_put_prop_string(ctx, -2, "getAttributes");
+    duk_push_c_function(ctx, Serializable_GetAttribute, 1);
+    duk_put_prop_string(ctx, -2, "getAttribute");
     duk_push_c_function(ctx, Serializable_SetAttribute, 2);
     duk_put_prop_string(ctx, -2, "setAttribute");
     duk_pop(ctx);

+ 5 - 0
Source/AtomicJS/Packages/Atomic/Scene.json

@@ -20,6 +20,11 @@
 	},
 	"typescript_decl" : {
 
+		"Serializable" : [
+			"getAttributes():AttributeInfo[];",
+			"getAttribute(name:string):any;",
+			"setAttribute(name:string, value:any):void;"
+		],
 		"Node" : [
 			"saveXML(file:File):boolean;",
 			"getChildrenWithName(name:string, recursive?:boolean):Node[];",

+ 5 - 0
Source/ToolCore/Assets/Asset.cpp

@@ -10,6 +10,7 @@
 #include "MaterialImporter.h"
 #include "TextureImporter.h"
 #include "PrefabImporter.h"
+#include "JavascriptImporter.h"
 
 #include "Asset.h"
 
@@ -194,6 +195,10 @@ bool Asset::CreateImporter()
         {
             importer_ = new PrefabImporter(context_, this);
         }
+        else if (ext == ".js")
+        {
+            importer_ = new JavascriptImporter(context_, this);
+        }
         else if (ext == ".scene")
         {
             importer_ = new SceneImporter(context_, this);

+ 59 - 0
Source/ToolCore/Assets/JavascriptImporter.cpp

@@ -0,0 +1,59 @@
+
+#include <Atomic/Resource/ResourceCache.h>
+#include <Atomic/Resource/Image.h>
+
+#include "Asset.h"
+#include "AssetDatabase.h"
+#include "JavascriptImporter.h"
+
+namespace ToolCore
+{
+
+JavascriptImporter::JavascriptImporter(Context* context, Asset *asset) : AssetImporter(context, asset)
+{
+    requiresCacheFile_ = false;
+}
+
+JavascriptImporter::~JavascriptImporter()
+{
+
+}
+
+void JavascriptImporter::SetDefaults()
+{
+    AssetImporter::SetDefaults();
+}
+
+bool JavascriptImporter::Import(const String& guid)
+{
+    AssetDatabase* db = GetSubsystem<AssetDatabase>();
+    Asset* asset = db->GetAssetByGUID(guid);
+
+    if (!asset)
+        return false;
+
+    return true;
+}
+
+bool JavascriptImporter::LoadSettingsInternal()
+{
+    if (!AssetImporter::LoadSettingsInternal())
+        return false;
+
+    JSONValue import = jsonRoot_.GetChild("JavascriptImporter", JSON_OBJECT);
+
+    return true;
+}
+
+bool JavascriptImporter::SaveSettingsInternal()
+{
+    if (!AssetImporter::SaveSettingsInternal())
+        return false;
+
+    JSONValue import = jsonRoot_.CreateChild("JavascriptImporter");
+
+    return true;
+}
+
+
+}

+ 29 - 0
Source/ToolCore/Assets/JavascriptImporter.h

@@ -0,0 +1,29 @@
+
+#pragma once
+
+#include "AssetImporter.h"
+
+namespace ToolCore
+{
+
+class JavascriptImporter : public AssetImporter
+{
+    OBJECT(JavascriptImporter);
+
+public:
+    /// Construct.
+    JavascriptImporter(Context* context, Asset* asset);
+    virtual ~JavascriptImporter();
+
+    virtual void SetDefaults();
+
+    bool Import(const String& guid);
+
+protected:
+
+    virtual bool LoadSettingsInternal();
+    virtual bool SaveSettingsInternal();
+
+};
+
+}

+ 1 - 0
Source/ToolCore/Command/PlayCmd.cpp

@@ -78,6 +78,7 @@ void PlayCmd::Run()
     paths.Push(env->GetCoreDataDir());
     paths.Push(env->GetPlayerDataDir());
     paths.Push(project->GetResourcePath());
+    paths.Push(project->GetProjectPath());
 
     String resourcePaths;
     resourcePaths.Join(paths, "!");