Browse Source

First cut at editable JSComponent fields

Josh Engebretson 10 years ago
parent
commit
181f924fe5

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

@@ -301,6 +301,9 @@ void js_push_variant(duk_context *ctx, const Variant& v)
 
     switch (type)
     {
+    case VAR_NONE:
+        duk_push_undefined(ctx);
+        break;
 
     case VAR_VOIDPTR:
         duk_push_null(ctx);

+ 60 - 2
Source/AtomicJS/Javascript/JSComponent.cpp

@@ -65,6 +65,7 @@ void JSComponent::RegisterObject(Context* context)
 {
     context->RegisterFactory<JSComponent>(LOGIC_CATEGORY);
     ACCESSOR_ATTRIBUTE("Is Enabled", IsEnabled, SetEnabled, bool, true, AM_DEFAULT);
+    ATTRIBUTE("FieldValues", VariantMap, fieldValues_, Variant::emptyVariantMap, AM_FILE);
     MIXED_ACCESSOR_ATTRIBUTE("ComponentFile", GetScriptAttr, SetScriptAttr, ResourceRef, ResourceRef(JSComponentFile::GetTypeStatic()), AM_DEFAULT);
 }
 
@@ -151,6 +152,65 @@ void JSComponent::InitModule()
         return;
     }
 
+    // store, so pop doesn't clear
+    UpdateReferences();
+
+    // apply fields
+
+    const HashMap<String, VariantType>& fields =  componentFile_->GetFields();
+
+    if (fields.Size())
+    {
+        // push self
+        js_push_class_object_instance(ctx, this, "JSComponent");
+
+        HashMap<String, VariantType>::ConstIterator itr = fields.Begin();
+        while (itr != fields.End())
+        {
+            if (fieldValues_.Contains(itr->first_))
+            {
+                Variant& v = fieldValues_[itr->first_];
+
+                if (v.GetType() == itr->second_)
+                {
+                    js_push_variant(ctx, v);
+                    duk_put_prop_string(ctx, -2, itr->first_.CString());
+                }
+            }
+            else
+            {
+                Variant v;
+
+                switch (itr->second_)
+                {
+                case VAR_BOOL:
+                    v = false;
+                    break;
+                case VAR_STRING:
+                    v = "";
+                    break;
+                case VAR_FLOAT:
+                    v = 0.0f;
+                    break;
+                case VAR_VECTOR3:
+                    v = Vector3::ZERO;
+                    break;
+                default:
+                    break;
+                }
+
+                js_push_variant(ctx,  v);
+                duk_put_prop_string(ctx, -2, itr->first_.CString());
+            }
+
+            itr++;
+        }
+
+        // pop self
+        duk_pop(ctx);
+    }
+
+
     duk_get_prop_string(ctx, -1, "component");
     if (!duk_is_function(ctx, -1))
     {
@@ -168,8 +228,6 @@ void JSComponent::InitModule()
         return;
     }
 
-    UpdateReferences();
-
     duk_set_top(ctx, top);
 
 }

+ 6 - 3
Source/AtomicJS/Javascript/JSComponent.h

@@ -63,10 +63,9 @@ public:
     void ApplyAttributes();
 
     /// Get script attribute
+    VariantMap& GetFieldValues() { return fieldValues_; }
     ResourceRef GetScriptAttr() const;
-
-    /// Set script attribute.
-    void SetScriptAttr(const ResourceRef& value);
+    JSComponentFile* GetComponentFile() { return componentFile_; }
 
     /// Handle enabled/disabled state change. Changes update event subscription.
     virtual void OnSetEnabled();
@@ -79,6 +78,8 @@ public:
     /// Return whether the DelayedStart() function has been called.
     bool IsDelayedStartCalled() const { return delayedStartCalled_; }
 
+    /// Set script attribute.
+    void SetScriptAttr(const ResourceRef& value);
     void SetComponentFile(JSComponentFile* cfile, bool loading = false);
 
 protected:
@@ -133,6 +134,8 @@ private:
     WeakPtr<JSVM> vm_;
     SharedPtr<JSComponentFile> componentFile_;
 
+    VariantMap fieldValues_;
+
 };
 
 }

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

@@ -49,7 +49,71 @@ void JSComponentFile::RegisterObject(Context* context)
 
 bool JSComponentFile::BeginLoad(Deserializer& source)
 {
-    SetMemoryUse(0);
+    // TODO: cache these for non-editor builds
+
+    unsigned dataSize = source.GetSize();
+    if (!dataSize && !source.GetName().Empty())
+    {
+        LOGERROR("Zero sized component file in " + source.GetName());
+        return false;
+    }
+
+    SharedArrayPtr<char> buffer(new char[dataSize + 1]);
+    if (source.Read(buffer.Get(), dataSize) != dataSize)
+        return false;
+    buffer[dataSize] = '\0';
+
+    String text = buffer.Get();
+    Vector<String> lines = text.Split('\n');
+
+    for (unsigned i = 0; i < lines.Size(); i++)
+    {
+        String line = lines[i].Trimmed();
+
+        if (line[0] != '\"')
+            continue;
+
+        unsigned pos = line.Find("\";");
+        if (pos == String::NPOS)
+            continue;
+
+        text = line.Substring(1, pos - 1);
+
+        Vector<String> field = text.Split(' ');
+
+        if (field.Size() != 2 || !field[0].Length() || !field[1].Length())
+            continue;
+
+        String name = field[0];
+        String stringType = field[1];
+
+        VariantType variantType = VAR_NONE;
+
+        if (stringType == "boolean")
+        {
+            variantType = VAR_BOOL;
+        }
+        else if (stringType == "string")
+        {
+            variantType = VAR_STRING;
+        }
+        else if (stringType == "number")
+        {
+            variantType = VAR_FLOAT;
+        }
+        else if (stringType == "Vector3")
+        {
+            variantType = VAR_VECTOR3;
+        }
+
+        if (variantType == VAR_NONE)
+            continue;
+
+        fields_[name] = variantType;
+
+    }
+
+    SetMemoryUse(dataSize);
 
     return true;
 }

+ 4 - 0
Source/AtomicJS/Javascript/JSComponentFile.h

@@ -41,6 +41,8 @@ public:
     /// Register object factory.
     static void RegisterObject(Context* context);
 
+    const HashMap<String, VariantType>& GetFields() const { return fields_; }
+
     /// Load resource from stream. May be called from a worker thread. Return true if successful.
     virtual bool BeginLoad(Deserializer& source);
     /// Save resource
@@ -48,6 +50,8 @@ public:
 
 private:
 
+    HashMap<String, VariantType> fields_;
+
 };
 
 }

+ 199 - 49
Source/AtomicJS/Javascript/JSSceneSerializable.cpp

@@ -45,36 +45,79 @@ static int Serializable_SetAttribute(duk_context* ctx)
 
     const Vector<AttributeInfo>* attributes = serial->GetAttributes();
 
-    for (unsigned i = 0; i < attributes->Size(); i++)
-    {
-        const AttributeInfo* attr = &attributes->At(i);
+    VariantType variantType = VAR_NONE;
+
+    bool isAttr = false;
 
-        if (attr->name_ == name)
+    if (attributes)
+    {
+        for (unsigned i = 0; i < attributes->Size(); i++)
         {
-            if (attr->type_ == VAR_QUATERNION)
-            {
-                Vector3 v3 = v.GetVector3();
-                Quaternion q;
-                q.FromEulerAngles(v3.x_, v3.y_, v3.z_);
-                v = q;
-            }
+            const AttributeInfo* attr = &attributes->At(i);
 
-            else if (attr->type_ == VAR_COLOR)
+            if (!attr->name_.Compare(name))
             {
-                Vector4 v4 = v.GetVector4();
-                Color c(v4.x_, v4.y_, v4.z_, v4.w_ );
-                v = c;
+                isAttr = true;
+                variantType = attr->type_;
+                break;
             }
-            else if (attr->type_ == VAR_INT)
+        }
+    }
+
+    JSComponent* jsc = NULL;
+
+    // check dynamic
+    if (!isAttr)
+    {
+        if (serial->GetType() == JSComponent::GetTypeStatic())
+        {
+            jsc = (JSComponent*) serial;
+            JSComponentFile* file = jsc->GetComponentFile();
+
+            const HashMap<String, VariantType>& fields = file->GetFields();
+
+            if (fields.Contains(name))
             {
-                v = (int) v.GetFloat();
+                HashMap<String, VariantType>::ConstIterator itr = fields.Find(name);
+                variantType = itr->second_;
             }
-
-            break;
         }
     }
 
-    serial->SetAttribute(name, v);
+    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;
+    }
+
+    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();
+    }
+
+    if (isAttr)
+    {
+        serial->SetAttribute(name, v);
+        return 0;
+    }
+
+    // check dynamic
+    if (jsc)
+    {
+        VariantMap& values = jsc->GetFieldValues();
+        values[name] = v;
+    }
 
     return 0;
 }
@@ -85,8 +128,68 @@ static int Serializable_GetAttribute(duk_context* ctx)
 
     duk_push_this(ctx);
     Serializable* serial = js_to_class_instance<Serializable>(ctx, -1, 0);
-    js_push_variant(ctx,  serial->GetAttribute(name));
+    const Vector<AttributeInfo>* attrs = serial->GetAttributes();
+
+    if (attrs)
+    {
+        for (unsigned i = 0; i < attrs->Size(); i++)
+        {
+            const AttributeInfo* attr = &attrs->At(i);
+
+            if (!attr->name_.Compare(name))
+            {
+                // FIXME: this is a double lookup
+                js_push_variant(ctx,  serial->GetAttribute(name));
+                return 1;
+            }
+        }
+    }
+
+    if (serial->GetType() == JSComponent::GetTypeStatic())
+    {
+        JSComponent* jsc = (JSComponent*) serial;
+        JSComponentFile* file = jsc->GetComponentFile();
+
+        const HashMap<String, VariantType>& fields = file->GetFields();
+
+        if (fields.Contains(name))
+        {
+            VariantMap& values = jsc->GetFieldValues();
+
+            if (values.Contains(name))
+            {
+                js_push_variant(ctx,  values[name]);
+                return 1;
+            }
+            else
+            {
+                HashMap<String, VariantType>::ConstIterator itr = fields.Find(name);
+                Variant v;
+                switch (itr->second_)
+                {
+                case VAR_BOOL:
+                    v = false;
+                    break;
+                case VAR_STRING:
+                    v = "";
+                    break;
+                case VAR_FLOAT:
+                    v = 0.0f;
+                    break;
+                case VAR_VECTOR3:
+                    v = Vector3::ZERO;
+                    break;
+                default:
+                    break;
+                }
+
+                js_push_variant(ctx,  v);
+                return 1;
+            }
+        }
+    }
 
+    duk_push_undefined(ctx);
     return 1;
 }
 
@@ -110,49 +213,96 @@ static int Serializable_GetAttributes(duk_context* ctx)
     duk_dup(ctx, -1);
     duk_put_prop_index(ctx, -4, type);
 
-    if (!attrs)
-        return 1;
-
-    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");
 
-        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_array(ctx);
+            duk_push_boolean(ctx, 0);
+            duk_put_prop_string(ctx, -2, "field");
 
-        const char** enumPtr = attr->enumNames_;
-        unsigned enumCount = 0;
+            duk_push_array(ctx);
 
-        if (enumPtr)
-        {
-            while (*enumPtr)
+            const char** enumPtr = attr->enumNames_;
+            unsigned enumCount = 0;
+
+            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");
+
+            // store attr object
+            duk_put_prop_index(ctx, -2, i);
         }
+    }
+
+    // dynamic script fields
+    if (serial->GetType() == JSComponent::GetTypeStatic())
+    {
+        JSComponent* jsc = (JSComponent*) serial;
+        JSComponentFile* file = jsc->GetComponentFile();
+
+        const HashMap<String, VariantType>& fields =  file->GetFields();
+
+        if (fields.Size())
+        {
+            HashMap<String, VariantType>::ConstIterator itr = fields.Begin();
+            while (itr != fields.End())
+            {
+                duk_push_object(ctx);
 
-        duk_put_prop_string(ctx, -2, "enumNames");
+                duk_push_number(ctx, (double) itr->second_);
+                duk_put_prop_string(ctx, -2, "type");
 
-        // store attr object
-        duk_put_prop_index(ctx, -2, i);
+                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_string(ctx,"");
+                duk_put_prop_string(ctx, -2, "defaultValue");
+
+                duk_push_boolean(ctx, 1);
+                duk_put_prop_string(ctx, -2, "field");
+
+                duk_push_array(ctx);
+
+                duk_put_prop_string(ctx, -2, "enumNames");
+
+                // store attr object
+                duk_put_prop_index(ctx, -2, count++);
+
+                itr++;
+            }
+        }
     }
 
     return 1;