Mailing List
Home
Forum Home
Softimage
Carrara
trueSpace
Dir3d-l
Maya - a powerful 3D animation and visual effects software
Macromedia Flash Development
Subjects
Cameras
scaleDown command
black out solved
Aircraft Tutorial
Mathematical XYZ ?
Its done This vs That
Its done first week
recommendations for screen video captures?
3DExplorer "Oddity "
New Director
ProTeam renewals
Fuel 's new websites (X post)
Blue peter create a make toy
targeting groups question
XPost: Shockwave 3D game ( sort of )
RES: RES: RES: Fish Modeling
Emitting particles from object intersection
Fuel 's new websites (X post)
Texturing
Big Break Contest Videos
New Plugins
Models and Texture on my updated site
Error Installing Patch tS6 6
Plasma?
Looking for Inspiration
Weird EMail Q
It 's done first week ?
Cherry not cranberry
New game
Camera Animation Problem
Particle plugins?
 
Custom Objects and Classes for Scripting

Custom Objects and Classes for Scripting

2005-03-26       - By Bradley R. Gabe

 Back
Reply:     1     2     3     4     5     6     7     8     9     10     >>  


>which makes sense.  But I was wondering about the instantiation of the
>object itself.  First of all, what are some of the best standards and
>practices of creating objects in jscript?  My understanding is that there
>are a couple of ways to do it and I was wondering if anyone has any reason
>why one way in particular is better for XSI.

From recent experience, I've learned that it is necessary to structure
your object instatiation such that you can use the same call inside XSI, or
ouside XSI in javascript land for netview development. For typical
javascript object instatiation, after the class file is included into the
current script, the following syntax is required:

//Instantiate an included custom object in a netview script
var obj = new CustomObject();

In XSI, including a file into your current script is slow compared to just
registering the command and calling it directly. Since calling commands is
an XSi thing and not a jscript thing, jscript is not going to recognize
your custom command with respect to the 'new' call. Your command has to
return the new instance so you don't need the 'new' call:

//Instantiate a custom object from an XSI command
var obj = CustomObject();

As an addendum to my blog entry, I need to talk about structuring the
instantiate such that your custom objects can work inside XSI, or inside
netview javascript in a seamless fashion. While I suspect there are more
elegant ways to do it (perhaps going all Python would be one), I've found
that I can overcome the difference between XSI and javascript object
instantiation by splitting my constructor into 2 separate functions. This
allows me to use the exact same call, whether I'm running from within an
XSI command or from a javascript doing a netview.

The first function is a class template which only defines the properties
and methods.
The second function does the instantiation and construction and returns the
new class instance.

From within XSI, I parse the command and tell it to run the second
function as the command procedure.
From within javascript, after the file is included, I can run the second
function the same way I would within XSI.

The other thing I've discovered is that a separate constructor function
makes it easier to overload your object input and decide whether or not to
return an object if the input is bad. In the example below, I use the
constructor function to test the input and set class properties based on
input type, or log errors and return a null object if the input is invalid:

// CLASS TEMPLATE
function Class_CustomObject(inputValue)
{
        // Class Properties -- ---- ---- ---- ---- ------
        this.type = 'CustomObject';
        this.size = 0;
        this.Model = null;
        this.description = '';

        // Class Methods -- ---- ---- ---- ---- --
        this.SetSize = CustomObject_SetSize;
        this.GetModel = CustomObject_GetModel;
        this.LogError = CustomObject_LogError;
}

// CLASS CONSTRUCTOR
function CustomObject(inputValue)
{
        // Get pointers to application for netview
        var xsi = new ActiveXObject('XSI.Application');
        var app = xsi.Application;

        // Instantiate a new object
        var obj = new CustomObject();

        // Based on inputValue, return something -- ---- ---- ---- ---- ------

        // If user provides no input, do not instantiate
        if(!inputValue) return(null);

        // If user inputs a number, set the size property
        if(typeof(inputValue) == 'number'){
                obj.size = inputValue;
                return(obj);
        }

        // If user inputs an object and it is a #model, point the Model
property to it
        else if(typeof(inputValue) == 'object' && inputValue.type == '#model){
                obj.Model = inputValue;
                return(obj);
        }

        // If we got this far, input is not a valid type
        app.LogMessage('CustomObject(Argument[0]) -- Invalid input', 2);
        return(false);
}


>I intend to roll an object as a utility library of functions (as suggested
>as one possible use in the blog entry).  If I'm understanding the example,
>I think thats what GUITools is doing as well.  Am I to understand that the
>object is instantiated every time the "GUITools" command is called?  Or is
>it cache'ing it somewhere in global memory the first time and just passing
>the same instance on subsequent calls?  Or is the instantiation so cheap,
>it doesn't matter that you instantiate it in every function you use it
>in?  Is there a good place to toss an object where it will persist for the
>remainder of the given XSI session?  Or is that foolhearty?

I ran into some problems with this technique recently after stacking too
many objects too deep. While it was never an issue in XSI 3.5 on linux, it
seems that with the changes to command registration in XSI 4+ and on
windows, one must be cautious about treating jscript too much like a real
programming language.

An important aspect to know about jscript is that its object functionality
is a bit of a hack. In C++, Java, and other compiled languages when you
instantiate an object, you get a separate memory space and control over
your construction and destruction. Inheritance and polymorphism is stable
and reliable to many levels deep.

In jscript, the whole object functionality is a clever hack in the
language, using arrays and string copies of your functions. Methods, for
example, are simply pointers to your function stored as a string in an
array. When you call the method, jscript runs an eval() on your function
string, then runs the function. When you include an ancestor object into
your current object, jscript loads in the file and does string
concatenation at runtime.

What this means is that you should be really careful about nesting objects
inside other objects too many levels deep. 2 or 3 levels is okay, but any
more than that and you are risking a jscript meltdown at runtime. Test your
stuff early and often, especially for performance in order to prevent
unexpected problems. The moment you run into strange and unexplainable
variable scope issues, you've gone too many levels deep and you'll have to
explode some of your earliest objects.

Other scripting languages, such as Python and Php are built around this
kind of object component construction, and don't suffer the same isses.
However, I have heard some rumors about a compilable version of jscript, so
perhaps the future for jscript and OOP may be better.



>thanks,
>-brad
>---
>Unsubscribe? Mail Majordomo@(protected) with the following text in body:
>unsubscribe xsi

<html>
<body>
<blockquote type=cite class=cite cite="">which makes sense.&nbsp; But I
was wondering about the instantiation of the object itself.&nbsp; First
of all, what are some of the best standards and practices of creating
objects in jscript?&nbsp; My understanding is that there are a couple of
ways to do it and I was wondering if anyone has any reason why one way in
particular is better for XSI.</blockquote><br>
From recent experience, I've learned that it is necessary to structure
your object instatiation such that you can use the same call inside XSI,
or ouside XSI in javascript land for netview development. For typical
javascript object instatiation, after the class file is included into the
current script, the following syntax is required:<br><br>
<font face="Courier New, Courier" color="#008000">//Instantiate an
included custom object in a netview script<br>
</font><font face="Courier New, Courier">var obj = new
CustomObject();<br><br>
</font>In XSI, including a file into your current script is slow compared
to just registering the command and calling it directly. Since calling
commands is an XSi thing and not a jscript thing, jscript is not going to
recognize your custom command with respect to the 'new' call. Your
command has to return the new instance so you don't need the 'new'
call:<br><br>
<font face="Courier New, Courier" color="#008000">//Instantiate a custom
object from an XSI command<br>
</font><font face="Courier New, Courier">var obj =
CustomObject();<br><br>
</font>As an addendum to my blog entry, I need to talk about structuring
the instantiate such that your custom objects can work inside XSI, or
inside netview javascript in a seamless fashion. While I suspect there
are more elegant ways to do it (perhaps going all Python would be one),
I've found that I can overcome the difference between XSI and javascript
object instantiation by splitting my constructor into 2 separate
functions. This allows me to use the exact same call, whether I'm running
from within an XSI command or from a javascript doing a
netview.<br><br>
The first function is a class template which only defines the properties
and methods.<br>
The second function does the instantiation and construction and returns
the new class instance.<br><br>
From within XSI, I parse the command and tell it to run the second
function as the command procedure.<br>
From within javascript, after the file is included, I can run the second
function the same way I would within XSI.<br><br>
The other thing I've discovered is that a separate constructor function
makes it easier to overload your object input and decide whether or not
to return an object if the input is bad. In the example below, I use the
constructor function to test the input and set class properties based on
input type, or log errors and return a null object if the input is
invalid:<br><br>
<font face="Courier New, Courier" color="#008000">// CLASS TEMPLATE<br>
</font><font face="Courier New, Courier">function
Class_CustomObject(inputValue)<br>
{<br>
<x-tab>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</x-tab></font><font
face="Courier New, Courier" color="#008000">//
Class Properties -- ---- ---- ---- ---- ------<br>
</font><font face="Courier New, Courier"><x-tab>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;</x-tab>this.type
= 'CustomObject';<x-tab>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</x-tab><br>
<x-tab>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</x-tab>this.size
= 0;<br>
<x-tab>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</x-tab>this.Model
= null;<br>
<x-tab>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</x-tab>this.description
= '';<br><br>
<x-tab>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</x-tab></font><font
face="Courier New, Courier" color="#008000">//
Class Methods -- ---- ---- ---- ---- --<br>
</font><font face="Courier New, Courier"><x-tab>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;</x-tab>this.SetSize
= CustomObject_SetSize;<br>
<x-tab>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</x-tab>this.GetModel
= CustomObject_GetModel;<br>
<x-tab>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</x-tab>this.LogError
= CustomObject_LogError;<br>
}<br><br>
</font><font face="Courier New, Courier" color="#008000">// CLASS
CONSTRUCTOR<br>
</font><font face="Courier New, Courier">function
CustomObject(inputValue)<br>
{<br>
<x-tab>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</x-tab></font><font
face="Courier New, Courier" color="#008000">//
Get pointers to application for netview<br>
</font><font face="Courier New, Courier"><x-tab>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;</x-tab>var
xsi = new ActiveXObject('XSI.Application');<br>
<x-tab>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</x-tab>var app =
xsi.Application;<br><br>
<x-tab>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</x-tab></font><font
face="Courier New, Courier" color="#008000">//
Instantiate a new object<br>
</font><font face="Courier New, Courier"><x-tab>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;</x-tab>var
obj = new CustomObject();<br><br>
<x-tab>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</x-tab></font><font
face="Courier New, Courier" color="#008000">//
Based on inputValue, return something
-- ---- ---- ---- ---- ------<br><br>
</font><font face="Courier New, Courier"><x-tab>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;</x-tab></font><font face="Courier New, Courier" color="
#008000">//
If user provides no input, do not instantiate<br>
</font><font face="Courier New, Courier"><x-tab>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;</x-tab>if(!inputValue)
return(null);<br><br>
<x-tab>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</x-tab></font><font
face="Courier New, Courier" color="#008000">//
If user inputs a number, set the size property<br>
</font><font face="Courier New, Courier"><x-tab>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;</x-tab>if(typeof(inputValue)
== 'number'){<br>
<x-tab>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</x-tab><x-tab>&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</x-tab>obj.size
= inputValue;<br>
<x-tab>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</x-tab><x-tab>&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</x-tab>return(obj);<br>
<x-tab>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</x-tab>}<br><br>
<x-tab>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</x-tab></font><font
face="Courier New, Courier" color="#008000">//
If user inputs an object and it is a #model, point the Model property to
it<br>
</font><font face="Courier New, Courier"><x-tab>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;</x-tab>else
if(typeof(inputValue) == 'object' &amp;&amp; inputValue.type ==
'#model){<br>
<x-tab>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</x-tab><x-tab>&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</x-tab>obj.Model
= inputValue;<br>
<x-tab>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</x-tab><x-tab>&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</x-tab>return(obj);<br>
<x-tab>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</x-tab>}<br>
<x-tab>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</x-tab><br>
<x-tab>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</x-tab></font><font
face="Courier New, Courier" color="#008000">//
If we got this far, input is not a valid type<br>
</font><font face="Courier New, Courier"><x-tab>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;</x-tab>app.LogMessage('CustomObject(Argument[0])
-- Invalid input', 2);<br>
<x-tab>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</x-tab>return(false);
<br>
}<br><br>
<br>
</font><blockquote type=cite class=cite cite="">I intend to roll an
object as a utility library of functions (as suggested as one possible
use in the blog entry).&nbsp; If I'm understanding the example, I think
thats what GUITools is doing as well.&nbsp; Am I to understand that the
object is instantiated every time the &quot;GUITools&quot; command is
called?&nbsp; Or is it cache'ing it somewhere in global memory the first
time and just passing the same instance on subsequent calls?&nbsp; Or is
the instantiation so cheap, it doesn't matter that you instantiate it in
every function you use it in?&nbsp; Is there a good place to toss an
object where it will persist for the remainder of the given XSI
session?&nbsp; Or is that foolhearty?</blockquote><br>
I ran into some problems with this technique recently after stacking too
many objects too deep. While it was never an issue in XSI 3.5 on linux,
it seems that with the changes to command registration in XSI 4+ and on
windows, one must be cautious about treating jscript too much like a real
programming language.<br><br>
An important aspect to know about jscript is that its object
functionality is a bit of a hack. In C++, Java, and other compiled
languages when you instantiate an object, you get a separate memory space
and control over your construction and destruction. Inheritance and
polymorphism is stable and reliable to many levels deep.<br><br>
In jscript, the whole object functionality is a clever hack in the
language, using arrays and string copies of your functions. Methods, for
example, are simply pointers to your function stored as a string in an
array. When you call the method, jscript runs an eval() on your function
string, then runs the function. When you include an ancestor object into
your current object, jscript loads in the file and does string
concatenation at runtime.<br><br>
What this means is that you should be really careful about nesting
objects inside other objects too many levels deep. 2 or 3 levels is okay,
but any more than that and you are risking a jscript meltdown at runtime.
Test your stuff early and often, especially for performance in order to
prevent unexpected problems. The moment you run into strange and
unexplainable variable scope issues, you've gone too many levels deep and
you'll have to explode some of your earliest objects.<br><br>
Other scripting languages, such as Python and Php are built around this
kind of object component construction, and don't suffer the same isses.
However, I have heard some rumors about a compilable version of jscript,
so perhaps the future for jscript and OOP may be better. <br><br>
<br><br>
<blockquote type=cite class=cite cite="">thanks,<br>
-brad<br>
---<br>
Unsubscribe? Mail Majordomo@(protected) with the following text in
body:<br>
unsubscribe xsi</blockquote></body>
</html>