Эх сурвалжийг харах

Inspector array/vector support for dynamic script defined arrays (C# only currently), fix for color widget inspector, adding VariantVector to bindings

Josh Engebretson 9 жил өмнө
parent
commit
11aa7f3a2c
37 өөрчлөгдсөн 1827 нэмэгдсэн , 1001 устгасан
  1. 0 1
      Script/AtomicEditor/ui/frames/inspector/AssemblyInspector.ts
  2. 202 23
      Script/AtomicEditor/ui/frames/inspector/AttributeInfoEdit.ts
  3. 4 4
      Script/AtomicEditor/ui/frames/inspector/InspectorUtils.ts
  4. 0 1
      Script/AtomicEditor/ui/frames/inspector/PrefabInspector.ts
  5. 1 1
      Script/AtomicEditor/ui/frames/inspector/SelectionInspector.ts
  6. 31 12
      Script/AtomicEditor/ui/frames/inspector/SerializableEditType.ts
  7. 112 35
      Script/AtomicNET/AtomicNET/Scene/CSComponentCore.cs
  8. 2 0
      Script/AtomicNET/AtomicNETService/AssemblyInspector.cs
  9. 58 36
      Script/AtomicNET/AtomicNETService/CSComponentInspector.cs
  10. 10 0
      Script/AtomicNET/AtomicNETService/Program.cs
  11. 2 2
      Script/Packages/Atomic/Scene.json
  12. 1 1
      Script/TypeScript/AtomicWork.d.ts
  13. 1 20
      Source/Atomic/Graphics/AnimatedModel.cpp
  14. 32 0
      Source/Atomic/Graphics/StaticModel.cpp
  15. 7 0
      Source/Atomic/Graphics/StaticModel.h
  16. 11 4
      Source/Atomic/Script/ScriptComponentFile.cpp
  17. 24 2
      Source/Atomic/Script/ScriptComponentFile.h
  18. 39 6
      Source/Atomic/Script/ScriptVariant.h
  19. 14 0
      Source/Atomic/Script/ScriptVariantMap.h
  20. 68 0
      Source/Atomic/Script/ScriptVector.h
  21. 581 482
      Source/AtomicJS/Javascript/JSAPI.cpp
  22. 5 1
      Source/AtomicJS/Javascript/JSAPI.h
  23. 1 1
      Source/AtomicJS/Javascript/JSComponent.cpp
  24. 1 1
      Source/AtomicJS/Javascript/JSComponentFile.cpp
  25. 426 291
      Source/AtomicJS/Javascript/JSSceneSerializable.cpp
  26. 22 17
      Source/AtomicNET/NETScript/CSComponentAssembly.cpp
  27. 0 7
      Source/ThirdParty/TurboBadger/tb_widgets.h
  28. 49 4
      Source/ToolCore/JSBind/CSharp/CSFunctionWriter.cpp
  29. 20 1
      Source/ToolCore/JSBind/JSBFunction.cpp
  30. 5 1
      Source/ToolCore/JSBind/JSBFunction.h
  31. 9 1
      Source/ToolCore/JSBind/JSBHeaderVisitor.h
  32. 32 30
      Source/ToolCore/JSBind/JSBType.h
  33. 11 1
      Source/ToolCore/JSBind/JSBTypeScript.cpp
  34. 3 1
      Source/ToolCore/JSBind/JavaScript/JSClassWriter.cpp
  35. 41 14
      Source/ToolCore/JSBind/JavaScript/JSFunctionWriter.cpp
  36. 1 0
      Source/ToolCore/JSBind/JavaScript/JSModuleWriter.cpp
  37. 1 0
      Source/ToolCore/JSBind/JavaScript/JSPackageWriter.cpp

+ 0 - 1
Script/AtomicEditor/ui/frames/inspector/AssemblyInspector.ts

@@ -21,7 +21,6 @@
 //
 
 import InspectorWidget = require("./InspectorWidget");
-import ArrayEditWidget = require("./ArrayEditWidget");
 import InspectorUtils = require("./InspectorUtils");
 
 class AssemblyInspector extends InspectorWidget {

+ 202 - 23
Script/AtomicEditor/ui/frames/inspector/AttributeInfoEdit.ts

@@ -36,6 +36,8 @@ class AttributeInfoEdit extends Atomic.UILayout {
     nameOverride: string;
     hideName: boolean = false;
 
+    arrayIndex:number = -1;
+
     constructor() {
 
         super();
@@ -74,7 +76,7 @@ class AttributeInfoEdit extends Atomic.UILayout {
 
         this.layoutDistribution = Atomic.UI_LAYOUT_DISTRIBUTION.UI_LAYOUT_DISTRIBUTION_GRAVITY;
 
-        if (attr.type == Atomic.VariantType.VAR_VECTOR3 || attr.type == Atomic.VariantType.VAR_COLOR ||
+        if (attr.type == Atomic.VariantType.VAR_VECTOR3  ||
             attr.type == Atomic.VariantType.VAR_QUATERNION) {
             this.axis = Atomic.UI_AXIS.UI_AXIS_Y;
             this.layoutPosition = Atomic.UI_LAYOUT_POSITION.UI_LAYOUT_POSITION_LEFT_TOP;
@@ -121,7 +123,7 @@ class AttributeInfoEdit extends Atomic.UILayout {
 
     }
 
-    static createAttrEdit(editType: SerializableEditType, attrInfo: Atomic.AttributeInfo): AttributeInfoEdit {
+    static createAttrEdit(editType: SerializableEditType, attrInfo: Atomic.AttributeInfo, nameOverride:string=undefined, typeOverride:Atomic.VariantType = undefined ): AttributeInfoEdit {
 
         var type: typeof AttributeInfoEdit;
         var customTypes = AttributeInfoEdit.customAttrEditTypes[editType.typeName];
@@ -131,16 +133,22 @@ class AttributeInfoEdit extends Atomic.UILayout {
 
         }
 
-        if (!type) {
+        if (typeOverride)
+            type = AttributeInfoEdit.standardAttrEditTypes[typeOverride];
 
-            type = AttributeInfoEdit.standardAttrEditTypes[attrInfo.type];
+        if (!type && attrInfo.isArray) {
+            type = ArrayAttributeEdit;
+        }
 
+        if (!type) {
+            type = AttributeInfoEdit.standardAttrEditTypes[attrInfo.type];
         }
 
         if (!type)
             return null;
 
         var attrEdit = new type();
+        attrEdit.nameOverride = nameOverride;
         if (!attrEdit.initialize(editType, attrInfo))
             return null;
 
@@ -195,7 +203,7 @@ class BoolAttributeEdit extends AttributeInfoEdit {
             var object = this.editType.getFirstObject();
             this.editWidget.skinBg = "TBCheckBox";
             if (object) {
-                var value = object.getAttribute(this.attrInfo.name);
+                var value = object.getAttribute(this.attrInfo.name, this.arrayIndex);
                 this.editWidget.value = (value ? 1 : 0);
             }
 
@@ -212,7 +220,7 @@ class BoolAttributeEdit extends AttributeInfoEdit {
 
         if (ev.type == Atomic.UI_EVENT_TYPE.UI_EVENT_TYPE_CHANGED) {
 
-            this.editType.onAttributeInfoEdited(this.attrInfo, this.editWidget.value ? true : false);
+            this.editType.onAttributeInfoEdited(this.attrInfo, this.editWidget.value ? true : false, -1, true, this.arrayIndex);
             this.refresh();
 
             return true;
@@ -248,7 +256,7 @@ class StringAttributeEdit extends AttributeInfoEdit {
         if (uniform) {
             var object = this.editType.getFirstObject();
             if (object) {
-                var value = object.getAttribute(this.attrInfo.name);
+                var value = object.getAttribute(this.attrInfo.name, this.arrayIndex);
                 this.editWidget.text = value;
             }
 
@@ -262,7 +270,7 @@ class StringAttributeEdit extends AttributeInfoEdit {
 
     handleUIWidgetEditCompleteEvent(ev) {
 
-        this.editType.onAttributeInfoEdited(this.attrInfo, this.editWidget.text);
+        this.editType.onAttributeInfoEdited(this.attrInfo, this.editWidget.text, -1, true, this.arrayIndex);
         this.refresh();
 
     }
@@ -332,7 +340,7 @@ class IntAttributeEdit extends AttributeInfoEdit {
         if (uniform) {
             var object = this.editType.getFirstObject();
             if (object) {
-                var value = object.getAttribute(this.attrInfo.name);
+                var value = object.getAttribute(this.attrInfo.name, this.arrayIndex);
 
                 var widget = this.editWidget;
                 var attrInfo = this.attrInfo;
@@ -356,7 +364,7 @@ class IntAttributeEdit extends AttributeInfoEdit {
     handleUIWidgetEditCompleteEvent(ev) {
 
         // non-enum
-        this.editType.onAttributeInfoEdited(this.attrInfo, Number(this.editWidget.text));
+        this.editType.onAttributeInfoEdited(this.attrInfo, Number(this.editWidget.text), -1, true, this.arrayIndex);
         this.refresh();
 
     }
@@ -375,7 +383,7 @@ class IntAttributeEdit extends AttributeInfoEdit {
 
             if (ev.target.id == id) {
 
-                this.editType.onAttributeInfoEdited(this.attrInfo, Number(ev.refid) - 1);
+                this.editType.onAttributeInfoEdited(this.attrInfo, Number(ev.refid) - 1, -1, true, this.arrayIndex);
                 this.refresh();
 
             }
@@ -430,14 +438,14 @@ class FloatAttributeEdit extends AttributeInfoEdit {
 
                 var widget = this.editWidget;
                 var attrInfo = this.attrInfo;
-                var value = object.getAttribute(attrInfo.name);
+                var value = object.getAttribute(attrInfo.name, this.arrayIndex);
 
                 if (value == undefined) {
 
                     console.log("WARNING: Undefined value for object: ", this.editType.typeName + "." + attrInfo.name);
                     widget.text = "???";
 
-                } else {
+                } else {                    
                     widget.text = parseFloat(value.toFixed(5)).toString();
                 }
 
@@ -453,7 +461,7 @@ class FloatAttributeEdit extends AttributeInfoEdit {
 
     handleUIWidgetEditCompleteEvent(ev) {
 
-        this.editType.onAttributeInfoEdited(this.attrInfo, Number(this.editWidget.text));
+        this.editType.onAttributeInfoEdited(this.attrInfo, Number(this.editWidget.text), -1, true, this.arrayIndex);
         this.refresh();
 
     }
@@ -541,7 +549,7 @@ class NumberArrayAttributeEdit extends AttributeInfoEdit {
 
                 if (object) {
 
-                    var value = object.getAttribute(this.attrInfo.name);
+                    var value = object.getAttribute(this.attrInfo.name, this.arrayIndex);
                     select.value = parseFloat(value[i].toFixed(5));
 
                 }
@@ -560,7 +568,7 @@ class NumberArrayAttributeEdit extends AttributeInfoEdit {
     handleUIWidgetEditCompleteEvent(ev: Atomic.UIWidgetEditCompleteEvent) {
 
         var index = Number(ev.widget.id) - 1;
-        this.editType.onAttributeInfoEdited(this.attrInfo, ev.widget.value, index);
+        this.editType.onAttributeInfoEdited(this.attrInfo, ev.widget.value, index, true, this.arrayIndex);
         this.refresh();
 
     }
@@ -583,7 +591,7 @@ class NumberArrayAttributeEdit extends AttributeInfoEdit {
             if (captured) {
 
                 var index = Number(ev.target.id) - 1;
-                this.editType.onAttributeInfoEdited(this.attrInfo, ev.target.value, index, false);
+                this.editType.onAttributeInfoEdited(this.attrInfo, ev.target.value, index, false, this.arrayIndex);
 
             }
 
@@ -633,7 +641,11 @@ class ColorAttributeEdit extends AttributeInfoEdit {
     createLayout() {
 
         var layout = new Atomic.UILayout();
-        var o = InspectorUtils.createAttrColorFieldWithSelectButton(this.attrInfo.name, layout);
+        let name = this.attrInfo.name;
+        if (this.nameOverride) {
+            name = this.nameOverride;
+        }
+        var o = InspectorUtils.createAttrColorFieldWithSelectButton(name, layout);
 
         var colorWidget = this.colorWidget = o.colorWidget;
         var selectButton = o.selectButton;
@@ -642,9 +654,9 @@ class ColorAttributeEdit extends AttributeInfoEdit {
         layout.gravity = Atomic.UI_GRAVITY.UI_GRAVITY_LEFT_RIGHT;
         layout.layoutDistribution = Atomic.UI_LAYOUT_DISTRIBUTION.UI_LAYOUT_DISTRIBUTION_GRAVITY;
 
-
         var lp = new Atomic.UILayoutParams();
         lp.width = 140;
+        lp.height = 24;
         colorWidget.layoutParams = lp;
 
         this.editWidget = layout;
@@ -658,7 +670,7 @@ class ColorAttributeEdit extends AttributeInfoEdit {
             let object = this.editType.getFirstObject();
 
             if (object) {
-                color = object.getAttribute(this.attrInfo.name);
+                color = object.getAttribute(this.attrInfo.name, this.arrayIndex);
             }
 
             colorWidget.color = color;
@@ -694,7 +706,7 @@ class ColorAttributeEdit extends AttributeInfoEdit {
 
                     if (color[i] != newColor[i]) {
 
-                        this.editType.onAttributeInfoEdited(this.attrInfo, newColor);
+                        this.editType.onAttributeInfoEdited(this.attrInfo, newColor, -1, true, this.arrayIndex);
                         this.refresh();
                         committed = true;
                         break;
@@ -730,8 +742,11 @@ class ColorAttributeEdit extends AttributeInfoEdit {
         let object = this.editType.getFirstObject();
 
         if (object) {
-            this.colorWidget.color = object.getAttribute(this.attrInfo.name);
+            let color = object.getAttribute(this.attrInfo.name, this.arrayIndex);
+            this.colorWidget.color = color;
         }
+
+        
     }
 
     // updates color on selection without committing to undo/redo for preview
@@ -742,7 +757,7 @@ class ColorAttributeEdit extends AttributeInfoEdit {
         for (var i in this.editType.objects) {
 
             let object = this.editType.objects[i];
-            object.setAttribute(this.attrInfo.name, rgba );
+            object.setAttribute(this.attrInfo.name, rgba, this.arrayIndex);
 
         }
 
@@ -1127,6 +1142,170 @@ class ResourceRefListAttributeEdit extends AttributeInfoEdit {
 }
 
 
+class ArrayAttributeEdit extends AttributeInfoEdit {
+
+    layout: Atomic.UILayout;
+    indexEdits: AttributeInfoEdit[] = [];
+    sizeEdit: Atomic.UIEditField;
+
+    initialize(editType: SerializableEditType, attrInfo: Atomic.AttributeInfo): boolean {
+
+        return super.initialize(editType, attrInfo);
+
+    }
+
+    createIndexEdit(index: number) {
+
+        var indexEdit = AttributeInfoEdit.createAttrEdit(this.editType, this.attrInfo, index.toString(), this.attrInfo.type);
+        indexEdit.arrayIndex = index;
+
+        this.layout.addChild(indexEdit);
+
+        this.indexEdits.push(indexEdit);        
+
+    }
+
+    createEditWidget() {
+
+        this.spacing = 0;
+
+        var layout = this.layout = new Atomic.UILayout();
+
+        layout.axis = Atomic.UI_AXIS.UI_AXIS_Y;
+        layout.spacing = 2;
+        layout.layoutSize = Atomic.UI_LAYOUT_SIZE.UI_LAYOUT_SIZE_AVAILABLE;
+        layout.gravity = Atomic.UI_GRAVITY.UI_GRAVITY_LEFT_RIGHT;
+        layout.layoutPosition = Atomic.UI_LAYOUT_POSITION.UI_LAYOUT_POSITION_LEFT_TOP;
+        layout.layoutDistribution = Atomic.UI_LAYOUT_DISTRIBUTION.UI_LAYOUT_DISTRIBUTION_GRAVITY;
+
+        var lp = new Atomic.UILayoutParams();
+        lp.width = 304;
+        layout.layoutParams = lp;
+
+        var name = this.attrInfo.name + " Size";
+        if (name == "AnimationResources Size")
+            name = "Animations";
+
+        var sizeEdit = this.sizeEdit = InspectorUtils.createAttrEditField(name, layout);
+
+        lp = new Atomic.UILayoutParams();
+        lp.width = 160;
+        sizeEdit.layoutParams = lp;
+
+        sizeEdit.subscribeToEvent(sizeEdit, "UIWidgetEditComplete", (ev) => this.handleUIWidgetEditCompleteEvent(ev));
+
+        this.editWidget = layout;
+
+    }
+
+    createLayout() {
+
+        this.createEditWidget();
+
+        this.editWidget.subscribeToEvent(this.editWidget, "WidgetEvent", (data) => this.handleWidgetEvent(data));
+
+        this.addChild(this.editWidget);
+
+    }
+
+    handleUIWidgetEditCompleteEvent(ev) {
+
+        var size = Number(this.sizeEdit.text);
+
+        if (size > 128 || size < 0)
+            return;
+
+        var editType = this.editType;
+
+        var refresh = false;
+
+        for (var i in editType.objects) {
+
+            var object = editType.objects[i];
+
+            var vector = <Atomic.ScriptVector>(object.getAttribute(this.attrInfo.name));
+
+            if (vector.size != size) {
+
+                vector.resize(size);
+                object.setAttribute(this.attrInfo.name, vector);
+
+                // record for undo/redo
+                let scene = this.editType.getEditScene();
+                if (scene) {
+                    scene.sendEvent("SceneEditEnd");
+                    scene.sendEvent("ComponentEditEnd");                    
+                }
+
+                refresh = true;
+            } 
+
+        }
+
+        if (refresh)
+            this.refresh();
+        
+    }
+
+    refresh() {
+
+        var editType = this.editType;
+
+        var object = this.editType.getFirstObject();
+
+        if (!object) {
+            this.visibility = Atomic.UI_WIDGET_VISIBILITY.UI_WIDGET_VISIBILITY_GONE;
+            return;
+        }
+
+        this.visibility = Atomic.UI_WIDGET_VISIBILITY.UI_WIDGET_VISIBILITY_VISIBLE;
+
+        var maxLength = -1;
+        var i;
+        for (i in editType.objects) {
+
+            object = editType.objects[i];
+
+            var vector = <Atomic.ScriptVector>(object.getAttribute(this.attrInfo.name));
+
+            if (vector.size > maxLength) {
+
+                maxLength = vector.size;
+            }
+
+        }
+
+        this.sizeEdit.text = maxLength.toString();
+
+        if (maxLength == -1) {
+            this.visibility = Atomic.UI_WIDGET_VISIBILITY.UI_WIDGET_VISIBILITY_GONE;
+            return;
+        }
+
+        for (i = this.indexEdits.length; i < maxLength; i++) {
+
+            this.createIndexEdit(i);
+
+        }
+
+        for (i = 0; i < this.indexEdits.length; i++) {
+
+            var indexEdit = this.indexEdits[i];
+
+            if (i < maxLength) {
+                indexEdit.visibility = Atomic.UI_WIDGET_VISIBILITY.UI_WIDGET_VISIBILITY_VISIBLE;
+                indexEdit.refresh();
+            }
+            else {
+                indexEdit.visibility = Atomic.UI_WIDGET_VISIBILITY.UI_WIDGET_VISIBILITY_GONE;
+            }
+
+        }
+
+    }
+
+}
+
 
 AttributeInfoEdit.standardAttrEditTypes[Atomic.VariantType.VAR_BOOL] = BoolAttributeEdit;
 AttributeInfoEdit.standardAttrEditTypes[Atomic.VariantType.VAR_INT] = IntAttributeEdit;

+ 4 - 4
Script/AtomicEditor/ui/frames/inspector/InspectorUtils.ts

@@ -143,7 +143,7 @@ class InspectorUtils {
   static createAttrEditFieldWithSelectButton(name:string, parent:Atomic.UIWidget):{editField:Atomic.UIEditField, selectButton:Atomic.UIButton} {
 
     var attrLayout = new Atomic.UILayout();
-    attrLayout.layoutDistribution = Atomic.UI_LAYOUT_DISTRIBUTION.UI_LAYOUT_DISTRIBUTION_AVAILABLE;
+    attrLayout.layoutDistributionPosition = Atomic.UI_LAYOUT_DISTRIBUTION_POSITION.UI_LAYOUT_DISTRIBUTION_POSITION_LEFT_TOP;
 
     if (name) {
       var _name = InspectorUtils.createAttrName(name);
@@ -151,7 +151,7 @@ class InspectorUtils {
     }
 
     var fieldLayout = new Atomic.UILayout();
-    fieldLayout.layoutDistribution = Atomic.UI_LAYOUT_DISTRIBUTION.UI_LAYOUT_DISTRIBUTION_AVAILABLE;
+    fieldLayout.layoutDistributionPosition = Atomic.UI_LAYOUT_DISTRIBUTION_POSITION.UI_LAYOUT_DISTRIBUTION_POSITION_LEFT_TOP;
 
     var edit = InspectorUtils.createEditField();
 
@@ -172,7 +172,7 @@ class InspectorUtils {
   static createAttrColorFieldWithSelectButton(name:string, parent:Atomic.UIWidget):{colorWidget:Atomic.UIColorWidget, selectButton:Atomic.UIButton} {
 
     var attrLayout = new Atomic.UILayout();
-    attrLayout.layoutDistribution = Atomic.UI_LAYOUT_DISTRIBUTION.UI_LAYOUT_DISTRIBUTION_AVAILABLE;
+    attrLayout.layoutDistributionPosition = Atomic.UI_LAYOUT_DISTRIBUTION_POSITION.UI_LAYOUT_DISTRIBUTION_POSITION_LEFT_TOP;
 
     if (name) {
       var _name = InspectorUtils.createAttrName(name);
@@ -180,7 +180,7 @@ class InspectorUtils {
     }
 
     var fieldLayout = new Atomic.UILayout();
-    fieldLayout.layoutDistribution = Atomic.UI_LAYOUT_DISTRIBUTION.UI_LAYOUT_DISTRIBUTION_AVAILABLE;
+    fieldLayout.layoutDistributionPosition = Atomic.UI_LAYOUT_DISTRIBUTION_POSITION.UI_LAYOUT_DISTRIBUTION_POSITION_LEFT_TOP;
 
     var colorWidget = InspectorUtils.createColorWidget();
 

+ 0 - 1
Script/AtomicEditor/ui/frames/inspector/PrefabInspector.ts

@@ -21,7 +21,6 @@
 //
 
 import InspectorWidget = require("./InspectorWidget");
-import ArrayEditWidget = require("./ArrayEditWidget");
 import InspectorUtils = require("./InspectorUtils");
 
 class PrefabInspector extends InspectorWidget {

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

@@ -238,7 +238,7 @@ class CSComponentSection extends ComponentSection {
         if (object) {
             var value = object.getAttribute("Class");
             if (value)
-                this.text = value;
+                this.text = value + " - C#";
         }
     }
 

+ 31 - 12
Script/AtomicEditor/ui/frames/inspector/SerializableEditType.ts

@@ -85,7 +85,11 @@ class SerializableEditType {
 
     }
 
-    onAttributeInfoEdited(attrInfo: Atomic.AttributeInfo, value: any, index: number = -1, genEdit: boolean = true) {
+    /**
+     * Updates selected object attribute on edit, index parameter is for the edit type (for example NumberArrayAttributeEdit)
+     * attrArrayIndex is for setting which array index to set for array AttributeInfo types
+     */
+    onAttributeInfoEdited(attrInfo: Atomic.AttributeInfo, value: any, index: number = -1, genEdit: boolean = true, attrArrayIndex: number = -1) {
 
         let editTypeName = this.objects.length > 0 ? this.objects[0].typeName : "";
 
@@ -95,23 +99,23 @@ class SerializableEditType {
 
             if (index >= 0) {
 
-                var idxValue = object.getAttribute(attrInfo.name);
+                var idxValue = object.getAttribute(attrInfo.name, attrArrayIndex);
 
                 if (attrInfo.type == Atomic.VariantType.VAR_RESOURCEREFLIST) {
 
                     idxValue.resources[index] = value;
-                    object.setAttribute(attrInfo.name, idxValue);
+                    object.setAttribute(attrInfo.name, idxValue, attrArrayIndex);
 
                 } else {
 
                     idxValue[index] = value;
-                    object.setAttribute(attrInfo.name, idxValue);
+                    object.setAttribute(attrInfo.name, idxValue, attrArrayIndex);
 
                 }
 
             } else {
 
-                object.setAttribute(attrInfo.name, value);
+                object.setAttribute(attrInfo.name, value, attrArrayIndex);
 
             }
 
@@ -120,6 +124,25 @@ class SerializableEditType {
         if (!genEdit)
             return;
 
+        let scene = this.getEditScene();
+
+        if (scene) {
+
+            scene.sendEvent("SceneEditEnd");
+
+            if (editTypeName != "Node") {
+
+                scene.sendEvent("ComponentEditEnd");
+                
+            }
+        }
+            
+
+
+    }
+
+    getEditScene():Atomic.Scene {
+
         var node: Atomic.Node = null;
         if (this.nodes.length) {
             node = this.nodes[0];
@@ -127,14 +150,10 @@ class SerializableEditType {
             node = <Atomic.Node>this.objects[0];
         }
 
-        if (node) {
-            node.scene.sendEvent("SceneEditEnd");
-
-            if (editTypeName != "Node") {
-                node.scene.sendEvent("ComponentEditEnd");
-            }
-        }
+        if (node)
+            return node.scene;
 
+        return null;        
     }
 
     compareTypes(otherType: SerializableEditType, multiSelect:boolean = false): boolean {

+ 112 - 35
Script/AtomicNET/AtomicNET/Scene/CSComponentCore.cs

@@ -55,10 +55,58 @@ namespace AtomicEngine
 
         }
 
-        public void ApplyFieldValues(CSComponent component, IntPtr fieldValuePtr)
+#if ATOMIC_DESKTOP || ATOMIC_MOBILE
+        public void SetFieldValue(object o, FieldInfo field)
         {
+            var fieldType = field.FieldType;
+            var typeCode = Type.GetTypeCode(fieldType);
+
             // FIXME: This will need to be optimized, specifically to use uint key hashes for value lookup
+            switch (typeCode)
+            {
+                case TypeCode.Boolean:
+                    field.SetValue(o, fieldMap.GetBool(field.Name));
+                    break;
+
+                case TypeCode.Int32:
+                    field.SetValue(o, fieldMap.GetInt(field.Name));
+                    break;
+
+                case TypeCode.Single:
+                    field.SetValue(o, fieldMap.GetFloat(field.Name));
+                    break;
+
+                case TypeCode.String:
+                    field.SetValue(o, fieldMap.GetString(field.Name));
+                    break;
+
+                default:
+
+                    if (fieldType == typeof(Vector3))
+                    {
+                        field.SetValue(o, fieldMap.GetVector3(field.Name));
+                    }
+                    else if (fieldType == typeof(Quaternion))
+                    {
+                        field.SetValue(o, fieldMap.GetQuaternion(field.Name));
+                    }
+                    else if (fieldType.IsSubclassOf(typeof(Resource)))
+                    {
+                        field.SetValue(o, fieldMap.GetResourceFromRef(field.Name));
+                    }
+                    else if (fieldType.IsSubclassOf(typeof(RefCounted)))
+                    {
+                        field.SetValue(o, fieldMap.GetPtr(field.Name));
+                    }
 
+                    break;
+            }
+
+        }
+#endif
+
+        public void ApplyFieldValues(CSComponent component, IntPtr fieldValuePtr)
+        {
 #if ATOMIC_DESKTOP || ATOMIC_MOBILE
 
             fieldMap.CopyVariantMap(fieldValuePtr);
@@ -66,7 +114,7 @@ namespace AtomicEngine
             foreach (var field in InspectorFields)
             {
                 if (fieldMap.Contains(field.Name))
-                {
+                {                   
                     var fieldType = field.FieldType;
 
                     if (fieldType.IsEnum)
@@ -75,50 +123,77 @@ namespace AtomicEngine
                         continue;
                     }
 
-                    switch (Type.GetTypeCode(fieldType))
+                    if (!fieldType.IsArray)
                     {
-                        case TypeCode.Boolean:
-                            field.SetValue(component, fieldMap.GetBool(field.Name));
-                            break;
-
-                        case TypeCode.Int32:
-                            field.SetValue(component, fieldMap.GetInt(field.Name));
-                            break;
+                        SetFieldValue(component, field); 
+                    }
+                    else
+                    {   
+                        fieldMap.GetVariantVector(field.Name, arrayMarshal);
 
-                        case TypeCode.Single:
-                            field.SetValue(component, fieldMap.GetFloat(field.Name));
-                            break;
+                        var elementType = fieldType.GetElementType();
+                        uint sz = arrayMarshal.Size;
+                        Array array = Array.CreateInstance(elementType, sz);
 
-                        case TypeCode.String:
-                            field.SetValue(component, fieldMap.GetString(field.Name));
-                            break;
+                        var typeCode = Type.GetTypeCode(elementType);
 
-                        default:
+                        for (uint i = 0; i < sz; i++)
+                        {
+                            var variant = arrayMarshal[i];
 
-                            if (fieldType == typeof(Vector3))
-                            {
-                                field.SetValue(component, fieldMap.GetVector3(field.Name));
-                            }
-                            else if (fieldType == typeof(Quaternion))
-                            {
-                                field.SetValue(component, fieldMap.GetQuaternion(field.Name));
-                            }
-                            else if (fieldType.IsSubclassOf(typeof(Resource)))
+                            // FIXME: This will need to be optimized, specifically to use uint key hashes for value lookup
+                            switch (typeCode)
                             {
-                                field.SetValue(component, fieldMap.GetResourceFromRef(field.Name));
-                            }
-                            else if (fieldType.IsSubclassOf(typeof(RefCounted)))
-                            {
-                                field.SetValue(component, fieldMap.GetPtr(field.Name));
-                            }
+                                case TypeCode.Boolean:
+                                    array.SetValue((bool) variant.GetBool(), i);
+                                    break;
+
+                                case TypeCode.Int32:
+                                    array.SetValue(variant.GetInt(), i);
+                                    break;
+
+                                case TypeCode.UInt32:
+                                    array.SetValue(variant.GetUInt(), i);
+                                    break;
+
+                                case TypeCode.Single:
+                                    array.SetValue(variant.GetFloat(), i);
+                                    break;
+
+                                case TypeCode.String:
+                                    array.SetValue(variant.GetString(), i);
+                                    break;
+
+                                default:
+
+                                    if (elementType == typeof(Vector3))
+                                    {
+                                         array.SetValue(variant.GetVector3(), i);
+                                    }
+                                    else if (elementType == typeof(Vector2))
+                                    {
+                                         array.SetValue(variant.GetVector2(), i);
+                                    }
+                                    else if (elementType == typeof(Quaternion))
+                                    {
+                                         array.SetValue(variant.GetQuaternion(), i);
+                                    }
+                                    else if (elementType == typeof(Color))
+                                    {
+                                         array.SetValue(variant.GetColor(), i);
+                                    }
+
+                                    break;
+                            }                            
+                    
+                        }
+
+                        field.SetValue(component, array);
 
-                            break;
                     }
                 }
             }
-
 #endif
-
         }
 
         public FieldInfo[] InspectorFields;
@@ -140,6 +215,8 @@ namespace AtomicEngine
         ScriptVariantMap fieldMap = new ScriptVariantMap();
 
         public Dictionary<uint, FieldInfo> fieldLookup = new Dictionary<uint, FieldInfo>();
+
+        private Vector<ScriptVariant> arrayMarshal = new Vector<ScriptVariant>();
     }
 
     public class CSComponentCore : NETScriptObject

+ 2 - 0
Script/AtomicNET/AtomicNETService/AssemblyInspector.cs

@@ -228,6 +228,7 @@ namespace AtomicTools
             var dict = new Dictionary<string, object>();
 
             dict["isEnum"] = IsEnum;
+            dict["isArray"] = IsArray;
             dict["typeName"] = TypeName;
             dict["name"] = Name;
             dict["defaultValue"] = DefaultValue;
@@ -240,6 +241,7 @@ namespace AtomicTools
         }
 
         public bool IsEnum = false;
+        public bool IsArray = false;
 
         public string TypeName;
 

+ 58 - 36
Script/AtomicNET/AtomicNETService/CSComponentInspector.cs

@@ -97,6 +97,50 @@ namespace AtomicTools
 
         }
 
+        private void DecodeTypeHandleTypeName(BlobReader sigReader, out String typeName, out bool isEnum)
+        {
+            typeName = "";
+            isEnum = false;
+
+            EntityHandle token = sigReader.ReadTypeHandle();
+            HandleKind tokenType = token.Kind;
+
+            if (tokenType == HandleKind.TypeDefinition)
+            {
+
+                // can store local enum typedefs
+                // enum initializers are stored as constant value in the IL
+
+                var typeDef = metaReader.GetTypeDefinition((TypeDefinitionHandle)token);
+
+                var baseTypeToken = typeDef.BaseType;
+
+                if (baseTypeToken.Kind != HandleKind.TypeReference)
+                {
+                    return;
+                }
+                    
+
+                var baseTypeRef = metaReader.GetTypeReference((TypeReferenceHandle)baseTypeToken);
+
+                if (metaReader.GetString(baseTypeRef.Name) != "Enum")
+                    return;
+
+                isEnum = true;
+                typeName = metaReader.GetString(typeDef.Name);
+
+            }
+            else if (tokenType == HandleKind.TypeReference)
+            {
+
+                // TypeReference, ok
+                var typeRef = metaReader.GetTypeReference((TypeReferenceHandle)token);
+
+                typeName = metaReader.GetString(typeRef.Name);
+
+            }
+        }
+
         private void InspectFields(FieldDefinitionHandleCollection fields)
         {
             foreach (var fieldHandle in fields)
@@ -125,49 +169,27 @@ namespace AtomicTools
 
                         string typeName = typeCode.ToString();
 
-                        if (typeCode == SignatureTypeCode.TypeHandle)
+                        if (typeCode == SignatureTypeCode.SZArray)
                         {
+                            inspectorField.IsArray = true;
+                            SignatureTypeCode code = sigReader.ReadSignatureTypeCode();
 
-                            EntityHandle token = sigReader.ReadTypeHandle();
-                            HandleKind tokenType = token.Kind;
-
-                            if (tokenType == HandleKind.TypeDefinition)
+                            if (code == SignatureTypeCode.TypeHandle)
                             {
-
-                                // can store local enum typedefs
-                                // enum initializers are stored as constant value in the IL
-
-                                var typeDef = metaReader.GetTypeDefinition((TypeDefinitionHandle)token);
-
-                                var baseTypeToken = typeDef.BaseType;
-
-                                if (baseTypeToken.Kind != HandleKind.TypeReference)
-                                    continue;
-
-                                var baseTypeRef = metaReader.GetTypeReference((TypeReferenceHandle)baseTypeToken);
-
-                                if (metaReader.GetString(baseTypeRef.Name) != "Enum")
-                                    continue;
-
-                                inspectorField.IsEnum = true;
-                                typeName = metaReader.GetString(typeDef.Name);
-
-                            }
-                            else if (tokenType == HandleKind.TypeReference)
-                            {
-
-                                // TypeReference, ok
-                                var typeRef = metaReader.GetTypeReference((TypeReferenceHandle)token);
-
-                                typeName = metaReader.GetString(typeRef.Name);
-
+                                bool isEnum;
+                                DecodeTypeHandleTypeName(sigReader, out typeName, out isEnum);
                             }
                             else
                             {
-                                // ???
-                                continue;
+                                typeName = code.ToString();
                             }
-
+                            
+                        }
+                        else if (typeCode == SignatureTypeCode.TypeHandle)
+                        {
+                            bool isEnum;
+                            DecodeTypeHandleTypeName(sigReader, out typeName, out isEnum);
+                            inspectorField.IsEnum = isEnum;
                         }
 
                         inspectorField.TypeName = typeName;

+ 10 - 0
Script/AtomicNET/AtomicNETService/Program.cs

@@ -8,6 +8,16 @@ namespace AtomicTools
     {
         public static void Main(string[] args)
         {
+            for (uint i = 0; i < args.Length; i++)
+            {
+                if (args[i] == "--debugassembly" && i + 1 < args.Length)
+                {
+                    var assemblyJSON = AtomicTools.InspectAssembly(args[i + 1]);
+                    Console.WriteLine(assemblyJSON);
+                    return;
+                }
+            }
+
             // create the service
             var app = NETServiceApplication.Create();
 

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

@@ -31,8 +31,8 @@
 
 		"Serializable" : [
 			"getAttributes():AttributeInfo[];",
-			"getAttribute(name:string):any;",
-			"setAttribute(name:string, value:any):void;"
+			"getAttribute(name:string, index?:number):any;",
+			"setAttribute(name:string, value:any, index?:number):void;"
 		],
 		"Node" : [
 			"saveXML(file:File):boolean;",

+ 1 - 1
Script/TypeScript/AtomicWork.d.ts

@@ -121,7 +121,7 @@ declare module Atomic {
         resourceTypeName: string;
         dynamic: boolean;
         tooltip: string;
-
+        isArray:boolean;
     }
 
     export interface ShaderParameter {

+ 1 - 20
Source/Atomic/Graphics/AnimatedModel.cpp

@@ -324,26 +324,7 @@ void AnimatedModel::UpdateBatches(const FrameInfo& frame)
 
     // 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;
-            }
-        }
-    }
+        UpdateBatchesHideGeometry();
 
     // ATOMIC END
 

+ 32 - 0
Source/Atomic/Graphics/StaticModel.cpp

@@ -162,6 +162,12 @@ void StaticModel::UpdateBatches(const FrameInfo& frame)
         lodDistance_ = newLodDistance;
         CalculateLodLevels();
     }
+
+    // ATOMIC BEGIN
+    if (geometryDisabled_)
+        UpdateBatchesHideGeometry();
+    // ATOMIC END
+
 }
 
 Geometry* StaticModel::GetLodGeometry(unsigned batchIndex, unsigned level)
@@ -586,6 +592,32 @@ const VariantVector& StaticModel::GetGeometryEnabledAttr() const
     return geometryEnabled_;
 }
 
+void StaticModel::UpdateBatchesHideGeometry()
+{
+    if (!geometryDisabled_ || !batches_.Size())
+        return;
+
+    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;
+        }
+    }
+
+}
+
 // ATOMIC END
 
 }

+ 7 - 0
Source/Atomic/Graphics/StaticModel.h

@@ -116,6 +116,9 @@ public:
     /// Hide a named submesh
     void HideGeometry(const String& name);
 
+    /// Returns true if any geometry is hidden in the model
+    bool GetGeometryHidden() const { return geometryDisabled_; }
+
     void SetGeometryEnabledAttr(const VariantVector& value);
     const VariantVector& GetGeometryEnabledAttr() const;
 
@@ -145,6 +148,10 @@ protected:
     mutable ResourceRefList materialsAttr_;
 
     // ATOMIC BEGIN
+
+    // Apply geometry hiding when updating batches
+    void UpdateBatchesHideGeometry();
+
     mutable VariantVector geometryEnabled_;
     /// true if any geometry has been disabled
     mutable bool geometryDisabled_;

+ 11 - 4
Source/Atomic/Script/ScriptComponentFile.cpp

@@ -53,10 +53,11 @@ void ScriptComponentFile::AddEnum(const String& enumName, const EnumInfo& enumIn
     enumValues.Push(enumInfo);
 }
 
-void ScriptComponentFile::AddField(const String& fieldName, VariantType variantType, const String &classname, const String& tooltip)
+void ScriptComponentFile::AddField(const String& fieldName, VariantType variantType, bool isArray, const String &classname, const String& tooltip)
 {
     FieldMap& fields = classFields_[classname];
-    fields[fieldName] = variantType;
+    FieldInfo finfo(fieldName, variantType, isArray);
+    fields[fieldName] = finfo;
 
     if (tooltip.Length())
     {
@@ -145,11 +146,17 @@ void ScriptComponentFile::GetDefaultFieldValue(const String& name, Variant& v,co
     if (!fieldMap)
         return;
 
-    const VariantType* variantType = (*fieldMap)[name];
+    const FieldInfo* finfo = (*fieldMap)[name];
+
+    if (!finfo || finfo->isArray_)
+        return;
+
+    VariantType variantType = finfo->variantType_;
+
     if (!variantType)
         return;
 
-    switch (*variantType)
+    switch (variantType)
     {
     case VAR_BOOL:
         v = false;

+ 24 - 2
Source/Atomic/Script/ScriptComponentFile.h

@@ -29,6 +29,28 @@
 namespace Atomic
 {
 
+
+struct FieldInfo
+{
+    FieldInfo()
+    {
+        name_ = "UNINITIALIZED_FIELDINFO";
+        variantType_ = VAR_NONE;
+        isArray_ = false;
+    }
+
+    FieldInfo(const String& name, VariantType variantType, bool isArray = false)
+    {
+        name_ = name;
+        variantType_ = variantType;
+        isArray_ = isArray;
+    }
+
+    String name_;
+    VariantType variantType_;
+    bool isArray_;
+};
+
 struct EnumInfo
 {
     EnumInfo(const String& name = String::EMPTY, const Variant& v = Variant::EMPTY)
@@ -42,7 +64,7 @@ struct EnumInfo
 };
 
 // TODO: these should be broken out into some class info structs, getting unwieldy
-typedef HashMap<String, VariantType> FieldMap;
+typedef HashMap<String, FieldInfo> FieldMap;
 typedef HashMap<String, Vector<EnumInfo>> EnumMap;
 typedef HashMap<String, String> FieldTooltipMap;
 
@@ -80,7 +102,7 @@ protected:
     void Clear();
 
     void AddEnum(const String& enumName, const EnumInfo& enumInfo, const String& classname = String::EMPTY);
-    void AddField(const String& fieldName, VariantType variantType, const String& classname = String::EMPTY, const String& tooltip = String::EMPTY);
+    void AddField(const String& fieldName, VariantType variantType, bool isArray, const String& classname = String::EMPTY, const String& tooltip = String::EMPTY);
     void AddDefaultValue(const String& fieldName, const Variant& value, const String& classname = String::EMPTY);
 
     // only valid in editor

+ 39 - 6
Source/Atomic/Script/ScriptVariant.h

@@ -42,35 +42,68 @@ namespace Atomic
 
         }
 
+        ScriptVariant(const Variant& source) : RefCounted()
+        {
+            variant_ = source;
+        }
+
         virtual ~ScriptVariant()
         {
 
         }
 
-        const Variant& GetVariant() { return variant_; }
+        const Variant& GetVariant() const { return variant_; }
 
         void SetVariant(const Variant& value) { variant_ = value; }
 
-        Vector2 GetVector2() { return variant_.GetVector2(); }
+        bool GetBool() const { return variant_.GetBool(); }
+
+        void SetBool(bool value) { variant_ = value; }
+
+        int GetInt() const { return variant_.GetInt(); }
+
+        void SetInt(int value) { variant_ = value; }
+
+        unsigned GetUInt() const { return variant_.GetUInt(); }
+
+        void SetUInt(unsigned value) { variant_ = value; }
+
+        float GetFloat() const { return variant_.GetFloat(); }
+
+        void SetFloat(float value) { variant_ = value; }
+
+        const Vector2& GetVector2() const { return variant_.GetVector2(); }
 
         void SetVector2(const Vector2& value) { variant_ = value; }
 
-        Vector3 GetVector3() { return variant_.GetVector3(); }
+        const Vector3& GetVector3() const { return variant_.GetVector3(); }
 
         void SetVector3(const Vector3& value) { variant_ = value; }
 
-        Vector4 GetVector4() { return variant_.GetVector4(); }
+        const Quaternion& GetQuaternion() const { return variant_.GetQuaternion(); }
+
+        void SetQuaternion(const Quaternion& value) { variant_ = value; }
+
+        const Vector4& GetVector4() const { return variant_.GetVector4(); }
 
         void SetVector4(const Vector4& value) { variant_ = value; }
 
-        Color GetColor() { return variant_.GetColor(); }
+        const Color& GetColor() const { return variant_.GetColor(); }
 
         void SetColor(const Color& value) { variant_ = value; }
 
-        String GetString() { return variant_.GetString(); }
+        const String& GetString() const { return variant_.GetString(); }
 
         void SetString(const String& value) { variant_ = value; }
 
+        const VariantVector& GetVariantVector() const { return variant_.GetVariantVector(); }
+
+        void SetVariantVector(const VariantVector& value) { variant_ = value; }
+
+        const VariantMap& GetVariantMap() const { return variant_.GetVariantMap(); }
+
+        void SetVariantMap(const VariantMap& value) { variant_ = value; }
+
     private:
 
         Variant variant_;

+ 14 - 0
Source/Atomic/Script/ScriptVariantMap.h

@@ -147,6 +147,20 @@ public:
 
     }
 
+    const VariantVector& GetVariantVector(StringHash key) const
+    {
+        static VariantVector empty;
+
+        Variant* variant = vmap_[key];
+
+        if (!variant)
+            return empty;
+
+        return variant->GetVariantVector();
+
+    }
+
+
     VariantType GetVariantType(StringHash key) const
     {
         Variant* variant = vmap_[key];

+ 68 - 0
Source/Atomic/Script/ScriptVector.h

@@ -20,7 +20,10 @@
 // THE SOFTWARE.
 //
 
+#include "../Atomic/IO/Log.h"
+
 #include "ScriptSystem.h"
+#include "ScriptVariant.h"
 
 #pragma once
 
@@ -88,6 +91,47 @@ public:
         return refVector_.Size();
     }
 
+    void Resize(unsigned size) 
+    {
+        return refVector_.Resize(size);
+    }
+
+    bool AdaptFromVector(const VariantVector& vectorIn)
+    {
+        // copy to temporary vector, so refs we hold aren't deleted, before they can be set
+        // also allows us to save some instantiations
+        Vector<SharedPtr<RefCounted>> keepAlive = refVector_;
+
+        refVector_.Clear();
+
+        for (unsigned i = 0; i < vectorIn.Size(); i++)
+        {
+            if (i < keepAlive.Size())
+            {
+                const SharedPtr<RefCounted>& item = keepAlive[i];
+
+                if (item.Null() || item->GetClassID() != ScriptVariant::GetClassIDStatic())
+                {
+                    ATOMIC_LOGERROR("ScriptVector::AdaptFromVector(VariantVector) - item == null or item class != ScriptVariant");
+                    return false;
+                }
+
+                ScriptVariant* scriptVariant = static_cast<ScriptVariant*>(item.Get());
+                scriptVariant->SetVariant(vectorIn[i]);
+                refVector_.Push(item);
+
+            }
+            else
+            {
+                refVector_.Push(SharedPtr<RefCounted>(new ScriptVariant(vectorIn[i])));
+            }
+
+        }
+
+        return true;
+    }
+
+
     template <class T>
     bool AdaptFromVector(PODVector<T> vectorIn)
     {
@@ -152,6 +196,30 @@ public:
 
     }
 
+    bool AdaptToVector(VariantVector& vectorOut, const Variant& defaultValue = Variant::EMPTY)
+    {
+        vectorOut.Clear();
+
+        for (unsigned i = 0; i < refVector_.Size(); i++)
+        {
+            const SharedPtr<RefCounted>& item = refVector_[i];
+
+            if (item.Null() || item->GetClassID() != ScriptVariant::GetClassIDStatic())
+            {
+                vectorOut.Push(defaultValue);
+                continue;
+            }
+
+            ScriptVariant* scriptVariant = static_cast<ScriptVariant*>(item.Get());
+
+            vectorOut.Push(scriptVariant->GetVariant());
+        }
+
+        return true;
+
+    }
+
+
     template <class T>
     bool AdaptToVector(PODVector<T> vectorOut)
     {

+ 581 - 482
Source/AtomicJS/Javascript/JSAPI.cpp

@@ -22,6 +22,7 @@
 
 #include <Atomic/Core/Context.h>
 #include <Atomic/Resource/ResourceCache.h>
+#include <Atomic/Script/ScriptVector.h>
 
 #include "JSAPI.h"
 #include "JSVM.h"
@@ -47,658 +48,756 @@
 namespace Atomic
 {
 
-void js_class_get_prototype(duk_context* ctx, const char* package, const char *classname)
-{
-    duk_get_global_string(ctx, package);
-    duk_get_prop_string(ctx, -1, classname);
-    duk_get_prop_string(ctx, -1, "prototype");
-    duk_remove(ctx, -2); // remove class object
-    duk_remove(ctx, -2); // remove Atomic object
-}
+    void js_class_get_prototype(duk_context* ctx, const char* package, const char *classname)
+    {
+        duk_get_global_string(ctx, package);
+        duk_get_prop_string(ctx, -1, classname);
+        duk_get_prop_string(ctx, -1, "prototype");
+        duk_remove(ctx, -2); // remove class object
+        duk_remove(ctx, -2); // remove Atomic object
+    }
 
-void js_class_get_constructor(duk_context* ctx, const char* package, const char *classname)
-{
-    duk_get_global_string(ctx, package);
-    duk_get_prop_string(ctx, -1, classname);
-    duk_remove(ctx, -2); // remove package
-}
+    void js_class_get_constructor(duk_context* ctx, const char* package, const char *classname)
+    {
+        duk_get_global_string(ctx, package);
+        duk_get_prop_string(ctx, -1, classname);
+        duk_remove(ctx, -2); // remove package
+    }
 
-void js_constructor_basecall(duk_context* ctx, const char* package, const char* baseclass)
-{
-    int top = duk_get_top(ctx);
-    duk_get_global_string(ctx, package);
-    duk_get_prop_string(ctx, -1, baseclass);
-    assert(duk_is_function(ctx, -1));
-    duk_push_this(ctx);
-    duk_call_method(ctx, 0);
-    duk_pop_n(ctx, 2);
-    assert (top == duk_get_top(ctx));
-}
+    void js_constructor_basecall(duk_context* ctx, const char* package, const char* baseclass)
+    {
+        int top = duk_get_top(ctx);
+        duk_get_global_string(ctx, package);
+        duk_get_prop_string(ctx, -1, baseclass);
+        assert(duk_is_function(ctx, -1));
+        duk_push_this(ctx);
+        duk_call_method(ctx, 0);
+        duk_pop_n(ctx, 2);
+        assert(top == duk_get_top(ctx));
+    }
 
-void js_class_declare_internal(JSVM* vm, void* uniqueClassID, const char* package, const char* classname, duk_c_function constructor)
-{
-    duk_context* ctx = vm->GetJSContext();
+    void js_class_declare_internal(JSVM* vm, void* uniqueClassID, const char* package, const char* classname, duk_c_function constructor)
+    {
+        duk_context* ctx = vm->GetJSContext();
 
-    // uniqueClassID must be non-null
-    assert(uniqueClassID);
+        // uniqueClassID must be non-null
+        assert(uniqueClassID);
 
-    // stash a lookup from the uniqueID to the package and class name
+        // stash a lookup from the uniqueID to the package and class name
 
-    duk_push_heap_stash(ctx);
-    duk_push_pointer(ctx, uniqueClassID);
+        duk_push_heap_stash(ctx);
+        duk_push_pointer(ctx, uniqueClassID);
 
-    duk_push_object(ctx);
-    duk_push_string(ctx, package);
-    duk_put_prop_index(ctx, -2, 0);
-    duk_push_string(ctx, classname);
-    duk_put_prop_index(ctx, -2, 1);
+        duk_push_object(ctx);
+        duk_push_string(ctx, package);
+        duk_put_prop_index(ctx, -2, 0);
+        duk_push_string(ctx, classname);
+        duk_put_prop_index(ctx, -2, 1);
 
-    // store class object into uniqueClassID key
-    duk_put_prop(ctx, -3);
+        // store class object into uniqueClassID key
+        duk_put_prop(ctx, -3);
 
-    // pop heap stash
-    duk_pop(ctx);
+        // pop heap stash
+        duk_pop(ctx);
 
-    // store the constructor
-    duk_get_global_string(ctx, package);
-    duk_push_c_function(ctx, constructor, DUK_VARARGS);
-    duk_put_prop_string(ctx, -2, classname);
-    duk_pop(ctx);
-}
+        // store the constructor
+        duk_get_global_string(ctx, package);
+        duk_push_c_function(ctx, constructor, DUK_VARARGS);
+        duk_put_prop_string(ctx, -2, classname);
+        duk_pop(ctx);
+    }
 
-void js_class_push_propertyobject(JSVM* vm, const char* package, const char* classname)
-{
-    duk_context* ctx = vm->GetJSContext();
-    String pname;
-    pname.AppendWithFormat("__%s__Properties", classname);
-
-    duk_get_global_string(ctx, package);
-    duk_push_object(ctx);
-    duk_dup(ctx, -1);
-    duk_put_prop_string(ctx, -3, pname.CString());
-    duk_remove(ctx, -2); // remove Atomic object
-}
+    void js_class_push_propertyobject(JSVM* vm, const char* package, const char* classname)
+    {
+        duk_context* ctx = vm->GetJSContext();
+        String pname;
+        pname.AppendWithFormat("__%s__Properties", classname);
 
-void js_setup_prototype(JSVM* vm, const char* package, const char* classname, const char* basePackage, const char* basename, bool hasProperties)
-{
-    duk_context* ctx = vm->GetJSContext();
+        duk_get_global_string(ctx, package);
+        duk_push_object(ctx);
+        duk_dup(ctx, -1);
+        duk_put_prop_string(ctx, -3, pname.CString());
+        duk_remove(ctx, -2); // remove Atomic object
+    }
 
-    String pname;
-    pname.AppendWithFormat("__%s__Properties", classname);
+    void js_setup_prototype(JSVM* vm, const char* package, const char* classname, const char* basePackage, const char* basename, bool hasProperties)
+    {
+        duk_context* ctx = vm->GetJSContext();
 
-    int top = duk_get_top(ctx);
+        String pname;
+        pname.AppendWithFormat("__%s__Properties", classname);
 
-    duk_get_global_string(ctx,package);
-    duk_get_prop_string(ctx, -1, classname);
-    assert(duk_is_c_function(ctx, -1));
+        int top = duk_get_top(ctx);
 
-    if (!strlen(basename))
-    {
-        // prototype
-        duk_push_object(ctx);
-        duk_dup(ctx, -2); // AObject constructor function
-        duk_put_prop_string(ctx, -2, "constructor");
-        duk_put_prop_string(ctx, -2, "prototype");
+        duk_get_global_string(ctx, package);
+        duk_get_prop_string(ctx, -1, classname);
+        assert(duk_is_c_function(ctx, -1));
 
-        duk_pop_n(ctx, 2);
+        if (!strlen(basename))
+        {
+            // prototype
+            duk_push_object(ctx);
+            duk_dup(ctx, -2); // AObject constructor function
+            duk_put_prop_string(ctx, -2, "constructor");
+            duk_put_prop_string(ctx, -2, "prototype");
 
-        assert (top == duk_get_top(ctx));
+            duk_pop_n(ctx, 2);
 
-        return;
+            assert(top == duk_get_top(ctx));
 
-    }
-
-    // prototype
-    duk_get_global_string(ctx, "Object");
-    duk_get_prop_string(ctx, -1, "create");
+            return;
 
-    assert(duk_is_function(ctx, -1));
+        }
 
-    duk_remove(ctx, -2); // remove Object
+        // prototype
+        duk_get_global_string(ctx, "Object");
+        duk_get_prop_string(ctx, -1, "create");
 
-    duk_get_global_string(ctx, basePackage);
-    duk_get_prop_string(ctx, -1, basename);
-    assert(duk_is_function(ctx, -1));
-    duk_get_prop_string(ctx, -1, "prototype");
+        assert(duk_is_function(ctx, -1));
 
-    assert(duk_is_object(ctx, -1));
+        duk_remove(ctx, -2); // remove Object
 
-    duk_remove(ctx, -2); // remove basename
+        duk_get_global_string(ctx, basePackage);
+        duk_get_prop_string(ctx, -1, basename);
+        assert(duk_is_function(ctx, -1));
+        duk_get_prop_string(ctx, -1, "prototype");
 
-    int numargs = 1;
-    if (hasProperties)
-    {
-        duk_get_global_string(ctx, package);
-        duk_get_prop_string(ctx, -1, pname.CString());
         assert(duk_is_object(ctx, -1));
-        duk_remove(ctx, -2);
-        duk_remove(ctx, -3); // remove package
-        numargs++;
-    }
-    else
-        duk_remove(ctx, -2); // remove package
 
-    duk_call(ctx, numargs);
+        duk_remove(ctx, -2); // remove basename
 
-    assert(duk_is_object(ctx, -1));
+        int numargs = 1;
+        if (hasProperties)
+        {
+            duk_get_global_string(ctx, package);
+            duk_get_prop_string(ctx, -1, pname.CString());
+            assert(duk_is_object(ctx, -1));
+            duk_remove(ctx, -2);
+            duk_remove(ctx, -3); // remove package
+            numargs++;
+        }
+        else
+            duk_remove(ctx, -2); // remove package
 
-    duk_dup(ctx, -2);
-    duk_put_prop_string(ctx, -2, "constructor");
+        duk_call(ctx, numargs);
 
-    //duk_dup(ctx, -1);
-    duk_put_prop_string(ctx, -2, "prototype");
+        assert(duk_is_object(ctx, -1));
 
-    // pop the classname object
-    duk_pop(ctx);
+        duk_dup(ctx, -2);
+        duk_put_prop_string(ctx, -2, "constructor");
 
-    // pop the Atomic Object
-    duk_pop(ctx);
+        //duk_dup(ctx, -1);
+        duk_put_prop_string(ctx, -2, "prototype");
 
-    assert (top == duk_get_top(ctx));
-}
+        // pop the classname object
+        duk_pop(ctx);
 
+        // pop the Atomic Object
+        duk_pop(ctx);
 
-// When subscribing to native event, this method will be called
-// to provide the event meta data (type and callback)
-static int js_push_native_event_metadata(duk_context* ctx) {
+        assert(top == duk_get_top(ctx));
+    }
 
-    duk_push_current_function(ctx);
 
-    duk_push_object(ctx);
-    duk_get_prop_string(ctx, -2, "_eventType");
-    duk_put_prop_string(ctx, -2, "_eventType");
-    duk_dup(ctx, 0);
-    duk_put_prop_string(ctx, -2, "_callback");
+    // When subscribing to native event, this method will be called
+    // to provide the event meta data (type and callback)
+    static int js_push_native_event_metadata(duk_context* ctx) {
 
-    return 1;
-}
+        duk_push_current_function(ctx);
 
-void js_define_native_event(duk_context* ctx, const String& eventType, const String &eventName)
-{
-    // push c function which takes 1 argument, the callback
-    duk_push_c_function(ctx, js_push_native_event_metadata, 1);
+        duk_push_object(ctx);
+        duk_get_prop_string(ctx, -2, "_eventType");
+        duk_put_prop_string(ctx, -2, "_eventType");
+        duk_dup(ctx, 0);
+        duk_put_prop_string(ctx, -2, "_callback");
 
-    // store the event type in the function object
-    duk_push_string(ctx, eventType.CString());
-    duk_put_prop_string(ctx, -2, "_eventType");
+        return 1;
+    }
 
-    // store to module object
-    duk_put_prop_string(ctx, -2, eventName.CString());
+    void js_define_native_event(duk_context* ctx, const String& eventType, const String &eventName)
+    {
+        // push c function which takes 1 argument, the callback
+        duk_push_c_function(ctx, js_push_native_event_metadata, 1);
 
-}
+        // store the event type in the function object
+        duk_push_string(ctx, eventType.CString());
+        duk_put_prop_string(ctx, -2, "_eventType");
 
-void js_object_to_variantmap(duk_context* ctx, int objIdx, VariantMap &v)
-{
-    v.Clear();
+        // store to module object
+        duk_put_prop_string(ctx, -2, eventName.CString());
 
-    duk_enum(ctx, objIdx, DUK_ENUM_OWN_PROPERTIES_ONLY);
+    }
 
-    while (duk_next(ctx, -1 /*enum_index*/, 1 /*get_value*/)) {
+    void js_object_to_variantmap(duk_context* ctx, int objIdx, VariantMap &v)
+    {
+        v.Clear();
 
-        /* [ ... enum key ] */
+        duk_enum(ctx, objIdx, DUK_ENUM_OWN_PROPERTIES_ONLY);
 
-        const char* key = duk_to_string(ctx, -2);
+        while (duk_next(ctx, -1 /*enum_index*/, 1 /*get_value*/)) {
 
-        if (duk_is_number(ctx, -1)) {
+            /* [ ... enum key ] */
 
-            v[key] = (float) duk_to_number(ctx, -1);
+            const char* key = duk_to_string(ctx, -2);
 
-        } else if (duk_is_boolean(ctx, -1)) {
+            if (duk_is_number(ctx, -1)) {
 
-            v[key] = duk_to_boolean(ctx, -1) ? true : false;
+                v[key] = (float)duk_to_number(ctx, -1);
 
-        }
-        else if (duk_is_string(ctx, -1)) {
+            }
+            else if (duk_is_boolean(ctx, -1)) {
 
-            v[key] = duk_to_string(ctx, -1);
+                v[key] = duk_to_boolean(ctx, -1) ? true : false;
 
-        } else if (duk_get_heapptr(ctx, -1)) {
+            }
+            else if (duk_is_string(ctx, -1)) {
 
-            v[key] = js_to_class_instance<Object>(ctx, -1, 0);
+                v[key] = duk_to_string(ctx, -1);
 
-        }
+            }
+            else if (duk_get_heapptr(ctx, -1)) {
 
-        duk_pop_2(ctx);  /* pop_key & value*/
-    }
+                v[key] = js_to_class_instance<Object>(ctx, -1, 0);
 
-    duk_pop(ctx);  /* pop enum object */
+            }
 
-}
+            duk_pop_2(ctx);  /* pop_key & value*/
+        }
 
-duk_bool_t js_check_is_buffer_and_get_data(duk_context* ctx, duk_idx_t idx, void** data, duk_size_t* size)
-{
-    void* temp;
-    if (duk_is_buffer(ctx, idx))
+        duk_pop(ctx);  /* pop enum object */
+
+    }
+
+    duk_bool_t js_check_is_buffer_and_get_data(duk_context* ctx, duk_idx_t idx, void** data, duk_size_t* size)
     {
-        temp = duk_get_buffer_data(ctx, idx, size);
-        if (data)
+        void* temp;
+        if (duk_is_buffer(ctx, idx))
         {
-            *data = temp;
+            temp = duk_get_buffer_data(ctx, idx, size);
+            if (data)
+            {
+                *data = temp;
+            }
+            return true;
         }
-        return true;
-    }
-    if (!(duk_is_object(ctx, idx) &&
-        duk_has_prop_string(ctx, idx, "length") &&
-        duk_has_prop_string(ctx, idx, "byteLength") &&
-        duk_has_prop_string(ctx, idx, "byteOffset") &&
-        duk_has_prop_string(ctx, idx, "BYTES_PER_ELEMENT")))
-    {
-        if (data)
+        if (!(duk_is_object(ctx, idx) &&
+            duk_has_prop_string(ctx, idx, "length") &&
+            duk_has_prop_string(ctx, idx, "byteLength") &&
+            duk_has_prop_string(ctx, idx, "byteOffset") &&
+            duk_has_prop_string(ctx, idx, "BYTES_PER_ELEMENT")))
         {
-            *data = nullptr;
+            if (data)
+            {
+                *data = nullptr;
+            }
+            if (size)
+            {
+                *size = 0;
+            }
+            return false;
         }
-        if (size)
+        temp = duk_require_buffer_data(ctx, idx, size);
+        if (data)
         {
-            *size = 0;
+            *data = temp;
         }
-        return false;
+        return true;
     }
-    temp = duk_require_buffer_data(ctx, idx, size);
-    if (data)
+
+    void js_push_default_variant(duk_context* ctx, VariantType variantType, Variant& value)
     {
-        *data = temp;
-    }
-    return true;
-}
+        value = Variant::EMPTY;
+        
+        switch (variantType)
+        {
 
-void js_to_variant(duk_context* ctx, int variantIdx, Variant &v, VariantType variantType)
-{
-    v.Clear();
+        case VAR_NONE:
+            break;
 
-    // convert to abs index
-    if (variantIdx < 0)
-        variantIdx = duk_get_top(ctx) + variantIdx;
+        case VAR_INT:
+            value = 0;
+            break;
 
-    if (duk_is_boolean(ctx, variantIdx))
-    {
-        v = duk_to_boolean(ctx, variantIdx) ? true : false;
-        return;
-    }
+        case VAR_BOOL:
+            value = false;
+            break;
 
-    if (duk_is_string(ctx, variantIdx))
-    {
-        v = duk_to_string(ctx, variantIdx);
-        return;
-    }
+        case VAR_FLOAT:
+            value = 0.0f;
+            break;
 
-    if (duk_is_number(ctx, variantIdx))
-    {
-        v = (float) duk_to_number(ctx, variantIdx);
-        return;
-    }
+        case VAR_VECTOR2:
+            value = Vector2::ZERO;
+            break;
 
-    if (duk_is_pointer(ctx, variantIdx))
-    {
-        v = (RefCounted*) duk_get_pointer(ctx, variantIdx);
-        return;
+        case VAR_VECTOR3:
+            value = Vector3::ZERO;
+            break;
+
+        case VAR_VECTOR4:
+            value = Vector4::ZERO;
+            break;
+
+        case VAR_QUATERNION:
+            value = Quaternion::IDENTITY;
+            break;
+
+        case VAR_COLOR:
+            value = Color::WHITE;
+            break;
+
+        case VAR_STRING:
+            value = "";
+            break;
+
+        case VAR_INTRECT:
+            value = IntRect::ZERO;
+            break;
+
+        case VAR_INTVECTOR2:
+            value = IntVector2::ZERO;
+            break;
+
+        case VAR_DOUBLE:
+            // set float here too, so standard edits work
+            value = 0.0f;
+            break;
+
+        default:
+            break;
+        }
+
+        js_push_variant(ctx, value);
     }
 
-    if (duk_is_array(ctx, variantIdx))
+    void js_to_variant(duk_context* ctx, int variantIdx, Variant &v, VariantType variantType)
     {
-        if (duk_get_length(ctx, variantIdx) == 2)
+        v.Clear();
+
+        // convert to abs index
+        if (variantIdx < 0)
+            variantIdx = duk_get_top(ctx) + variantIdx;
+
+        if (duk_is_boolean(ctx, variantIdx))
         {
-            Vector2 v2;
-            duk_get_prop_index(ctx, variantIdx, 0);
-            v2.x_ = duk_to_number(ctx, -1);
-            duk_get_prop_index(ctx, variantIdx, 1);
-            v2.y_ = duk_to_number(ctx, -1);
-            duk_pop_n(ctx, 2);
-            v = v2;
+            v = duk_to_boolean(ctx, variantIdx) ? true : false;
             return;
         }
-        else if (duk_get_length(ctx, variantIdx) == 3)
+
+        if (duk_is_string(ctx, variantIdx))
         {
-            Vector3 v3;
-            duk_get_prop_index(ctx, variantIdx, 0);
-            v3.x_ = duk_to_number(ctx, -1);
-            duk_get_prop_index(ctx, variantIdx, 1);
-            v3.y_ = duk_to_number(ctx, -1);
-            duk_get_prop_index(ctx, variantIdx, 2);
-            v3.z_ = duk_to_number(ctx, -1);
-            duk_pop_n(ctx, 3);
-            v = v3;
+            v = duk_to_string(ctx, variantIdx);
             return;
         }
-        else if (duk_get_length(ctx, variantIdx) == 4)
+
+        if (duk_is_number(ctx, variantIdx))
         {
-            Vector4 v4;
-            duk_get_prop_index(ctx, variantIdx, 0);
-            v4.x_ = duk_to_number(ctx, -1);
-            duk_get_prop_index(ctx, variantIdx, 1);
-            v4.y_ = duk_to_number(ctx, -1);
-            duk_get_prop_index(ctx, variantIdx, 2);
-            v4.z_ = duk_to_number(ctx, -1);
-            duk_get_prop_index(ctx, variantIdx, 3);
-            v4.w_ = duk_to_number(ctx, -1);
-            duk_pop_n(ctx, 4);
-            v = v4;
+            v = (float)duk_to_number(ctx, variantIdx);
             return;
         }
 
+        if (duk_is_pointer(ctx, variantIdx))
+        {
+            v = (RefCounted*)duk_get_pointer(ctx, variantIdx);
+            return;
+        }
 
-        return;
-    }
-
-    {
-        void* bufferData;
-        duk_size_t bufferSize;
-        if (js_check_is_buffer_and_get_data(ctx, variantIdx, &bufferData, &bufferSize))
+        if (duk_is_array(ctx, variantIdx))
         {
-            // copy the buffer into the variant
-            v.SetBuffer(bufferData, (unsigned)bufferSize);
+            if (duk_get_length(ctx, variantIdx) == 2)
+            {
+                Vector2 v2;
+                duk_get_prop_index(ctx, variantIdx, 0);
+                v2.x_ = duk_to_number(ctx, -1);
+                duk_get_prop_index(ctx, variantIdx, 1);
+                v2.y_ = duk_to_number(ctx, -1);
+                duk_pop_n(ctx, 2);
+                v = v2;
+                return;
+            }
+            else if (duk_get_length(ctx, variantIdx) == 3)
+            {
+                Vector3 v3;
+                duk_get_prop_index(ctx, variantIdx, 0);
+                v3.x_ = duk_to_number(ctx, -1);
+                duk_get_prop_index(ctx, variantIdx, 1);
+                v3.y_ = duk_to_number(ctx, -1);
+                duk_get_prop_index(ctx, variantIdx, 2);
+                v3.z_ = duk_to_number(ctx, -1);
+                duk_pop_n(ctx, 3);
+                v = v3;
+                return;
+            }
+            else if (duk_get_length(ctx, variantIdx) == 4)
+            {
+                Vector4 v4;
+                duk_get_prop_index(ctx, variantIdx, 0);
+                v4.x_ = duk_to_number(ctx, -1);
+                duk_get_prop_index(ctx, variantIdx, 1);
+                v4.y_ = duk_to_number(ctx, -1);
+                duk_get_prop_index(ctx, variantIdx, 2);
+                v4.z_ = duk_to_number(ctx, -1);
+                duk_get_prop_index(ctx, variantIdx, 3);
+                v4.w_ = duk_to_number(ctx, -1);
+                duk_pop_n(ctx, 4);
+                v = v4;
+                return;
+            }
+
+
             return;
         }
-    }
 
-    // object check after array and buffer object check
-    if (duk_is_object(ctx, variantIdx))
-    {
-        if (variantType == VAR_RESOURCEREFLIST)
         {
-            ResourceRefList refList;
+            void* bufferData;
+            duk_size_t bufferSize;
+            if (js_check_is_buffer_and_get_data(ctx, variantIdx, &bufferData, &bufferSize))
+            {
+                // copy the buffer into the variant
+                v.SetBuffer(bufferData, (unsigned)bufferSize);
+                return;
+            }
+        }
 
-            duk_get_prop_string(ctx, variantIdx, "typeName");
-            refList.type_ = duk_to_string(ctx, -1);
+        // object check after array and buffer object check
+        if (duk_is_object(ctx, variantIdx))
+        {
+            if (variantType == VAR_RESOURCEREFLIST)
+            {
+                ResourceRefList refList;
 
-            duk_get_prop_string(ctx, variantIdx, "resources");
-            int length = duk_get_length(ctx, -1);
+                duk_get_prop_string(ctx, variantIdx, "typeName");
+                refList.type_ = duk_to_string(ctx, -1);
 
-            for (int i = 0; i < length; i++) {
+                duk_get_prop_string(ctx, variantIdx, "resources");
+                int length = duk_get_length(ctx, -1);
 
-                duk_get_prop_index(ctx, -1, i);
+                for (int i = 0; i < length; i++) {
 
-                Resource* resource = NULL;
+                    duk_get_prop_index(ctx, -1, i);
 
-                if (duk_is_object(ctx, -1))
-                {
-                     resource = js_to_class_instance<Resource>(ctx, -1, 0);
+                    Resource* resource = NULL;
 
-                }
+                    if (duk_is_object(ctx, -1))
+                    {
+                        resource = js_to_class_instance<Resource>(ctx, -1, 0);
 
-                if (resource) {
-                    refList.names_.Push(resource->GetName());
+                    }
+
+                    if (resource) {
+                        refList.names_.Push(resource->GetName());
+                    }
+                    else
+                        refList.names_.Push(String::EMPTY);
+
+                    duk_pop(ctx);
                 }
-                else
-                    refList.names_.Push(String::EMPTY);
 
-                duk_pop(ctx);
-            }
+                duk_pop_n(ctx, 2);
 
-            duk_pop_n(ctx, 2);
+                v = refList;
+            }
+            else
+            {
+                RefCounted* o = js_to_class_instance<RefCounted>(ctx, variantIdx, 0);
+                if (o)
+                    v = o;
+            }
 
-            v = refList;
-        }
-        else
-        {
-            RefCounted* o = js_to_class_instance<RefCounted>(ctx, variantIdx, 0);
-            if (o)
-                v = o;
+            return;
         }
 
-        return;
-    }
 
+    }
 
-}
+    // variant map Proxy getter, so we can convert access to string based
+    // member lookup, to string hash on the fly
 
-// variant map Proxy getter, so we can convert access to string based
-// member lookup, to string hash on the fly
+    static int variantmap_property_get(duk_context* ctx)
+    {
+        // targ, key, recv
 
-static int variantmap_property_get(duk_context* ctx)
-{
-    // targ, key, recv
+        if (duk_is_string(ctx, 1))
+        {
+            StringHash key = duk_to_string(ctx, 1);
+            duk_get_prop_index(ctx, 0, (unsigned)key.Value());
+            return 1;
+        }
 
-    if (duk_is_string(ctx, 1))
-    {
-        StringHash key = duk_to_string(ctx, 1);
-        duk_get_prop_index(ctx, 0, (unsigned) key.Value());
+        duk_push_undefined(ctx);
         return 1;
+
     }
 
-    duk_push_undefined(ctx);
-    return 1;
+    // removes all keys from the variant map proxy target, REGARDLESS of key given for delete
+    // see (lengthy) note in JSEventDispatcher::EndSendEvent
+    static int variantmap_property_deleteproperty(duk_context* ctx)
+    {
+        // deleteProperty: function (targ, key)
 
-}
+        duk_enum(ctx, 0, DUK_ENUM_OWN_PROPERTIES_ONLY);
 
-// removes all keys from the variant map proxy target, REGARDLESS of key given for delete
-// see (lengthy) note in JSEventDispatcher::EndSendEvent
-static int variantmap_property_deleteproperty(duk_context* ctx)
-{
-    // deleteProperty: function (targ, key)
+        while (duk_next(ctx, -1, 0)) {
+            duk_del_prop(ctx, 0);
+        }
 
-    duk_enum(ctx, 0, DUK_ENUM_OWN_PROPERTIES_ONLY);
+        duk_push_boolean(ctx, 1);
+        return 1;
 
-    while (duk_next(ctx, -1, 0)) {
-        duk_del_prop(ctx, 0);
     }
 
-    duk_push_boolean(ctx, 1);
-    return 1;
 
-}
+    void js_push_variantmap(duk_context* ctx, const VariantMap &vmap)
+    {
 
+        // setup proxy so we can map string
+        duk_get_global_string(ctx, "Proxy");
 
-void js_push_variantmap(duk_context* ctx, const VariantMap &vmap)
-{
+        duk_push_object(ctx);
 
-    // setup proxy so we can map string
-    duk_get_global_string(ctx, "Proxy");
+        VariantMap::ConstIterator itr = vmap.Begin();
 
-    duk_push_object(ctx);
+        while (itr != vmap.End()) {
 
-    VariantMap::ConstIterator itr = vmap.Begin();
+            js_push_variant(ctx, itr->second_);
 
-    while (itr != vmap.End()) {
 
-        js_push_variant(ctx, itr->second_);
+            if (duk_is_undefined(ctx, -1)) {
 
+                duk_pop(ctx);
+            }
+            else
+            {
+                duk_put_prop_index(ctx, -2, (unsigned)itr->first_.Value());
+            }
 
-        if (duk_is_undefined(ctx, -1)) {
+            itr++;
 
-            duk_pop(ctx);
-        }
-        else
-        {
-            duk_put_prop_index(ctx, -2, (unsigned) itr->first_.Value());
         }
 
-        itr++;
-
-    }
-
-    // setup property handler
-    duk_push_object(ctx);
-    duk_push_c_function(ctx, variantmap_property_get, 3);
-    duk_put_prop_string(ctx, -2, "get");
-    duk_push_c_function(ctx, variantmap_property_deleteproperty, 2);
-    duk_put_prop_string(ctx, -2, "deleteProperty");
-
-    duk_new(ctx, 2);
+        // setup property handler
+        duk_push_object(ctx);
+        duk_push_c_function(ctx, variantmap_property_get, 3);
+        duk_put_prop_string(ctx, -2, "get");
+        duk_push_c_function(ctx, variantmap_property_deleteproperty, 2);
+        duk_put_prop_string(ctx, -2, "deleteProperty");
 
+        duk_new(ctx, 2);
 
-}
 
-void js_push_variant(duk_context *ctx, const Variant& v)
-{
-    switch (v.GetType())
-    {
-    case VAR_NONE:
-        duk_push_undefined(ctx);
-        break;
-
-    case VAR_VOIDPTR:
-        duk_push_null(ctx);
-        break;
+    }
 
-    case VAR_PTR:
+    void js_push_variant(duk_context *ctx, const Variant& v, int arrayIndex)
     {
-        RefCounted* ref = v.GetPtr();
-
-        // if we're null or don't have any refs, return null
-        if (!ref || !ref->Refs())
+        switch (v.GetType())
         {
-            duk_push_null(ctx);
+        case VAR_NONE:
+            duk_push_undefined(ctx);
             break;
-        }
 
-        // check that class is supported
-        duk_push_heap_stash(ctx);
-        duk_push_pointer(ctx, (void*)ref->GetClassID());
-        duk_get_prop(ctx, -2);
+        case VAR_VOIDPTR:
+            duk_push_null(ctx);
+            break;
 
-        if (!duk_is_object(ctx, -1))
+        case VAR_PTR:
         {
-            duk_pop_2(ctx);
-            duk_push_undefined(ctx);
-        }
-        else
-        {
-            duk_pop_2(ctx);
-            js_push_class_object_instance(ctx, ref);
-        }
+            RefCounted* ref = v.GetPtr();
 
-    }   break;
+            // if we're null or don't have any refs, return null
+            if (!ref || !ref->Refs())
+            {
+                duk_push_null(ctx);
+                break;
+            }
 
-    case VAR_RESOURCEREF:
-    {
-        const ResourceRef& resourceRef(v.GetResourceRef());
-        ResourceCache* cache = JSVM::GetJSVM(ctx)->GetContext()->GetSubsystem<ResourceCache>();
-        Resource* resource = cache->GetResource(resourceRef.type_, resourceRef.name_);
-        js_push_class_object_instance(ctx, resource);
-    }   break;
+            // check that class is supported
+            duk_push_heap_stash(ctx);
+            duk_push_pointer(ctx, (void*)ref->GetClassID());
+            duk_get_prop(ctx, -2);
 
-    case VAR_RESOURCEREFLIST:
-    {
+            if (!duk_is_object(ctx, -1))
+            {
+                duk_pop_2(ctx);
+                duk_push_undefined(ctx);
+            }
+            else
+            {
+                duk_pop_2(ctx);
+                js_push_class_object_instance(ctx, ref);
+            }
 
-        const ResourceRefList& resourceRefList(v.GetResourceRefList());
-        const Context* context = JSVM::GetJSVM(ctx)->GetContext();
+        }   break;
 
-        duk_push_object(ctx);
-        duk_push_string(ctx, context->GetTypeName(resourceRefList.type_).CString());
-        duk_put_prop_string(ctx, -2, "typeName");
+        case VAR_RESOURCEREF:
+        {
+            const ResourceRef& resourceRef(v.GetResourceRef());
+            ResourceCache* cache = JSVM::GetJSVM(ctx)->GetContext()->GetSubsystem<ResourceCache>();
+            Resource* resource = cache->GetResource(resourceRef.type_, resourceRef.name_);
+            js_push_class_object_instance(ctx, resource);
+        }   break;
 
-        duk_push_array(ctx);
+        case VAR_RESOURCEREFLIST:
+        {
 
-        ResourceCache* cache = context->GetSubsystem<ResourceCache>();
+            const ResourceRefList& resourceRefList(v.GetResourceRefList());
+            const Context* context = JSVM::GetJSVM(ctx)->GetContext();
 
-        for (unsigned i = 0; i < resourceRefList.names_.Size(); i++) {
+            duk_push_object(ctx);
+            duk_push_string(ctx, context->GetTypeName(resourceRefList.type_).CString());
+            duk_put_prop_string(ctx, -2, "typeName");
 
-            Resource* resource = cache->GetResource(resourceRefList.type_, resourceRefList.names_[i]);
-            js_push_class_object_instance(ctx, resource);
-            duk_put_prop_index(ctx, -2, i);
-        }
+            duk_push_array(ctx);
 
-        duk_put_prop_string(ctx, -2, "resources");
+            ResourceCache* cache = context->GetSubsystem<ResourceCache>();
 
-    } break;
+            for (unsigned i = 0; i < resourceRefList.names_.Size(); i++) {
 
-    case VAR_BOOL:
-        duk_push_boolean(ctx, v.GetBool() ? 1 : 0);
-        break;
+                Resource* resource = cache->GetResource(resourceRefList.type_, resourceRefList.names_[i]);
+                js_push_class_object_instance(ctx, resource);
+                duk_put_prop_index(ctx, -2, i);
+            }
 
-    case VAR_INT:
-        duk_push_number(ctx, v.GetInt());
-        break;
+            duk_put_prop_string(ctx, -2, "resources");
 
-    case VAR_FLOAT:
-        duk_push_number(ctx, v.GetFloat());
-        break;
+        } break;
 
-    case VAR_STRING:
-    {
-        const String& string(v.GetString());
-        duk_push_lstring(ctx, string.CString(), string.Length());
-    }   break;
+        case VAR_BOOL:
+            duk_push_boolean(ctx, v.GetBool() ? 1 : 0);
+            break;
 
-    case VAR_BUFFER:
-    {
-        const PODVector<unsigned char>& buffer(v.GetBuffer()); // The braces are to scope this reference.
-        duk_push_fixed_buffer(ctx, buffer.Size());
-        duk_push_buffer_object(ctx, -1, 0, buffer.Size(), DUK_BUFOBJ_UINT8ARRAY);
-        duk_replace(ctx, -2);
-        unsigned char* data = (unsigned char*)duk_require_buffer_data(ctx, -1, (duk_size_t*)nullptr);
-        memcpy(data, buffer.Buffer(), buffer.Size());
-    }   break;
-
-    case VAR_VECTOR2:
-    {
-        const Vector2& vector2(v.GetVector2());
-        duk_push_array(ctx);
-        duk_push_number(ctx, vector2.x_);
-        duk_put_prop_index(ctx, -2, 0);
-        duk_push_number(ctx, vector2.y_);
-        duk_put_prop_index(ctx, -2, 1);
-    }   break;
+        case VAR_INT:
+            duk_push_number(ctx, v.GetInt());
+            break;
 
-    case VAR_INTVECTOR2:
-    {
-        const IntVector2& intVector2(v.GetIntVector2());
-        duk_push_array(ctx);
-        duk_push_number(ctx, intVector2.x_);
-        duk_put_prop_index(ctx, -2, 0);
-        duk_push_number(ctx, intVector2.y_);
-        duk_put_prop_index(ctx, -2, 1);
-    }   break;
+        case VAR_FLOAT:
+            duk_push_number(ctx, v.GetFloat());
+            break;
 
-    case VAR_VECTOR3:
-    {
-        const Vector3& vector3(v.GetVector3());
-        duk_push_array(ctx);
-        duk_push_number(ctx, vector3.x_);
-        duk_put_prop_index(ctx, -2, 0);
-        duk_push_number(ctx, vector3.y_);
-        duk_put_prop_index(ctx, -2, 1);
-        duk_push_number(ctx, vector3.z_);
-        duk_put_prop_index(ctx, -2, 2);
-    }   break;
+        case VAR_DOUBLE:
+            duk_push_number(ctx, v.GetFloat());
+            break;
 
-    case VAR_QUATERNION:
-    {
-        const Vector3& vector3(v.GetQuaternion().EulerAngles());
-        duk_push_array(ctx);
-        duk_push_number(ctx, vector3.x_);
-        duk_put_prop_index(ctx, -2, 0);
-        duk_push_number(ctx, vector3.y_);
-        duk_put_prop_index(ctx, -2, 1);
-        duk_push_number(ctx, vector3.z_);
-        duk_put_prop_index(ctx, -2, 2);
-    }   break;
+        case VAR_STRING:
+        {
+            const String& string(v.GetString());
+            duk_push_lstring(ctx, string.CString(), string.Length());
+        }   break;
 
-    case VAR_COLOR:
-    {
-        const Color& color(v.GetColor());
-        duk_push_array(ctx);
-        duk_push_number(ctx, color.r_);
-        duk_put_prop_index(ctx, -2, 0);
-        duk_push_number(ctx, color.g_);
-        duk_put_prop_index(ctx, -2, 1);
-        duk_push_number(ctx, color.b_);
-        duk_put_prop_index(ctx, -2, 2);
-        duk_push_number(ctx, color.a_);
-        duk_put_prop_index(ctx, -2, 3);
-    }   break;
+        case VAR_BUFFER:
+        {
+            const PODVector<unsigned char>& buffer(v.GetBuffer()); // The braces are to scope this reference.
+            duk_push_fixed_buffer(ctx, buffer.Size());
+            duk_push_buffer_object(ctx, -1, 0, buffer.Size(), DUK_BUFOBJ_UINT8ARRAY);
+            duk_replace(ctx, -2);
+            unsigned char* data = (unsigned char*)duk_require_buffer_data(ctx, -1, (duk_size_t*)nullptr);
+            memcpy(data, buffer.Buffer(), buffer.Size());
+        }   break;
+
+        case VAR_VECTOR2:
+        {
+            const Vector2& vector2(v.GetVector2());
+            duk_push_array(ctx);
+            duk_push_number(ctx, vector2.x_);
+            duk_put_prop_index(ctx, -2, 0);
+            duk_push_number(ctx, vector2.y_);
+            duk_put_prop_index(ctx, -2, 1);
+        }   break;
+
+        case VAR_INTVECTOR2:
+        {
+            const IntVector2& intVector2(v.GetIntVector2());
+            duk_push_array(ctx);
+            duk_push_number(ctx, intVector2.x_);
+            duk_put_prop_index(ctx, -2, 0);
+            duk_push_number(ctx, intVector2.y_);
+            duk_put_prop_index(ctx, -2, 1);
+        }   break;
+
+        case VAR_VECTOR3:
+        {
+            const Vector3& vector3(v.GetVector3());
+            duk_push_array(ctx);
+            duk_push_number(ctx, vector3.x_);
+            duk_put_prop_index(ctx, -2, 0);
+            duk_push_number(ctx, vector3.y_);
+            duk_put_prop_index(ctx, -2, 1);
+            duk_push_number(ctx, vector3.z_);
+            duk_put_prop_index(ctx, -2, 2);
+        }   break;
+
+        case VAR_QUATERNION:
+        {
+            const Vector3& vector3(v.GetQuaternion().EulerAngles());
+            duk_push_array(ctx);
+            duk_push_number(ctx, vector3.x_);
+            duk_put_prop_index(ctx, -2, 0);
+            duk_push_number(ctx, vector3.y_);
+            duk_put_prop_index(ctx, -2, 1);
+            duk_push_number(ctx, vector3.z_);
+            duk_put_prop_index(ctx, -2, 2);
+        }   break;
+
+        case VAR_COLOR:
+        {
+            const Color& color(v.GetColor());
+            duk_push_array(ctx);
+            duk_push_number(ctx, color.r_);
+            duk_put_prop_index(ctx, -2, 0);
+            duk_push_number(ctx, color.g_);
+            duk_put_prop_index(ctx, -2, 1);
+            duk_push_number(ctx, color.b_);
+            duk_put_prop_index(ctx, -2, 2);
+            duk_push_number(ctx, color.a_);
+            duk_put_prop_index(ctx, -2, 3);
+        }   break;
+
+        case VAR_VECTOR4:
+        {
+            const Vector4& vector4(v.GetVector4());
+            duk_push_array(ctx);
+            duk_push_number(ctx, vector4.x_);
+            duk_put_prop_index(ctx, -2, 0);
+            duk_push_number(ctx, vector4.y_);
+            duk_put_prop_index(ctx, -2, 1);
+            duk_push_number(ctx, vector4.z_);
+            duk_put_prop_index(ctx, -2, 2);
+            duk_push_number(ctx, vector4.w_);
+            duk_put_prop_index(ctx, -2, 3);
+        }   break;
+
+        case VAR_VARIANTVECTOR:
+        {
+            const VariantVector& vector(v.GetVariantVector());
+
+            // if we don't specify an array index, wrap and push the vector (EXPENSIVE!)
+            if (arrayIndex == -1)
+            {
+                SharedPtr<ScriptVector> scriptVector(new ScriptVector());
+                scriptVector->AdaptFromVector(vector);
+                js_push_class_object_instance(ctx, scriptVector);
+            }
+            else
+            {
+                if (arrayIndex < 0 || arrayIndex >= vector.Size())
+                {
+                    duk_push_undefined(ctx);
+                }
+                else
+                {
+                    // recursively push the variant
+                    js_push_variant(ctx, vector[arrayIndex]);
+                }
+            }
 
-    case VAR_VECTOR4:
-    {
-        const Vector4& vector4(v.GetVector4());
-        duk_push_array(ctx);
-        duk_push_number(ctx, vector4.x_);
-        duk_put_prop_index(ctx, -2, 0);
-        duk_push_number(ctx, vector4.y_);
-        duk_put_prop_index(ctx, -2, 1);
-        duk_push_number(ctx, vector4.z_);
-        duk_put_prop_index(ctx, -2, 2);
-        duk_push_number(ctx, vector4.w_);
-        duk_put_prop_index(ctx, -2, 3);
-    }   break;
+        }   break;
 
-    default:
-        duk_push_undefined(ctx);
-        break;
-    }
+        default:
+            duk_push_undefined(ctx);
+            break;
+        }
 
 
-}
+    }
 
 
 }

+ 5 - 1
Source/AtomicJS/Javascript/JSAPI.h

@@ -58,9 +58,13 @@ void js_class_get_constructor(duk_context* ctx, const char* package, const char
 void js_define_native_event(duk_context* ctx, const String& eventType, const String& eventName);
 
 /// Pushes variant value or undefined if can't be pushed
-void js_push_variant(duk_context* ctx, const Variant &v);
+void js_push_variant(duk_context* ctx, const Variant &v, int arrayIndex = -1);
 void js_push_variantmap(duk_context* ctx, const VariantMap &vmap);
 
+// Push a default value for the given variant type and set variantOut to the pushed value
+void js_push_default_variant(duk_context* ctx, VariantType variantType, Variant& variantOut);
+
+/// Sets a variant value from the duktape stack
 void js_to_variant(duk_context* ctx, int variantIdx, Variant &v, VariantType variantType = VAR_NONE);
 
 void js_object_to_variantmap(duk_context* ctx, int objIdx, VariantMap &v);

+ 1 - 1
Source/AtomicJS/Javascript/JSComponent.cpp

@@ -190,7 +190,7 @@ void JSComponent::InitInstance(bool hasArgs, int argIdx)
             {
                 Variant& v = fieldValues_[itr->first_];
 
-                if (v.GetType() == itr->second_)
+                if (v.GetType() == itr->second_.variantType_)
                 {
                     js_push_variant(ctx, v);
                     duk_put_prop_string(ctx, -2, itr->first_.CString());

+ 1 - 1
Source/AtomicJS/Javascript/JSComponentFile.cpp

@@ -415,7 +415,7 @@ bool JSComponentFile::BeginLoad(Deserializer& source)
 
                     if (variantType != VAR_NONE)
                     {
-                        AddField(name, variantType);
+                        AddField(name, variantType, false);
                     }
 
                     duk_pop_2(ctx);  // pop key value

+ 426 - 291
Source/AtomicJS/Javascript/JSSceneSerializable.cpp

@@ -27,6 +27,7 @@
 
 // These serialization functions need to operate on various script classes
 // including JS and C#, so use the base classes and avoid bringing in derived specifics
+#include <Atomic/Script/ScriptVector.h>
 #include <Atomic/Script/ScriptComponent.h>
 #include <Atomic/Script/ScriptComponentFile.h>
 
@@ -37,429 +38,563 @@
 namespace Atomic
 {
 
-/*
-    /// Attribute type.
-    VariantType type_;
-    /// Name.
-    String name_;
-    /// Byte offset from start of object.
-    unsigned offset_;
-    /// Enum names.
-    const char** enumNames_;
-    /// Helper object for accessor mode.
-    SharedPtr<AttributeAccessor> accessor_;
-    /// Default value for network replication.
-    Variant defaultValue_;
-    /// Attribute mode: whether to use for serialization, network replication, or both.
-    unsigned mode_;
-    /// Attribute data pointer if elsewhere than in the Serializable.
-    void* ptr_;
-
-*/
-
-static int Serializable_SetAttribute(duk_context* ctx)
-{
-    const char* name = duk_to_string(ctx, 0);
+    /*
+        /// Attribute type.
+        VariantType type_;
+        /// Name.
+        String name_;
+        /// Byte offset from start of object.
+        unsigned offset_;
+        /// Enum names.
+        const char** enumNames_;
+        /// Helper object for accessor mode.
+        SharedPtr<AttributeAccessor> accessor_;
+        /// Default value for network replication.
+        Variant defaultValue_;
+        /// Attribute mode: whether to use for serialization, network replication, or both.
+        unsigned mode_;
+        /// Attribute data pointer if elsewhere than in the Serializable.
+        void* ptr_;
+
+    */
+
+    static int Serializable_SetAttribute(duk_context* ctx)
+    {
+        const char* name = duk_to_string(ctx, 0);
 
-    duk_push_this(ctx);
-    Serializable* serial = js_to_class_instance<Serializable>(ctx, -1, 0);
+        // for setting array values
+        int arrayIndex = -1;
+        if (duk_get_top(ctx) > 2)
+        {
+            float _arrayIndex = (float) duk_get_number(ctx, 2);
+            if (_arrayIndex >= 0)
+                arrayIndex = _arrayIndex;
+        }
 
-    const Vector<AttributeInfo>* attributes = serial->GetAttributes();
+        duk_push_this(ctx);
+        Serializable* serial = js_to_class_instance<Serializable>(ctx, -1, 0);
 
-    VariantType variantType = VAR_NONE;
+        const Vector<AttributeInfo>* attributes = serial->GetAttributes();
 
-    bool isAttr = false;
+        VariantType variantType = VAR_NONE;
+        VariantType arrayVariantType = VAR_NONE;
 
-    if (attributes)
-    {
-        for (unsigned i = 0; i < attributes->Size(); i++)
-        {
-            const AttributeInfo* attr = &attributes->At(i);
+        bool isAttr = false;
 
-            if (!attr->name_.Compare(name))
+        if (attributes)
+        {
+            for (unsigned i = 0; i < attributes->Size(); i++)
             {
-                isAttr = true;
-                variantType = attr->type_;
-                break;
+                const AttributeInfo* attr = &attributes->At(i);
+
+                if (!attr->name_.Compare(name))
+                {
+                    isAttr = true;
+                    variantType = attr->type_;
+                    break;
+                }
             }
         }
-    }
 
 
-    Variant v;
-    js_to_variant(ctx, 1, v, variantType);
+        Variant v;
+        js_to_variant(ctx, 1, v, variantType);
 
-    ScriptComponent* jsc = NULL;
+        ScriptComponent* jsc = NULL;
 
-    // check dynamic
-    if (!isAttr)
-    {
-        if (serial->GetBaseType() == ScriptComponent::GetTypeStatic())
+        // check dynamic
+        if (!isAttr)
         {
-
-            jsc = (ScriptComponent*) serial;
-            ScriptComponentFile* file = jsc->GetComponentFile();
-
-            if (file)
+            if (serial->GetBaseType() == ScriptComponent::GetTypeStatic())
             {
-                const String& className = jsc->GetComponentClassName();
 
-                const HashMap<String, VariantType>& fields = file->GetFields(className);
-                const HashMap<String, Vector<EnumInfo>>& enums = file->GetEnums(className);
+                jsc = (ScriptComponent*)serial;
+                ScriptComponentFile* file = jsc->GetComponentFile();
 
-                if (VariantType *fvType = fields[name])
+                if (file)
                 {
-                    variantType = *fvType;
+                    const String& className = jsc->GetComponentClassName();
+
+                    const FieldMap& fields = file->GetFields(className);
+                    const HashMap<String, Vector<EnumInfo>>& enums = file->GetEnums(className);
 
-                    if (enums.Contains(name))
+                    if (FieldInfo *finfo = fields[name])
                     {
-                        int idx = (int) v.GetFloat();
+                        variantType = finfo->variantType_;
 
-                        if (idx > 0 && idx < enums[name]->Size())
+                        if (finfo->isArray_)
                         {
-                            VariantMap& values = jsc->GetFieldValues();
-                            values[name] = enums[name]->At(idx).value_;
-                            return 0;
+                            arrayVariantType = variantType;
+                            variantType = VAR_VARIANTVECTOR;
+                        }
+                        else if (enums.Contains(name))
+                        {
+                            int idx = (int)v.GetFloat();
+
+                            if (idx > 0 && idx < enums[name]->Size())
+                            {
+                                VariantMap& values = jsc->GetFieldValues();
+                                values[name] = enums[name]->At(idx).value_;
+                                return 0;
+                            }
                         }
                     }
                 }
             }
         }
-    }
 
-    if (variantType == VAR_NONE)
-        return 0;
-
-    if (variantType == VAR_QUATERNION)
-    {
-        Vector3 v3 = v.GetVector3();
-        Quaternion q;
-        q.FromEulerAngles(v3.x_, v3.y_, v3.z_);
-        v = q;
-    }
+        if (variantType == VAR_NONE)
+            return 0;
 
-    else if (variantType == VAR_COLOR)
-    {
-        Vector4 v4 = v.GetVector4();
-        Color c(v4.x_, v4.y_, v4.z_, v4.w_ );
-        v = c;
-    }
-    else if (variantType == VAR_INT)
-    {
-        v = (int) v.GetFloat();
-    }
-    else if (variantType == VAR_RESOURCEREF)
-    {
-        RefCounted* ref = v.GetPtr();
-
-        if (ref && ref->IsObject())
+        if (variantType == VAR_QUATERNION)
         {
-            Object* o = (Object*) ref;
+            Vector3 v3 = v.GetVector3();
+            Quaternion q;
+            q.FromEulerAngles(v3.x_, v3.y_, v3.z_);
+            v = q;
+        }
 
-            // TODO: calling code must ensure we are a resource, can this be done here?
-            Resource* resource = (Resource*) o;
+        else if (variantType == VAR_COLOR)
+        {
+            Vector4 v4 = v.GetVector4();
+            Color c(v4.x_, v4.y_, v4.z_, v4.w_);
+            v = c;
+        }
+        else if (variantType == VAR_INT)
+        {
+            v = (int)v.GetFloat();
+        }
+        else if (variantType == VAR_RESOURCEREF)
+        {
+            RefCounted* ref = v.GetPtr();
 
-            v = ResourceRef(resource->GetType(), resource->GetName());
+            if (ref && ref->IsObject())
+            {
+                Object* o = (Object*)ref;
 
-        }
+                // TODO: calling code must ensure we are a resource, can this be done here?
+                Resource* resource = (Resource*)o;
 
-    }    
+                v = ResourceRef(resource->GetType(), resource->GetName());
 
-    if (isAttr)
-    {
-        serial->SetAttribute(name, v);
-        return 0;
-    }
+            }
 
-    // check dynamic
-    if (jsc)
-    {
-        VariantMap& values = jsc->GetFieldValues();
-        values[name] = v;
-    }
+        }
+        else if (variantType == VAR_VARIANTVECTOR)
+        {
+            if (arrayIndex >= 0)
+            {
+                const VariantMap& values = jsc->GetFieldValues();
+                Variant *v2 = values[name];
 
-    return 0;
-}
+                // we're setting an index value
+                if (v2 && v2->GetType() == VAR_VARIANTVECTOR)
+                {
+                    if (arrayIndex < v2->GetVariantVector().Size())
+                    {
+                        VariantVector* vector = v2->GetVariantVectorPtr();
 
-static int Serializable_GetAttribute(duk_context* ctx)
-{
-    const char* name = duk_to_string(ctx, 0);
+                        if (v.GetType() == VAR_VECTOR4)
+                        {
+                            if (arrayVariantType == VAR_COLOR)
+                            {
+                                const Vector4& v4 = v.GetVector4();
+                                v = Color(v4.x_, v4.y_, v4.z_, v4.w_);
+                            }
+                            else if (arrayVariantType == VAR_QUATERNION)
+                            {
+                                const Vector4& v4 = v.GetVector4();
+                                v = Quaternion(v4.w_, v4.x_, v4.y_, v4.z_);
+                            }
+                        }
 
-    duk_push_this(ctx);
-    Serializable* serial = js_to_class_instance<Serializable>(ctx, -1, 0);
-    const Vector<AttributeInfo>* attrs = serial->GetAttributes();
+                        if (v.GetType() == VAR_FLOAT)
+                        {
+                            if (arrayVariantType == VAR_INT)
+                                v = (int)v.GetFloat();
+                        }
 
-    if (attrs)
-    {
-        for (unsigned i = 0; i < attrs->Size(); i++)
-        {
-            const AttributeInfo* attr = &attrs->At(i);
+                        (*vector)[arrayIndex] = v;
+                        jsc->GetFieldValues()[name] = *vector;
+                        return 0;
+                    }
+                }
 
-            if (!attr->name_.Compare(name))
+            }
+            else
             {
-                // FIXME: this is a double lookup
-                js_push_variant(ctx,  serial->GetAttribute(name));
-                return 1;
+                ScriptVector* vector = static_cast<ScriptVector*>(v.GetPtr());
+                assert(vector && vector->GetClassID() == ScriptVector::GetClassIDStatic());
+                VariantVector adapter;
+                vector->AdaptToVector(adapter);
+                v = adapter;
             }
         }
+
+        if (isAttr)
+        {
+            serial->SetAttribute(name, v);
+            return 0;
+        }
+
+        // check dynamic
+        if (jsc)
+        {
+            VariantMap& values = jsc->GetFieldValues();
+            values[name] = v;
+        }
+
+        return 0;
     }
 
-    if (serial->GetBaseType() == ScriptComponent::GetTypeStatic())
+    static int Serializable_GetAttribute(duk_context* ctx)
     {
-        ScriptComponent* jsc = (ScriptComponent*) serial;
-        ScriptComponentFile* file = jsc->GetComponentFile();
+        const char* name = duk_to_string(ctx, 0);
 
-        if (file)
+        // for getting array values
+        int arrayIndex = -1;
+        if (duk_get_top(ctx) > 1)
         {
-            const String& componentClassName = jsc->GetComponentClassName();
+            int _arrayIndex = (int)duk_get_number(ctx, 1);
+            if (_arrayIndex >= 0)
+                arrayIndex = _arrayIndex;
+        }
 
-            const FieldMap& fields = file->GetFields(componentClassName);
+        duk_push_this(ctx);
+        Serializable* serial = js_to_class_instance<Serializable>(ctx, -1, 0);
+        const Vector<AttributeInfo>* attrs = serial->GetAttributes();
 
-            if (fields.Contains(name))
+        if (attrs)
+        {
+            for (unsigned i = 0; i < attrs->Size(); i++)
             {
-                const VariantMap& values = jsc->GetFieldValues();
+                const AttributeInfo* attr = &attrs->At(i);
 
-                if (Variant* vptr = values[name])
+                if (!attr->name_.Compare(name))
                 {
-                    js_push_variant(ctx,  *vptr);
+                    // FIXME: this is a double lookup
+                    js_push_variant(ctx, serial->GetAttribute(name));
                     return 1;
                 }
-                else
+            }
+        }
+
+        if (serial->GetBaseType() == ScriptComponent::GetTypeStatic())
+        {
+            ScriptComponent* jsc = (ScriptComponent*)serial;
+            ScriptComponentFile* file = jsc->GetComponentFile();
+
+            if (file)
+            {
+                const String& componentClassName = jsc->GetComponentClassName();
+
+                const FieldMap& fields = file->GetFields(componentClassName);
+
+                FieldInfo* finfo = fields[name];
+
+                if (finfo)
                 {
-                    Variant v;
-                    file->GetDefaultFieldValue(name, v, componentClassName);
-                    js_push_variant(ctx,  v);
-                    return 1;
+                    const VariantMap& values = jsc->GetFieldValues();
+
+                    if (Variant* vptr = values[name])
+                    {
+                        if (finfo->isArray_ && arrayIndex >= 0)
+                        {
+                            assert(vptr->GetType() == VAR_VARIANTVECTOR);
+
+                            VariantVector* vector = vptr->GetVariantVectorPtr();
+
+                            if (arrayIndex >= vector->Size())
+                            {
+                                duk_push_undefined(ctx);
+                                return 1;
+                            }
+
+                            const Variant& current = (*vector)[arrayIndex];
+
+                            if (current.GetType() != finfo->variantType_)
+                            {
+                                Variant value;
+                                js_push_default_variant(ctx, finfo->variantType_, value);
+                                (*vector)[arrayIndex] = value;
+                            }
+                            else
+                            {
+                                js_push_variant(ctx, current, arrayIndex);
+                            }
+                        }
+                        else
+                        {
+                            js_push_variant(ctx, *vptr, arrayIndex);
+                        }
+
+                        return 1;
+                    }
+                    else
+                    {
+                        if (finfo->isArray_)
+                        {
+                            if (arrayIndex < 0)
+                            {
+                                SharedPtr<ScriptVector> vector(new ScriptVector());
+                                js_push_class_object_instance(ctx, vector);
+                                return 1;
+                            }
+                            else
+                            {
+                                Variant value;
+                                js_push_default_variant(ctx, finfo->variantType_, value);
+
+                                VariantVector newVector;
+
+                                if (arrayIndex >= newVector.Size())
+                                {
+                                    newVector.Resize(arrayIndex + 1);
+                                }
+
+                                jsc->GetFieldValues()[name] = newVector;
+
+                                return 1;
+                            }
+                        }
+
+                        Variant v;
+                        file->GetDefaultFieldValue(name, v, componentClassName);
+                        js_push_variant(ctx, v);
+                        return 1;
+                    }
                 }
             }
         }
-    }
 
-    duk_push_undefined(ctx);
-    return 1;
-}
+        duk_push_undefined(ctx);
+        return 1;
+    }
 
-static void GetDynamicAttributes(duk_context* ctx, unsigned& count, const VariantMap& defaultFieldValues,
-                                 const FieldMap& fields,
-                                 const EnumMap& enums, 
-                                 const FieldTooltipMap& tooltips)
-{
-    if (fields.Size())
+    static void GetDynamicAttributes(duk_context* ctx, unsigned& count, const VariantMap& defaultFieldValues,
+        const FieldMap& fields,
+        const EnumMap& enums,
+        const FieldTooltipMap& tooltips)
     {
-        HashMap<String, VariantType>::ConstIterator itr = fields.Begin();
-        while (itr != fields.End())
+        if (fields.Size())
         {
-            duk_push_object(ctx);
+            HashMap<String, FieldInfo>::ConstIterator itr = fields.Begin();
+            while (itr != fields.End())
+            {
+                duk_push_object(ctx);
 
-            duk_push_number(ctx, (double) itr->second_);
-            duk_put_prop_string(ctx, -2, "type");
+                duk_push_number(ctx, (double)itr->second_.variantType_);
+                duk_put_prop_string(ctx, -2, "type");
 
-            if (itr->second_ == VAR_RESOURCEREF && defaultFieldValues.Contains(itr->first_))
-            {
-                if (defaultFieldValues[itr->first_]->GetType() == VAR_RESOURCEREF)
+                if (itr->second_.variantType_ == VAR_RESOURCEREF && defaultFieldValues.Contains(itr->first_))
                 {
-                    const ResourceRef& ref = defaultFieldValues[itr->first_]->GetResourceRef();
-                    const String& typeName = JSVM::GetJSVM(ctx)->GetContext()->GetTypeName(ref.type_);
-
-                    if (typeName.Length())
+                    if (defaultFieldValues[itr->first_]->GetType() == VAR_RESOURCEREF)
                     {
-                        duk_push_string(ctx, typeName.CString());
-                        duk_put_prop_string(ctx, -2, "resourceTypeName");
+                        const ResourceRef& ref = defaultFieldValues[itr->first_]->GetResourceRef();
+                        const String& typeName = JSVM::GetJSVM(ctx)->GetContext()->GetTypeName(ref.type_);
 
+                        if (typeName.Length())
+                        {
+                            duk_push_string(ctx, typeName.CString());
+                            duk_put_prop_string(ctx, -2, "resourceTypeName");
+
+                        }
                     }
                 }
-            }
 
-            duk_push_string(ctx, itr->first_.CString());
-            duk_put_prop_string(ctx, -2, "name");
+                duk_push_string(ctx, itr->first_.CString());
+                duk_put_prop_string(ctx, -2, "name");
 
-            duk_push_number(ctx, (double) AM_DEFAULT);
-            duk_put_prop_string(ctx, -2, "mode");
+                duk_push_number(ctx, (double)AM_DEFAULT);
+                duk_put_prop_string(ctx, -2, "mode");
 
-            duk_push_string(ctx,"");
-            duk_put_prop_string(ctx, -2, "defaultValue");
+                duk_push_string(ctx, "");
+                duk_put_prop_string(ctx, -2, "defaultValue");
 
-            duk_push_boolean(ctx, 1);
-            duk_put_prop_string(ctx, -2, "dynamic");
+                duk_push_boolean(ctx, 1);
+                duk_put_prop_string(ctx, -2, "dynamic");
 
-            if (tooltips.Contains(itr->first_))
-            {
-                duk_push_string(ctx, tooltips[itr->first_]->CString());
-                duk_put_prop_string(ctx, -2, "tooltip");
-            }
+                duk_push_boolean(ctx, itr->second_.isArray_ ? 1 : 0);
+                duk_put_prop_string(ctx, -2, "isArray");
 
-            duk_push_array(ctx);
+                if (tooltips.Contains(itr->first_))
+                {
+                    duk_push_string(ctx, tooltips[itr->first_]->CString());
+                    duk_put_prop_string(ctx, -2, "tooltip");
+                }
 
-            if (enums.Contains(itr->first_))
-            {
-                unsigned enumCount = 0;
-                const Vector<EnumInfo>* infos = enums[itr->first_];
-                Vector<EnumInfo>::ConstIterator eitr = infos->Begin();
+                duk_push_array(ctx);
 
-                while (eitr != infos->End())
+                if (enums.Contains(itr->first_))
                 {
-                    duk_push_string(ctx, eitr->name_.CString());
-                    duk_put_prop_index(ctx, -2, enumCount++);
-                    eitr++;
-                }
+                    unsigned enumCount = 0;
+                    const Vector<EnumInfo>* infos = enums[itr->first_];
+                    Vector<EnumInfo>::ConstIterator eitr = infos->Begin();
 
-            }
+                    while (eitr != infos->End())
+                    {
+                        duk_push_string(ctx, eitr->name_.CString());
+                        duk_put_prop_index(ctx, -2, enumCount++);
+                        eitr++;
+                    }
+
+                }
 
-            duk_put_prop_string(ctx, -2, "enumNames");
+                duk_put_prop_string(ctx, -2, "enumNames");
 
-            // store attr object
-            duk_put_prop_index(ctx, -2, count++);
+                // store attr object
+                duk_put_prop_index(ctx, -2, count++);
 
-            itr++;
+                itr++;
+            }
         }
     }
-}
 
 
 
-static int Serializable_GetAttributes(duk_context* ctx)
-{
-    duk_push_this(ctx);
-    Serializable* serial = js_to_class_instance<Serializable>(ctx, -1, 0);
-    unsigned type = serial->GetType().Value();
+    static int Serializable_GetAttributes(duk_context* ctx)
+    {
+        duk_push_this(ctx);
+        Serializable* serial = js_to_class_instance<Serializable>(ctx, -1, 0);
+        unsigned type = serial->GetType().Value();
 
-    duk_get_global_string(ctx, "__atomic_scene_serializable_attributes");
-    duk_get_prop_index(ctx, -1, type);
+        duk_get_global_string(ctx, "__atomic_scene_serializable_attributes");
+        duk_get_prop_index(ctx, -1, type);
 
-    // return cached array of attrinfo, unless JSComponent which has dynamic fields
-    if (serial->GetBaseType() != ScriptComponent::GetTypeStatic() && duk_is_object(ctx, -1))
-        return 1;
+        // return cached array of attrinfo, unless JSComponent which has dynamic fields
+        if (serial->GetBaseType() != ScriptComponent::GetTypeStatic() && duk_is_object(ctx, -1))
+            return 1;
 
-    const Vector<AttributeInfo>* attrs = serial->GetAttributes();
+        const Vector<AttributeInfo>* attrs = serial->GetAttributes();
 
-    duk_push_array(ctx);
-    duk_dup(ctx, -1);
-    duk_put_prop_index(ctx, -4, type);
+        duk_push_array(ctx);
+        duk_dup(ctx, -1);
+        duk_put_prop_index(ctx, -4, type);
 
-    unsigned count = 0;
-    if (attrs)
-    {
-        count = attrs->Size();
-        for (unsigned i = 0; i < attrs->Size(); i++)
+        unsigned count = 0;
+        if (attrs)
         {
-            const AttributeInfo* attr = &attrs->At(i);
+            count = attrs->Size();
+            for (unsigned i = 0; i < attrs->Size(); i++)
+            {
+                const AttributeInfo* attr = &attrs->At(i);
 
-            if (attr->mode_ & AM_NOEDIT)
-                continue;
+                if (attr->mode_ & AM_NOEDIT)
+                    continue;
 
-            duk_push_object(ctx);
+                duk_push_object(ctx);
 
-            duk_push_number(ctx, (double) attr->type_);
-            duk_put_prop_string(ctx, -2, "type");
+                duk_push_number(ctx, (double)attr->type_);
+                duk_put_prop_string(ctx, -2, "type");
 
-            if (attr->type_ == VAR_RESOURCEREF)
-            {
-                if (attr->defaultValue_.GetType() == VAR_RESOURCEREF)
+                if (attr->type_ == VAR_RESOURCEREF)
                 {
-                    const ResourceRef& ref = attr->defaultValue_.GetResourceRef();
-                    const String& typeName = serial->GetContext()->GetTypeName(ref.type_);
-
-                    if (typeName.Length())
+                    if (attr->defaultValue_.GetType() == VAR_RESOURCEREF)
                     {
-                        duk_push_string(ctx, typeName.CString());
-                        duk_put_prop_string(ctx, -2, "resourceTypeName");
+                        const ResourceRef& ref = attr->defaultValue_.GetResourceRef();
+                        const String& typeName = serial->GetContext()->GetTypeName(ref.type_);
+
+                        if (typeName.Length())
+                        {
+                            duk_push_string(ctx, typeName.CString());
+                            duk_put_prop_string(ctx, -2, "resourceTypeName");
 
+                        }
                     }
-                }
 
-            }
+                }
 
-            if (attr->type_ == VAR_RESOURCEREFLIST)
-            {
-                if (attr->defaultValue_.GetType() == VAR_RESOURCEREFLIST)
+                if (attr->type_ == VAR_RESOURCEREFLIST)
                 {
-                    const ResourceRefList& ref = attr->defaultValue_.GetResourceRefList();
-                    const String& typeName = serial->GetContext()->GetTypeName(ref.type_);
-
-                    if (typeName.Length())
+                    if (attr->defaultValue_.GetType() == VAR_RESOURCEREFLIST)
                     {
-                        duk_push_string(ctx, typeName.CString());
-                        duk_put_prop_string(ctx, -2, "resourceTypeName");
+                        const ResourceRefList& ref = attr->defaultValue_.GetResourceRefList();
+                        const String& typeName = serial->GetContext()->GetTypeName(ref.type_);
+
+                        if (typeName.Length())
+                        {
+                            duk_push_string(ctx, typeName.CString());
+                            duk_put_prop_string(ctx, -2, "resourceTypeName");
 
+                        }
                     }
-                }
 
-            }
+                }
 
 
-            duk_push_string(ctx, attr->name_.CString());
-            duk_put_prop_string(ctx, -2, "name");
+                duk_push_string(ctx, attr->name_.CString());
+                duk_put_prop_string(ctx, -2, "name");
 
-            duk_push_number(ctx, (double) attr->mode_);
-            duk_put_prop_string(ctx, -2, "mode");
+                duk_push_number(ctx, (double)attr->mode_);
+                duk_put_prop_string(ctx, -2, "mode");
 
-            duk_push_string(ctx,attr->defaultValue_.ToString().CString());
-            duk_put_prop_string(ctx, -2, "defaultValue");
+                duk_push_string(ctx, attr->defaultValue_.ToString().CString());
+                duk_put_prop_string(ctx, -2, "defaultValue");
 
-            duk_push_boolean(ctx, 0);
-            duk_put_prop_string(ctx, -2, "dynamic");
+                duk_push_boolean(ctx, 0);
+                duk_put_prop_string(ctx, -2, "dynamic");
 
-            duk_push_array(ctx);
+                duk_push_array(ctx);
 
-            const char** enumPtr = attr->enumNames_;
-            unsigned enumCount = 0;
+                const char** enumPtr = attr->enumNames_;
+                unsigned enumCount = 0;
 
-            if (enumPtr)
-            {
-                while (*enumPtr)
+                if (enumPtr)
                 {
-                    duk_push_string(ctx, *enumPtr);
-                    duk_put_prop_index(ctx, -2, enumCount++);
-                    enumPtr++;
+                    while (*enumPtr)
+                    {
+                        duk_push_string(ctx, *enumPtr);
+                        duk_put_prop_index(ctx, -2, enumCount++);
+                        enumPtr++;
+                    }
                 }
-            }
 
-            duk_put_prop_string(ctx, -2, "enumNames");
+                duk_put_prop_string(ctx, -2, "enumNames");
 
-            // store attr object
-            duk_put_prop_index(ctx, -2, i);
+                // store attr object
+                duk_put_prop_index(ctx, -2, i);
+            }
         }
-    }
-
-    // dynamic script fields
-    if (serial->GetBaseType() == ScriptComponent::GetTypeStatic())
-    {
-        ScriptComponent* jsc = (ScriptComponent*) serial;
-        ScriptComponentFile* file = jsc->GetComponentFile();
 
-        if (file)
+        // dynamic script fields
+        if (serial->GetBaseType() == ScriptComponent::GetTypeStatic())
         {
+            ScriptComponent* jsc = (ScriptComponent*)serial;
+            ScriptComponentFile* file = jsc->GetComponentFile();
 
-            const String& className = jsc->GetComponentClassName();
-            const VariantMap& defaultFieldValues = file->GetDefaultFieldValues(className);
-            const FieldMap& fields =  file->GetFields(className);
-            const FieldTooltipMap& fieldTooltips = file->GetFieldTooltips(className);
-            const EnumMap& enums = file->GetEnums(className);
+            if (file)
+            {
 
-            GetDynamicAttributes(ctx, count, defaultFieldValues, fields, enums, fieldTooltips);
+                const String& className = jsc->GetComponentClassName();
+                const VariantMap& defaultFieldValues = file->GetDefaultFieldValues(className);
+                const FieldMap& fields = file->GetFields(className);
+                const FieldTooltipMap& fieldTooltips = file->GetFieldTooltips(className);
+                const EnumMap& enums = file->GetEnums(className);
+
+                GetDynamicAttributes(ctx, count, defaultFieldValues, fields, enums, fieldTooltips);
+            }
         }
-    }
 
-    return 1;
-}
+        return 1;
+    }
 
-void jsapi_init_scene_serializable(JSVM* vm)
-{
-    duk_context* ctx = vm->GetJSContext();
+    void jsapi_init_scene_serializable(JSVM* vm)
+    {
+        duk_context* ctx = vm->GetJSContext();
 
-    // cached attr
-    duk_push_object(ctx);
-    duk_put_global_string(ctx, "__atomic_scene_serializable_attributes");
+        // cached attr
+        duk_push_object(ctx);
+        duk_put_global_string(ctx, "__atomic_scene_serializable_attributes");
 
-    js_class_get_prototype(ctx, "Atomic", "Serializable");
-    duk_push_c_function(ctx, Serializable_GetAttributes, 0);
-    duk_put_prop_string(ctx, -2, "getAttributes");
-    duk_push_c_function(ctx, Serializable_GetAttribute, 1);
-    duk_put_prop_string(ctx, -2, "getAttribute");
-    duk_push_c_function(ctx, Serializable_SetAttribute, 2);
-    duk_put_prop_string(ctx, -2, "setAttribute");
-    duk_pop(ctx);
+        js_class_get_prototype(ctx, "Atomic", "Serializable");
+        duk_push_c_function(ctx, Serializable_GetAttributes, 0);
+        duk_put_prop_string(ctx, -2, "getAttributes");
+        duk_push_c_function(ctx, Serializable_GetAttribute, DUK_VARARGS);
+        duk_put_prop_string(ctx, -2, "getAttribute");
+        duk_push_c_function(ctx, Serializable_SetAttribute, DUK_VARARGS);
+        duk_put_prop_string(ctx, -2, "setAttribute");
+        duk_pop(ctx);
 
-}
+    }
 
 }

+ 22 - 17
Source/AtomicNET/NETScript/CSComponentAssembly.cpp

@@ -61,6 +61,7 @@ namespace Atomic
         typeMap_["Vector4"] = VAR_VECTOR4;
         typeMap_["Quaternion"] = VAR_QUATERNION;
         typeMap_["IntVector2"] = VAR_INTVECTOR2;
+        typeMap_["Color"] = VAR_COLOR;
 
     }
 
@@ -91,7 +92,8 @@ namespace Atomic
                 VariantType varType = VAR_NONE;
 
                 bool isEnum = jfield.Get("isEnum").GetBool();
-                String typeName = jfield.Get("typeName").GetString();
+                bool isArray = jfield.Get("isArray").GetBool();
+                String typeName = jfield.Get("typeName").GetString();               
                 String fieldName = jfield.Get("name").GetString();
                 String defaultValue = jfield.Get("defaultValue").GetString();
                 String tooltip;
@@ -156,30 +158,33 @@ namespace Atomic
 
                 }
 
-                if (!defaultValue.Length() && varType == VAR_RESOURCEREF)
+                if (!isArray)
                 {
-                    // We still need a default value for ResourceRef's so we know the classtype
-                    AddDefaultValue(fieldName, ResourceRef(typeName), className);
-                }
-                else
-                {
-                    Variant value;
-
-                    if (varType == VAR_RESOURCEREF)
+                    if (!defaultValue.Length() && varType == VAR_RESOURCEREF)
                     {
-                        ResourceRef rref(typeName);
-                        rref.name_ = defaultValue;
-                        value = rref;
+                        // We still need a default value for ResourceRef's so we know the classtype
+                        AddDefaultValue(fieldName, ResourceRef(typeName), className);
                     }
                     else
                     {
-                        value.FromString(varType, defaultValue);
-                    }
+                        Variant value;
+
+                        if (varType == VAR_RESOURCEREF)
+                        {
+                            ResourceRef rref(typeName);
+                            rref.name_ = defaultValue;
+                            value = rref;
+                        }
+                        else
+                        {
+                            value.FromString(varType, defaultValue);
+                        }
 
-                    AddDefaultValue(fieldName, value, className);
+                        AddDefaultValue(fieldName, value, className);
+                    }
                 }
 
-                AddField(fieldName, varType, className, tooltip);
+                AddField(fieldName, varType, isArray, className, tooltip);
 
             }
 

+ 0 - 7
Source/ThirdParty/TurboBadger/tb_widgets.h

@@ -265,13 +265,6 @@ public:
     /** Set both min max and preferred height to the given height. */
     void SetHeight(int height) { min_h = max_h = pref_h = height; }
 
-    // ATOMIC BEGIN
-    bool operator == (const LayoutParams &lp) const { return min_w == lp.min_w &&
-                min_h == lp.min_h && max_w == lp.max_w && max_h == lp.max_h &&
-                pref_w == lp.pref_w && pref_h == lp.pref_h; }
-    // ATOMIC END
-
-
     int min_w, min_h;			///< The minimal preferred width and height.
     int max_w, max_h;			///< The maximum preferred width and height.
     int pref_w, pref_h;			///< The preferred width and height.

+ 49 - 4
Source/ToolCore/JSBind/CSharp/CSFunctionWriter.cpp

@@ -59,9 +59,14 @@ void CSFunctionWriter::GenNativeCallParameters(String& sig)
 
     Vector<String> args;
 
-    if (parameters.Size())
+    unsigned numParams = parameters.Size();
+
+    if (function_->HasMutatedReturn())
+        numParams--;
+
+    if (numParams)
     {
-        for (unsigned int i = 0; i < parameters.Size(); i++)
+        for (unsigned int i = 0; i < numParams; i++)
         {
             JSBFunctionType* ptype = parameters.At(i);
 
@@ -129,6 +134,14 @@ void CSFunctionWriter::WriteNativeFunction(String& source)
 
     source += "\n";
 
+    if (function_->HasMutatedReturn())
+    {
+        line = ToString("if (!__retValue) return;\n");
+        source += IndentLine(line);
+        line = ToString("VariantVector __retValueVector;\n");
+        source += IndentLine(line);
+    }
+
     // vector marshal
 
     bool hasVectorMarshal = false;
@@ -138,6 +151,10 @@ void CSFunctionWriter::WriteNativeFunction(String& source)
     {
         JSBFunctionType* ftype = fparams[i];
 
+        // skip mutated input param
+        if (function_->HasMutatedReturn() && i == fparams.Size() - 1)
+            break;
+
         // Interface        
         JSBClass* interface = 0;
         if (ftype->type_->asClassType() && ftype->type_->asClassType()->class_->IsInterface())
@@ -166,7 +183,19 @@ void CSFunctionWriter::WriteNativeFunction(String& source)
 
         hasVectorMarshal = true;
 
-        if (vtype->isPODVector_)
+        if (vtype->isVariantVector_)
+        {
+            const String& pname = ftype->name_;
+
+            // TODO: handle early out with return value
+            if (!function_->returnType_)
+                source += IndentLine(ToString("if (!%s) return;\n", pname.CString()));
+
+            source += IndentLine(ToString("VariantVector %s__vector;\n", pname.CString()));
+            source += IndentLine(ToString("%s->AdaptToVector(%s__vector);\n", pname.CString(), pname.CString()));
+
+        }
+        else if (vtype->isPODVector_)
         {
             const String& pname = ftype->name_;
             source += IndentLine(ToString("PODVector<%s*> %s__vector;\n", className.CString(), pname.CString()));
@@ -241,7 +270,17 @@ void CSFunctionWriter::WriteNativeFunction(String& source)
         }
         else
         {
-            line = ToString("%sself->%s(%s);\n", returnStatement.CString(), function_->GetName().CString(), callSig.CString());
+            if (function_->hasMutatedReturn_)
+            {
+                // this handles VariantVector case now, can be expanded
+                line = ToString("__retValueVector = self->%s(%s);\n", function_->GetName().CString(), callSig.CString());
+            }
+            else
+            {
+                line = ToString("%sself->%s(%s);\n", returnStatement.CString(), function_->GetName().CString(), callSig.CString());
+            }
+
+
         }
 
     }
@@ -277,6 +316,12 @@ void CSFunctionWriter::WriteNativeFunction(String& source)
         if (!vtype)
             continue;
 
+        if (function_->HasMutatedReturn() && i == fparams.Size() - 1)
+        {
+            source += IndentLine("__retValue->AdaptFromVector(__retValueVector);\n");
+            break;
+        }
+
         JSBClassType* classType = vtype->vectorType_->asClassType();
 
         if (!classType)

+ 20 - 1
Source/ToolCore/JSBind/JSBFunction.cpp

@@ -32,7 +32,8 @@ JSBFunction::JSBFunction(JSBClass* klass) : class_(klass), returnType_(0),
                                   isConstructor_(false), isDestructor_(false),
                                   isGetter_(false), isSetter_(false),
                                   isOverload_(false), skip_(false),
-                                  isVirtual_(false), isStatic_(false)
+                                  isVirtual_(false), isStatic_(false),
+                                  hasMutatedReturn_(false)
 {
     id_ = idCounter_++;
 }
@@ -45,11 +46,29 @@ void JSBFunction::Process()
         return;
     }
 
+    // methods that return a VariantVector are mutated to take a ScriptVector argument
+    if (!hasMutatedReturn_ && returnType_ && returnType_->type_->asVectorType())
+    {
+        JSBVectorType* vtype = returnType_->type_->asVectorType();
+
+        if (vtype->isVariantVector_)
+        {
+            // mark up as mutated
+            hasMutatedReturn_ = true;
+            JSBFunctionType* ftype = new JSBFunctionType(returnType_->type_);
+            ftype->name_ = "__retValue";
+            parameters_.Push(ftype);
+            returnType_ = 0;
+        }
+    }
+
     // only setup properties for methods which weren't skipped for JS, for example overloads
 
     if (GetSkipLanguage(BINDINGLANGUAGE_JAVASCRIPT))
         return;
 
+
+
     // if not already marked as a getter
     if (!isGetter_)
     {

+ 5 - 1
Source/ToolCore/JSBind/JSBFunction.h

@@ -155,6 +155,9 @@ public:
     bool IsStatic() const { return isStatic_; }
     bool IsInterface() const { return isInterface_; }
 
+    // true if return value has been mutated to be passed in at end of parameters (optimization)
+    bool HasMutatedReturn() const { return hasMutatedReturn_; }
+
     bool Skip(BindingLanguage language = BINDINGLANGUAGE_ANY) const
     {
         if (skip_ || language == BINDINGLANGUAGE_ANY)
@@ -301,7 +304,8 @@ private:
     bool isOverload_;
     bool isVirtual_;
     bool isStatic_;
-    bool skip_;
+    bool hasMutatedReturn_;
+    bool skip_;    
     PODVector<BindingLanguage> skipLanguages_;
 };
 

+ 9 - 1
Source/ToolCore/JSBind/JSBHeaderVisitor.h

@@ -92,7 +92,15 @@ public:
             if (classname.StartsWith("Atomic::"))
                 classname.Replace("Atomic::", "");
 
-            if (classname == "Vector" || classname == "PODVector")
+            if (classname == "VariantVector")
+            {
+                JSBClass* jclass = JSBPackage::GetClassAllPackages("ScriptVariant");
+                assert(jclass);
+
+                jtype = new JSBVectorType(new JSBClassType(jclass), false, true);
+
+            }
+            else if (classname == "Vector" || classname == "PODVector")
             {
                 PODVector<TemplateType> types;
                 unwrapTemplateType(fst, types);

+ 32 - 30
Source/ToolCore/JSBind/JSBType.h

@@ -222,74 +222,76 @@ public:
 
 };
 
-class JSBVectorType : public JSBType
-{
 
+class JSBClassType : public JSBType
+{
 public:
 
-    JSBVectorType(JSBType* vtype, bool podVector = false) : vectorType_(vtype),
-        vectorTypeIsWeakPtr_(false),
-        vectorTypeIsSharedPtr_(false),
-        isPODVector_(podVector) {}
+    JSBClass* class_;
 
-    virtual JSBVectorType* asVectorType() { return this; }
+    virtual JSBClassType* asClassType() { return this; }
 
-    String ToString();
+    JSBClassType(JSBClass* klass) : class_(klass)
+    {
+
+    }
+
+    String ToString()
+    {
+        return class_->GetNativeName();
+    }
 
     virtual bool Match (JSBType* other)
     {
         if (!other)
             return false;
 
-        JSBVectorType* pother = other->asVectorType();
+        JSBClassType* pother = other->asClassType();
 
-        if (!pother || !vectorType_->Match(pother->vectorType_))
+        if (!pother || class_ != pother->class_)
             return false;
 
         return true;
     }
 
-    JSBType* vectorType_;
-    bool vectorTypeIsWeakPtr_;
-    bool vectorTypeIsSharedPtr_;
-    bool isPODVector_;
 
 };
 
-
-
-class JSBClassType : public JSBType
+class JSBVectorType : public JSBType
 {
-public:
 
-    JSBClass* class_;
-
-    virtual JSBClassType* asClassType() { return this; }
+public:
 
-    JSBClassType(JSBClass* klass) : class_(klass)
-    {
+    JSBVectorType(JSBType* vtype, bool podVector = false, bool variantVector = false) : vectorType_(vtype),
+        vectorTypeIsWeakPtr_(false),
+        vectorTypeIsSharedPtr_(false),
+        isPODVector_(podVector),
+        isVariantVector_(variantVector) {}
 
-    }
+    virtual JSBVectorType* asVectorType() { return this; }
 
-    String ToString()
-    {
-        return class_->GetNativeName();
-    }
+    String ToString();
 
     virtual bool Match (JSBType* other)
     {
         if (!other)
             return false;
 
-        JSBClassType* pother = other->asClassType();
+        JSBVectorType* pother = other->asVectorType();
 
-        if (!pother || class_ != pother->class_)
+        if (!pother || !vectorType_->Match(pother->vectorType_))
             return false;
 
         return true;
     }
 
+    JSBType* vectorType_;
+    bool vectorTypeIsWeakPtr_;
+    bool vectorTypeIsSharedPtr_;
+    bool isPODVector_;
+    bool isVariantVector_;
 
 };
 
+
 }

+ 11 - 1
Source/ToolCore/JSBind/JSBTypeScript.cpp

@@ -82,7 +82,10 @@ String JSBTypeScript::GetScriptType(JSBFunctionType* ftype)
 
     if (ftype->type_->asVectorType())
     {
-        scriptType = "string[]";
+        if (ftype->type_->asVectorType()->isVariantVector_)
+            scriptType = "ScriptVector";
+        else
+            scriptType = "string[]";
     }
 
     return scriptType;
@@ -148,6 +151,13 @@ void JSBTypeScript::ExportFunction(JSBFunction* function)
 
         String name = ftype->name_;
 
+        if (function->HasMutatedReturn() && i == parameters.Size() - 1)
+        {
+            // TODO: would be great to type this as Vector<ScriptVariant> somehow
+            scriptType = "ScriptVector";
+            name = "outVector";
+        }
+
         // TS doesn't like arguments named arguments
         if (name == "arguments")
             name = "args";

+ 3 - 1
Source/ToolCore/JSBind/JavaScript/JSClassWriter.cpp

@@ -179,7 +179,9 @@ bool JSClassWriter::OmitFunction(JSBFunction* function)
     {
         JSBFunctionType* ptype = parameters[i];
 
-        if (ptype->type_->asVectorType())
+        JSBVectorType* vtype = ptype->type_->asVectorType();
+
+        if (vtype && !vtype->isVariantVector_)
         {
             if (!ptype->isConst_ || ptype->type_->asVectorType()->isPODVector_)
             {

+ 41 - 14
Source/ToolCore/JSBind/JavaScript/JSFunctionWriter.cpp

@@ -196,10 +196,20 @@ void JSFunctionWriter::WriteParameterMarshal(String& source)
             }
             else if (ptype->type_->asVectorType())
             {
-                // read only vector arguments
-                if (ptype->isConst_)
+                JSBVectorType* vtype = ptype->type_->asVectorType();
+
+                if (vtype->isVariantVector_)
                 {
-                    JSBVectorType* vtype = ptype->type_->asVectorType();
+                    // variant vector arguments
+                    source.AppendWithFormat("VariantVector __arg%i;\nScriptVector* __scriptVectorArg%i = js_to_class_instance<ScriptVector>(ctx, %i, 0);\n", cparam, cparam, cparam);
+                    if (!function_->HasMutatedReturn())
+                        source.AppendWithFormat("__scriptVectorArg%i->AdaptToVector(__arg%i);\n", cparam, cparam);
+                }
+                else if (ptype->isConst_)
+                {                    
+                    // JS/TS side needs work for vector parameters, right now we support const (read only)
+                    // Vector of String/StringHash
+
                     source.AppendWithFormat("%s __arg%i;\n", vtype->ToString().CString(), cparam);
 
                     source.AppendWithFormat("if (duk_get_top(ctx) >= %i)\n{\n", cparam + 1);
@@ -222,7 +232,6 @@ void JSFunctionWriter::WriteParameterMarshal(String& source)
 
                 }
             }
-
         }
     }
 }
@@ -437,22 +446,34 @@ void JSFunctionWriter::WriteFunction(String& source)
 
     }
 
+    const Vector<JSBFunctionType*>& parameters = function_->GetParameters();
+
     if (function_->IsStatic())
     {
         source.AppendWithFormat("%s::%s(", klass->GetNativeName().CString(), function_->name_.CString());
     }
     else
     {
-        source.AppendWithFormat("native->%s(", function_->name_.CString());
-    }
+        if (function_->HasMutatedReturn())
+        {
+            source.AppendWithFormat("__arg%i = native->%s(", parameters.Size() - 1, function_->name_.CString());
+        }
+        else
+        {
+            source.AppendWithFormat("native->%s(", function_->name_.CString());
+        }
 
-    const Vector<JSBFunctionType*>& parameters = function_->GetParameters();
+    }    
 
-    for (unsigned int i = 0; i < parameters.Size(); i++)
+    unsigned numParams = parameters.Size();
+    if (numParams && function_->HasMutatedReturn())
+        numParams--;
+
+    for (unsigned int i = 0; i < numParams; i++)
     {
         source.AppendWithFormat("__arg%i",  i);
 
-        if (i != parameters.Size() - 1)
+        if (i != numParams - 1)
         {
             source += ", ";
         }
@@ -460,7 +481,17 @@ void JSFunctionWriter::WriteFunction(String& source)
 
     source += ");\n";
 
-    if (returnDeclared)
+    if (!returnDeclared)
+    {
+        if (function_->HasMutatedReturn())
+        {
+            // this handles the VariantVector case currently, can be expanded
+            source.AppendWithFormat("__scriptVectorArg%i->AdaptFromVector(__arg%i);\n", parameters.Size() - 1,  parameters.Size() - 1);
+        }
+
+        source += "return 0;\n";
+    }
+    else
     {
         if (returnType->type_->asStringType())
         {
@@ -535,10 +566,6 @@ void JSFunctionWriter::WriteFunction(String& source)
 
         source += "return 1;\n";
     }
-    else
-    {
-        source += "return 0;\n";
-    }
 
     source.Append("}\n");
 }

+ 1 - 0
Source/ToolCore/JSBind/JavaScript/JSModuleWriter.cpp

@@ -313,6 +313,7 @@ void JSModuleWriter::GenerateSource()
     }
 
     source += "#include <Duktape/duktape.h>\n";
+    source += "#include <Atomic/Script/ScriptVector.h>\n";
     source += "#include <AtomicJS/Javascript/JSVM.h>\n";
     source += "#include <AtomicJS/Javascript/JSAPI.h>\n";
 

+ 1 - 0
Source/ToolCore/JSBind/JavaScript/JSPackageWriter.cpp

@@ -125,6 +125,7 @@ void JSPackageWriter::GenerateSource()
     }
 
     source += "#include <Duktape/duktape.h>\n";
+    source += "#include <Atomic/Script/ScriptVector.h>\n";
     source += "#include <AtomicJS/Javascript/JSVM.h>\n";
     source += "#include <AtomicJS/Javascript/JSAPI.h>\n";