Explorar o código

Merge pull request #482 from AtomicGameEngine/JME-ATOMIC-SUBMESH

Animation sharing between FBX/Blender/etc +Submesh visibility editing
JoshEngebretson %!s(int64=10) %!d(string=hai) anos
pai
achega
dc1f11877c
Modificáronse 32 ficheiros con 1383 adicións e 896 borrados
  1. 9 27
      Script/AtomicEditor/ui/frames/inspector/ArrayEditWidget.ts
  2. 106 27
      Script/AtomicEditor/ui/frames/inspector/AttributeInfoEdit.ts
  3. 345 0
      Script/AtomicEditor/ui/frames/inspector/ComponentAttributeUI.ts
  4. 26 2
      Script/AtomicEditor/ui/frames/inspector/InspectorUtils.ts
  5. 8 9
      Script/AtomicEditor/ui/frames/inspector/MaterialInspector.ts
  6. 7 1
      Script/AtomicEditor/ui/frames/inspector/ModelInspector.ts
  7. 1 1
      Script/AtomicEditor/ui/frames/inspector/TextureSelector.ts
  8. 2 2
      Script/AtomicEditor/ui/modal/ModalOps.ts
  9. 54 15
      Script/AtomicEditor/ui/modal/ResourceSelection.ts
  10. 4 1
      Script/Packages/ToolCore/ToolCore.json
  11. 34 0
      Source/Atomic/Atomic3D/AnimatedModel.cpp
  12. 82 26
      Source/Atomic/Atomic3D/AnimationController.cpp
  13. 26 7
      Source/Atomic/Atomic3D/AnimationController.h
  14. 25 29
      Source/Atomic/Atomic3D/Model.cpp
  15. 5 9
      Source/Atomic/Atomic3D/Model.h
  16. 123 1
      Source/Atomic/Atomic3D/StaticModel.cpp
  17. 27 0
      Source/Atomic/Atomic3D/StaticModel.h
  18. 0 48
      Source/AtomicEditor/Editors/JSResourceEditor.cpp
  19. 0 2
      Source/AtomicEditor/Editors/SceneEditor3D/SceneEditor3D.cpp
  20. 0 191
      Source/AtomicEditor/Javascript/JSAutocomplete.cpp
  21. 0 59
      Source/AtomicEditor/Javascript/JSAutocomplete.h
  22. 12 1
      Source/ThirdParty/Assimp/code/FBXConverter.cpp
  23. 407 385
      Source/ThirdParty/TurboBadger/tb_editfield.cpp
  24. 0 10
      Source/ThirdParty/TurboBadger/tb_style_edit.cpp
  25. 0 2
      Source/ThirdParty/TurboBadger/tb_style_edit.h
  26. 1 0
      Source/ThirdParty/TurboBadger/tb_widgets_listener.h
  27. 3 1
      Source/ToolCore/Assets/AssetDatabase.cpp
  28. 1 1
      Source/ToolCore/Assets/AssetDatabase.h
  29. 41 36
      Source/ToolCore/Assets/ModelImporter.cpp
  30. 3 0
      Source/ToolCore/Assets/ModelImporter.h
  31. 2 0
      Source/ToolCore/Import/OpenAssetImporter.cpp
  32. 29 3
      Source/ToolCoreJS/ToolCoreJS.cpp

+ 9 - 27
Script/AtomicEditor/ui/frames/inspector/ArrayEditWidget.ts

@@ -9,7 +9,7 @@ import InspectorUtils = require("./InspectorUtils");
 
 
 class ArrayEditWidget extends Atomic.UILayout {
 class ArrayEditWidget extends Atomic.UILayout {
 
 
-    constructor(title:string) {
+    constructor(title: string) {
 
 
         super();
         super();
 
 
@@ -29,48 +29,30 @@ class ArrayEditWidget extends Atomic.UILayout {
 
 
         InspectorUtils.createSeparator(this);
         InspectorUtils.createSeparator(this);
 
 
-        this.countEditField = <Atomic.UIEditField> countEdit.getWidget("editfield");
+        this.countEditField = <Atomic.UIEditField>countEdit.getWidget("editfield");
 
 
         this.subscribeToEvent(this.countEditField, "UIWidgetEditComplete", (ev) => this.handleUIWidgetEditCompleteEvent(ev));
         this.subscribeToEvent(this.countEditField, "UIWidgetEditComplete", (ev) => this.handleUIWidgetEditCompleteEvent(ev));
-        this.subscribeToEvent(this.countEditField, "WidgetFocusChanged", (data) => this.handleCountWidgetFocusChanged(data));
 
 
     }
     }
 
 
-    handleCountWidgetFocusChanged(ev) {
+    handleUIWidgetEditCompleteEvent(ev):boolean {
 
 
-        if (ev.focused) {
+        var count = Number(this.countEditField.text);
 
 
-            this.countRestore = this.countEditField.text;
+        if (this.onCountChanged) {
 
 
-        } else {
-
-            this.countEditField.text = this.countRestore;
+            this.onCountChanged(count);
 
 
         }
         }
 
 
-    }
-
-    handleUIWidgetEditCompleteEvent(ev) {
-
-      if (this.countRestore != this.countEditField.text) {
-
-          this.countRestore = this.countEditField.text;
-
-          if (this.onCountChanged) {
-
-            this.onCountChanged(Number(this.countRestore));
-
-          }
-
-      }
+        return true;
 
 
     }
     }
 
 
-    countEdit:Atomic.UIEditField;
+    countEdit: Atomic.UIEditField;
 
 
-    onCountChanged: (count:number) => void;
+    onCountChanged: (count: number) => void;
 
 
-    countRestore: string;
     countEditField: Atomic.UIEditField;
     countEditField: Atomic.UIEditField;
 
 
 }
 }

+ 106 - 27
Script/AtomicEditor/ui/frames/inspector/AttributeInfoEdit.ts

@@ -17,6 +17,7 @@ class AttributeInfoEdit extends Atomic.UILayout {
     editWidget: Atomic.UIWidget;
     editWidget: Atomic.UIWidget;
 
 
     nameOverride: string;
     nameOverride: string;
+    hideName: boolean = false;
 
 
     constructor() {
     constructor() {
 
 
@@ -52,11 +53,6 @@ class AttributeInfoEdit extends Atomic.UILayout {
 
 
         this.layoutDistribution = Atomic.UI_LAYOUT_DISTRIBUTION_GRAVITY;
         this.layoutDistribution = Atomic.UI_LAYOUT_DISTRIBUTION_GRAVITY;
 
 
-        var name = new Atomic.UITextField();
-        name.textAlign = Atomic.UI_TEXT_ALIGN_LEFT;
-        name.skinBg = "InspectorTextAttrName";
-        name.layoutParams = attrNameLP;
-
         if (attr.type == Atomic.VAR_VECTOR3 || attr.type == Atomic.VAR_COLOR ||
         if (attr.type == Atomic.VAR_VECTOR3 || attr.type == Atomic.VAR_COLOR ||
             attr.type == Atomic.VAR_QUATERNION) {
             attr.type == Atomic.VAR_QUATERNION) {
             this.axis = Atomic.UI_AXIS_Y;
             this.axis = Atomic.UI_AXIS_Y;
@@ -64,19 +60,28 @@ class AttributeInfoEdit extends Atomic.UILayout {
             this.skinBg = "InspectorVectorAttrLayout";
             this.skinBg = "InspectorVectorAttrLayout";
         }
         }
 
 
-        var bname = attr.name;
+        if (!this.hideName) {
+
+            var name = new Atomic.UITextField();
+            name.textAlign = Atomic.UI_TEXT_ALIGN_LEFT;
+            name.skinBg = "InspectorTextAttrName";
+            name.layoutParams = attrNameLP;
+            var bname = attr.name;
 
 
-        if (bname == "Is Enabled")
-            bname = "Enabled";
+            if (bname == "Is Enabled")
+                bname = "Enabled";
 
 
-        if (this.nameOverride)
-            name.text = this.nameOverride;
-        else
-            name.text = bname;
+            if (this.nameOverride)
+                name.text = this.nameOverride;
+            else
+                name.text = bname;
 
 
-        name.fontDescription = AttributeInfoEdit.fontDesc;
+            name.fontDescription = AttributeInfoEdit.fontDesc;
 
 
-        this.addChild(name);
+            this.addChild(name);
+
+
+        }
 
 
         this.addChild(this.editWidget);
         this.addChild(this.editWidget);
 
 
@@ -139,7 +144,7 @@ class AttributeInfoEdit extends Atomic.UILayout {
     private static Ctor = (() => {
     private static Ctor = (() => {
 
 
         var attrNameLP = AttributeInfoEdit.attrNameLP = new Atomic.UILayoutParams();
         var attrNameLP = AttributeInfoEdit.attrNameLP = new Atomic.UILayoutParams();
-        attrNameLP.width = 100;
+        attrNameLP.width = 120;
 
 
         var fd = AttributeInfoEdit.fontDesc = new Atomic.UIFontDescription();
         var fd = AttributeInfoEdit.fontDesc = new Atomic.UIFontDescription();
         fd.id = "Vera";
         fd.id = "Vera";
@@ -203,7 +208,7 @@ class StringAttributeEdit extends AttributeInfoEdit {
         field.skinBg = "TBAttrEditorField";;
         field.skinBg = "TBAttrEditorField";;
         field.fontDescription = AttributeInfoEdit.fontDesc;
         field.fontDescription = AttributeInfoEdit.fontDesc;
         var lp = new Atomic.UILayoutParams();
         var lp = new Atomic.UILayoutParams();
-        lp.width = 140;
+        lp.width = 160;
         field.layoutParams = lp;
         field.layoutParams = lp;
 
 
         field.subscribeToEvent(field, "UIWidgetEditComplete", (ev) => this.handleUIWidgetEditCompleteEvent(ev));
         field.subscribeToEvent(field, "UIWidgetEditComplete", (ev) => this.handleUIWidgetEditCompleteEvent(ev));
@@ -404,11 +409,11 @@ class FloatAttributeEdit extends AttributeInfoEdit {
 
 
                 if (value == undefined) {
                 if (value == undefined) {
 
 
-                  console.log("WARNING: Undefined value for object: ", this.editType.typeName + "." + attrInfo.name);
-                  widget.text = "???";
+                    console.log("WARNING: Undefined value for object: ", this.editType.typeName + "." + attrInfo.name);
+                    widget.text = "???";
 
 
                 } else {
                 } else {
-                  widget.text = parseFloat(value.toFixed(5)).toString();
+                    widget.text = parseFloat(value.toFixed(5)).toString();
                 }
                 }
 
 
             }
             }
@@ -636,7 +641,7 @@ class ResourceRefAttributeEdit extends AttributeInfoEdit {
 
 
         if (parent) {
         if (parent) {
 
 
-          parent.sendEvent("AttributeEditResourceChanged", { attrInfoEdit: this, resource: resource});
+            parent.sendEvent("AttributeEditResourceChanged", { attrInfoEdit: this, resource: resource });
 
 
         }
         }
 
 
@@ -679,10 +684,17 @@ class ResourceRefAttributeEdit extends AttributeInfoEdit {
                 var text = "";
                 var text = "";
 
 
                 if (resource) {
                 if (resource) {
-                    text = resource.name;
-                    var asset = ToolCore.assetDatabase.getAssetByCachePath(resource.name);
-                    if (asset)
-                        text = asset.name;
+                    if (resource instanceof Atomic.Animation) {
+
+                        text = (<Atomic.Animation>resource).animationName;
+
+                    } else {
+
+                        text = resource.name;
+                        var asset = ToolCore.assetDatabase.getAssetByCachePath(resource.name);
+                        if (asset)
+                            text = asset.name;
+                    }
                 }
                 }
                 this.editField.text = text;
                 this.editField.text = text;
             }
             }
@@ -718,9 +730,20 @@ class ResourceRefAttributeEdit extends AttributeInfoEdit {
 
 
         selectButton.onClick = () => {
         selectButton.onClick = () => {
 
 
-            EditorUI.getModelOps().showResourceSelection("Select " + resourceTypeName + " Resource", importerName, function(asset: ToolCore.Asset) {
+            EditorUI.getModelOps().showResourceSelection("Select " + resourceTypeName + " Resource", importerName, resourceTypeName, function(retObject: any) {
+
+                var resource: Atomic.Resource = null;
+
+                if (retObject instanceof ToolCore.Asset) {
+
+                    resource = (<ToolCore.Asset>retObject).getResource(resourceTypeName);
+
+                } else if (retObject instanceof Atomic.Resource) {
+
+                    resource = <Atomic.Resource>retObject;
+
+                }
 
 
-                var resource = asset.getResource(resourceTypeName);
                 this.editType.onAttributeInfoEdited(this.attrInfo, resource, this.refListIndex);
                 this.editType.onAttributeInfoEdited(this.attrInfo, resource, this.refListIndex);
                 this.onResourceChanged(resource);
                 this.onResourceChanged(resource);
                 this.refresh();
                 this.refresh();
@@ -770,6 +793,7 @@ class ResourceRefListAttributeEdit extends AttributeInfoEdit {
 
 
     layout: Atomic.UILayout;
     layout: Atomic.UILayout;
     refEdits: ResourceRefAttributeEdit[] = [];
     refEdits: ResourceRefAttributeEdit[] = [];
+    sizeEdit: Atomic.UIEditField;
 
 
     initialize(editType: SerializableEditType, attrInfo: Atomic.AttributeInfo): boolean {
     initialize(editType: SerializableEditType, attrInfo: Atomic.AttributeInfo): boolean {
 
 
@@ -799,13 +823,24 @@ class ResourceRefListAttributeEdit extends AttributeInfoEdit {
         layout.spacing = 2;
         layout.spacing = 2;
         layout.layoutSize = Atomic.UI_LAYOUT_SIZE_AVAILABLE;
         layout.layoutSize = Atomic.UI_LAYOUT_SIZE_AVAILABLE;
         layout.gravity = Atomic.UI_GRAVITY_LEFT_RIGHT;
         layout.gravity = Atomic.UI_GRAVITY_LEFT_RIGHT;
+        layout.layoutPosition = Atomic.UI_LAYOUT_POSITION_LEFT_TOP;
         layout.layoutDistribution = Atomic.UI_LAYOUT_DISTRIBUTION_GRAVITY;
         layout.layoutDistribution = Atomic.UI_LAYOUT_DISTRIBUTION_GRAVITY;
 
 
         var lp = new Atomic.UILayoutParams();
         var lp = new Atomic.UILayoutParams();
         lp.width = 304;
         lp.width = 304;
-
         layout.layoutParams = lp;
         layout.layoutParams = lp;
 
 
+        var name = this.attrInfo.name + " Size";
+        if (name == "AnimationResources Size")
+            name = "Animations";
+
+        var sizeEdit = this.sizeEdit = InspectorUtils.createAttrEditField(name, layout);
+
+        var lp = new Atomic.UILayoutParams();
+        lp.width = 160;
+        sizeEdit.layoutParams = lp;
+
+        sizeEdit.subscribeToEvent(sizeEdit, "UIWidgetEditComplete", (ev) => this.handleUIWidgetEditCompleteEvent(ev));
 
 
         this.editWidget = layout;
         this.editWidget = layout;
 
 
@@ -821,6 +856,48 @@ class ResourceRefListAttributeEdit extends AttributeInfoEdit {
 
 
     }
     }
 
 
+    handleUIWidgetEditCompleteEvent(ev) {
+
+        var size = Number(this.sizeEdit.text);
+
+        if (size > 64 || size < 0)
+            return;
+
+        var editType = this.editType;
+
+        var refresh = false;
+
+        for (var i in editType.objects) {
+
+            var object = editType.objects[i];
+            var value = object.getAttribute(this.attrInfo.name);
+
+            if (value.resources.length > size) {
+
+                value.resources.length = size;
+                object.setAttribute(this.attrInfo.name, value);
+                refresh = true;
+
+            } else if (value.resources.length < size) {
+
+                for (var j = value.resources.length; j < size; j++) {
+
+                    value.resources.push(null);
+
+                }
+
+                object.setAttribute(this.attrInfo.name, value);
+                refresh = true;
+
+            }
+
+        }
+
+        if (refresh)
+            this.refresh();
+
+    }
+
     refresh() {
     refresh() {
 
 
         var editType = this.editType;
         var editType = this.editType;
@@ -848,6 +925,8 @@ class ResourceRefListAttributeEdit extends AttributeInfoEdit {
 
 
         }
         }
 
 
+        this.sizeEdit.text = maxLength.toString();
+
         if (maxLength == -1) {
         if (maxLength == -1) {
             this.visibility = Atomic.UI_WIDGET_VISIBILITY_GONE;
             this.visibility = Atomic.UI_WIDGET_VISIBILITY_GONE;
             return;
             return;

+ 345 - 0
Script/AtomicEditor/ui/frames/inspector/ComponentAttributeUI.ts

@@ -5,8 +5,10 @@
 // license information: https://github.com/AtomicGameEngine/AtomicGameEngine
 // license information: https://github.com/AtomicGameEngine/AtomicGameEngine
 //
 //
 
 
+import EditorUI = require("ui/EditorUI");
 import InspectorUtils = require("./InspectorUtils");
 import InspectorUtils = require("./InspectorUtils");
 import AttributeInfoEdit = require("./AttributeInfoEdit");
 import AttributeInfoEdit = require("./AttributeInfoEdit");
+import SerializableEditType = require("./SerializableEditType");
 
 
 class LightCascadeAttributeEdit extends AttributeInfoEdit {
 class LightCascadeAttributeEdit extends AttributeInfoEdit {
 
 
@@ -101,4 +103,347 @@ class LightCascadeAttributeEdit extends AttributeInfoEdit {
 
 
 }
 }
 
 
+interface MaterialEdit {
+
+    index: number;
+    editField: Atomic.UIEditField;
+    selectButton: Atomic.UIButton;
+
+}
+
+class SubmeshAttributeEdit extends AttributeInfoEdit {
+
+    materialIndexes: number[] = [];
+
+    materialEdits: { [index: number]: MaterialEdit } = {};
+
+    mainLayout: Atomic.UILayout;
+    enabledCheckBox: Atomic.UICheckBox;
+    nameField: Atomic.UITextField;
+    name: string;
+
+    constructor(name: string) {
+
+        super();
+        this.name = name;
+        this.hideName = true;
+    }
+
+    createMaterialEdit(materialIndex: number) {
+
+        var o = InspectorUtils.createAttrEditFieldWithSelectButton("", this.mainLayout);
+
+        var lp = new Atomic.UILayoutParams();
+        lp.width = 250;
+        o.editField.layoutParams = lp;
+        o.editField.readOnly = true;
+
+        var selectButton = o.selectButton;
+
+        var materialEdit: MaterialEdit = { index: materialIndex, editField: o.editField, selectButton: selectButton };
+        this.materialEdits[materialIndex] = materialEdit;
+
+        var resourceTypeName = "Material";
+        var importerName = ToolCore.assetDatabase.getResourceImporterName(resourceTypeName);
+
+        selectButton.onClick = () => {
+
+            EditorUI.getModelOps().showResourceSelection("Select " + resourceTypeName + " Resource", importerName, resourceTypeName, function(retObject: any) {
+
+                var resource: Atomic.Resource = null;
+
+                if (retObject instanceof ToolCore.Asset) {
+
+                    resource = (<ToolCore.Asset>retObject).getResource(resourceTypeName);
+
+                } else if (retObject instanceof Atomic.Resource) {
+
+                    resource = <Atomic.Resource>retObject;
+
+                }
+
+                this.editType.onAttributeInfoEdited(this.attrInfo, resource, materialIndex);
+                this.refresh();
+
+            }.bind(this));
+        }
+
+        // handle dropping of component on field
+        o.editField.subscribeToEvent(o.editField, "DragEnded", (ev: Atomic.DragEndedEvent) => {
+
+            if (ev.target == o.editField) {
+
+                var dragObject = ev.dragObject;
+
+                var importer;
+
+                if (dragObject.object && dragObject.object.typeName == "Asset") {
+
+                    var asset = <ToolCore.Asset>dragObject.object;
+
+                    if (asset.importerTypeName == importerName) {
+                        importer = asset.importer;
+                    }
+
+                }
+
+                if (importer) {
+
+                    var resource = asset.getResource(resourceTypeName);
+
+                    this.editType.onAttributeInfoEdited(this.attrInfo, resource, materialIndex);
+                    this.refresh();
+                }
+            }
+
+        });
+
+    }
+
+    createEditWidget() {
+
+        var mainLayout = this.mainLayout = new Atomic.UILayout();
+        mainLayout.axis = Atomic.UI_AXIS_Y;
+        mainLayout.layoutSize = Atomic.UI_LAYOUT_SIZE_AVAILABLE;
+        mainLayout.layoutPosition = Atomic.UI_LAYOUT_POSITION_LEFT_TOP;
+        mainLayout.gravity = Atomic.UI_GRAVITY_LEFT_RIGHT;
+        mainLayout.layoutDistribution = Atomic.UI_LAYOUT_DISTRIBUTION_GRAVITY;
+
+        var cb = InspectorUtils.createAttrCheckBox(this.name, mainLayout);
+        this.enabledCheckBox = cb.checkBox;
+
+        cb.checkBox.subscribeToEvent(cb.checkBox, "WidgetEvent", (ev: Atomic.UIWidgetEvent) => {
+
+            if (ev.type == Atomic.UI_EVENT_TYPE_CHANGED) {
+
+                var scene: Atomic.Scene;
+
+                for (var i in this.editType.objects) {
+
+                    var staticModel = <Atomic.StaticModel>this.editType.objects[i];
+
+                    scene = staticModel.scene;
+
+                    if (cb.checkBox.value) {
+
+                        staticModel.showGeometry(this.name);
+
+                    } else {
+
+                        staticModel.hideGeometry(this.name);
+
+                    }
+
+                }
+
+                scene.sendEvent("SceneEditEnd");
+
+                return true;
+
+            }
+
+            return false;
+
+
+        });
+
+
+        this.nameField = cb.textField;
+
+        this.editWidget = mainLayout;
+    }
+
+    refresh() {
+
+        var editType = this.editType;
+
+        var object = this.editType.getFirstObject();
+
+        if (!object) {
+            this.visibility = Atomic.UI_WIDGET_VISIBILITY_GONE;
+            return;
+        }
+
+        this.visibility = Atomic.UI_WIDGET_VISIBILITY_VISIBLE;
+
+        var enabled = (<Atomic.StaticModel>object).getGeometryVisible(this.name);
+        var mixed = false;
+        for (var i in editType.objects) {
+
+            object = editType.objects[i];
+            var _enabled = (<Atomic.StaticModel>object).getGeometryVisible(this.name);
+            if (_enabled != enabled) {
+                mixed = true;
+                break;
+            }
+        }
+
+        if (mixed) {
+
+            this.enabledCheckBox.skinBg = "TBGreyCheckBoxNonUniform";
+            this.enabledCheckBox.value = 1;
+
+        } else {
+
+            this.enabledCheckBox.skinBg = "TBGreyCheckBox";
+            this.enabledCheckBox.value = enabled ? 1 : 0;
+
+        }
+
+        for (var i in this.materialIndexes) {
+
+            var idx = this.materialIndexes[i];
+
+            if (!this.materialEdits[idx]) {
+                this.createMaterialEdit(idx);
+            }
+
+            var matEdit = this.materialEdits[idx];
+
+            var uniform = editType.getUniformValue(this.attrInfo, matEdit.index);
+
+            if (uniform) {
+
+                var object = editType.getFirstObject();
+
+                if (object) {
+
+                    // for cached resources, use the asset name, otherwise use the resource path name
+                    var resource: Atomic.Resource;
+                    if (matEdit.index != -1) {
+                        resource = object.getAttribute(this.attrInfo.name).resources[matEdit.index];
+                    } else {
+                        resource = <Atomic.Resource>object.getAttribute(this.attrInfo.name);
+                    }
+
+                    var text = "";
+
+                    if (resource) {
+                        if (resource instanceof Atomic.Animation) {
+
+                            text = (<Atomic.Animation>resource).animationName;
+
+                        } else {
+
+                            text = resource.name;
+                            var asset = ToolCore.assetDatabase.getAssetByCachePath(resource.name);
+                            if (asset)
+                                text = asset.name;
+                        }
+                    }
+                    var pathinfo = Atomic.splitPath(text);
+
+                    matEdit.editField.text = pathinfo.fileName;
+                }
+
+
+            } else {
+                matEdit.editField.text = "--";
+            }
+
+        }
+
+    }
+
+}
+
+class SubmeshListAttributeEdit extends AttributeInfoEdit {
+
+    layout: Atomic.UILayout;
+
+    submeshEdits: { [name: string]: SubmeshAttributeEdit } = {};
+
+    constructor() {
+
+        super();
+
+        this.hideName = true;
+
+    }
+
+    createEditWidget() {
+
+        this.spacing = 0;
+
+        var layout = this.layout = new Atomic.UILayout();
+
+        layout.axis = Atomic.UI_AXIS_Y;
+        layout.spacing = 2;
+        layout.layoutSize = Atomic.UI_LAYOUT_SIZE_AVAILABLE;
+        layout.layoutPosition = Atomic.UI_LAYOUT_POSITION_LEFT_TOP;
+        layout.gravity = Atomic.UI_GRAVITY_LEFT_RIGHT;
+        layout.layoutDistribution = Atomic.UI_LAYOUT_DISTRIBUTION_GRAVITY;
+
+        var lp = new Atomic.UILayoutParams();
+        lp.width = 304;
+        layout.layoutParams = lp;
+
+        var name = new Atomic.UITextField();
+        name.textAlign = Atomic.UI_TEXT_ALIGN_LEFT;
+        name.skinBg = "InspectorTextAttrName";
+        name.layoutParams = AttributeInfoEdit.attrNameLP;
+        name.text = "Submeshes";
+
+        layout.addChild(name);
+
+        InspectorUtils.createSeparator(layout);
+
+        this.editWidget = layout;
+
+    }
+
+    refresh() {
+
+        var editType = this.editType;
+
+        var object = this.editType.getFirstObject();
+
+        if (!object) {
+            this.visibility = Atomic.UI_WIDGET_VISIBILITY_GONE;
+            return;
+        }
+
+        this.visibility = Atomic.UI_WIDGET_VISIBILITY_VISIBLE;
+
+        var name: string;
+        for (var i in editType.objects) {
+
+            // TODO: check for multiple selection with different models and display multiple selection info box
+
+            var staticModel = <Atomic.StaticModel>editType.objects[i];
+            var model = staticModel.model;
+
+            if (!model)
+                continue;
+
+            for (var j = 0; j < model.numGeometries; j++) {
+
+                name = model.getGeometryName(j);
+
+                if (!name)
+                    name = "Mesh";
+
+                if (!this.submeshEdits.hasOwnProperty(name)) {
+
+                    var submeshEdit = new SubmeshAttributeEdit(name);
+                    submeshEdit.initialize(this.editType, this.attrInfo);
+                    this.layout.addChild(submeshEdit);
+                    this.submeshEdits[name] = submeshEdit;
+                }
+
+                this.submeshEdits[name].materialIndexes.push(j);
+
+            }
+
+        }
+
+        for (name in this.submeshEdits)
+            this.submeshEdits[name].refresh();
+
+    }
+
+}
+
+AttributeInfoEdit.registerCustomAttr("AnimatedModel", "Material", SubmeshListAttributeEdit);
+AttributeInfoEdit.registerCustomAttr("StaticModel", "Material", SubmeshListAttributeEdit);
 AttributeInfoEdit.registerCustomAttr("Light", "CSM Splits", LightCascadeAttributeEdit);
 AttributeInfoEdit.registerCustomAttr("Light", "CSM Splits", LightCascadeAttributeEdit);

+ 26 - 2
Script/AtomicEditor/ui/frames/inspector/InspectorUtils.ts

@@ -47,7 +47,7 @@ class InspectorUtils {
 
 
     // atttribute name layout param
     // atttribute name layout param
     var atlp = new Atomic.UILayoutParams();
     var atlp = new Atomic.UILayoutParams();
-    atlp.width = 100;
+    atlp.width = 120;
     nameField.layoutParams = atlp;
     nameField.layoutParams = atlp;
 
 
     return nameField;
     return nameField;
@@ -61,7 +61,7 @@ class InspectorUtils {
     edit.skinBg = "TBAttrEditorField";
     edit.skinBg = "TBAttrEditorField";
     edit.fontDescription = InspectorUtils.attrFontDesc;
     edit.fontDescription = InspectorUtils.attrFontDesc;
     var lp = new Atomic.UILayoutParams();
     var lp = new Atomic.UILayoutParams();
-    lp.width = 140;
+    lp.width = 160;
     edit.layoutParams = lp;
     edit.layoutParams = lp;
 
 
     return edit;
     return edit;
@@ -71,6 +71,9 @@ class InspectorUtils {
   static createAttrEditField(name:string, parent:Atomic.UIWidget):Atomic.UIEditField {
   static createAttrEditField(name:string, parent:Atomic.UIWidget):Atomic.UIEditField {
 
 
     var attrLayout = new Atomic.UILayout();
     var attrLayout = new Atomic.UILayout();
+
+    attrLayout.layoutSize = Atomic.UI_LAYOUT_SIZE_AVAILABLE;
+    attrLayout.gravity = Atomic.UI_GRAVITY_LEFT_RIGHT;
     attrLayout.layoutDistribution = Atomic.UI_LAYOUT_DISTRIBUTION_GRAVITY;
     attrLayout.layoutDistribution = Atomic.UI_LAYOUT_DISTRIBUTION_GRAVITY;
 
 
     var _name = InspectorUtils.createAttrName(name);
     var _name = InspectorUtils.createAttrName(name);
@@ -85,6 +88,27 @@ class InspectorUtils {
 
 
   }
   }
 
 
+  static createAttrCheckBox(name:string, parent:Atomic.UIWidget):{ textField:Atomic.UITextField, checkBox: Atomic.UICheckBox} {
+
+    var attrLayout = new Atomic.UILayout();
+
+    attrLayout.layoutSize = Atomic.UI_LAYOUT_SIZE_AVAILABLE;
+    attrLayout.gravity = Atomic.UI_GRAVITY_LEFT_RIGHT;
+    attrLayout.layoutDistribution = Atomic.UI_LAYOUT_DISTRIBUTION_GRAVITY;
+
+    var _name = InspectorUtils.createAttrName(name);
+    attrLayout.addChild(_name);
+
+    var checkBox = new Atomic.UICheckBox();
+
+    attrLayout.addChild(checkBox);
+    parent.addChild(attrLayout);
+
+    return {textField: _name, checkBox : checkBox};
+
+  }
+
+
   static createAttrEditFieldWithSelectButton(name:string, parent:Atomic.UIWidget):{editField:Atomic.UIEditField, selectButton:Atomic.UIButton} {
   static createAttrEditFieldWithSelectButton(name:string, parent:Atomic.UIWidget):{editField:Atomic.UIEditField, selectButton:Atomic.UIButton} {
 
 
     var attrLayout = new Atomic.UILayout();
     var attrLayout = new Atomic.UILayout();

+ 8 - 9
Script/AtomicEditor/ui/frames/inspector/MaterialInspector.ts

@@ -17,8 +17,10 @@ var solidSource = new Atomic.UIMenuItemSource();
 solidSource.addItem(new Atomic.UIMenuItem("Diffuse", "Diffuse"));
 solidSource.addItem(new Atomic.UIMenuItem("Diffuse", "Diffuse"));
 solidSource.addItem(new Atomic.UIMenuItem("Diffuse Emissive", "Diffuse Emissive"));
 solidSource.addItem(new Atomic.UIMenuItem("Diffuse Emissive", "Diffuse Emissive"));
 solidSource.addItem(new Atomic.UIMenuItem("Diffuse Normal", "Diffuse Normal"));
 solidSource.addItem(new Atomic.UIMenuItem("Diffuse Normal", "Diffuse Normal"));
+solidSource.addItem(new Atomic.UIMenuItem("Diffuse Specular", "Diffuse Specular"));
 solidSource.addItem(new Atomic.UIMenuItem("Diffuse Normal Specular", "Diffuse Normal Specular"));
 solidSource.addItem(new Atomic.UIMenuItem("Diffuse Normal Specular", "Diffuse Normal Specular"));
 solidSource.addItem(new Atomic.UIMenuItem("Diffuse Unlit", "Diffuse Unlit"));
 solidSource.addItem(new Atomic.UIMenuItem("Diffuse Unlit", "Diffuse Unlit"));
+solidSource.addItem(new Atomic.UIMenuItem("No Texture", "No Texture"));
 
 
 var tranSource = new Atomic.UIMenuItemSource();
 var tranSource = new Atomic.UIMenuItemSource();
 tranSource.addItem(new Atomic.UIMenuItem("Alpha", "Alpha"));
 tranSource.addItem(new Atomic.UIMenuItem("Alpha", "Alpha"));
@@ -49,11 +51,13 @@ var techniqueLookup = {
     "Techniques/Diff.xml": "Diffuse",
     "Techniques/Diff.xml": "Diffuse",
     "Techniques/DiffEmissive.xml": "Diffuse Emissive",
     "Techniques/DiffEmissive.xml": "Diffuse Emissive",
     "Techniques/DiffNormal.xml": "Diffuse Normal",
     "Techniques/DiffNormal.xml": "Diffuse Normal",
+    "Techniques/DiffSpec.xml": "Diffuse Specular",
     "Techniques/DiffNormalSpec.xml": "Diffuse Normal Specular",
     "Techniques/DiffNormalSpec.xml": "Diffuse Normal Specular",
     "Techniques/DiffUnlit.xml": "Diffuse Unlit",
     "Techniques/DiffUnlit.xml": "Diffuse Unlit",
     "Techniques/DiffAlpha.xml": "Alpha",
     "Techniques/DiffAlpha.xml": "Alpha",
     "Techniques/DiffAlphaMask.xml": "Alpha Mask",
     "Techniques/DiffAlphaMask.xml": "Alpha Mask",
-    "Techniques/DiffAdd.xml": "Additive"
+    "Techniques/DiffAdd.xml": "Additive",
+    "Techniques/NoTexture.xml": "No Texture"
 }
 }
 
 
 var techniqueReverseLookup = {};
 var techniqueReverseLookup = {};
@@ -237,7 +241,7 @@ class MaterialInspector extends ScriptWidget {
 
 
         var inspector = this;
         var inspector = this;
 
 
-        EditorUI.getModelOps().showResourceSelection("Select Texture", "TextureImporter", function(asset: ToolCore.Asset, args: any) {
+        EditorUI.getModelOps().showResourceSelection("Select Texture", "TextureImporter", "Texture2D", function(asset: ToolCore.Asset, args: any) {
 
 
             var texture = <Atomic.Texture2D> Atomic.cache.getResource("Texture2D", asset.path);
             var texture = <Atomic.Texture2D> Atomic.cache.getResource("Texture2D", asset.path);
 
 
@@ -388,15 +392,10 @@ class MaterialInspector extends ScriptWidget {
         field.skinBg = "TBAttrEditorField";;
         field.skinBg = "TBAttrEditorField";;
         field.fontDescription = this.fd;
         field.fontDescription = this.fd;
         var lp = new Atomic.UILayoutParams();
         var lp = new Atomic.UILayoutParams();
-        lp.width = 140;
+        lp.width = 160;
         field.layoutParams = lp;
         field.layoutParams = lp;
 
 
-        field.text = material.name;
-
-        var texture = material.getTexture(Atomic.TU_DIFFUSE);
-
-        if (texture)
-            field.text = texture.name;
+        field.text = Atomic.splitPath(material.name).fileName;
 
 
         nameLayout.addChild(field);
         nameLayout.addChild(field);
 
 

+ 7 - 1
Script/AtomicEditor/ui/frames/inspector/ModelInspector.ts

@@ -69,7 +69,13 @@ class ModelInspector extends InspectorWidget {
         // Model Section
         // Model Section
         var modelLayout = this.createSection(rootLayout, "Model", 1);
         var modelLayout = this.createSection(rootLayout, "Model", 1);
 
 
-        this.scaleEdit = this.createAttrEditField("Scale", modelLayout);
+        var editField = InspectorUtils.createAttrEditField("Name", modelLayout);
+
+        var lp = new Atomic.UILayoutParams();
+        editField.readOnly = true;
+        editField.text = asset.name;
+
+        this.scaleEdit = InspectorUtils.createAttrEditField("Scale", modelLayout);
         this.scaleEdit.text = this.importer.scale.toString();
         this.scaleEdit.text = this.importer.scale.toString();
 
 
         // Animations Section
         // Animations Section

+ 1 - 1
Script/AtomicEditor/ui/frames/inspector/TextureSelector.ts

@@ -35,7 +35,7 @@ class TextureSelector extends Atomic.UIWindow {
 
 
         var db = ToolCore.getAssetDatabase();
         var db = ToolCore.getAssetDatabase();
 
 
-        var textures = db.getAssetsByImporterType("TextureImporter");
+        var textures = db.getAssetsByImporterType("TextureImporter", "Texture2D");
 
 
         for (var i in textures) {
         for (var i in textures) {
 
 

+ 2 - 2
Script/AtomicEditor/ui/modal/ModalOps.ts

@@ -120,11 +120,11 @@ class ModalOps extends Atomic.ScriptObject {
     }
     }
 
 
 
 
-    showResourceSelection(windowText: string, importerType: string, callback: (asset: ToolCore.Asset, args: any) => void, args: any = undefined) {
+    showResourceSelection(windowText: string, importerType: string, resourceType:string, callback: (retObject: any, args: any) => void, args: any = undefined) {
 
 
         if (this.show()) {
         if (this.show()) {
 
 
-            this.opWindow = new ResourceSelection(windowText, importerType, callback, args);
+            this.opWindow = new ResourceSelection(windowText, importerType, resourceType, callback, args);
 
 
         }
         }
 
 

+ 54 - 15
Script/AtomicEditor/ui/modal/ResourceSelection.ts

@@ -12,33 +12,56 @@ import ModalWindow = require("./ModalWindow");
 class ResourceSelection extends ModalWindow {
 class ResourceSelection extends ModalWindow {
 
 
     folderList: Atomic.UIListView;
     folderList: Atomic.UIListView;
-    callback: (asset: ToolCore.Asset, args:any) => void;
-    args:any;
+    callback: (returnObject: any, args: any) => void;
+    args: any;
+    resourceType: string;
 
 
-    populate(importerType: string) {
+    populate(importerType: string, resourceType: string) {
 
 
         var db = ToolCore.assetDatabase;
         var db = ToolCore.assetDatabase;
-        var assets = db.getAssetsByImporterType(importerType);
+        var assets = db.getAssetsByImporterType(importerType, resourceType);
 
 
         for (var i in assets) {
         for (var i in assets) {
 
 
             var asset = assets[i];
             var asset = assets[i];
 
 
             if (importerType == "JavascriptImporter") {
             if (importerType == "JavascriptImporter") {
-                if (!(<ToolCore.JavascriptImporter> asset.importer).isComponentFile())
+                if (!(<ToolCore.JavascriptImporter>asset.importer).isComponentFile())
                     continue;
                     continue;
             }
             }
 
 
-            this.folderList.addRootItem(asset.relativePath, "", asset.guid);
+            // TODO: Generalize this for other cache assets
+            if (resourceType == "Animation") {
+
+                var modelImporter = <ToolCore.ModelImporter>(asset.importer);
+                var animations = modelImporter.getAnimations();
+
+                if (animations.length) {
+
+                    for (var i in animations) {
+
+                        this.folderList.addRootItem(animations[i].animationName + " : " + asset.name, "", animations[i].name);
+
+                    }
+
+
+                }
+
+            } else {
+
+                this.folderList.addRootItem(asset.relativePath, "", asset.guid);
+
+            }
 
 
         }
         }
 
 
     }
     }
 
 
-    constructor(windowText: string, importerType: string, callback: (asset: ToolCore.Asset, args:any) => void, args:any) {
+    constructor(windowText: string, importerType: string, resourceType: string, callback: (asset: ToolCore.Asset, args: any) => void, args: any) {
 
 
         super();
         super();
 
 
+        this.resourceType = resourceType;
         this.callback = callback;
         this.callback = callback;
         this.args = args;
         this.args = args;
 
 
@@ -52,7 +75,7 @@ class ResourceSelection extends ModalWindow {
 
 
         foldercontainer.addChild(folderList);
         foldercontainer.addChild(folderList);
 
 
-        this.populate(importerType);
+        this.populate(importerType, resourceType);
 
 
         this.text = windowText;
         this.text = windowText;
         this.setSize(800, 600);
         this.setSize(800, 600);
@@ -62,9 +85,9 @@ class ResourceSelection extends ModalWindow {
 
 
     handleWidgetEvent(ev: Atomic.UIWidgetEvent) {
     handleWidgetEvent(ev: Atomic.UIWidgetEvent) {
 
 
-        if(ev.count >= 2) {
+        if (ev.count >= 2) {
             var id = ev.target.id;
             var id = ev.target.id;
-            if(id == this.folderList.rootList.id) {
+            if (id == this.folderList.rootList.id) {
                 this.selectFile();
                 this.selectFile();
             }
             }
         }
         }
@@ -89,12 +112,28 @@ class ResourceSelection extends ModalWindow {
 
 
     }
     }
 
 
-    selectFile():boolean {
+    selectFile(): boolean {
+
         var id = this.folderList.selectedItemID;
         var id = this.folderList.selectedItemID;
-        if(id.length) {
-            this.callback(ToolCore.assetDatabase.getAssetByGUID(id), this.args);
-            this.hide();
-            return true;
+
+        if (this.resourceType == "Animation") {
+
+          if (id.length) {
+              this.callback(Atomic.cache.getResource("Animation", id), this.args);
+              this.hide();
+              return true;
+          }
+
+          this.hide();
+          return true;
+
+        } else {
+
+            if (id.length) {
+                this.callback(ToolCore.assetDatabase.getAssetByGUID(id), this.args);
+                this.hide();
+                return true;
+            }
         }
         }
         return false;
         return false;
     }
     }

+ 4 - 1
Script/Packages/ToolCore/ToolCore.json

@@ -15,9 +15,12 @@
 						 	 "ProjectBuildSettings", "MacBuildSettings", "WindowsBuildSettings", "WebBuildSettings", "AndroidBuildSettings", "IOSBuildSettings"],
 						 	 "ProjectBuildSettings", "MacBuildSettings", "WindowsBuildSettings", "WebBuildSettings", "AndroidBuildSettings", "IOSBuildSettings"],
 	"typescript_decl" : {
 	"typescript_decl" : {
 
 
+		"ModelImporter" : [
+			"getAnimations():Atomic.Animation[];"	
+		],
 		"AssetDatabase" : [
 		"AssetDatabase" : [
 			"getFolderAssets(folder:string):ToolCore.Asset[];",
 			"getFolderAssets(folder:string):ToolCore.Asset[];",
-			"getAssetsByImporterType(type:string):ToolCore.Asset[];"
+			"getAssetsByImporterType(importerType:string, resourceType:string):ToolCore.Asset[];"
 		]
 		]
 	}
 	}
 
 

+ 34 - 0
Source/Atomic/Atomic3D/AnimatedModel.cpp

@@ -113,6 +113,14 @@ void AnimatedModel::RegisterObject(Context* context)
         Variant::emptyVariantVector, AM_FILE);
         Variant::emptyVariantVector, AM_FILE);
     ACCESSOR_ATTRIBUTE("Morphs", GetMorphsAttr, SetMorphsAttr, PODVector<unsigned char>, Variant::emptyBuffer,
     ACCESSOR_ATTRIBUTE("Morphs", GetMorphsAttr, SetMorphsAttr, PODVector<unsigned char>, Variant::emptyBuffer,
         AM_DEFAULT | AM_NOEDIT);
         AM_DEFAULT | AM_NOEDIT);
+
+    // ATOMIC BEGIN
+
+    ACCESSOR_ATTRIBUTE("Geometry Enabled", GetGeometryEnabledAttr, SetGeometryEnabledAttr, VariantVector,
+        Variant::emptyVariantVector, AM_FILE | AM_NOEDIT);
+
+    // ATOMIC END
+
 }
 }
 
 
 bool AnimatedModel::Load(Deserializer& source, bool setInstanceDefault)
 bool AnimatedModel::Load(Deserializer& source, bool setInstanceDefault)
@@ -273,6 +281,30 @@ void AnimatedModel::UpdateBatches(const FrameInfo& frame)
         lodDistance_ = newLodDistance;
         lodDistance_ = newLodDistance;
         CalculateLodLevels();
         CalculateLodLevels();
     }
     }
+
+    // Handle mesh hiding
+    if (geometryDisabled_)
+    {
+        for (unsigned i = 0; i < batches_.Size(); ++i)
+        {
+            SourceBatch* batch = &batches_[i];
+            StaticModelGeometryData* data = &geometryData_[i];
+
+            if (batch->geometry_)
+                data->batchGeometry_ = batch->geometry_;
+
+            if (data->enabled_ && !batch->geometry_)
+            {
+                batch->geometry_ = data->batchGeometry_;
+            }
+            else if (!data->enabled_ && batch->geometry_)
+            {
+                data->batchGeometry_ = batch->geometry_;
+                batch->geometry_ = 0;
+            }
+        }
+    }
+
 }
 }
 
 
 void AnimatedModel::UpdateGeometry(const FrameInfo& frame)
 void AnimatedModel::UpdateGeometry(const FrameInfo& frame)
@@ -333,6 +365,8 @@ void AnimatedModel::SetModel(Model* model, bool createBones)
         {
         {
             geometries_[i] = geometries[i];
             geometries_[i] = geometries[i];
             geometryData_[i].center_ = geometryCenters[i];
             geometryData_[i].center_ = geometryCenters[i];
+            geometryData_[i].enabled_ = true;
+            geometryData_[i].batchGeometry_ = 0;
         }
         }
 
 
         // Copy geometry bone mappings
         // Copy geometry bone mappings

+ 82 - 26
Source/Atomic/Atomic3D/AnimationController.cpp

@@ -52,7 +52,10 @@ static const unsigned MAX_NODE_ANIMATION_STATES = 256;
 extern const char* LOGIC_CATEGORY;
 extern const char* LOGIC_CATEGORY;
 
 
 AnimationController::AnimationController(Context* context) :
 AnimationController::AnimationController(Context* context) :
-    Component(context)
+    Component(context),
+    animationResourcesAttr_(Animation::GetTypeStatic()),
+    autoPlay_(true),
+    autoPlayed_(false)
 {
 {
 }
 }
 
 
@@ -71,6 +74,12 @@ void AnimationController::RegisterObject(Context* context)
         Variant::emptyBuffer, AM_NET | AM_LATESTDATA | AM_NOEDIT);
         Variant::emptyBuffer, AM_NET | AM_LATESTDATA | AM_NOEDIT);
     MIXED_ACCESSOR_ATTRIBUTE("Node Animation States", GetNodeAnimationStatesAttr, SetNodeAnimationStatesAttr, VariantVector,
     MIXED_ACCESSOR_ATTRIBUTE("Node Animation States", GetNodeAnimationStatesAttr, SetNodeAnimationStatesAttr, VariantVector,
         Variant::emptyVariantVector, AM_FILE | AM_NOEDIT);
         Variant::emptyVariantVector, AM_FILE | AM_NOEDIT);
+
+    // ATOMIC BEGIN
+    MIXED_ACCESSOR_ATTRIBUTE("Animation", GetAnimationAttr, SetAnimationAttr, ResourceRef, ResourceRef(Animation::GetTypeStatic()), AM_DEFAULT);
+    ATTRIBUTE("Autoplay", bool, autoPlay_, true, AM_DEFAULT);
+    ACCESSOR_ATTRIBUTE("AnimationResources", GetAnimationResourcesAttr, SetAnimationResourcesAttr, ResourceRefList, ResourceRefList(Animation::GetTypeStatic()), AM_DEFAULT);
+    // ATOMIC END
 }
 }
 
 
 void AnimationController::OnSetEnabled()
 void AnimationController::OnSetEnabled()
@@ -87,6 +96,12 @@ void AnimationController::OnSetEnabled()
 
 
 void AnimationController::Update(float timeStep)
 void AnimationController::Update(float timeStep)
 {
 {
+    if (autoPlay_ && !autoPlayed_ && animation_.NotNull())
+    {
+        autoPlayed_ = true;
+        Play(animation_->GetAnimationName(), 0, true);
+    }
+
     // Loop through animations
     // Loop through animations
     for (Vector<AnimationControl>::Iterator i = animations_.Begin(); i != animations_.End();)
     for (Vector<AnimationControl>::Iterator i = animations_.Begin(); i != animations_.End();)
     {
     {
@@ -166,12 +181,19 @@ bool AnimationController::Play(const String& name, unsigned char layer, bool loo
         Animation* newAnimation = 0;
         Animation* newAnimation = 0;
 
 
         // Check if we're using attached animation resource
         // Check if we're using attached animation resource
-        for (unsigned i = 0; i < animationsResources_.Size(); i++)
+        if (animation_.NotNull() && animation_->GetAnimationName() == name)
         {
         {
-            if (name == animationsResources_[i]->GetAnimationName())
+            newAnimation = animation_;
+        }
+        else
+        {
+            for (unsigned i = 0; i < animationResources_.Size(); i++)
             {
             {
-                newAnimation = GetSubsystem<ResourceCache>()->GetResource<Animation>(animationsResources_[i]->GetName());
-                break;
+                if (name == animationResources_[i]->GetAnimationName())
+                {
+                    newAnimation = animationResources_[i];
+                    break;
+                }
             }
             }
         }
         }
 
 
@@ -806,7 +828,9 @@ VariantVector AnimationController::GetNodeAnimationStatesAttr() const
 void AnimationController::OnSceneSet(Scene* scene)
 void AnimationController::OnSceneSet(Scene* scene)
 {
 {
     if (scene && IsEnabledEffective())
     if (scene && IsEnabledEffective())
+    {
         SubscribeToEvent(scene, E_SCENEPOSTUPDATE, HANDLER(AnimationController, HandleScenePostUpdate));
         SubscribeToEvent(scene, E_SCENEPOSTUPDATE, HANDLER(AnimationController, HandleScenePostUpdate));
+    }
     else if (!scene)
     else if (!scene)
         UnsubscribeFromEvent(E_SCENEPOSTUPDATE);
         UnsubscribeFromEvent(E_SCENEPOSTUPDATE);
 }
 }
@@ -856,12 +880,19 @@ void AnimationController::FindAnimation(const String& name, unsigned& index, Ani
     StringHash nameHash(name);
     StringHash nameHash(name);
 
 
     // Check if we're using attached animation resource
     // Check if we're using attached animation resource
-    for (unsigned i = 0; i < animationsResources_.Size(); i++)
+    if (animation_.NotNull() && animation_->GetAnimationName() == name)
+    {
+        nameHash = animation_->GetName();
+    }
+    else
     {
     {
-        if (name == animationsResources_[i]->GetAnimationName())
+        for (unsigned i = 0; i < animationResources_.Size(); i++)
         {
         {
-            nameHash = animationsResources_[i]->GetName();
-            break;
+            if (name == animationResources_[i]->GetAnimationName())
+            {
+                nameHash = animationResources_[i]->GetName();
+                break;
+            }
         }
         }
     }
     }
 
 
@@ -892,6 +923,19 @@ void AnimationController::HandleScenePostUpdate(StringHash eventType, VariantMap
     Update(eventData[P_TIMESTEP].GetFloat());
     Update(eventData[P_TIMESTEP].GetFloat());
 }
 }
 
 
+// ATOMIC BEGIN
+
+void AnimationController::SetAnimationAttr(const ResourceRef& value)
+{
+    ResourceCache* cache = GetSubsystem<ResourceCache>();
+    animation_ = cache->GetResource<Animation>(value.name_);
+}
+
+ResourceRef AnimationController::GetAnimationAttr() const
+{
+    return GetResourceRef(animation_, Animation::GetTypeStatic());
+}
+
 void AnimationController::AddAnimationResource(Animation* animation)
 void AnimationController::AddAnimationResource(Animation* animation)
 {
 {
     if (!animation)
     if (!animation)
@@ -899,8 +943,8 @@ void AnimationController::AddAnimationResource(Animation* animation)
 
 
     SharedPtr<Animation> anim(animation);
     SharedPtr<Animation> anim(animation);
 
 
-    if (!animationsResources_.Contains(anim))
-        animationsResources_.Push(anim);
+    if (!animationResources_.Contains(anim))
+        animationResources_.Push(anim);
 }
 }
 
 
 void AnimationController::RemoveAnimationResource(Animation* animation)
 void AnimationController::RemoveAnimationResource(Animation* animation)
@@ -908,34 +952,46 @@ void AnimationController::RemoveAnimationResource(Animation* animation)
     if (!animation)
     if (!animation)
         return;
         return;
 
 
-    animationsResources_.Remove(SharedPtr<Animation>(animation));
+    animationResources_.Remove(SharedPtr<Animation>(animation));
 
 
 }
 }
 
 
 void AnimationController::ClearAnimationResources()
 void AnimationController::ClearAnimationResources()
 {
 {
-    animationsResources_.Clear();
+    animationResources_.Clear();
 }
 }
 
 
-void AnimationController::ApplyAttributes()
+void AnimationController::SetAnimationResourcesAttr(const ResourceRefList& value)
 {
 {
+    animationResources_.Clear();
 
 
-    // This currently requires that the AnimationController is after the AnimatedModel
-    // component on the node, look into removing the requirement
-
-    AnimatedModel* animatedModel = GetComponent<AnimatedModel>();
-
-    if (!animatedModel)
-        return;
-
-    Model* model = animatedModel->GetModel();
+    ResourceCache* cache = GetSubsystem<ResourceCache>();
+    for (unsigned i = 0; i < value.names_.Size(); ++i)
+    {
+        Animation* animation = cache->GetResource<Animation>(value.names_[i]);
+        if (!animation)
+        {
+            //LOGERRORF("AnimationController::SetAnimationResourcesAttr - Unable to load animation: %s", value.names_[i].CString());
+            animationResources_.Push(SharedPtr<Animation>(0));
+        }
+        else
+        {
+            animationResources_.Push(SharedPtr<Animation>(animation));
+        }
 
 
-    if (!model)
-        return;
+    }
 
 
-    animationsResources_ = model->GetAnimationResources();
+}
 
 
+const ResourceRefList& AnimationController::GetAnimationResourcesAttr() const
+{
+    animationResourcesAttr_.names_.Resize(animationResources_.Size());
+    for (unsigned i = 0; i < animationResources_.Size(); ++i)
+        animationResourcesAttr_.names_[i] = GetResourceName(animationResources_[i]);
 
 
+    return animationResourcesAttr_;
 }
 }
 
 
+// ATOMIC END
+
 }
 }

+ 26 - 7
Source/Atomic/Atomic3D/AnimationController.h

@@ -180,20 +180,29 @@ public:
     /// Return node animation states attribute.
     /// Return node animation states attribute.
     VariantVector GetNodeAnimationStatesAttr() const;
     VariantVector GetNodeAnimationStatesAttr() const;
 
 
-    // Animation Resources
+    // ATOMIC BEGIN
 
 
     void AddAnimationResource(Animation* animation);
     void AddAnimationResource(Animation* animation);
     void RemoveAnimationResource(Animation* animation);
     void RemoveAnimationResource(Animation* animation);
     void ClearAnimationResources();
     void ClearAnimationResources();
+    const Vector<SharedPtr<Animation>>& GetAnimationResources() { return animationResources_; }
+
+    /// Set animation resources attribute.
+    void SetAnimationResourcesAttr(const ResourceRefList& value);
+    /// Return animation resources attribute.
+    const ResourceRefList& GetAnimationResourcesAttr() const;
+
+    /// Set animation attribute.
+    void SetAnimationAttr(const ResourceRef& value);
+    /// Return animation attribute.
+    ResourceRef GetAnimationAttr() const;
+
+    // ATOMIC END
 
 
 protected:
 protected:
     /// Handle scene being assigned.
     /// Handle scene being assigned.
     virtual void OnSceneSet(Scene* scene);
     virtual void OnSceneSet(Scene* scene);
 
 
-    // ATOMIC BEGIN
-    void ApplyAttributes();
-    // ATOMIC END
-
 private:
 private:
     /// Add an animation state either to AnimatedModel or as a node animation.
     /// Add an animation state either to AnimatedModel or as a node animation.
     AnimationState* AddAnimationState(Animation* animation);
     AnimationState* AddAnimationState(Animation* animation);
@@ -211,8 +220,18 @@ private:
     /// Attribute buffer for network replication.
     /// Attribute buffer for network replication.
     mutable VectorBuffer attrBuffer_;
     mutable VectorBuffer attrBuffer_;
 
 
-    /// animation resources
-    Vector<SharedPtr<Animation> > animationsResources_;
+    // ATOMIC BEGIN
+
+    SharedPtr<Animation> animation_;
+    bool autoPlay_;
+    bool autoPlayed_;
+
+    /// animation resources    
+    Vector<SharedPtr<Animation>> animationResources_;
+    mutable ResourceRefList animationResourcesAttr_;
+
+    // ATOMIC END
+
 };
 };
 
 
 }
 }

+ 25 - 29
Source/Atomic/Atomic3D/Model.cpp

@@ -91,6 +91,7 @@ bool Model::BeginLoad(Deserializer& source)
     geometries_.Clear();
     geometries_.Clear();
     geometryBoneMappings_.Clear();
     geometryBoneMappings_.Clear();
     geometryCenters_.Clear();
     geometryCenters_.Clear();
+    geometryNames_.Clear();
     morphs_.Clear();
     morphs_.Clear();
     vertexBuffers_.Clear();
     vertexBuffers_.Clear();
     indexBuffers_.Clear();
     indexBuffers_.Clear();
@@ -302,14 +303,11 @@ bool Model::BeginLoad(Deserializer& source)
     // MODEL_VERSION
     // MODEL_VERSION
     unsigned version = source.ReadUInt();
     unsigned version = source.ReadUInt();
 
 
-    ResourceRefList animList = source.ReadResourceRefList();
-
-    animationsResources_.Clear();
-
-    ResourceCache* cache = GetSubsystem<ResourceCache>();
-    for (unsigned i = 0; i < animList.names_.Size(); ++i)
+    // Read geometry names
+    geometryNames_.Resize(geometries_.Size());
+    for (unsigned i = 0; i < geometries_.Size(); ++i)
     {
     {
-        AddAnimationResource(cache->GetResource<Animation>(animList.names_[i]));
+        geometryNames_[i] = source.ReadString();
     }
     }
 
 
     SetMemoryUse(memoryUse);
     SetMemoryUse(memoryUse);
@@ -455,13 +453,9 @@ bool Model::Save(Serializer& dest) const
 
 
     dest.WriteUInt(MODEL_VERSION);
     dest.WriteUInt(MODEL_VERSION);
 
 
-    // animation resources
-
-    ResourceRefList animList(Animation::GetTypeStatic());
-    animList.names_.Resize(animationsResources_.Size());
-    for (unsigned i = 0; i < animationsResources_.Size(); ++i)
-        animList.names_[i] = GetResourceName(animationsResources_[i]);
-    dest.WriteResourceRefList(animList);
+    // Write geometry names
+    for (unsigned i = 0; i < geometryNames_.Size(); ++i)
+        dest.WriteString(geometryNames_[i]);
 
 
     // ATOMIC END
     // ATOMIC END
 
 
@@ -530,6 +524,7 @@ void Model::SetNumGeometries(unsigned num)
     geometries_.Resize(num);
     geometries_.Resize(num);
     geometryBoneMappings_.Resize(num);
     geometryBoneMappings_.Resize(num);
     geometryCenters_.Resize(num);
     geometryCenters_.Resize(num);
+    geometryNames_.Resize(num);
 
 
     // For easier creation of from-scratch geometry, ensure that all geometries start with at least 1 LOD level (0 makes no sense)
     // For easier creation of from-scratch geometry, ensure that all geometries start with at least 1 LOD level (0 makes no sense)
     for (unsigned i = 0; i < geometries_.Size(); ++i)
     for (unsigned i = 0; i < geometries_.Size(); ++i)
@@ -671,8 +666,11 @@ SharedPtr<Model> Model::Clone(const String& cloneName) const
 
 
     // Deep copy all the geometry LOD levels and refer to the copied vertex/index buffers
     // Deep copy all the geometry LOD levels and refer to the copied vertex/index buffers
     ret->geometries_.Resize(geometries_.Size());
     ret->geometries_.Resize(geometries_.Size());
+    ret->geometryNames_.Resize(geometryNames_.Size());
     for (unsigned i = 0; i < geometries_.Size(); ++i)
     for (unsigned i = 0; i < geometries_.Size(); ++i)
     {
     {
+        ret->geometryNames_[i] = geometryNames_[i];
+
         ret->geometries_[i].Resize(geometries_[i].Size());
         ret->geometries_[i].Resize(geometries_[i].Size());
         for (unsigned j = 0; j < geometries_[i].Size(); ++j)
         for (unsigned j = 0; j < geometries_[i].Size(); ++j)
         {
         {
@@ -769,31 +767,29 @@ unsigned Model::GetMorphRangeCount(unsigned bufferIndex) const
 
 
 // ATOMIC BEGIN
 // ATOMIC BEGIN
 
 
-void Model::AddAnimationResource(Animation* animation)
+bool Model::SetGeometryName(unsigned index, const String& name)
 {
 {
-    if (!animation)
-        return;
+    if (index >= geometryNames_.Size())
+    {
+        LOGERROR("Geometry name index out of bounds");
+        return false;
+    }
+
+    geometryNames_[index] = name;
 
 
-    SharedPtr<Animation> anim(animation);
+    return true;
 
 
-    if (!animationsResources_.Contains(anim))
-        animationsResources_.Push(anim);
 }
 }
 
 
-void Model::RemoveAnimationResource(Animation* animation)
+const String& Model::GetGeometryName(unsigned index) const
 {
 {
-    if (!animation)
-        return;
+    if (index >= geometryNames_.Size())
+        return String::EMPTY;
 
 
-    animationsResources_.Remove(SharedPtr<Animation>(animation));
+    return geometryNames_[index];
 
 
 }
 }
 
 
-void Model::ClearAnimationResources()
-{
-    animationsResources_.Clear();
-}
-
 // ATOMIC END
 // ATOMIC END
 
 
 }
 }

+ 5 - 9
Source/Atomic/Atomic3D/Model.h

@@ -211,11 +211,9 @@ public:
 
 
     // ATOMIC BEGIN
     // ATOMIC BEGIN
 
 
-    void AddAnimationResource(Animation* animation);
-    void RemoveAnimationResource(Animation* animation);
-    void ClearAnimationResources();
-    unsigned GetAnimationCount() const { return animationsResources_.Size(); }
-    const Vector<SharedPtr<Animation>>& GetAnimationResources() { return animationsResources_; }
+    bool SetGeometryName(unsigned index, const String& name);
+    const String& GetGeometryName(unsigned index) const;
+    const Vector<String>& GetGeometryNames() const { return geometryNames_; }
 
 
     // ATOMIC END
     // ATOMIC END
 
 
@@ -248,11 +246,9 @@ private:
     Vector<PODVector<GeometryDesc> > loadGeometries_;
     Vector<PODVector<GeometryDesc> > loadGeometries_;
 
 
     // ATOMIC BEGIN
     // ATOMIC BEGIN
-
-    /// animation resources
-    Vector<SharedPtr<Animation> > animationsResources_;
-
+    Vector<String> geometryNames_;
     // ATOMIC END
     // ATOMIC END
+
 };
 };
 
 
 }
 }

+ 123 - 1
Source/Atomic/Atomic3D/StaticModel.cpp

@@ -46,7 +46,8 @@ extern const char* GEOMETRY_CATEGORY;
 StaticModel::StaticModel(Context* context) :
 StaticModel::StaticModel(Context* context) :
     Drawable(context, DRAWABLE_GEOMETRY),
     Drawable(context, DRAWABLE_GEOMETRY),
     occlusionLodLevel_(M_MAX_UNSIGNED),
     occlusionLodLevel_(M_MAX_UNSIGNED),
-    materialsAttr_(Material::GetTypeStatic())
+    materialsAttr_(Material::GetTypeStatic()),
+    geometryDisabled_(false)
 {
 {
 }
 }
 
 
@@ -70,6 +71,13 @@ void StaticModel::RegisterObject(Context* context)
     ACCESSOR_ATTRIBUTE("LOD Bias", GetLodBias, SetLodBias, float, 1.0f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE("LOD Bias", GetLodBias, SetLodBias, float, 1.0f, AM_DEFAULT);
     COPY_BASE_ATTRIBUTES(Drawable);
     COPY_BASE_ATTRIBUTES(Drawable);
     ATTRIBUTE("Occlusion LOD Level", int, occlusionLodLevel_, M_MAX_UNSIGNED, AM_DEFAULT);
     ATTRIBUTE("Occlusion LOD Level", int, occlusionLodLevel_, M_MAX_UNSIGNED, AM_DEFAULT);
+
+    // ATOMIC BEGIN
+
+    ACCESSOR_ATTRIBUTE("Geometry Enabled", GetGeometryEnabledAttr, SetGeometryEnabledAttr, VariantVector,
+        Variant::emptyVariantVector, AM_FILE | AM_NOEDIT);
+
+    // ATOMIC END
 }
 }
 
 
 void StaticModel::ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQueryResult>& results)
 void StaticModel::ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQueryResult>& results)
@@ -262,6 +270,8 @@ void StaticModel::SetModel(Model* model)
             batches_[i].worldTransform_ = worldTransform;
             batches_[i].worldTransform_ = worldTransform;
             geometries_[i] = geometries[i];
             geometries_[i] = geometries[i];
             geometryData_[i].center_ = geometryCenters[i];
             geometryData_[i].center_ = geometryCenters[i];
+            geometryData_[i].enabled_ = true;
+            geometryData_[i].batchGeometry_ = 0;
         }
         }
 
 
         SetBoundingBox(model->GetBoundingBox());
         SetBoundingBox(model->GetBoundingBox());
@@ -454,4 +464,116 @@ void StaticModel::HandleModelReloadFinished(StringHash eventType, VariantMap& ev
     SetModel(currentModel);
     SetModel(currentModel);
 }
 }
 
 
+// ATOMIC BEGIN
+
+bool StaticModel::GetGeometryVisible(const String& name)
+{
+    if (!model_)
+        return false;
+
+    const Vector<String>& names = model_->GetGeometryNames();
+
+    for (unsigned i = 0; i < names.Size(); i++)
+    {
+        if (name == names[i])
+            return geometryData_[i].enabled_;
+    }
+
+    return false;
+
+}
+
+void StaticModel::ShowGeometry(const String& name)
+{
+    if (!model_)
+        return;
+
+    const Vector<String>& names = model_->GetGeometryNames();
+
+    for (unsigned i = 0; i < names.Size(); i++)
+    {
+        if (name == names[i])
+        {
+            if (geometryData_[i].batchGeometry_)
+                batches_[i].geometry_ = geometryData_[i].batchGeometry_;
+
+            geometryData_[i].batchGeometry_ = 0;
+            geometryData_[i].enabled_ = true;
+        }
+    }
+
+    geometryDisabled_ = false;
+    for (unsigned i = 0; i < geometryData_.Size(); i++)
+    {
+        if (!geometryData_[i].enabled_)
+        {
+            geometryDisabled_ = true;
+            break;
+        }
+    }
+
+}
+
+void StaticModel::HideGeometry(const String& name)
+{
+    if (!model_)
+        return;
+
+    const Vector<String>& names = model_->GetGeometryNames();
+
+    for (unsigned i = 0; i < names.Size(); i++)
+    {
+        if (name == names[i])
+        {
+            geometryDisabled_ = true;
+
+            if (batches_[i].geometry_)
+                geometryData_[i].batchGeometry_ = batches_[i].geometry_;
+
+            geometryData_[i].enabled_ = false;
+        }
+    }
+}
+
+void StaticModel::SetGeometryEnabledAttr(const VariantVector& value)
+{
+    if (!value.Size() || value.Size() != geometryData_.Size())
+    {
+        geometryDisabled_ = false;
+        geometryEnabled_.Clear();
+        return;
+    }
+
+    bool init = !geometryEnabled_.Size();
+
+    geometryEnabled_ = value;
+
+    for (unsigned i = 0; i < geometryData_.Size(); i++)
+    {
+        geometryData_[i].enabled_ = geometryEnabled_[i].GetBool();
+        if (!geometryData_[i].enabled_)
+            geometryDisabled_ = true;
+        if (init)
+            geometryData_[i].batchGeometry_ = 0;
+    }
+
+}
+const VariantVector& StaticModel::GetGeometryEnabledAttr() const
+{
+    geometryEnabled_.Resize(geometryData_.Size());
+
+    geometryDisabled_ = false;
+    for (unsigned i = 0; i < geometryData_.Size(); i++)
+    {
+        geometryEnabled_[i] = geometryData_[i].enabled_;
+
+        if (!geometryData_[i].enabled_)
+            geometryDisabled_ = true;
+    }
+
+    return geometryEnabled_;
+}
+
+// ATOMIC END
+
 }
 }

+ 27 - 0
Source/Atomic/Atomic3D/StaticModel.h

@@ -36,6 +36,13 @@ struct StaticModelGeometryData
     Vector3 center_;
     Vector3 center_;
     /// Current LOD level.
     /// Current LOD level.
     unsigned lodLevel_;
     unsigned lodLevel_;
+
+    // ATOMIC BEGIN
+
+    bool enabled_;
+    Geometry* batchGeometry_;
+
+    // ATOMIC END
 };
 };
 
 
 /// Static model component.
 /// Static model component.
@@ -99,6 +106,20 @@ public:
     /// Return materials attribute.
     /// Return materials attribute.
     const ResourceRefList& GetMaterialsAttr() const;
     const ResourceRefList& GetMaterialsAttr() const;
 
 
+    // ATOMIC BEGIN
+
+    /// Get whether a named submesh is visible
+    bool GetGeometryVisible(const String& name);
+    /// Show a named submesh
+    void ShowGeometry(const String& name);
+    /// Hide a named submesh
+    void HideGeometry(const String& name);
+
+    void SetGeometryEnabledAttr(const VariantVector& value);
+    const VariantVector& GetGeometryEnabledAttr() const;
+
+    // ATOMIC END
+
 protected:
 protected:
     /// Recalculate the world-space bounding box.
     /// Recalculate the world-space bounding box.
     virtual void OnWorldBoundingBoxUpdate();
     virtual void OnWorldBoundingBoxUpdate();
@@ -122,6 +143,12 @@ protected:
     /// Material list attribute.
     /// Material list attribute.
     mutable ResourceRefList materialsAttr_;
     mutable ResourceRefList materialsAttr_;
 
 
+    // ATOMIC BEGIN
+    mutable VariantVector geometryEnabled_;
+    /// true if any geometry has been disabled
+    mutable bool geometryDisabled_;
+    // ATOMIC END
+
 private:
 private:
     /// Handle model reload finished.
     /// Handle model reload finished.
     void HandleModelReloadFinished(StringHash eventType, VariantMap& eventData);
     void HandleModelReloadFinished(StringHash eventType, VariantMap& eventData);

+ 0 - 48
Source/AtomicEditor/Editors/JSResourceEditor.cpp

@@ -16,7 +16,6 @@
 
 
 #include "JSResourceEditor.h"
 #include "JSResourceEditor.h"
 
 
-#include "../Javascript/JSAutocomplete.h"
 #include "../Javascript/JSTheme.h"
 #include "../Javascript/JSTheme.h"
 #include "../Javascript/JSASTSyntaxColorVisitor.h"
 #include "../Javascript/JSASTSyntaxColorVisitor.h"
 
 
@@ -133,9 +132,6 @@ JSResourceEditor ::JSResourceEditor(Context* context, const String &fullpath, UI
         syntaxColor.visit(program);
         syntaxColor.visit(program);
     }
     }
 
 
-    autocomplete_ = new JSAutocomplete(text);
-    autocomplete_->UpdateLocals();
-
     SubscribeToEvent(E_UPDATE, HANDLER(JSResourceEditor, HandleUpdate));
     SubscribeToEvent(E_UPDATE, HANDLER(JSResourceEditor, HandleUpdate));
 
 
     // FIXME: Set the size at the end of setup, so all children are updated accordingly
     // FIXME: Set the size at the end of setup, so all children are updated accordingly
@@ -222,27 +218,6 @@ void JSResourceEditor::OnChange(TBStyleEdit* styleEdit)
     textDirty_ = true;
     textDirty_ = true;
 
 
     SetModified(true);
     SetModified(true);
-
-    autocomplete_->Hide();
-
-    TBTextFragment* fragment = 0;
-    int ofs = styleEdit_->caret.pos.ofs;
-    fragment = styleEdit_->caret.pos.block->FindFragment(ofs, true);
-
-    if (fragment && fragment->len && (styleEdit_->caret.pos.ofs == (fragment->ofs + fragment->len)))
-    {
-        String value(fragment->Str(), fragment->len);
-        bool hasCompletions = autocomplete_->UpdateCompletions(value);
-
-        if (hasCompletions)
-        {
-            autocomplete_->SetPosition(TBPoint(fragment->xpos, (styleEdit_->caret.y - styleEdit_->scroll_y) + fragment->line_height));
-
-            // autocomplete disabled until it can be looked at
-            //autocomplete_->Show();
-        }
-    }
-
     UpdateLineNumbers();
     UpdateLineNumbers();
 }
 }
 
 
@@ -250,10 +225,6 @@ bool JSResourceEditor::OnEvent(const TBWidgetEvent &ev)
 {
 {
     if (ev.type == EVENT_TYPE_KEY_DOWN)
     if (ev.type == EVENT_TYPE_KEY_DOWN)
     {
     {
-        if (autocomplete_ && autocomplete_->Visible())
-        {
-            return autocomplete_->OnEvent(ev);
-        }
 
 
         if (ev.special_key == TB_KEY_ESC)
         if (ev.special_key == TB_KEY_ESC)
         {
         {
@@ -315,25 +286,6 @@ void JSResourceEditor::HandleUpdate(StringHash eventType, VariantMap& eventData)
     lineNumberList_->GetScrollContainer()->ScrollTo(0, styleEdit_->scroll_y);
     lineNumberList_->GetScrollContainer()->ScrollTo(0, styleEdit_->scroll_y);
     lineNumberList_->SetValue(styleEdit_->GetCaretLine());
     lineNumberList_->SetValue(styleEdit_->GetCaretLine());
 
 
-    if (autocomplete_->Visible())
-    {
-        TBTextFragment* fragment = 0;
-        int ofs = styleEdit_->caret.pos.ofs;
-        fragment = styleEdit_->caret.pos.block->FindFragment(ofs, true);
-
-        if (fragment && (styleEdit_->caret.pos.ofs == (fragment->ofs + fragment->len)))
-        {
-            String value(fragment->Str(), fragment->len);
-            bool hasCompletions = autocomplete_->UpdateCompletions(value);
-
-            if (!hasCompletions)
-            {
-                autocomplete_->Hide();
-            }
-        }
-
-    }
-
     // Timestep parameter is same no matter what event is being listened to
     // Timestep parameter is same no matter what event is being listened to
     float timeStep = eventData[Update::P_TIMESTEP].GetFloat();
     float timeStep = eventData[Update::P_TIMESTEP].GetFloat();
 
 

+ 0 - 2
Source/AtomicEditor/Editors/SceneEditor3D/SceneEditor3D.cpp

@@ -210,13 +210,11 @@ void SceneEditor3D::HandleUpdate(StringHash eventType, VariantMap& eventData)
 
 
 void SceneEditor3D::HandlePlayStarted(StringHash eventType, VariantMap& eventData)
 void SceneEditor3D::HandlePlayStarted(StringHash eventType, VariantMap& eventData)
 {
 {
-    sceneView_->Disable();
 
 
 }
 }
 
 
 void SceneEditor3D::HandlePlayStopped(StringHash eventType, VariantMap& eventData)
 void SceneEditor3D::HandlePlayStopped(StringHash eventType, VariantMap& eventData)
 {
 {
-    sceneView_->Enable();
 }
 }
 
 
 void SceneEditor3D::HandleGizmoEditModeChanged(StringHash eventType, VariantMap& eventData)
 void SceneEditor3D::HandleGizmoEditModeChanged(StringHash eventType, VariantMap& eventData)

+ 0 - 191
Source/AtomicEditor/Javascript/JSAutocomplete.cpp

@@ -1,191 +0,0 @@
-//
-// Copyright (c) 2014-2015, THUNDERBEAST GAMES LLC All rights reserved
-// LICENSE: Atomic Game Engine Editor and Tools EULA
-// Please see LICENSE_ATOMIC_EDITOR_AND_TOOLS.md in repository root for
-// license information: https://github.com/AtomicGameEngine/AtomicGameEngine
-//
-
-#include <Atomic/IO/Log.h>
-#include "JSAutocomplete.h"
-
-namespace AtomicEditor
-{
-
-JSAutocomplete::JSAutocomplete(TBEditField* editField) :
-    editField_(editField),
-    styleEdit_(editField->GetStyleEdit()),
-    autoList_(0)
-{
-    autoList_ = new TBSelectList();
-    autoList_->SetSource(&autoSource_);
-
-    autoList_->SetSize(150, 100);
-    autoList_->SetIgnoreInput(true);
-
-    editField->AddChild(autoList_);
-
-    Hide();
-}
-
-bool JSAutocomplete::UpdateCompletions(const String& value)
-{
-    if (value == currentValue_)
-        return autoSource_.GetNumItems() > 0;
-
-    currentValue_ = value;
-
-    String lstring(value[0]);
-    if (!locals_.Contains(lstring))
-    {
-        return false;
-    }
-
-    autoSource_.DeleteAllItems();
-
-    const List<String>& tokens = locals_[lstring];
-
-    for (List<String>::ConstIterator i = tokens.Begin(); i != tokens.End(); ++i)
-    {
-        if (*i != value && i->StartsWith(value))
-        {
-            autoSource_.AddItem(new TBGenericStringItem(i->CString()));
-        }
-
-    }
-
-    autoList_->SetValue(0);
-
-    return autoSource_.GetNumItems() > 0;
-
-}
-
-void JSAutocomplete::UpdateLocals()
-{
-    TBBlock *block = styleEdit_->blocks.GetFirst();
-    while (block)
-    {
-        for (TBTextFragment* frag = block->fragments.GetFirst(); frag; frag = frag->GetNext())
-        {
-            if (frag->len > 3)
-            {
-                String lstring(frag->Str()[0]);
-
-                String token(frag->Str(), frag->len);
-
-                if (!locals_[lstring].Contains(token))
-                {
-                    //LOGINFOF("Adding Token %s to locals", token.CString());
-                    locals_[lstring].Push(token);
-                }
-
-            }
-
-        }
-
-        block = block->GetNext();
-    }
-}
-
-void JSAutocomplete::SetPosition(const TBPoint &pos)
-{
-    autoList_->SetPosition(pos);
-}
-
-bool JSAutocomplete::OnEvent(const TBWidgetEvent &ev)
-{
-    if (ev.type == EVENT_TYPE_KEY_DOWN)
-    {
-        if (ev.special_key == TB_KEY_UP)
-        {
-            int v = autoList_->GetValue() - 1;
-            if (v < 0)
-            {
-                styleEdit_->autocomplete_visible = false;
-                autoList_->SetVisibilility(WIDGET_VISIBILITY_INVISIBLE);
-                autoList_->SetValue(0);
-                return styleEdit_->KeyDown(ev.key, ev.special_key, ev.modifierkeys);
-
-            }
-            else
-            {
-                autoList_->SetValue(v);
-            }
-        }
-        else if (ev.special_key == TB_KEY_DOWN)
-        {
-            int v = autoList_->GetValue() + 1;
-            if (v >= autoList_->GetSource()->GetNumItems())
-            {
-                styleEdit_->autocomplete_visible = false;
-                autoList_->SetVisibilility(WIDGET_VISIBILITY_INVISIBLE);
-                autoList_->SetValue(0);
-                return styleEdit_->KeyDown(ev.key, ev.special_key, ev.modifierkeys);
-            }
-            else
-            {
-                autoList_->SetValue(v);
-            }
-        }
-        else if (ev.special_key == TB_KEY_ENTER || ev.special_key == TB_KEY_TAB)
-        {
-            TBStr str = autoList_->GetSource()->GetItemString(autoList_->GetValue());
-
-            TBTextFragment* fragment = 0;
-            int ofs = styleEdit_->caret.pos.ofs;
-            if (ofs >= 0)
-            {
-                fragment = styleEdit_->caret.pos.block->FindFragment(ofs, true);
-                if (fragment)
-                {
-                    int gofs = fragment->GetGlobalOfs();
-                    styleEdit_->selection.Select(gofs, gofs + fragment->len);
-                    styleEdit_->InsertText(str.CStr(), str.Length());
-                }
-            }
-
-            styleEdit_->autocomplete_visible = false;
-            autoList_->SetVisibilility(WIDGET_VISIBILITY_INVISIBLE);
-            autoList_->SetValue(0);
-
-            return true;
-        }
-        else if (ev.special_key == TB_KEY_ESC)
-        {
-            styleEdit_->autocomplete_visible = false;
-            autoList_->SetVisibilility(WIDGET_VISIBILITY_INVISIBLE);
-            autoList_->SetValue(0);
-            return true;
-        }
-
-    }
-
-    return false;
-}
-
-JSAutocomplete::~JSAutocomplete()
-{
-    autoList_->SetSource(NULL);
-    autoSource_.DeleteAllItems();
-}
-
-void JSAutocomplete::Show()
-{
-    styleEdit_->autocomplete_visible = true;
-    autoList_->SetVisibilility(WIDGET_VISIBILITY_VISIBLE);
-    autoList_->SetValue(0);
-}
-
-void JSAutocomplete::Hide()
-{
-    styleEdit_->autocomplete_visible = false;
-    autoList_->SetVisibilility(WIDGET_VISIBILITY_INVISIBLE);
-    autoList_->SetValue(0);
-}
-
-bool JSAutocomplete::Visible()
-{
-    return autoList_->GetVisibility() == WIDGET_VISIBILITY_VISIBLE;
-}
-
-
-}

+ 0 - 59
Source/AtomicEditor/Javascript/JSAutocomplete.h

@@ -1,59 +0,0 @@
-//
-// Copyright (c) 2014-2015, THUNDERBEAST GAMES LLC All rights reserved
-// LICENSE: Atomic Game Engine Editor and Tools EULA
-// Please see LICENSE_ATOMIC_EDITOR_AND_TOOLS.md in repository root for
-// license information: https://github.com/AtomicGameEngine/AtomicGameEngine
-//
-
-#pragma once
-
-#include <Atomic/Container/Str.h>
-#include <Atomic/Container/HashMap.h>
-#include <Atomic/Container/List.h>
-#include <Atomic/Math/StringHash.h>
-
-#include <TurboBadger/tb_select.h>
-#include <TurboBadger/tb_editfield.h>
-#include <TurboBadger/tb_style_edit.h>
-
-using namespace Atomic;
-
-using namespace tb;
-
-namespace AtomicEditor
-{
-
-// per document autocompletion
-class JSAutocomplete
-{
-public:
-
-    JSAutocomplete(TBEditField* editField);
-
-    ~JSAutocomplete();
-
-    void Show();
-    void Hide();
-    bool Visible();
-
-    void SetPosition(const TBPoint& pos);
-    bool UpdateCompletions(const String& value);
-
-    bool OnEvent(const TBWidgetEvent &ev);
-
-    void UpdateLocals();
-
-private:
-
-    HashMap<StringHash, List<String> > locals_;
-
-    TBEditField* editField_;
-    TBStyleEdit* styleEdit_;
-    TBSelectList* autoList_;
-    TBGenericStringItemSource autoSource_;
-    String currentValue_;
-
-};
-
-
-}

+ 12 - 1
Source/ThirdParty/Assimp/code/FBXConverter.cpp

@@ -725,7 +725,18 @@ private:
                 const TransformationComp comp = static_cast<TransformationComp>(i);
                 const TransformationComp comp = static_cast<TransformationComp>(i);
 
 
                 if (chain[i].IsIdentity() && (anim_chain_bitmask & bit) == 0) {
                 if (chain[i].IsIdentity() && (anim_chain_bitmask & bit) == 0) {
-                    continue;
+
+                    // ATOMIC BEGIN
+                    // Only optimize these out if not a TRS
+                    // As these may be animated in an external FBX
+                    // and should not be dropped
+                    if (comp != TransformationComp_Translation &&
+                        comp != TransformationComp_Rotation &&
+                        comp != TransformationComp_Scaling)
+                    {
+                        continue;
+                    }
+                    // ATOMIC END
                 }
                 }
 
 
                 aiNode* nd = new aiNode();
                 aiNode* nd = new aiNode();

+ 407 - 385
Source/ThirdParty/TurboBadger/tb_editfield.cpp

@@ -22,349 +22,371 @@ const int SELECTION_SCROLL_DELAY = 1000/30;
 /** Get the delta that should be scrolled if dragging the pointer outside the range min-max */
 /** Get the delta that should be scrolled if dragging the pointer outside the range min-max */
 int GetSelectionScrollSpeed(int pointerpos, int min, int max)
 int GetSelectionScrollSpeed(int pointerpos, int min, int max)
 {
 {
-	int d = 0;
-	if (pointerpos < min)
-		d = pointerpos - min;
-	else if (pointerpos > max)
-		d = pointerpos - max;
-	d *= d;
-	d /= 40;
-	return (pointerpos < min) ? -d : d;
+    int d = 0;
+    if (pointerpos < min)
+        d = pointerpos - min;
+    else if (pointerpos > max)
+        d = pointerpos - max;
+    d *= d;
+    d /= 40;
+    return (pointerpos < min) ? -d : d;
 }
 }
 
 
 TBEditField::TBEditField()
 TBEditField::TBEditField()
-	: m_edit_type(EDIT_TYPE_TEXT)
-	, m_adapt_to_content_size(false)
-	, m_virtual_width(250)
+    : m_edit_type(EDIT_TYPE_TEXT)
+    , m_adapt_to_content_size(false)
+    , m_virtual_width(250)
 {
 {
-	SetIsFocusable(true);
-	SetWantLongClick(true);
-	AddChild(&m_scrollbar_x);
-	AddChild(&m_scrollbar_y);
-	AddChild(&m_root);
-	m_root.SetGravity(WIDGET_GRAVITY_ALL);
-	m_scrollbar_x.SetGravity(WIDGET_GRAVITY_BOTTOM | WIDGET_GRAVITY_LEFT_RIGHT);
-	m_scrollbar_y.SetGravity(WIDGET_GRAVITY_RIGHT | WIDGET_GRAVITY_TOP_BOTTOM);
-	m_scrollbar_y.SetAxis(AXIS_Y);
-	int scrollbar_y_w = m_scrollbar_y.GetPreferredSize().pref_w;
-	int scrollbar_x_h = m_scrollbar_x.GetPreferredSize().pref_h;
-	m_scrollbar_x.SetRect(TBRect(0, - scrollbar_x_h, - scrollbar_y_w, scrollbar_x_h));
-	m_scrollbar_y.SetRect(TBRect(- scrollbar_y_w, 0, scrollbar_y_w, 0));
-	m_scrollbar_x.SetOpacity(0);
-	m_scrollbar_y.SetOpacity(0);
+    SetIsFocusable(true);
+    SetWantLongClick(true);
+    AddChild(&m_scrollbar_x);
+    AddChild(&m_scrollbar_y);
+    AddChild(&m_root);
+    m_root.SetGravity(WIDGET_GRAVITY_ALL);
+    m_scrollbar_x.SetGravity(WIDGET_GRAVITY_BOTTOM | WIDGET_GRAVITY_LEFT_RIGHT);
+    m_scrollbar_y.SetGravity(WIDGET_GRAVITY_RIGHT | WIDGET_GRAVITY_TOP_BOTTOM);
+    m_scrollbar_y.SetAxis(AXIS_Y);
+    int scrollbar_y_w = m_scrollbar_y.GetPreferredSize().pref_w;
+    int scrollbar_x_h = m_scrollbar_x.GetPreferredSize().pref_h;
+    m_scrollbar_x.SetRect(TBRect(0, - scrollbar_x_h, - scrollbar_y_w, scrollbar_x_h));
+    m_scrollbar_y.SetRect(TBRect(- scrollbar_y_w, 0, scrollbar_y_w, 0));
+    m_scrollbar_x.SetOpacity(0);
+    m_scrollbar_y.SetOpacity(0);
 
 
-	SetSkinBg(TBIDC("TBEditField"), WIDGET_INVOKE_INFO_NO_CALLBACKS);
-	m_style_edit.SetListener(this);
+    SetSkinBg(TBIDC("TBEditField"), WIDGET_INVOKE_INFO_NO_CALLBACKS);
+    m_style_edit.SetListener(this);
 
 
-	m_root.SetRect(GetVisibleRect());
+    m_root.SetRect(GetVisibleRect());
 
 
-	m_placeholder.SetTextAlign(TB_TEXT_ALIGN_LEFT);
+    m_placeholder.SetTextAlign(TB_TEXT_ALIGN_LEFT);
 
 
-	m_content_factory.editfield = this;
-	m_style_edit.SetContentFactory(&m_content_factory);
+    m_content_factory.editfield = this;
+    m_style_edit.SetContentFactory(&m_content_factory);
 }
 }
 
 
 TBEditField::~TBEditField()
 TBEditField::~TBEditField()
 {
 {
-	RemoveChild(&m_root);
-	RemoveChild(&m_scrollbar_y);
-	RemoveChild(&m_scrollbar_x);
+    RemoveChild(&m_root);
+    RemoveChild(&m_scrollbar_y);
+    RemoveChild(&m_scrollbar_x);
 }
 }
 
 
 TBRect TBEditField::GetVisibleRect()
 TBRect TBEditField::GetVisibleRect()
 {
 {
-	TBRect rect = GetPaddingRect();
-	if (m_scrollbar_y.GetOpacity())
-		rect.w -= m_scrollbar_y.GetRect().w;
-	if (m_scrollbar_x.GetOpacity())
-		rect.h -= m_scrollbar_x.GetRect().h;
-	return rect;
+    TBRect rect = GetPaddingRect();
+    if (m_scrollbar_y.GetOpacity())
+        rect.w -= m_scrollbar_y.GetRect().w;
+    if (m_scrollbar_x.GetOpacity())
+        rect.h -= m_scrollbar_x.GetRect().h;
+    return rect;
 }
 }
 
 
 void TBEditField::UpdateScrollbarVisibility(bool multiline)
 void TBEditField::UpdateScrollbarVisibility(bool multiline)
 {
 {
-	bool enable_vertical = multiline && !m_adapt_to_content_size;
-	m_scrollbar_y.SetOpacity(enable_vertical ? 1.f : 0.f);
-	m_root.SetRect(GetVisibleRect());
+    bool enable_vertical = multiline && !m_adapt_to_content_size;
+    m_scrollbar_y.SetOpacity(enable_vertical ? 1.f : 0.f);
+    m_root.SetRect(GetVisibleRect());
 }
 }
 
 
 void TBEditField::SetAdaptToContentSize(bool adapt)
 void TBEditField::SetAdaptToContentSize(bool adapt)
 {
 {
-	if (m_adapt_to_content_size == adapt)
-		return;
-	m_adapt_to_content_size = adapt;
-	UpdateScrollbarVisibility(GetMultiline());
+    if (m_adapt_to_content_size == adapt)
+        return;
+    m_adapt_to_content_size = adapt;
+    UpdateScrollbarVisibility(GetMultiline());
 }
 }
 
 
 void TBEditField::SetVirtualWidth(int virtual_width)
 void TBEditField::SetVirtualWidth(int virtual_width)
 {
 {
-	if (m_virtual_width == virtual_width)
-		return;
-	m_virtual_width = virtual_width;
+    if (m_virtual_width == virtual_width)
+        return;
+    m_virtual_width = virtual_width;
 
 
-	if (m_adapt_to_content_size && m_style_edit.packed.wrapping)
-		InvalidateLayout(INVALIDATE_LAYOUT_RECURSIVE);
+    if (m_adapt_to_content_size && m_style_edit.packed.wrapping)
+        InvalidateLayout(INVALIDATE_LAYOUT_RECURSIVE);
 }
 }
 
 
 void TBEditField::SetMultiline(bool multiline)
 void TBEditField::SetMultiline(bool multiline)
 {
 {
-	if (multiline == GetMultiline())
-		return;
-	UpdateScrollbarVisibility(multiline);
-	m_style_edit.SetMultiline(multiline);
-	SetWrapping(multiline);
-	InvalidateSkinStates();
-	TBWidget::Invalidate();
+    if (multiline == GetMultiline())
+        return;
+    UpdateScrollbarVisibility(multiline);
+    m_style_edit.SetMultiline(multiline);
+    SetWrapping(multiline);
+    InvalidateSkinStates();
+    TBWidget::Invalidate();
 }
 }
 
 
 void TBEditField::SetStyling(bool styling)
 void TBEditField::SetStyling(bool styling)
 {
 {
-	m_style_edit.SetStyling(styling);
+    m_style_edit.SetStyling(styling);
 }
 }
 
 
 void TBEditField::SetReadOnly(bool readonly)
 void TBEditField::SetReadOnly(bool readonly)
 {
 {
-	if (readonly == GetReadOnly())
-		return;
-	m_style_edit.SetReadOnly(readonly);
-	InvalidateSkinStates();
-	TBWidget::Invalidate();
+    if (readonly == GetReadOnly())
+        return;
+    m_style_edit.SetReadOnly(readonly);
+    InvalidateSkinStates();
+    TBWidget::Invalidate();
 }
 }
 
 
 void TBEditField::SetWrapping(bool wrapping)
 void TBEditField::SetWrapping(bool wrapping)
 {
 {
-	if (wrapping == GetWrapping())
-		return;
+    if (wrapping == GetWrapping())
+        return;
 
 
-	m_style_edit.SetWrapping(wrapping);
+    m_style_edit.SetWrapping(wrapping);
 
 
-	// Invalidate the layout when the wrap mode change and we should adapt our size to it
-	if (m_adapt_to_content_size)
-		InvalidateLayout(INVALIDATE_LAYOUT_RECURSIVE);
+    // Invalidate the layout when the wrap mode change and we should adapt our size to it
+    if (m_adapt_to_content_size)
+        InvalidateLayout(INVALIDATE_LAYOUT_RECURSIVE);
 }
 }
 
 
 void TBEditField::SetEditType(EDIT_TYPE type)
 void TBEditField::SetEditType(EDIT_TYPE type)
 {
 {
-	if (m_edit_type == type)
-		return;
-	m_edit_type = type;
-	m_style_edit.SetPassword(type == EDIT_TYPE_PASSWORD);
-	InvalidateSkinStates();
-	TBWidget::Invalidate();
+    if (m_edit_type == type)
+        return;
+    m_edit_type = type;
+    m_style_edit.SetPassword(type == EDIT_TYPE_PASSWORD);
+    InvalidateSkinStates();
+    TBWidget::Invalidate();
 }
 }
 
 
 bool TBEditField::GetCustomSkinCondition(const TBSkinCondition::CONDITION_INFO &info)
 bool TBEditField::GetCustomSkinCondition(const TBSkinCondition::CONDITION_INFO &info)
 {
 {
-	if (info.custom_prop == TBIDC("edit-type"))
-	{
-		switch (m_edit_type)
-		{
-		case EDIT_TYPE_TEXT:		return info.value == TBIDC("text");
-		case EDIT_TYPE_SEARCH:		return info.value == TBIDC("search");
-		case EDIT_TYPE_PASSWORD:	return info.value == TBIDC("password");
-		case EDIT_TYPE_EMAIL:		return info.value == TBIDC("email");
-		case EDIT_TYPE_PHONE:		return info.value == TBIDC("phone");
-		case EDIT_TYPE_URL:			return info.value == TBIDC("url");
-		case EDIT_TYPE_NUMBER:		return info.value == TBIDC("number");
-		};
-	}
-	else if (info.custom_prop == TBIDC("multiline"))
-		return !((uint32)info.value) == !GetMultiline();
-	else if (info.custom_prop == TBIDC("readonly"))
-		return !((uint32)info.value) == !GetReadOnly();
-	return false;
+    if (info.custom_prop == TBIDC("edit-type"))
+    {
+        switch (m_edit_type)
+        {
+        case EDIT_TYPE_TEXT:		return info.value == TBIDC("text");
+        case EDIT_TYPE_SEARCH:		return info.value == TBIDC("search");
+        case EDIT_TYPE_PASSWORD:	return info.value == TBIDC("password");
+        case EDIT_TYPE_EMAIL:		return info.value == TBIDC("email");
+        case EDIT_TYPE_PHONE:		return info.value == TBIDC("phone");
+        case EDIT_TYPE_URL:			return info.value == TBIDC("url");
+        case EDIT_TYPE_NUMBER:		return info.value == TBIDC("number");
+        };
+    }
+    else if (info.custom_prop == TBIDC("multiline"))
+        return !((uint32)info.value) == !GetMultiline();
+    else if (info.custom_prop == TBIDC("readonly"))
+        return !((uint32)info.value) == !GetReadOnly();
+    return false;
 }
 }
 
 
 void TBEditField::ScrollTo(int x, int y)
 void TBEditField::ScrollTo(int x, int y)
 {
 {
-	int old_x = m_scrollbar_x.GetValue();
-	int old_y = m_scrollbar_y.GetValue();
-	m_style_edit.SetScrollPos(x, y);
-	if (old_x != m_scrollbar_x.GetValue() ||
-		old_y != m_scrollbar_y.GetValue())
-		TBWidget::Invalidate();
+    int old_x = m_scrollbar_x.GetValue();
+    int old_y = m_scrollbar_y.GetValue();
+    m_style_edit.SetScrollPos(x, y);
+    if (old_x != m_scrollbar_x.GetValue() ||
+            old_y != m_scrollbar_y.GetValue())
+        TBWidget::Invalidate();
 }
 }
 
 
 TBWidget::ScrollInfo TBEditField::GetScrollInfo()
 TBWidget::ScrollInfo TBEditField::GetScrollInfo()
 {
 {
-	ScrollInfo info;
-	info.min_x = static_cast<int>(m_scrollbar_x.GetMinValue());
-	info.min_y = static_cast<int>(m_scrollbar_y.GetMinValue());
-	info.max_x = static_cast<int>(m_scrollbar_x.GetMaxValue());
-	info.max_y = static_cast<int>(m_scrollbar_y.GetMaxValue());
-	info.x = m_scrollbar_x.GetValue();
-	info.y = m_scrollbar_y.GetValue();
-	return info;
+    ScrollInfo info;
+    info.min_x = static_cast<int>(m_scrollbar_x.GetMinValue());
+    info.min_y = static_cast<int>(m_scrollbar_y.GetMinValue());
+    info.max_x = static_cast<int>(m_scrollbar_x.GetMaxValue());
+    info.max_y = static_cast<int>(m_scrollbar_y.GetMaxValue());
+    info.x = m_scrollbar_x.GetValue();
+    info.y = m_scrollbar_y.GetValue();
+    return info;
 }
 }
 
 
 bool TBEditField::OnEvent(const TBWidgetEvent &ev)
 bool TBEditField::OnEvent(const TBWidgetEvent &ev)
 {
 {
-	if (ev.type == EVENT_TYPE_CHANGED && ev.target == &m_scrollbar_x)
-	{
-		m_style_edit.SetScrollPos(m_scrollbar_x.GetValue(), m_style_edit.scroll_y);
+    if (ev.type == EVENT_TYPE_CHANGED && ev.target == &m_scrollbar_x)
+    {
+        m_style_edit.SetScrollPos(m_scrollbar_x.GetValue(), m_style_edit.scroll_y);
         OnScroll(m_scrollbar_x.GetValue(), m_style_edit.scroll_y);
         OnScroll(m_scrollbar_x.GetValue(), m_style_edit.scroll_y);
         TBWidget::OnEvent(ev);
         TBWidget::OnEvent(ev);
-		return true;
-	}
-	else if (ev.type == EVENT_TYPE_CHANGED && ev.target == &m_scrollbar_y)
-	{
-		m_style_edit.SetScrollPos(m_style_edit.scroll_x, m_scrollbar_y.GetValue());
+        return true;
+    }
+    else if (ev.type == EVENT_TYPE_CHANGED && ev.target == &m_scrollbar_y)
+    {
+        m_style_edit.SetScrollPos(m_style_edit.scroll_x, m_scrollbar_y.GetValue());
         OnScroll(m_style_edit.scroll_x, m_scrollbar_y.GetValue());
         OnScroll(m_style_edit.scroll_x, m_scrollbar_y.GetValue());
         TBWidget::OnEvent(ev);
         TBWidget::OnEvent(ev);
-		return true;
-	}
+        return true;
+    }
     else if (ev.type == EVENT_TYPE_CHANGED)
     else if (ev.type == EVENT_TYPE_CHANGED)
     {
     {
         TBWidget::OnEvent(ev);
         TBWidget::OnEvent(ev);
     }
     }
-	else if (ev.type == EVENT_TYPE_WHEEL && ev.modifierkeys == TB_MODIFIER_NONE)
-	{
-		int old_val = m_scrollbar_y.GetValue();
+    else if (ev.type == EVENT_TYPE_WHEEL && ev.modifierkeys == TB_MODIFIER_NONE)
+    {
+        int old_val = m_scrollbar_y.GetValue();
         m_scrollbar_y.SetValue(old_val + ev.delta_y * TBSystem::GetPixelsPerLine());
         m_scrollbar_y.SetValue(old_val + ev.delta_y * TBSystem::GetPixelsPerLine());
-		return m_scrollbar_y.GetValue() != old_val;
-	}
-	else if (ev.type == EVENT_TYPE_POINTER_DOWN && ev.target == this)
-	{
-		TBRect padding_rect = GetPaddingRect();
-		if (m_style_edit.MouseDown(
-			TBPoint(ev.target_x - padding_rect.x, ev.target_y - padding_rect.y),
-            1, ev.count, ev.modifierkeys, ev.touch))
-		{
-			// Post a message to start selection scroll
-			PostMessageDelayed(TBIDC("selscroll"), nullptr, SELECTION_SCROLL_DELAY);
-			return true;
-		}
-	}
-	else if (ev.type == EVENT_TYPE_POINTER_MOVE && ev.target == this)
-	{
-		TBRect padding_rect = GetPaddingRect();
-		return m_style_edit.MouseMove(TBPoint(ev.target_x - padding_rect.x, ev.target_y - padding_rect.y));
-	}
-	else if (ev.type == EVENT_TYPE_POINTER_UP && ev.target == this)
-	{
-		TBRect padding_rect = GetPaddingRect();
-		return m_style_edit.MouseUp(TBPoint(ev.target_x - padding_rect.x, ev.target_y - padding_rect.y),
-                                        1, ev.modifierkeys, ev.touch);
-	}
-	else if (ev.type == EVENT_TYPE_KEY_DOWN)
-	{
+        return m_scrollbar_y.GetValue() != old_val;
+    }
+    else if (ev.type == EVENT_TYPE_POINTER_DOWN && ev.target == this)
+    {
+        TBRect padding_rect = GetPaddingRect();
+        if (m_style_edit.MouseDown(
+                    TBPoint(ev.target_x - padding_rect.x, ev.target_y - padding_rect.y),
+                    1, ev.count, ev.modifierkeys, ev.touch))
+        {
+            // Post a message to start selection scroll
+            PostMessageDelayed(TBIDC("selscroll"), nullptr, SELECTION_SCROLL_DELAY);
+            return true;
+        }
+    }
+    else if (ev.type == EVENT_TYPE_POINTER_MOVE && ev.target == this)
+    {
+        TBRect padding_rect = GetPaddingRect();
+        return m_style_edit.MouseMove(TBPoint(ev.target_x - padding_rect.x, ev.target_y - padding_rect.y));
+    }
+    else if (ev.type == EVENT_TYPE_POINTER_UP && ev.target == this)
+    {
+        TBRect padding_rect = GetPaddingRect();
+        return m_style_edit.MouseUp(TBPoint(ev.target_x - padding_rect.x, ev.target_y - padding_rect.y),
+                                    1, ev.modifierkeys, ev.touch);
+    }
+    else if (ev.type == EVENT_TYPE_KEY_DOWN)
+    {
         TBWidget::OnEvent(ev);
         TBWidget::OnEvent(ev);
-		return m_style_edit.KeyDown(ev.key, ev.special_key, ev.modifierkeys);
-	}
-	else if (ev.type == EVENT_TYPE_KEY_UP)
-	{
+
+        if (ev.special_key == TB_KEY_ENTER || ev.special_key == TB_KEY_ESC)
+            if (!m_style_edit.packed.read_only && !m_style_edit.packed.multiline_on)
+            {
+                if (focused_widget == this)
+                {
+                    if (ev.special_key == TB_KEY_ESC)
+                    {
+                        SetText(m_initial_edit_text);
+                    }
+
+                    TBWidgetListener::InvokeWidgetFocusChanged(focused_widget, false);
+                    focused_widget->OnFocusChanged(false);
+                    focused_widget = nullptr;
+                    return true;
+                }
+
+            }
+
+        return m_style_edit.KeyDown(ev.key, ev.special_key, ev.modifierkeys);
+    }
+    else if (ev.type == EVENT_TYPE_KEY_UP)
+    {
         TBWidget::OnEvent(ev);
         TBWidget::OnEvent(ev);
-		return true;
-	}
-	else if ((ev.type == EVENT_TYPE_CLICK && ev.target->GetID() == TBIDC("popupmenu")) ||
-			(ev.type == EVENT_TYPE_SHORTCUT))
-	{
-		if (ev.ref_id == TBIDC("cut") && !m_style_edit.packed.read_only)
-			m_style_edit.Cut();
-		else if (ev.ref_id == TBIDC("copy"))
-			m_style_edit.Copy();
-		else if (ev.ref_id == TBIDC("paste") && !m_style_edit.packed.read_only)
-			m_style_edit.Paste();
-		else if (ev.ref_id == TBIDC("delete") && !m_style_edit.packed.read_only)
-			m_style_edit.Delete();
-		else if (ev.ref_id == TBIDC("undo") && !m_style_edit.packed.read_only)
-			m_style_edit.Undo();
-		else if (ev.ref_id == TBIDC("redo") && !m_style_edit.packed.read_only)
-			m_style_edit.Redo();
-		else if (ev.ref_id == TBIDC("selectall"))
-			m_style_edit.selection.SelectAll();
-		else
-			return false;
-		return true;
-	}
+        return true;
+    }
+    else if ((ev.type == EVENT_TYPE_CLICK && ev.target->GetID() == TBIDC("popupmenu")) ||
+             (ev.type == EVENT_TYPE_SHORTCUT))
+    {
+        if (ev.ref_id == TBIDC("cut") && !m_style_edit.packed.read_only)
+            m_style_edit.Cut();
+        else if (ev.ref_id == TBIDC("copy"))
+            m_style_edit.Copy();
+        else if (ev.ref_id == TBIDC("paste") && !m_style_edit.packed.read_only)
+            m_style_edit.Paste();
+        else if (ev.ref_id == TBIDC("delete") && !m_style_edit.packed.read_only)
+            m_style_edit.Delete();
+        else if (ev.ref_id == TBIDC("undo") && !m_style_edit.packed.read_only)
+            m_style_edit.Undo();
+        else if (ev.ref_id == TBIDC("redo") && !m_style_edit.packed.read_only)
+            m_style_edit.Redo();
+        else if (ev.ref_id == TBIDC("selectall"))
+            m_style_edit.selection.SelectAll();
+        else
+            return false;
+        return true;
+    }
     else if ((ev.type == EVENT_TYPE_CONTEXT_MENU || ev.type == EVENT_TYPE_RIGHT_POINTER_UP) && ev.target == this)
     else if ((ev.type == EVENT_TYPE_CONTEXT_MENU || ev.type == EVENT_TYPE_RIGHT_POINTER_UP) && ev.target == this)
-	{
-		TBPoint pos_in_root(ev.target_x, ev.target_y);
+    {
+        TBPoint pos_in_root(ev.target_x, ev.target_y);
         //ev.target->ConvertToRoot(pos_in_root.x, pos_in_root.y);
         //ev.target->ConvertToRoot(pos_in_root.x, pos_in_root.y);
 
 
-		if (TBMenuWindow *menu = new TBMenuWindow(ev.target, TBIDC("popupmenu")))
-		{
-			TBGenericStringItemSource *source = menu->GetList()->GetDefaultSource();
-			source->AddItem(new TBGenericStringItem(g_tb_lng->GetString(TBIDC("cut")), TBIDC("cut")));
-			source->AddItem(new TBGenericStringItem(g_tb_lng->GetString(TBIDC("copy")), TBIDC("copy")));
-			source->AddItem(new TBGenericStringItem(g_tb_lng->GetString(TBIDC("paste")), TBIDC("paste")));
-			source->AddItem(new TBGenericStringItem(g_tb_lng->GetString(TBIDC("delete")), TBIDC("delete")));
-			source->AddItem(new TBGenericStringItem("-"));
-			source->AddItem(new TBGenericStringItem(g_tb_lng->GetString(TBIDC("selectall")), TBIDC("selectall")));
-			menu->Show(source, TBPopupAlignment(pos_in_root), -1);
-		}
-		return true;
-	}
-	return false;
+        if (TBMenuWindow *menu = new TBMenuWindow(ev.target, TBIDC("popupmenu")))
+        {
+            TBGenericStringItemSource *source = menu->GetList()->GetDefaultSource();
+            source->AddItem(new TBGenericStringItem(g_tb_lng->GetString(TBIDC("cut")), TBIDC("cut")));
+            source->AddItem(new TBGenericStringItem(g_tb_lng->GetString(TBIDC("copy")), TBIDC("copy")));
+            source->AddItem(new TBGenericStringItem(g_tb_lng->GetString(TBIDC("paste")), TBIDC("paste")));
+            source->AddItem(new TBGenericStringItem(g_tb_lng->GetString(TBIDC("delete")), TBIDC("delete")));
+            source->AddItem(new TBGenericStringItem("-"));
+            source->AddItem(new TBGenericStringItem(g_tb_lng->GetString(TBIDC("selectall")), TBIDC("selectall")));
+            menu->Show(source, TBPopupAlignment(pos_in_root), -1);
+        }
+        return true;
+    }
+    return false;
 }
 }
 
 
 void TBEditField::OnPaint(const PaintProps &paint_props)
 void TBEditField::OnPaint(const PaintProps &paint_props)
 {
 {
-	TBRect visible_rect = GetVisibleRect();
+    TBRect visible_rect = GetVisibleRect();
 
 
-	bool clip = m_scrollbar_x.CanScroll() || m_scrollbar_y.CanScroll();
-	TBRect old_clip;
-	if (clip)
-		old_clip = g_renderer->SetClipRect(visible_rect, true);
+    bool clip = m_scrollbar_x.CanScroll() || m_scrollbar_y.CanScroll();
+    TBRect old_clip;
+    if (clip)
+        old_clip = g_renderer->SetClipRect(visible_rect, true);
 
 
-	int trans_x = visible_rect.x, trans_y = visible_rect.y;
-	g_renderer->Translate(trans_x, trans_y);
+    int trans_x = visible_rect.x, trans_y = visible_rect.y;
+    g_renderer->Translate(trans_x, trans_y);
 
 
-	// Draw text content, caret etc.
-	visible_rect.x = visible_rect.y = 0;
-	m_style_edit.Paint(visible_rect, GetCalculatedFontDescription(), paint_props.text_color);
+    // Draw text content, caret etc.
+    visible_rect.x = visible_rect.y = 0;
+    m_style_edit.Paint(visible_rect, GetCalculatedFontDescription(), paint_props.text_color);
 
 
-	// If empty, draw placeholder text with some opacity.
-	if (m_style_edit.IsEmpty())
-	{
-		float old_opacity = g_renderer->GetOpacity();
-		g_renderer->SetOpacity(old_opacity * g_tb_skin->GetDefaultPlaceholderOpacity());
-		TBRect placeholder_rect(visible_rect.x, visible_rect.y, visible_rect.w, GetFont()->GetHeight());
-		m_placeholder.Paint(this, placeholder_rect, paint_props.text_color);
-		g_renderer->SetOpacity(old_opacity);
-	}
-	g_renderer->Translate(-trans_x, -trans_y);
+    // If empty, draw placeholder text with some opacity.
+    if (m_style_edit.IsEmpty())
+    {
+        float old_opacity = g_renderer->GetOpacity();
+        g_renderer->SetOpacity(old_opacity * g_tb_skin->GetDefaultPlaceholderOpacity());
+        TBRect placeholder_rect(visible_rect.x, visible_rect.y, visible_rect.w, GetFont()->GetHeight());
+        m_placeholder.Paint(this, placeholder_rect, paint_props.text_color);
+        g_renderer->SetOpacity(old_opacity);
+    }
+    g_renderer->Translate(-trans_x, -trans_y);
 
 
-	if (clip)
-		g_renderer->SetClipRect(old_clip, false);
+    if (clip)
+        g_renderer->SetClipRect(old_clip, false);
 }
 }
 
 
 void TBEditField::OnPaintChildren(const PaintProps &paint_props)
 void TBEditField::OnPaintChildren(const PaintProps &paint_props)
 {
 {
-	TBWidget::OnPaintChildren(paint_props);
+    TBWidget::OnPaintChildren(paint_props);
 
 
-	// Draw fadeout skin at the needed edges.
-	DrawEdgeFadeout(GetVisibleRect(),
-		TBIDC("TBEditField.fadeout_x"),
-		TBIDC("TBEditField.fadeout_y"),
-		m_scrollbar_x.GetValue(),
-		m_scrollbar_y.GetValue(),
-		(int)(m_scrollbar_x.GetMaxValue() - m_scrollbar_x.GetValueDouble()),
-		(int)(m_scrollbar_y.GetMaxValue() - m_scrollbar_y.GetValueDouble()));
+    // Draw fadeout skin at the needed edges.
+    DrawEdgeFadeout(GetVisibleRect(),
+                    TBIDC("TBEditField.fadeout_x"),
+                    TBIDC("TBEditField.fadeout_y"),
+                    m_scrollbar_x.GetValue(),
+                    m_scrollbar_y.GetValue(),
+                    (int)(m_scrollbar_x.GetMaxValue() - m_scrollbar_x.GetValueDouble()),
+                    (int)(m_scrollbar_y.GetMaxValue() - m_scrollbar_y.GetValueDouble()));
 }
 }
 
 
 void TBEditField::OnAdded()
 void TBEditField::OnAdded()
 {
 {
-	m_style_edit.SetFont(GetCalculatedFontDescription());
+    m_style_edit.SetFont(GetCalculatedFontDescription());
 }
 }
 
 
 void TBEditField::OnFontChanged()
 void TBEditField::OnFontChanged()
 {
 {
-	m_style_edit.SetFont(GetCalculatedFontDescription());
+    m_style_edit.SetFont(GetCalculatedFontDescription());
 }
 }
 
 
 void TBEditField::OnFocusChanged(bool focused)
 void TBEditField::OnFocusChanged(bool focused)
 {
 {
-	m_style_edit.Focus(focused);
+    m_style_edit.Focus(focused);
 
 
     if (focused)
     if (focused)
     {
     {
-        if (!m_style_edit.packed.styling_on)
+        if (!m_style_edit.packed.multiline_on)
+        {
+            m_initial_edit_text.Clear();
             GetText(m_initial_edit_text);
             GetText(m_initial_edit_text);
+        }
     }
     }
     else
     else
     {
     {
-        if (!m_style_edit.packed.styling_on)
+        if (!m_style_edit.packed.multiline_on)
         {
         {
             TBStr curText;
             TBStr curText;
             GetText(curText);
             GetText(curText);
@@ -385,206 +407,206 @@ void TBEditField::OnFocusChanged(bool focused)
 
 
 void TBEditField::OnResized(int old_w, int old_h)
 void TBEditField::OnResized(int old_w, int old_h)
 {
 {
-	// Make the scrollbars move
-	TBWidget::OnResized(old_w, old_h);
+    // Make the scrollbars move
+    TBWidget::OnResized(old_w, old_h);
 
 
-	TBRect visible_rect = GetVisibleRect();
-	m_style_edit.SetLayoutSize(visible_rect.w, visible_rect.h, false);
+    TBRect visible_rect = GetVisibleRect();
+    m_style_edit.SetLayoutSize(visible_rect.w, visible_rect.h, false);
 
 
-	UpdateScrollbars();
+    UpdateScrollbars();
 }
 }
 
 
 PreferredSize TBEditField::OnCalculatePreferredContentSize(const SizeConstraints &constraints)
 PreferredSize TBEditField::OnCalculatePreferredContentSize(const SizeConstraints &constraints)
 {
 {
-	int font_height = GetFont()->GetHeight();
-	PreferredSize ps;
-	if (m_adapt_to_content_size)
-	{
-		int old_layout_width = m_style_edit.layout_width;
-		int old_layout_height = m_style_edit.layout_height;
-		if (m_style_edit.packed.wrapping)
-		{
-			// If we have wrapping enabled, we have to set a virtual width and format the text
-			// so we can get the actual content width with a constant result every time.
-			// If the layouter does not respect our size constraints in the end, we may
-			// get a completly different content height due to different wrapping.
-			// To fix that, we need to layout in 2 passes.
-
-			// A hacky fix is to do something we probably shouldn't: use the old layout width
-			// as virtual width for the new.
-			//int layout_width = old_layout_width > 0 ? MAX(old_layout_width, m_virtual_width) : m_virtual_width;
-			int layout_width = m_virtual_width;
-			if (constraints.available_w != SizeConstraints::NO_RESTRICTION)
-			{
-				layout_width = constraints.available_w;
-				if (TBSkinElement *bg_skin = GetSkinBgElement())
-					layout_width -= bg_skin->padding_left + bg_skin->padding_right;
-			}
-
-			m_style_edit.SetLayoutSize(layout_width, old_layout_height, true);
-			ps.size_dependency = SIZE_DEP_HEIGHT_DEPEND_ON_WIDTH;
-		}
-		int width = m_style_edit.GetContentWidth();
-		int height = m_style_edit.GetContentHeight();
-		if (m_style_edit.packed.wrapping)
-			m_style_edit.SetLayoutSize(old_layout_width, old_layout_height, true);
-		height = MAX(height, font_height);
-
-		ps.min_w = ps.pref_w /*= ps.max_w*/ = width; // should go with the hack above.
-		//ps.min_w = ps.pref_w = ps.max_w = width;
-		ps.min_h = ps.pref_h = ps.max_h = height;
-	}
-	else
-	{
-		ps.pref_h = ps.min_h = font_height;
-		if (m_style_edit.packed.multiline_on)
-		{
-			ps.pref_w = font_height * 10;
-			ps.pref_h = font_height * 5;
-		}
-		else
-			ps.max_h = ps.pref_h;
-	}
-	return ps;
+    int font_height = GetFont()->GetHeight();
+    PreferredSize ps;
+    if (m_adapt_to_content_size)
+    {
+        int old_layout_width = m_style_edit.layout_width;
+        int old_layout_height = m_style_edit.layout_height;
+        if (m_style_edit.packed.wrapping)
+        {
+            // If we have wrapping enabled, we have to set a virtual width and format the text
+            // so we can get the actual content width with a constant result every time.
+            // If the layouter does not respect our size constraints in the end, we may
+            // get a completly different content height due to different wrapping.
+            // To fix that, we need to layout in 2 passes.
+
+            // A hacky fix is to do something we probably shouldn't: use the old layout width
+            // as virtual width for the new.
+            //int layout_width = old_layout_width > 0 ? MAX(old_layout_width, m_virtual_width) : m_virtual_width;
+            int layout_width = m_virtual_width;
+            if (constraints.available_w != SizeConstraints::NO_RESTRICTION)
+            {
+                layout_width = constraints.available_w;
+                if (TBSkinElement *bg_skin = GetSkinBgElement())
+                    layout_width -= bg_skin->padding_left + bg_skin->padding_right;
+            }
+
+            m_style_edit.SetLayoutSize(layout_width, old_layout_height, true);
+            ps.size_dependency = SIZE_DEP_HEIGHT_DEPEND_ON_WIDTH;
+        }
+        int width = m_style_edit.GetContentWidth();
+        int height = m_style_edit.GetContentHeight();
+        if (m_style_edit.packed.wrapping)
+            m_style_edit.SetLayoutSize(old_layout_width, old_layout_height, true);
+        height = MAX(height, font_height);
+
+        ps.min_w = ps.pref_w /*= ps.max_w*/ = width; // should go with the hack above.
+        //ps.min_w = ps.pref_w = ps.max_w = width;
+        ps.min_h = ps.pref_h = ps.max_h = height;
+    }
+    else
+    {
+        ps.pref_h = ps.min_h = font_height;
+        if (m_style_edit.packed.multiline_on)
+        {
+            ps.pref_w = font_height * 10;
+            ps.pref_h = font_height * 5;
+        }
+        else
+            ps.max_h = ps.pref_h;
+    }
+    return ps;
 }
 }
 
 
 void TBEditField::OnMessageReceived(TBMessage *msg)
 void TBEditField::OnMessageReceived(TBMessage *msg)
 {
 {
-	if (msg->message == TBIDC("blink"))
-	{
-		m_style_edit.caret.on = !m_style_edit.caret.on;
-		m_style_edit.caret.Invalidate();
-
-		// Post another blink message so we blink again.
-		PostMessageDelayed(TBIDC("blink"), nullptr, CARET_BLINK_TIME);
-	}
-	else if (msg->message == TBIDC("selscroll") && captured_widget == this)
-	{
-		// Get scroll speed from where mouse is relative to the padding rect.
-		TBRect padding_rect = GetVisibleRect().Shrink(2, 2);
-		int dx = GetSelectionScrollSpeed(pointer_move_widget_x, padding_rect.x, padding_rect.x + padding_rect.w);
-		int dy = GetSelectionScrollSpeed(pointer_move_widget_y, padding_rect.y, padding_rect.y + padding_rect.h);
-		m_scrollbar_x.SetValue(m_scrollbar_x.GetValue() + dx);
-		m_scrollbar_y.SetValue(m_scrollbar_y.GetValue() + dy);
-
-		// Handle mouse move at the new scroll position, so selection is updated
-		if (dx || dy)
-			m_style_edit.MouseMove(TBPoint(pointer_move_widget_x, pointer_move_widget_y));
-
-		// Post another setscroll message so we continue scrolling if we still should.
-		if (m_style_edit.select_state)
-			PostMessageDelayed(TBIDC("selscroll"), nullptr, SELECTION_SCROLL_DELAY);
-	}
+    if (msg->message == TBIDC("blink"))
+    {
+        m_style_edit.caret.on = !m_style_edit.caret.on;
+        m_style_edit.caret.Invalidate();
+
+        // Post another blink message so we blink again.
+        PostMessageDelayed(TBIDC("blink"), nullptr, CARET_BLINK_TIME);
+    }
+    else if (msg->message == TBIDC("selscroll") && captured_widget == this)
+    {
+        // Get scroll speed from where mouse is relative to the padding rect.
+        TBRect padding_rect = GetVisibleRect().Shrink(2, 2);
+        int dx = GetSelectionScrollSpeed(pointer_move_widget_x, padding_rect.x, padding_rect.x + padding_rect.w);
+        int dy = GetSelectionScrollSpeed(pointer_move_widget_y, padding_rect.y, padding_rect.y + padding_rect.h);
+        m_scrollbar_x.SetValue(m_scrollbar_x.GetValue() + dx);
+        m_scrollbar_y.SetValue(m_scrollbar_y.GetValue() + dy);
+
+        // Handle mouse move at the new scroll position, so selection is updated
+        if (dx || dy)
+            m_style_edit.MouseMove(TBPoint(pointer_move_widget_x, pointer_move_widget_y));
+
+        // Post another setscroll message so we continue scrolling if we still should.
+        if (m_style_edit.select_state)
+            PostMessageDelayed(TBIDC("selscroll"), nullptr, SELECTION_SCROLL_DELAY);
+    }
 }
 }
 
 
 void TBEditField::OnChange()
 void TBEditField::OnChange()
 {
 {
-	// Invalidate the layout when the content change and we should adapt our size to it
-	if (m_adapt_to_content_size)
-		InvalidateLayout(INVALIDATE_LAYOUT_RECURSIVE);
+    // Invalidate the layout when the content change and we should adapt our size to it
+    if (m_adapt_to_content_size)
+        InvalidateLayout(INVALIDATE_LAYOUT_RECURSIVE);
 
 
-	TBWidgetEvent ev(EVENT_TYPE_CHANGED);
-	InvokeEvent(ev);
+    TBWidgetEvent ev(EVENT_TYPE_CHANGED);
+    InvokeEvent(ev);
 }
 }
 
 
 bool TBEditField::OnEnter()
 bool TBEditField::OnEnter()
 {
 {
-	return false;
+    return false;
 }
 }
 
 
 void TBEditField::Invalidate(const TBRect &rect)
 void TBEditField::Invalidate(const TBRect &rect)
 {
 {
-	TBWidget::Invalidate();
+    TBWidget::Invalidate();
 }
 }
 
 
 void TBEditField::DrawString(int32 x, int32 y, TBFontFace *font, const TBColor &color, const char *str, int32 len)
 void TBEditField::DrawString(int32 x, int32 y, TBFontFace *font, const TBColor &color, const char *str, int32 len)
 {
 {
-	font->DrawString(x, y, color, str, len);
+    font->DrawString(x, y, color, str, len);
 }
 }
 
 
 void TBEditField::DrawRect(const TBRect &rect, const TBColor &color)
 void TBEditField::DrawRect(const TBRect &rect, const TBColor &color)
 {
 {
-	g_renderer->DrawRect(rect, color);
+    g_renderer->DrawRect(rect, color);
 }
 }
 
 
 void TBEditField::DrawRectFill(const TBRect &rect, const TBColor &color)
 void TBEditField::DrawRectFill(const TBRect &rect, const TBColor &color)
 {
 {
-	g_renderer->DrawRectFill(rect, color);
+    g_renderer->DrawRectFill(rect, color);
 }
 }
 
 
 void TBEditField::DrawTextSelectionBg(const TBRect &rect)
 void TBEditField::DrawTextSelectionBg(const TBRect &rect)
 {
 {
-	TBWidgetSkinConditionContext context(this);
-	g_tb_skin->PaintSkin(rect, TBIDC("TBEditField.selection"), static_cast<SKIN_STATE>(GetAutoState()), context);
+    TBWidgetSkinConditionContext context(this);
+    g_tb_skin->PaintSkin(rect, TBIDC("TBEditField.selection"), static_cast<SKIN_STATE>(GetAutoState()), context);
 }
 }
 
 
 void TBEditField::DrawContentSelectionFg(const TBRect &rect)
 void TBEditField::DrawContentSelectionFg(const TBRect &rect)
 {
 {
-	TBWidgetSkinConditionContext context(this);
-	g_tb_skin->PaintSkin(rect, TBIDC("TBEditField.selection"), static_cast<SKIN_STATE>(GetAutoState()), context);
+    TBWidgetSkinConditionContext context(this);
+    g_tb_skin->PaintSkin(rect, TBIDC("TBEditField.selection"), static_cast<SKIN_STATE>(GetAutoState()), context);
 }
 }
 
 
 void TBEditField::DrawCaret(const TBRect &rect)
 void TBEditField::DrawCaret(const TBRect &rect)
 {
 {
-	if (GetIsFocused() && !m_style_edit.packed.read_only)
-		DrawTextSelectionBg(rect);
+    if (GetIsFocused() && !m_style_edit.packed.read_only)
+        DrawTextSelectionBg(rect);
 }
 }
 
 
 void TBEditField::Scroll(int32 dx, int32 dy)
 void TBEditField::Scroll(int32 dx, int32 dy)
 {
 {
-	TBWidget::Invalidate();
-	m_scrollbar_x.SetValue(m_style_edit.scroll_x);
-	m_scrollbar_y.SetValue(m_style_edit.scroll_y);
+    TBWidget::Invalidate();
+    m_scrollbar_x.SetValue(m_style_edit.scroll_x);
+    m_scrollbar_y.SetValue(m_style_edit.scroll_y);
 }
 }
 
 
 void TBEditField::UpdateScrollbars()
 void TBEditField::UpdateScrollbars()
 {
 {
-	int32 w = m_style_edit.layout_width;
-	int32 h = m_style_edit.layout_height;
-	m_scrollbar_x.SetLimits(0, m_style_edit.GetContentWidth() - w, w);
-	m_scrollbar_y.SetLimits(0, m_style_edit.GetContentHeight() - h, h);
+    int32 w = m_style_edit.layout_width;
+    int32 h = m_style_edit.layout_height;
+    m_scrollbar_x.SetLimits(0, m_style_edit.GetContentWidth() - w, w);
+    m_scrollbar_y.SetLimits(0, m_style_edit.GetContentHeight() - h, h);
 }
 }
 
 
 void TBEditField::CaretBlinkStart()
 void TBEditField::CaretBlinkStart()
 {
 {
-	// Post the delayed blink message if we don't already have one
-	if (!GetMessageByID(TBIDC("blink")))
-		PostMessageDelayed(TBIDC("blink"), nullptr, CARET_BLINK_TIME);
+    // Post the delayed blink message if we don't already have one
+    if (!GetMessageByID(TBIDC("blink")))
+        PostMessageDelayed(TBIDC("blink"), nullptr, CARET_BLINK_TIME);
 }
 }
 
 
 void TBEditField::CaretBlinkStop()
 void TBEditField::CaretBlinkStop()
 {
 {
-	// Remove the blink message if we have one
-	if (TBMessage *msg = GetMessageByID(TBIDC("blink")))
-		DeleteMessage(msg);
+    // Remove the blink message if we have one
+    if (TBMessage *msg = GetMessageByID(TBIDC("blink")))
+        DeleteMessage(msg);
 }
 }
 
 
 // == TBEditFieldScrollRoot =======================================================================
 // == TBEditFieldScrollRoot =======================================================================
 
 
 void TBEditFieldScrollRoot::OnPaintChildren(const PaintProps &paint_props)
 void TBEditFieldScrollRoot::OnPaintChildren(const PaintProps &paint_props)
 {
 {
-	// Avoid setting clipping (can be expensive) if we have no children to paint anyway.
-	if (!GetFirstChild())
-		return;
-	// Clip children
-	TBRect old_clip_rect = g_renderer->SetClipRect(GetPaddingRect(), true);
-	TBWidget::OnPaintChildren(paint_props);
-	g_renderer->SetClipRect(old_clip_rect, false);
+    // Avoid setting clipping (can be expensive) if we have no children to paint anyway.
+    if (!GetFirstChild())
+        return;
+    // Clip children
+    TBRect old_clip_rect = g_renderer->SetClipRect(GetPaddingRect(), true);
+    TBWidget::OnPaintChildren(paint_props);
+    g_renderer->SetClipRect(old_clip_rect, false);
 }
 }
 
 
 void TBEditFieldScrollRoot::GetChildTranslation(int &x, int &y) const
 void TBEditFieldScrollRoot::GetChildTranslation(int &x, int &y) const
 {
 {
-	TBEditField *edit_field = static_cast<TBEditField *>(GetParent());
-	x = (int) -edit_field->GetStyleEdit()->scroll_x;
-	y = (int) -edit_field->GetStyleEdit()->scroll_y;
+    TBEditField *edit_field = static_cast<TBEditField *>(GetParent());
+    x = (int) -edit_field->GetStyleEdit()->scroll_x;
+    y = (int) -edit_field->GetStyleEdit()->scroll_y;
 }
 }
 
 
 WIDGET_HIT_STATUS TBEditFieldScrollRoot::GetHitStatus(int x, int y)
 WIDGET_HIT_STATUS TBEditFieldScrollRoot::GetHitStatus(int x, int y)
 {
 {
-	// Return no hit on this widget, but maybe on any of the children.
-	if (TBWidget::GetHitStatus(x, y) && GetWidgetAt(x, y, false))
-		return WIDGET_HIT_STATUS_HIT;
-	return WIDGET_HIT_STATUS_NO_HIT;
+    // Return no hit on this widget, but maybe on any of the children.
+    if (TBWidget::GetHitStatus(x, y) && GetWidgetAt(x, y, false))
+        return WIDGET_HIT_STATUS_HIT;
+    return WIDGET_HIT_STATUS_NO_HIT;
 }
 }
 
 
 // == TBTextFragmentContentWidget =================================================================
 // == TBTextFragmentContentWidget =================================================================
@@ -592,75 +614,75 @@ WIDGET_HIT_STATUS TBEditFieldScrollRoot::GetHitStatus(int x, int y)
 class TBTextFragmentContentWidget : public TBTextFragmentContent
 class TBTextFragmentContentWidget : public TBTextFragmentContent
 {
 {
 public:
 public:
-	TBTextFragmentContentWidget(TBWidget *parent, TBWidget *widget);
-	virtual ~TBTextFragmentContentWidget();
+    TBTextFragmentContentWidget(TBWidget *parent, TBWidget *widget);
+    virtual ~TBTextFragmentContentWidget();
 
 
-	virtual void UpdatePos(int x, int y);
-	virtual int32 GetWidth(TBFontFace *font, TBTextFragment *fragment);
-	virtual int32 GetHeight(TBFontFace *font, TBTextFragment *fragment);
-	virtual int32 GetBaseline(TBFontFace *font, TBTextFragment *fragment);
+    virtual void UpdatePos(int x, int y);
+    virtual int32 GetWidth(TBFontFace *font, TBTextFragment *fragment);
+    virtual int32 GetHeight(TBFontFace *font, TBTextFragment *fragment);
+    virtual int32 GetBaseline(TBFontFace *font, TBTextFragment *fragment);
 private:
 private:
-	TBWidget *m_widget;
+    TBWidget *m_widget;
 };
 };
 
 
 TBTextFragmentContentWidget::TBTextFragmentContentWidget(TBWidget *parent, TBWidget *widget)
 TBTextFragmentContentWidget::TBTextFragmentContentWidget(TBWidget *parent, TBWidget *widget)
-	: m_widget(widget)
+    : m_widget(widget)
 {
 {
-	parent->GetContentRoot()->AddChild(widget);
+    parent->GetContentRoot()->AddChild(widget);
 }
 }
 
 
 TBTextFragmentContentWidget::~TBTextFragmentContentWidget()
 TBTextFragmentContentWidget::~TBTextFragmentContentWidget()
 {
 {
-	m_widget->GetParent()->RemoveChild(m_widget);
-	delete m_widget;
+    m_widget->GetParent()->RemoveChild(m_widget);
+    delete m_widget;
 }
 }
 
 
 void TBTextFragmentContentWidget::UpdatePos(int x, int y)
 void TBTextFragmentContentWidget::UpdatePos(int x, int y)
 {
 {
-	m_widget->SetRect(TBRect(x, y, GetWidth(nullptr, nullptr), GetHeight(nullptr, nullptr)));
+    m_widget->SetRect(TBRect(x, y, GetWidth(nullptr, nullptr), GetHeight(nullptr, nullptr)));
 }
 }
 
 
 int32 TBTextFragmentContentWidget::GetWidth(TBFontFace *font, TBTextFragment *fragment)
 int32 TBTextFragmentContentWidget::GetWidth(TBFontFace *font, TBTextFragment *fragment)
 {
 {
-	return m_widget->GetRect().w ? m_widget->GetRect().w : m_widget->GetPreferredSize().pref_w;
+    return m_widget->GetRect().w ? m_widget->GetRect().w : m_widget->GetPreferredSize().pref_w;
 }
 }
 
 
 int32 TBTextFragmentContentWidget::GetHeight(TBFontFace *font, TBTextFragment *fragment)
 int32 TBTextFragmentContentWidget::GetHeight(TBFontFace *font, TBTextFragment *fragment)
 {
 {
-	return m_widget->GetRect().h ? m_widget->GetRect().h : m_widget->GetPreferredSize().pref_h;
+    return m_widget->GetRect().h ? m_widget->GetRect().h : m_widget->GetPreferredSize().pref_h;
 }
 }
 
 
 int32 TBTextFragmentContentWidget::GetBaseline(TBFontFace *font, TBTextFragment *fragment)
 int32 TBTextFragmentContentWidget::GetBaseline(TBFontFace *font, TBTextFragment *fragment)
 {
 {
-	int height = GetHeight(font, fragment);
-	return (height + fragment->block->CalculateBaseline(font)) / 2;
+    int height = GetHeight(font, fragment);
+    return (height + fragment->block->CalculateBaseline(font)) / 2;
 }
 }
 
 
 // == TBEditFieldContentFactory ===================================================================
 // == TBEditFieldContentFactory ===================================================================
 
 
 int TBEditFieldContentFactory::GetContent(const char *text)
 int TBEditFieldContentFactory::GetContent(const char *text)
 {
 {
-	return TBTextFragmentContentFactory::GetContent(text);
+    return TBTextFragmentContentFactory::GetContent(text);
 }
 }
 
 
 TBTextFragmentContent *TBEditFieldContentFactory::CreateFragmentContent(const char *text, int text_len)
 TBTextFragmentContent *TBEditFieldContentFactory::CreateFragmentContent(const char *text, int text_len)
 {
 {
-	if (strncmp(text, "<widget ", MIN(text_len, 8)) == 0)
-	{
-		// Create a wrapper for the generated widget.
-		// Its size will adapt to the content.
-		if (TBWidget *widget = new TBWidget())
-		{
-			if (TBTextFragmentContentWidget *cw = new TBTextFragmentContentWidget(editfield, widget))
-			{
-				g_widgets_reader->LoadData(widget, text + 8, text_len - 9);
-				return cw;
-			}
-			delete widget;
-		}
-	}
-
-	return TBTextFragmentContentFactory::CreateFragmentContent(text, text_len);
+    if (strncmp(text, "<widget ", MIN(text_len, 8)) == 0)
+    {
+        // Create a wrapper for the generated widget.
+        // Its size will adapt to the content.
+        if (TBWidget *widget = new TBWidget())
+        {
+            if (TBTextFragmentContentWidget *cw = new TBTextFragmentContentWidget(editfield, widget))
+            {
+                g_widgets_reader->LoadData(widget, text + 8, text_len - 9);
+                return cw;
+            }
+            delete widget;
+        }
+    }
+
+    return TBTextFragmentContentFactory::CreateFragmentContent(text, text_len);
 }
 }
 
 
 }; // namespace tb
 }; // namespace tb

+ 0 - 10
Source/ThirdParty/TurboBadger/tb_style_edit.cpp

@@ -1418,7 +1418,6 @@ TBStyleEdit::TBStyleEdit()
 	, selection(nullptr)
 	, selection(nullptr)
 	, scroll_x(0)
 	, scroll_x(0)
 	, scroll_y(0)
 	, scroll_y(0)
-    , autocomplete_visible(false)
 	, select_state(0)
 	, select_state(0)
 	, mousedown_fragment(nullptr)
 	, mousedown_fragment(nullptr)
 	, font(nullptr)
 	, font(nullptr)
@@ -1752,15 +1751,6 @@ bool TBStyleEdit::KeyDown(int key, SPECIAL_KEY special_key, MODIFIER_KEYS modifi
 	if (select_state)
 	if (select_state)
 		return false;
 		return false;
 
 
-    if (autocomplete_visible
-        && (special_key == TB_KEY_UP || special_key == TB_KEY_DOWN
-            || special_key == TB_KEY_ENTER || special_key == TB_KEY_ESC
-            || special_key == TB_KEY_TAB)
-        && !modifierkeys)
-    {
-        return false;
-    }
-
 	bool handled = true;
 	bool handled = true;
 	bool move_caret = special_key == TB_KEY_LEFT || special_key == TB_KEY_RIGHT ||
 	bool move_caret = special_key == TB_KEY_LEFT || special_key == TB_KEY_RIGHT ||
 						special_key == TB_KEY_UP || special_key == TB_KEY_DOWN ||
 						special_key == TB_KEY_UP || special_key == TB_KEY_DOWN ||

+ 0 - 2
Source/ThirdParty/TurboBadger/tb_style_edit.h

@@ -442,8 +442,6 @@ public:
 	int32 scroll_x;
 	int32 scroll_x;
 	int32 scroll_y;
 	int32 scroll_y;
 
 
-    bool autocomplete_visible;
-
 	int8 select_state;
 	int8 select_state;
 	TBPoint mousedown_point;
 	TBPoint mousedown_point;
 	TBTextFragment *mousedown_fragment;
 	TBTextFragment *mousedown_fragment;

+ 1 - 0
Source/ThirdParty/TurboBadger/tb_widgets_listener.h

@@ -61,6 +61,7 @@ public:
 	virtual bool OnWidgetInvokeEvent(TBWidget *widget, const TBWidgetEvent &ev) { return false; }
 	virtual bool OnWidgetInvokeEvent(TBWidget *widget, const TBWidgetEvent &ev) { return false; }
 private:
 private:
 	friend class TBWidget;
 	friend class TBWidget;
+    friend class TBEditField;
 	static void InvokeWidgetDelete(TBWidget *widget);
 	static void InvokeWidgetDelete(TBWidget *widget);
 	static bool InvokeWidgetDying(TBWidget *widget);
 	static bool InvokeWidgetDying(TBWidget *widget);
 	static void InvokeWidgetAdded(TBWidget *parent, TBWidget *child);
 	static void InvokeWidgetAdded(TBWidget *parent, TBWidget *child);

+ 3 - 1
Source/ToolCore/Assets/AssetDatabase.cpp

@@ -382,7 +382,7 @@ void AssetDatabase::GetFolderAssets(String folder, PODVector<Asset*>& assets) co
 
 
 }
 }
 
 
-void AssetDatabase::GetAssetsByImporterType(StringHash type, PODVector<Asset*>& assets) const
+void AssetDatabase::GetAssetsByImporterType(StringHash type, const String &resourceType, PODVector<Asset*>& assets) const
 {
 {
     assets.Clear();
     assets.Clear();
 
 
@@ -538,6 +538,8 @@ String AssetDatabase::GetResourceImporterName(const String& resourceTypeName)
         resourceTypeToImporterType_["JSONFile"] = "JSONImporter";
         resourceTypeToImporterType_["JSONFile"] = "JSONImporter";
         resourceTypeToImporterType_["ParticleEffect2D"] = "PEXImporter";
         resourceTypeToImporterType_["ParticleEffect2D"] = "PEXImporter";
 
 
+        resourceTypeToImporterType_["Animation"] = "ModelImporter";
+
 
 
 #ifdef ATOMIC_DOTNET
 #ifdef ATOMIC_DOTNET
         resourceTypeToImporterType_["CSComponentAssembly"] = "NETAssemblyImporter";
         resourceTypeToImporterType_["CSComponentAssembly"] = "NETAssemblyImporter";

+ 1 - 1
Source/ToolCore/Assets/AssetDatabase.h

@@ -44,7 +44,7 @@ public:
 
 
     String GetResourceImporterName(const String& resourceTypeName);
     String GetResourceImporterName(const String& resourceTypeName);
 
 
-    void GetAssetsByImporterType(StringHash type, PODVector<Asset*>& assets) const;
+    void GetAssetsByImporterType(StringHash type, const String& resourceType, PODVector<Asset*>& assets) const;
 
 
     void GetDirtyAssets(PODVector<Asset*>& assets);
     void GetDirtyAssets(PODVector<Asset*>& assets);
 
 

+ 41 - 36
Source/ToolCore/Assets/ModelImporter.cpp

@@ -13,6 +13,7 @@
 
 
 #include <Atomic/Atomic3D/AnimatedModel.h>
 #include <Atomic/Atomic3D/AnimatedModel.h>
 #include <Atomic/Atomic3D/Animation.h>
 #include <Atomic/Atomic3D/Animation.h>
+#include <Atomic/Atomic3D/AnimationController.h>
 #include <Atomic/Atomic3D/StaticModel.h>
 #include <Atomic/Atomic3D/StaticModel.h>
 #include <Atomic/Atomic3D/Model.h>
 #include <Atomic/Atomic3D/Model.h>
 
 
@@ -104,18 +105,12 @@ bool ModelImporter::ImportAnimation(const String& filename, const String& name,
             ResourceCache* cache = GetSubsystem<ResourceCache>();
             ResourceCache* cache = GetSubsystem<ResourceCache>();
 
 
             AnimatedModel* animatedModel = importNode_->GetComponent<AnimatedModel>();
             AnimatedModel* animatedModel = importNode_->GetComponent<AnimatedModel>();
-
-            if (animatedModel)
+            AnimationController* controller = importNode_->GetComponent<AnimationController>();
+            if (animatedModel && controller)
             {
             {
-                Model* model = animatedModel->GetModel();
-
-                if (model)
-                {
-                    SharedPtr<Animation> animation = cache->GetTempResource<Animation>(fileName + extension);
-                    if (animation)
-                        model->AddAnimationResource(animation);
-                }
-
+                SharedPtr<Animation> animation = cache->GetTempResource<Animation>(fileName + extension);
+                if (animation)
+                    controller->AddAnimationResource(animation);
             }
             }
 
 
             LOGINFOF("Import Info: %s : %s", info.name_.CString(), fileName.CString());
             LOGINFOF("Import Info: %s : %s", info.name_.CString(), fileName.CString());
@@ -132,8 +127,8 @@ bool ModelImporter::ImportAnimations()
 {
 {
     if (!animationInfo_.Size())
     if (!animationInfo_.Size())
     {
     {
-       if (!ImportAnimation(asset_->GetPath(), "RootAnim"))
-           return false;
+        if (!ImportAnimation(asset_->GetPath(), "RootAnim"))
+            return false;
     }
     }
 
 
     // embedded animations
     // embedded animations
@@ -174,8 +169,8 @@ bool ModelImporter::ImportAnimations()
 
 
                 if (!importer->animationInfo_.Size())
                 if (!importer->animationInfo_.Size())
                 {
                 {
-                   if (!ImportAnimation(asset->GetPath(), animationName))
-                       return false;
+                    if (!ImportAnimation(asset->GetPath(), animationName))
+                        return false;
                 }
                 }
                 else
                 else
                 {
                 {
@@ -247,28 +242,9 @@ bool ModelImporter::Import()
                 ImportAnimations();
                 ImportAnimations();
             }
             }
 
 
-            AnimatedModel* animatedModel = importNode_->GetComponent<AnimatedModel>();
-            if (animatedModel)
-            {
-                Model* model = animatedModel->GetModel();
-                if (model && model->GetAnimationCount())
-                {
-                    // resave with animation info
-
-                    File mdlFile(context_);
-                    if (!mdlFile.Open(asset_->GetCachePath() + ".mdl", FILE_WRITE))
-                    {
-                        ErrorExit("Could not open output file " + asset_->GetCachePath() + ".mdl");
-                        return false;
-                    }
-
-                    model->Save(mdlFile);
-                }
-            }
         }
         }
     }
     }
 
 
-
     File outFile(context_);
     File outFile(context_);
 
 
     if (!outFile.Open(asset_->GetCachePath(), FILE_WRITE))
     if (!outFile.Open(asset_->GetCachePath(), FILE_WRITE))
@@ -304,6 +280,35 @@ void ModelImporter::SetAnimationCount(unsigned count)
 
 
 }
 }
 
 
+void ModelImporter::GetAnimations(PODVector<Animation*>& animations)
+{
+    animations.Clear();
+
+    SharedPtr<File> file(new File(context_, asset_->GetCachePath()));
+    SharedPtr<XMLFile> xml(new XMLFile(context_));
+
+    if (!xml->Load(*file))
+        return;
+
+    SharedPtr<Node> node(new Node(context_));
+    node->LoadXML(xml->GetRoot());
+
+    AnimationController* controller = node->GetComponent<AnimationController>();
+
+    if (!controller)
+        return;
+
+    const Vector<SharedPtr<Animation>>& animresources = controller->GetAnimationResources();
+
+    for (unsigned i = 0; i < animresources.Size(); i++)
+    {
+        if (animresources[i].NotNull())
+        {
+            animations.Push(animresources[i]);
+        }
+    }
+}
+
 bool ModelImporter::LoadSettingsInternal(JSONValue& jsonRoot)
 bool ModelImporter::LoadSettingsInternal(JSONValue& jsonRoot)
 {
 {
     if (!AssetImporter::LoadSettingsInternal(jsonRoot))
     if (!AssetImporter::LoadSettingsInternal(jsonRoot))
@@ -361,9 +366,9 @@ bool ModelImporter::SaveSettingsInternal(JSONValue& jsonRoot)
         animInfo.Push(jinfo);
         animInfo.Push(jinfo);
     }
     }
 
 
-   save.Set("animInfo", animInfo);
+    save.Set("animInfo", animInfo);
 
 
-   jsonRoot.Set("ModelImporter", save);
+    jsonRoot.Set("ModelImporter", save);
 
 
     return true;
     return true;
 }
 }

+ 3 - 0
Source/ToolCore/Assets/ModelImporter.h

@@ -12,6 +12,7 @@
 namespace Atomic
 namespace Atomic
 {
 {
     class Node;
     class Node;
+    class Animation;
 }
 }
 
 
 using namespace Atomic;
 using namespace Atomic;
@@ -71,6 +72,8 @@ public:
 
 
     Resource* GetResource(const String& typeName = String::EMPTY);
     Resource* GetResource(const String& typeName = String::EMPTY);
 
 
+    void GetAnimations(PODVector<Atomic::Animation *>& animations);
+
     AnimationImportInfo* GetAnimationInfo(unsigned index) { return animationInfo_[index]; }
     AnimationImportInfo* GetAnimationInfo(unsigned index) { return animationInfo_[index]; }
 
 
     /// Instantiate a node from the asset
     /// Instantiate a node from the asset

+ 2 - 0
Source/ToolCore/Import/OpenAssetImporter.cpp

@@ -468,6 +468,8 @@ bool OpenAssetImporter::BuildAndSaveModel(OutModel& model)
         outModel->SetNumGeometryLodLevels(destGeomIndex, 1);
         outModel->SetNumGeometryLodLevels(destGeomIndex, 1);
         outModel->SetGeometry(destGeomIndex, 0, geom);
         outModel->SetGeometry(destGeomIndex, 0, geom);
         outModel->SetGeometryCenter(destGeomIndex, center);
         outModel->SetGeometryCenter(destGeomIndex, center);
+        outModel->SetGeometryName(destGeomIndex, FromAIString(model.meshNodes_[i]->mName));
+
         if (model.bones_.Size() > maxBones_)
         if (model.bones_.Size() > maxBones_)
             allBoneMappings.Push(boneMappings);
             allBoneMappings.Push(boneMappings);
 
 

+ 29 - 3
Source/ToolCoreJS/ToolCoreJS.cpp

@@ -5,6 +5,8 @@
 // license information: https://github.com/AtomicGameEngine/AtomicGameEngine
 // license information: https://github.com/AtomicGameEngine/AtomicGameEngine
 //
 //
 
 
+#include <Atomic/Atomic3D/Animation.h>
+
 #include <AtomicJS/Javascript/JSVM.h>
 #include <AtomicJS/Javascript/JSVM.h>
 #include <ToolCore/ToolEnvironment.h>
 #include <ToolCore/ToolEnvironment.h>
 #include <ToolCore/ToolSystem.h>
 #include <ToolCore/ToolSystem.h>
@@ -13,6 +15,8 @@
 #include <ToolCore/License/LicenseSystem.h>
 #include <ToolCore/License/LicenseSystem.h>
 #include <ToolCore/Build/BuildSystem.h>
 #include <ToolCore/Build/BuildSystem.h>
 
 
+#include <ToolCore/Assets/ModelImporter.h>
+
 using namespace Atomic;
 using namespace Atomic;
 
 
 namespace Atomic
 namespace Atomic
@@ -87,6 +91,7 @@ static int AssetDatabase_GetAssetsByImporterType(duk_context* ctx)
     Project* project = ts->GetProject();
     Project* project = ts->GetProject();
 
 
     StringHash type = duk_require_string(ctx, 0);
     StringHash type = duk_require_string(ctx, 0);
+    String resourceType = duk_require_string(ctx, 1);
 
 
     duk_push_array(ctx);
     duk_push_array(ctx);
 
 
@@ -94,7 +99,7 @@ static int AssetDatabase_GetAssetsByImporterType(duk_context* ctx)
         return 1;
         return 1;
 
 
     PODVector<Asset*> assets;
     PODVector<Asset*> assets;
-    db->GetAssetsByImporterType(type, assets);
+    db->GetAssetsByImporterType(type, resourceType, assets);
 
 
     for(unsigned i = 0; i < assets.Size(); i++)
     for(unsigned i = 0; i < assets.Size(); i++)
     {
     {
@@ -105,6 +110,24 @@ static int AssetDatabase_GetAssetsByImporterType(duk_context* ctx)
     return 1;
     return 1;
 }
 }
 
 
+static int ModelImporter_GetAnimations(duk_context* ctx)
+{
+    duk_push_this(ctx);
+    ModelImporter* importer = js_to_class_instance<ModelImporter>(ctx, -1, 0);
+
+    PODVector<Animation*> animations;
+    importer->GetAnimations(animations);
+
+    duk_push_array(ctx);
+
+    for(unsigned i = 0; i < animations.Size(); i++)
+    {
+        js_push_class_object_instance(ctx, animations[i], 0);
+        duk_put_prop_index(ctx, -2, i);
+    }
+
+    return 1;
+}
 
 
 void jsapi_init_toolcore(JSVM* vm)
 void jsapi_init_toolcore(JSVM* vm)
 {
 {
@@ -146,11 +169,14 @@ void jsapi_init_toolcore(JSVM* vm)
     js_class_get_prototype(ctx, "ToolCore", "AssetDatabase");
     js_class_get_prototype(ctx, "ToolCore", "AssetDatabase");
     duk_push_c_function(ctx, AssetDatabase_GetFolderAssets, 1);
     duk_push_c_function(ctx, AssetDatabase_GetFolderAssets, 1);
     duk_put_prop_string(ctx, -2, "getFolderAssets");
     duk_put_prop_string(ctx, -2, "getFolderAssets");
-    duk_push_c_function(ctx, AssetDatabase_GetAssetsByImporterType, 1);
+    duk_push_c_function(ctx, AssetDatabase_GetAssetsByImporterType, 2);
     duk_put_prop_string(ctx, -2, "getAssetsByImporterType");
     duk_put_prop_string(ctx, -2, "getAssetsByImporterType");
     duk_pop(ctx);
     duk_pop(ctx);
 
 
-
+    js_class_get_prototype(ctx, "ToolCore", "ModelImporter");
+    duk_push_c_function(ctx, ModelImporter_GetAnimations, 0);
+    duk_put_prop_string(ctx, -2, "getAnimations");
+    duk_pop(ctx);
 }
 }
 
 
 }
 }