Implementing New Classes

JavaScript supports a basic object oriented paradigm, allowing you to implement new kinds of objects by deriving them from existing objects.

In this tutorial we show you how to implement new JavaScript classes in Realsoft 3D. We also explore the internal structure of Realsoft 3D and demonstrate how to transform geometric objects, create new geometric objects, export objects to a file and create new material objects.

[Note] Note
This tutorial is not a JavaScript tutorial. Basic knowledge of JavaScript's object oriented programming model is assumed.

Class Header Files

In the previous tutorials we used the include() function to load various header files.

For example, we loaded button's header file:

    include("oops/r3button.js");

Each of these header files define properties for one Realsoft 3D class. For example, 'scripts/js/oops/r3button.js' defines the JavaScript class corresponding to the Realsoft 3D Button class.

The substructure of 'scripts\js' folder corresponds to the library structure of Realsoft 3D. For example, the 'oops' sub folder stands for Realsoft's Object Oriented Programming System and it defines classes for the r3oops library. If you buy a plug-in that supports JavaScript you get a new folder that contains the header files corresponding to the classes in the plug-in library.

You can also add new sub folders into 'scripts/js' folder for your own JavaScript classes. In fact, the scripts folder should already have 'myclasses' sub folder, which contains a number of sample classes.

myWindow Class

Any of the sample scripts we have gone through so far can be turned to JavaScript classes easily.

Let's recall the first sample we went through in the previous Intro tutorial:

    include("oops/r3window.js");

    window = new r3Window(R3WGA_Parent, _r3gui,
                          R3WGA_Left, 300,
                          R3WGA_Top, 200,
                          R3WGA_Width, 300,
                          R3WGA_Height, 200,
                          R3WA_ReportCloseWindow, TRUE,
                          R3WA_ReportNewSize, TRUE,
                          R3WA_Title, "Dummy Window");

    window.REALIZE();

Creating window objects is straightforward, but specifying all the above attributes creates a lot of typing overhead.

Let's assume we want to create a new JavaScript window, which creates the above kind of a window with minimal typing overhead. This can be done by deriving a new class which takes care of setting the appropriate attributes for us.

    include("oops/r3window.js");

    // constructor function
    function myWindow(name, width, height)
    {
        if(!arguments.length)
            return;
        this.base = r3Window;

        // our super class
        this.base(R3WGA_Parent, _r3gui,
                  R3WGA_Left, 300,
                  R3WGA_Top, 200,
                  R3WGA_Width, width,
                  R3WGA_Height, height,
                  R3WA_ReportCloseWindow, TRUE,
                  R3WA_ReportNewSize, TRUE,
                  R3WA_Title, name);
    }
    // derive 'myWindow' from the 'r3Window' base class
    myWindow.prototype=new r3Window;

This is how to derive new classes in JavaScript. If you save the above code as 'js/myclasses/mywindow.js', you will be able to create windows as follows:

    include("myclasses/mywindow.js");

    win = new myWindow("My cool window", 300, 200);
    win.REALIZE();

[Note] Note
You should not put the R3WGM_REALIZE call into a constructor. This method should be called only once from the highest level (whoever creates your object is responsible also for realizing them). If you put the realize method into the constructor function of your class, it gets called multiple times causing flickering. Another method which you should not put into constructor functions is 'R3WGM_FIT'.

Implementing 'myToolBar' Class

Now that we know how to derive new JavaScript classes for existing classes, let's go through a more practical example. Let's create a fully functional tool bar class, which allows us to create custom tool bars as easily as possible.

Recall the packer example we went through in the beginning of the intro tutorial. We created a window with a packer geometric manager and then inserted a bunch of buttons into the packer. Typically toolbars contain one or more horizontally or vertically packed tool buttons. So we can take the packer example as a starting point for developing our tool bar class.

Again, we need to wrap the creation code into a constructor function to get a proper JavaScript class defined. Because the tool bar should be user configurable, we just create a window with an empty packer in the constructor. Then we implement another method which allows us to insert tool buttons into the toolbar.

So, let's see how all this can be implemented.

Here is the code:

    // our tool bar consists of a window, a packer and one or more buttons
    include("oops/r3button.js");
    include("oops/r3window.js");
    include("oops/r3packer.js");

    // let the user to control the orientation of the tool bar
    var MYTB_HORIZONTAL = 0
    var MYTB_VERTICAL = 1

    // add button with user specified label and callback function
    function mytbAddTool(buttonLabel, fnCallBack)
    {
        button = new r3Button(R3RA_Hook, fnCallBack,
                              R3WGA_Parent, this,
                              R3GA_Text, text);
        if(button) {
            // insert button into the packer 
            this.packer.ADD(R3PAPF_FILLX, 0, button);

            // tell the button where to find the project
            button.layer = this.layer;
        }
        return button;
    }

    // constructor: create a window with empty packer
    function myToolBar(titlebar, orientation, layer)
    {
        if(!arguments.length)
            return;
        this.base = r3Window;
        this.layer = layer;
        
        this.base(R3WGA_Left, 200,
                  R3WGA_Top, 150,
                  R3WA_ReportNewSize, TRUE,
                  R3WA_ReportCloseWindow, TRUE,
                  R3WA_Title, titlebar);

        // create a packer with given orientation
        this.packer = new r3Packer(0);
        this.packer.SetOrientation(orientation);

        // define method for inserting tool buttons
        this.AddTool = mytbAddTool;

        // and give the packer to the window, as usual
        this.SetGmanager(this.packer);
    }

    myToolBar.prototype=new r3Window;

Testing 'myToolBar' Class

The above JavaScript program can be found from 'scripts/js/myclasses/toolbars/mytoolbar.js'.

Let's add a tool button which creates an analytic sphere object. For this we need to create a call back function. This function is called when the user clicks the tool button. In the function we simply create a sphere and insert it into the geometry layer.

    function mySphereCallback(button, event, value)
    {
        // create a sphere
        sphere = new r3Sphere(0); 

        // set some sphere specific attributes
        sphere.SetRadius(0.1);
        sphere.SetCenter(new r3Vect(0.1, 0.0, 0.0));
        sphere.SetName("my sphere");

        // insert the sphere into the project
        button.layer.LOCKMUTEX(0, 0, sphere);
        button.layer.INSERT(0, 0, sphere);
        button.layer.RELEASE();
    }        

Now we have defined one callback which can create a sphere into the current layer. We have also defined a new tool bar class.

To actually create a tool bar, enter:

    tbar = new myToolBar(MYTB_HORIZONTAL, primLayer);
    tbar.AddTool("Sphere", mySphereCallback);

When you click the 'Sphere' button, the 'mySphereCallback' is called and new sphere will appear into the current project.

The 'scripts/js/myclasses/toolbars' folder contains several JavaScript examples derived from the 'myToolBar' class.