Browse Source

Merge pull request #160 from AtomicGameEngine/JME-ATOMIC-148

Prefab Improvements
JoshEngebretson 10 years ago
parent
commit
1ac89c4137

+ 5 - 0
Resources/EditorData/AtomicEditor/editor/skin/skin.tb.txt

@@ -178,3 +178,8 @@ elements
 		text-color #aaaaaa
 		min-width 140
 		max-width 140
+
+	HierarchyPrefabText
+		text-color #11aaaa
+	HierarchyPrefabText.selected
+		text-color #11ffff

+ 37 - 0
Script/AtomicEditor/ui/frames/HierarchyFrame.ts

@@ -56,6 +56,37 @@ class HierarchyFrame extends Atomic.UIWidget {
 
         });
 
+        this.subscribeToEvent("ComponentAdded", (ev: Atomic.ComponentAddedEvent) => {
+
+            if (!ev.component || ev.component.typeName != "PrefabComponent") return;
+
+            var node = ev.node;
+
+            var itemID = this.nodeIDToItemID[node.id];
+
+            if (itemID) {
+
+                this.hierList.setItemTextSkin(node.id.toString(), "HierarchyPrefabText");
+
+            }
+
+        });
+
+        this.subscribeToEvent("ComponentRemoved", (ev: Atomic.ComponentRemovedEvent) => {
+
+            if (!ev.component || ev.component.typeName != "PrefabComponent") return;
+
+            var node = ev.node;
+
+            var itemID = this.nodeIDToItemID[node.id];
+
+            if (itemID) {
+
+                this.hierList.setItemTextSkin(node.id.toString(), "Folder");
+            }
+
+        });
+
         this.subscribeToEvent("TemporaryChanged", (ev: Atomic.TemporaryChangedEvent) => {
 
             // this can happen on a temporary status change on a non-scripted class instance
@@ -299,6 +330,12 @@ class HierarchyFrame extends Atomic.UIWidget {
 
         var childItemID = this.hierList.addChildItem(parentID, name, icon, node.id.toString());
 
+        if (node.getComponent("PrefabComponent")) {
+
+            this.hierList.setItemTextSkin(node.id.toString(), "HierarchyPrefabText");
+
+        }
+
         this.nodeIDToItemID[node.id] = childItemID;
 
         for (var i = 0; i < node.getNumChildren(false); i++) {

+ 0 - 23
Script/AtomicEditor/ui/frames/inspector/ComponentInspector.ts

@@ -173,29 +173,6 @@ class ComponentInspector extends Atomic.UISection {
 
     addPrefabUI(layout: Atomic.UILayout) {
 
-        // expand prefab
-        this.value = 1;
-
-        var fd = new Atomic.UIFontDescription();
-        fd.id = "Vera";
-        fd.size = 11;
-
-        var selectButton = new Atomic.UIButton();
-        selectButton.text = "Select Prefab";
-        selectButton.fontDescription = fd;
-
-        selectButton.onClick = () => {
-
-            var node = (<Atomic.PrefabComponent> this.component).getPrefabNode();
-
-            this.sendEvent("EditorActiveNodeChange", { node: node });
-
-            return true;
-
-        }
-
-        layout.addChild(selectButton);
-
     }
 
     acceptAssetDrag(importerTypeName: string, ev: Atomic.DragEndedEvent): ToolCore.AssetImporter {

+ 5 - 5
Script/AtomicEditor/ui/frames/inspector/NodeInspector.ts

@@ -35,8 +35,8 @@ class NodeInspector extends ScriptWidget {
 
     getPrefabComponent(node: Atomic.Node): Atomic.PrefabComponent {
 
-        if (node.parent && node.parent.getComponent("PrefabComponent"))
-            return <Atomic.PrefabComponent> node.parent.getComponent("PrefabComponent");
+        if (node.getComponent("PrefabComponent"))
+            return <Atomic.PrefabComponent> node.getComponent("PrefabComponent");
 
         if (node.parent)
             return this.getPrefabComponent(node.parent);
@@ -47,7 +47,7 @@ class NodeInspector extends ScriptWidget {
 
     detectPrefab(node: Atomic.Node): boolean {
 
-        if (node.parent && node.parent.getComponent("PrefabComponent"))
+        if (node.getComponent("PrefabComponent"))
             return true;
 
         if (node.parent)
@@ -232,8 +232,8 @@ class NodeInspector extends ScriptWidget {
 
             var component = components[i];
 
-            if (component.isTemporary())
-              continue;
+            //if (component.isTemporary())
+            //  continue;
 
             var ci = new ComponentInspector();
 

+ 2 - 1
Script/Packages/Atomic/Scene.json

@@ -40,7 +40,8 @@
 			"getChildAtIndex(index:number):Node;",
 			"createJSComponent(name:string, args?:{});",
 			"getJSComponent(name:string):JSComponent;",
-			"createChildPrefab(childName:string, prefabPath:string);"
+			"createChildPrefab(childName:string, prefabPath:string):Node;",
+			"loadPrefab(prefabPath:string):boolean;"
 		],
 		"Scene" : [
 			"getMainCamera():Camera;"

+ 12 - 8
Script/TypeScript/Atomic.d.ts

@@ -1800,6 +1800,8 @@ declare module Atomic {
       getChildAtIndex(index:number):Node;
       createJSComponent(name:string, args?:{});
       getJSComponent(name:string):JSComponent;
+      createChildPrefab(childName:string, prefabPath:string):Node;
+      loadPrefab(prefabPath:string):boolean;
 
    }
 
@@ -1824,7 +1826,6 @@ declare module Atomic {
    export class PrefabComponent extends Component {
 
       prefabGUID: string;
-      prefabNode: Node;
 
       // Construct.
       constructor();
@@ -1834,7 +1835,6 @@ declare module Atomic {
       savePrefab(): boolean;
       undoPrefab(): void;
       breakPrefab(): void;
-      getPrefabNode(): Node;
 
    }
 
@@ -4566,8 +4566,8 @@ declare module Atomic {
       onSetEnabled(): void;
       // Set speed.
       setSpeed(speed: number): void;
-      // Set animation by animation set, name and loop mode.
-      setAnimation(animationSet: AnimationSet2D, name: string, loopMode?: LoopMode2D): void;
+      // Set animation by name and loop mode.
+      setAnimation(name: string, loopMode?: LoopMode2D): void;
       // Set animation set.
       setAnimationSet(animationSet: AnimationSet2D): void;
       // Set loop mode.
@@ -5206,7 +5206,7 @@ declare module Atomic {
 
    export class Light2D extends Component {
 
-      lightGroup: Light2DGroup;
+      lightGroupID: number;
       color: Color;
       numRays: number;
       lightType: LightType2D;
@@ -5218,8 +5218,8 @@ declare module Atomic {
       // Construct.
       constructor();
 
-      setLightGroup(group: Light2DGroup): void;
-      getLightGroup(): Light2DGroup;
+      setLightGroupID(id: number): void;
+      getLightGroupID(): number;
       getColor(): Color;
       setColor(color: Color): void;
       updateVertices(): void;
@@ -5277,17 +5277,20 @@ declare module Atomic {
 
       physicsWorld: PhysicsWorld2D;
       ambientColor: Color;
+      lightGroupID: number;
       frustumBox: BoundingBox;
 
       // Construct.
       constructor();
 
-      setPhysicsWorld(physicsWorld: PhysicsWorld2D): void;
       getPhysicsWorld(): PhysicsWorld2D;
       addLight2D(light: Light2D): void;
+      removeLight2D(light: Light2D): void;
       setDirty(): void;
       setAmbientColor(color: Color): void;
       getAmbientColor(): Color;
+      setLightGroupID(id: number): void;
+      getLightGroupID(): number;
       getFrustumBox(): BoundingBox;
 
    }
@@ -7094,6 +7097,7 @@ declare module Atomic {
       addRootItem(text: string, icon: string, id: string): number;
       addChildItem(parentItemID: number, text: string, icon: string, id: string): number;
       setItemText(id: string, text: string): void;
+      setItemTextSkin(id: string, skin: string): void;
       setItemIcon(id: string, icon: string): void;
       deleteItemByID(id: string): void;
       setExpanded(itemID: number, value: boolean): void;

+ 16 - 0
Script/TypeScript/AtomicWork.d.ts

@@ -127,6 +127,22 @@ declare module Atomic {
 
     }
 
+    export interface ComponentAddedEvent {
+
+        scene: Atomic.Scene;
+        node: Atomic.Node;
+        component: Atomic.Component;
+
+    }
+
+    export interface ComponentRemovedEvent {
+
+        scene: Atomic.Scene;
+        node: Atomic.Node;
+        component: Atomic.Component;
+
+    }
+
     export interface IPCJSErrorEvent {
 
         errorName: string;

+ 62 - 27
Source/Atomic/Scene/PrefabComponent.cpp

@@ -51,15 +51,53 @@ void PrefabComponent::LoadPrefabNode()
     ResourceCache* cache = GetSubsystem<ResourceCache>();
     XMLFile* xmlfile = cache->GetResource<XMLFile>(prefabGUID_);
 
-    prefabNode_->LoadXML(xmlfile->GetRoot());
-    prefabNode_->SetTemporary(true);
+    if (!xmlfile || !node_)
+        return;
+
+    bool temporary = IsTemporary();
+    unsigned id = GetID();
+
+    // We're going to be removed, so keep ourselves alive and
+    // a reference to node_ as we'll readd
+    SharedPtr<PrefabComponent> keepAlive(this);
+    SharedPtr<Node> node(node_);
+
+    // store original transform
+    Vector3 pos = node->GetPosition();
+    Quaternion rot = node->GetRotation();
+    Vector3 scale = node->GetScale();
+
+    node->LoadXML(xmlfile->GetRoot());
+
+    node->SetPosition(pos);
+    node->SetRotation(rot);
+    node->SetScale(scale);
+
+    // Get the root components of the load node
+    const Vector<SharedPtr<Component>>& rootComponents = node->GetComponents();
+
+    // set all loaded components to be temporary, set all loaded root components and
+    // direct children to temporary
+    for (unsigned i = 0; i < rootComponents.Size(); i++)
+    {
+        rootComponents.At(i)->SetTemporary(true);
+    }
+
+    const Vector<SharedPtr<Node> >& children = node->GetChildren();
+
+    for (unsigned i = 0; i < children.Size(); i++)
+    {
+        children.At(i)->SetTemporary(true);
+    }
 
-    prefabNode_->SetPosition(Vector3::ZERO);
-    prefabNode_->SetRotation(Quaternion::IDENTITY);
-    // prefabNode_->SetScale(Vector3::ONE);
+    // readd via stored node, which is the same as node_ after this add
+    this->SetTemporary(temporary);
+    node->AddComponent(this, id, REPLICATED);
 
+    // Get all the rigid bodies of the load node
     PODVector<RigidBody*> bodies;
-    prefabNode_->GetComponents<RigidBody>(bodies, true);
+    node_->GetComponents<RigidBody>(bodies, true);
+
     for (unsigned i = 0; i < bodies.Size(); i++)
     {
         RigidBody* body = bodies[i];
@@ -73,14 +111,28 @@ void PrefabComponent::BreakPrefab()
     if (!node_ || !node_->GetScene())
         return;
 
-    SharedPtr<PrefabComponent> keepAlive(this);
+    // flip temporary root children and components to break prefab
+    const Vector<SharedPtr<Component>>& rootComponents = node_->GetComponents();
+    const Vector<SharedPtr<Node> >& children = node_->GetChildren();
+
+    for (unsigned i = 0; i < rootComponents.Size(); i++)
+    {
+        if (rootComponents[i]->IsTemporary())
+        {
+            rootComponents[i]->SetTemporary(false);
+        }
+    }
 
-    if (prefabNode_.NotNull())
-        prefabNode_->SetTemporary(false);
+    for (unsigned i = 0; i < children.Size(); i++)
+    {
+        if (children[i]->IsTemporary())
+        {
+            children[i]->SetTemporary(false);
+        }
+    }
 
     node_->RemoveComponent(this);
 
-
 }
 
 void PrefabComponent::HandlePrefabChanged(StringHash eventType, VariantMap& eventData)
@@ -96,14 +148,7 @@ void PrefabComponent::HandlePrefabChanged(StringHash eventType, VariantMap& even
 
 void PrefabComponent::SetPrefabGUID(const String& guid)
 {
-    assert(prefabNode_.Null());
-
-    // ensure to use node_->CreateChild() so in scene, this may be fixed
-    // with update on https://github.com/urho3d/Urho3D/issues/748
-    assert(node_);
-
     prefabGUID_ = guid;
-    prefabNode_ = node_->CreateChild();
 
     if (prefabGUID_.Length())
     {
@@ -115,16 +160,6 @@ void PrefabComponent::SetPrefabGUID(const String& guid)
 void PrefabComponent::OnNodeSet(Node* node)
 {
     Component::OnNodeSet(node);
-
-
-    if (!node && prefabNode_.NotNull())
-    {
-        // a prefab node might not be temporary is prefab is broken{
-        if (prefabNode_->IsTemporary())
-            prefabNode_->Remove();
-
-        prefabNode_ = NULL;
-    }
 }
 
 }

+ 0 - 3
Source/Atomic/Scene/PrefabComponent.h

@@ -28,8 +28,6 @@ public:
     void UndoPrefab();
     void BreakPrefab();
 
-    Node* GetPrefabNode() { return prefabNode_; }
-
 protected:
 
     /// Handle scene node being assigned at creation.
@@ -42,7 +40,6 @@ private:
 
     void LoadPrefabNode();
 
-    SharedPtr<Node> prefabNode_;
     String prefabGUID_;
 
 };

+ 34 - 1
Source/Atomic/UI/UIListView.cpp

@@ -61,6 +61,7 @@ public:
     }
 
     void UpdateText(const String& text);
+    void UpdateTextSkin(const String& skin);
     void UpdateIcon(const String& icon);
 
     ListViewItemSource* source_;
@@ -69,6 +70,7 @@ public:
     PODVector<ListViewItem*> children_;
     ListViewItemWidget* widget_;
     String icon_;
+    String textSkin_;
 };
 
 class ListViewItemWidget : public TBLayout
@@ -89,6 +91,12 @@ public:
             icon_->SetSkinBg(TBIDC(icon.CString()));
     }
 
+    void UpdateTextSkin(const String& skin)
+    {
+        if (textField_)
+            textField_->SetSkinBg(TBIDC(skin.CString()));
+    }
+
 
 private:
     TBCheckBox* expandBox_;
@@ -126,6 +134,14 @@ void ListViewItem::UpdateIcon(const String& icon)
         widget_->UpdateIcon(icon);
 }
 
+void ListViewItem::UpdateTextSkin(const String& skin)
+{
+    textSkin_ = skin;
+    if (widget_)
+        widget_->UpdateTextSkin(skin);
+}
+
+
 ListViewItem* ListViewItem::AddChild(const char *text, const char* icon, const TBID &id)
 {
     ListViewItem* child = new ListViewItem(text, id, icon, source_);
@@ -237,7 +253,8 @@ ListViewItemWidget::ListViewItemWidget(ListViewItem *item, ListViewItemSource *s
 
     TBTextField* tfield = textField_ = new TBTextField();
     tfield->SetIgnoreInput(true);
-    tfield->SetSkinBg(TBIDC("Folder"));
+
+    tfield->SetSkinBg(item->textSkin_.Length() ? TBIDC(item->textSkin_.CString()) : TBIDC("Folder"));
     tfield->SetText(item->str);
     tfield->SetFontDescription(fd);
 
@@ -385,6 +402,22 @@ void UIListView::SetItemText(const String& id, const String& text)
 
 }
 
+void UIListView::SetItemTextSkin(const String& id, const String& skin)
+{
+    TBID tbid(id.CString());
+
+    for (int i = 0; i <  source_->GetNumItems(); i++)
+    {
+        if (source_->GetItemID(i) == tbid)
+        {
+            ListViewItem* item = source_->GetItem(i);
+            item->UpdateTextSkin(skin);
+            return;
+        }
+    }
+
+}
+
 void UIListView::SetItemIcon(const String& id, const String& icon)
 {
     TBID tbid(id.CString());

+ 2 - 1
Source/Atomic/UI/UIListView.h

@@ -27,7 +27,8 @@ public:
 
 
     void SetItemText(const String& id, const String& text);
-    void SetItemIcon(const String& id, const String& icon);
+    void SetItemTextSkin(const String& id, const String& skin);
+    void SetItemIcon(const String& id, const String& icon);    
     void DeleteItemByID(const String& id);
 
     void SetExpanded(unsigned itemID, bool value);

+ 23 - 21
Source/AtomicJS/Javascript/JSScene.cpp

@@ -7,6 +7,7 @@
 #include <Atomic/IO/File.h>
 #include <Atomic/Scene/Node.h>
 #include <Atomic/Scene/Scene.h>
+#include <Atomic/Scene/PrefabComponent.h>
 #include <Atomic/Graphics/Camera.h>
 
 #ifdef ATOMIC_3D
@@ -198,6 +199,21 @@ static int Node_SaveXML(duk_context* ctx)
     return 1;
 }
 
+static int Node_LoadPrefab(duk_context* ctx)
+{
+    const char* prefabName = duk_require_string(ctx, 0);
+
+    duk_push_this(ctx);
+    Node* node = js_to_class_instance<Node>(ctx, -1, 0);
+
+    PrefabComponent* prefabComponent = node->CreateComponent<PrefabComponent>();
+    prefabComponent->SetPrefabGUID(prefabName);
+
+    duk_push_boolean(ctx, 1);
+    return 1;
+
+}
+
 static int Node_CreateChildPrefab(duk_context* ctx)
 {
     const char* childName = duk_require_string(ctx, 0);
@@ -206,33 +222,18 @@ static int Node_CreateChildPrefab(duk_context* ctx)
     duk_push_this(ctx);
     Node* parent = js_to_class_instance<Node>(ctx, -1, 0);
 
-    Node* prefabNode = parent->CreateChild(childName);
+    Node* node = parent->CreateChild(childName);
 
-    ResourceCache* cache = parent->GetSubsystem<ResourceCache>();
-    XMLFile* xmlfile = cache->GetResource<XMLFile>(prefabName);
+    PrefabComponent* prefabComponent = node->CreateComponent<PrefabComponent>();
+    prefabComponent->SetPrefabGUID(prefabName);
 
-    prefabNode->LoadXML(xmlfile->GetRoot());
-    prefabNode->SetTemporary(true);
-
-    prefabNode->SetPosition(Vector3::ZERO);
-    prefabNode->SetRotation(Quaternion::IDENTITY);
-
-#ifdef ATOMIC_3D
-    PODVector<RigidBody*> bodies;
-    prefabNode->GetComponents<RigidBody>(bodies, true);
-    for (unsigned i = 0; i < bodies.Size(); i++)
-    {
-        RigidBody* body = bodies[i];
-        body->SetTransform(body->GetNode()->GetWorldPosition(), body->GetNode()->GetWorldRotation());
-    }
-#endif
-
-    js_push_class_object_instance(ctx, prefabNode, "Node");
+    js_push_class_object_instance(ctx, node, "Node");
 
     return 1;
 
 }
 
+
 static int Scene_LoadXML(duk_context* ctx)
 {
     JSVM* vm = JSVM::GetJSVM(ctx);
@@ -310,9 +311,10 @@ void jsapi_init_scene(JSVM* vm)
     duk_put_prop_string(ctx, -2, "getChildAtIndex");
     duk_push_c_function(ctx, Node_SaveXML, 1);
     duk_put_prop_string(ctx, -2, "saveXML");
+    duk_push_c_function(ctx, Node_LoadPrefab, 1);
+    duk_put_prop_string(ctx, -2, "loadPrefab");
     duk_push_c_function(ctx, Node_CreateChildPrefab, 2);
     duk_put_prop_string(ctx, -2, "createChildPrefab");
-
     duk_pop(ctx);
 
     js_class_get_prototype(ctx, "Atomic", "Scene");

+ 54 - 1
Source/ToolCore/Assets/PrefabImporter.cpp

@@ -49,16 +49,69 @@ void PrefabImporter::HandlePrefabSave(StringHash eventType, VariantMap& eventDat
     if (component->GetPrefabGUID() != asset_->GetGUID())
         return;
 
-    Node* node = component->GetPrefabNode();
+    Node* node = component->GetNode();
+
+    if (!node)
+        return;
+
+    // flip temporary root children and components to not be temporary for save
+    const Vector<SharedPtr<Component>>& rootComponents = node->GetComponents();
+    const Vector<SharedPtr<Node> >& children = node->GetChildren();
+
+    Vector<SharedPtr<Component>> tempComponents;
+    Vector<SharedPtr<Node>> tempChildren;
+
+    for (unsigned i = 0; i < rootComponents.Size(); i++)
+    {
+        if (rootComponents[i]->IsTemporary())
+        {
+            rootComponents[i]->SetTemporary(false);
+            tempComponents.Push(rootComponents[i]);
+        }
+    }
+
+    for (unsigned i = 0; i < children.Size(); i++)
+    {
+        if (children[i]->IsTemporary())
+        {
+            children[i]->SetTemporary(false);
+            tempChildren.Push(children);
+        }
+    }
+
+    // store original transform
+    Vector3 pos = node->GetPosition();
+    Quaternion rot = node->GetRotation();
+    Vector3 scale = node->GetScale();
 
     node->SetPosition(Vector3::ZERO);
     node->SetRotation(Quaternion::IDENTITY);
     node->SetScale(Vector3::ONE);
 
+    component->SetTemporary(true);
+
     SharedPtr<File> file(new File(context_, asset_->GetPath(), FILE_WRITE));
     node->SaveXML(*file);
     file->Close();
 
+    component->SetTemporary(false);
+
+    // restore
+    node->SetPosition(pos);
+    node->SetRotation(rot);
+    node->SetScale(scale);
+
+    for (unsigned i = 0; i < tempComponents.Size(); i++)
+    {
+        tempComponents[i]->SetTemporary(true);
+    }
+
+    for (unsigned i = 0; i < tempChildren.Size(); i++)
+    {
+        tempChildren[i]->SetTemporary(true);
+    }
+
+
     FileSystem* fs = GetSubsystem<FileSystem>();
     fs->Copy(asset_->GetPath(), asset_->GetCachePath());