JavaScriptEngine, how to add methods to a DynamicObject


#1

I'm investigating the JavaScriptEngine but i'm not sure if fully understand how these 'DynamicObjects' work.

I can't seem to find an example either, (maybe add it as a demo to the demo project?).

I got the JavaScript engine running, i use it in collaboration with OpenGL, so the user can enter a script (like in processing) and the OpenGL engine does the hard work.

I managed to add a color object and i'm able to set the color properties from script, see below

    dynamicObject = new DynamicObject();

    dynamicObject->setProperty("r", "0.0f");

    dynamicObject->setProperty("g", "0.0f");

    dynamicObject->setProperty("b", "0.0f");

    dynamicObject->setProperty("a", "1.0f");    

    jsengine.registerNativeObject("color", dynamicObject);

But how to add a method like say 'fillRect' that takes four floats as arguments? 

Could someone give me a pointer on how to do this?

    dynamicObject.setMethod ("fillRect", var::NativeFunction function ??);

#2

Allright i think i figured it out, i look at the JavascriptEngine::Rootobject for inspiration.

I created a DrawEngine like this.

struct DrawEngine   : public DynamicObject

{

    DrawEngine()

    {

        

    };

    

    typedef const var::NativeFunctionArgs& Args;

    

    static var get (Args a, int index) noexcept            { return index < a.numArguments ? a.arguments[index] : var(); }

    static bool isInt (Args a, int index) noexcept         { return get (a, index).isInt() || get (a, index).isInt64(); }

    static int getInt (Args a, int index) noexcept         { return get (a, index); }

    static double getDouble (Args a, int index) noexcept   { return get (a, index); }

    static String getString (Args a, int index) noexcept   { return get (a, index).toString(); }

    


    struct CanvasClass  : public DynamicObject

    {

        CanvasClass()

        {

            setMethod ("color",  color);

            setMethod ("fill",  fill);

            setMethod ("fillRect", fillRect);

        }

        

        

        static Identifier getClassName()

        {

            static const Identifier i ("Canvas");

            return i;

        }


        static var color  (Args a)

        {

            ra::gfx::color(getDouble (a, 0),

                           getDouble (a, 1),

                           getDouble (a, 2),

                           getDouble (a, 3)

                           );

            return true;

        }

        

        static var fill  (Args a)

        {

            ra::gfx::fillRect(-1.0f, -1.0f, 2.0f, 2.0f);

            return true;

        }

        

        static var fillRect (Args a)

        {

            ra::gfx::fillRect(getDouble (a, 0),

                              getDouble (a, 1),

                              getDouble (a, 2),

                              getDouble (a, 3)

                              );

            return true;

        };

        

    };


};

 

i register it like this

    jsengine.registerNativeObject(DrawEngine::CanvasClass::getClassName(), new DrawEngine::CanvasClass());

in my render callback i excute the script, and my script looks like this.


function draw()
{
    red += 0.01;
    if (red > 1.0)
        red = 0.0;
    canvas.color(red, 0.0, 0.0, 1.0);
}

works like a charm so far, would this be the way to go?


#3

Yes, that's the idea!


#4

I'm having a lot of fun with the JavaScript engine, a couple of questions though.

- You mention that you use the 'core JS libraries', what does this mean? I mean i can't find a reference to such a lib. Is the JavaScript parser completely build by you? I know that OSX has the JavaScriptCore framework (webkit).

- Can i instantiate Registered Objects in JavaScript, i mean can i register a type like for example 'Picture' and instantiate it a couple of times?

Picture picture1;
Picture picture2;

 

 

 


#5

"core JS libraries" was probably a bad way to describe it: what I meant was that it provides core JS objects like Math, Array, String and Object - if you look in juce_Javascript.cpp, you can see these objects being defined towards the end of the file.

Don't fully understand what you mean about registered types, but these things are just JS objects, you can clone them and do all the normal JS things with them.


#6

Hi Jules,

Well i can register two objects like this

    jsengine.registerNativeObject("canvas1", new DrawEngine::CanvasClass());
    jsengine.registerNativeObject("canvas1", new DrawEngine::CanvasClass());

so in the script i'm able to do this for instance

 function draw()
 {
     canvas1.color(1.0, 0.0, 0.0, 1.0);
     canvas1.fillRect(-0.5, -0.5, 0.1, 0.1);
    canvas2.color(1.0, 1.0, 0.0, 1.0);
     canvas1.fillRect(0.0, -0.5, 0.1, 0.1);
}

this works fine.
But can i let the user create these canvas objects in script, so i just register the class type and the in script i can choose to instantiate it.
So like this


Canvas canvas1;
Canvas canvas2;
 
 function draw()
 {
     canvas1.color(1.0, 0.0, 0.0, 1.0);
     canvas1.fillRect(-0.5, -0.5, 0.1, 0.1);

     canvas2.color(1.0, 1.0, 0.0, 1.0);
     canvas1.fillRect(0.0, -0.5, 0.1, 0.1);  
}

#7

Well no, that's not how javascript works - you'd use canvas1.clone() to create copies of it.


#8

What's the recommended way to do it (user created object instances in Javascript)?

A factory method?

And all the inserted methods in the new JS system are based on dynamic objects then? So there can't be a global method like createNewCanvas () that returns a canvas object? It would have to be something like:

Canvas1 = Canvas.createnewCanvas ()

Trying to remember my JS as I get my head around this...

Very exciting, btw. I have lua implmented in an app, but JS is better known, and your embedding seems easier than most approaches I've seen.

Bruce

 

 

 

 

 


#9

Hi,

In javascript everything is an object i learned back in the old days.

The code below is valid and works within the Juce JavascriptEngine. It draws to rects, one in red and one in green.


function Color(r, g, b)
{
    this.r = r;
    this.g = g;
    this.b = b;
}
var color1 = new Color(1, 0, 0);
var color2 = new Color(0, 1, 0);
 
function draw()
{
    canvas.color(color1.r, color1.g, color1.b, 1.0);
    canvas.fillRect(-0.5, -0.5, 0.1, 0.1);
    canvas.color(color2.r, color2.g, color2.b, 1.0);
    canvas.fillRect(0.0, 0.0, 0.1, 0.1);
}

 So this is perfectly fine code. It would be ideal that i could use the same syntax for classes that are registered using  jsengine.registerNativeObject. I've never actually heard of the clone() method, i'm not sure this is a standard method in Javascript.


#10

gekkie100: Can you take a look at my Feature Request post and see if that is the kind of thing you're talking about? I hadn't heard of clone either.

Bruce