<?xml version='1.0' encoding='UTF-8'?>

<?xml-stylesheet href="./_c74_tut.xsl" type="text/xsl"?>
<chapter name="Tutorial 47: Using Jitter Object Callbacks in JavaScript">
<setdocpatch name="47jJitterListener" patch="47jJitterListener.maxpat"/>

<previous name="jitterchapter46">Manipulating Matrix Data using JavaScript</previous>
<next name="jitterchapter48">Frames of MSP signals</next>
<parent name="jitindex">Jitter Tutorials</parent>



<h1>Tutorial 47: Using Jitter Object Callbacks in JavaScript</h1>
<p>In the last two tutorials, we've looked at some of the possibilities and advantages of using Jitter objects and matrices within JavaScript code. In this tutorial we'll encapsulate an entire Jitter OpenGL patch inside of JavaScript, using many of the techniques we've already seen. Most importantly, however, we'll learn how to "listen" to the <i>output</i> of Jitter objects that have been encapsulated in JavaScript in order to design functions that respond interactively to these objects.</p>


<p>A number of Jitter objects (such as <o>jit.movie</o>, <o>jit.pwindow</o>, and <o>jit.window</o>) output messages from their status (right-hand) outlets in response to processes initiated by the user in a Max patcher. For example, when you read a movie file into <o>jit.movie</o>, the object outputs the message <m>read</m> followed by the movie's filename and a status number out its status outlet. Similarly, the <o>jit.pwindow</o> and <o>jit.window</o> objects can respond to mouse events in their windows by sending messages out their status outlet. Because Jitter objects instantiated within JavaScript have no inlets and outlets <i>per se</i>, we need to explicitly create an object (called a JitterListener) to catch those messages and call a function (called a <i>callback function</i>) in response to them.</p>

<p>This Tutorial assumes you've looked at the earlier JavaScript tutorials, as well as the first OpenGL tutorial <i><link type="tutorial" module="jit" name="jitterchapter30">Tutorial 30:</link> Drawing 3D Text</i>.</p>

<bullet>Open the tutorial patch.</bullet>
<p>The first thing we notice about this tutorial patch is that there is very little in it, in terms of Max objects. Virtually all the work done in the patcher is accomplished inside the <o>js</o> object in the patch.</p>

<illustration><img src="images/jitterchapter47a.png"/><i>Our Tutorial patcher: not much to look at.</i></illustration>
<bullet>Click on the <o>toggle</o> box labeled <i>Display</i>. The <o>qmetro</o> object will begin to send <m>bang</m> messages into the <o>js</o> object, and the <o>jit.window</o> object should fill with a number of shapes (one large sphere and a few dozen small spheres) on a black background.</bullet>
<p>Our <o>js</o> object contains a complete set of Jitter objects performing an OpenGL rendering (including a <o>jit.window</o> object).</p>

<bullet>Move your mouse over the <o>jit.window</o>. The large sphere will "glue" to your mouse, following you along in the window. As the large sphere touches the smaller spheres, it will "push" them along as if they were solid objects colliding. Try to get a feel for moving the smaller spheres around with the larger one.</bullet>
<p>Our <o>js</o> file not only draws our OpenGL scene, but also handles interactive events from the mouse. This is done through a listening and callback mechanism (called a JitterListener) that we'll learn about in the JavaScript code.</p>

<illustration><img src="images/jitterchapter47b.png"/><i>Pushing the spheres around.</i></illustration>
<h2>Creating OpenGL objects in JavaScript</h2>
<bullet>Double-click the <o>js</o> object in our Tutorial patch. A text editor will appear that contains the source code for the <o>js</o> object in the patch. The code is saved as a file called "47jMarbles.js" in the same folder as the Tutorial patch. Look at the global code block at the top of the file.</bullet>
<p>Our JavaScript code creates all the JitterObject objects we need to render our scene: a <o>jit.window</o> object to display the drawing context, a <o>jit.gl.render</o> object to perform the rendering, and a number of <o>jit.gl.gridshape</o> objects to draw and animate the spheres in the scene. These objects are instantiated in the global block of code at the beginning of the JavaScript file.</p>



<p>
   <pre>var OBJECT_COUNT = 32; // number of little spheres   </pre></p>

<p>This line declares a variable (<i>OBJECT_COUNT</i>) that determines the number of smaller spheres in our scene.</p>

<p>
<pre><code language="javascript">// create a [jit.window] object for our display
// (this is the object we'll listen to):
var mywindow = new JitterObject("jit.window","ListenWindow");
// turn off depth testing... we're using blending instead:
mywindow.depthbuffer = 0;
// turn ON idlemousing... we want to listen for it:
mywindow.idlemouse = 1;</code></pre></p>

<p>Next, we create a <o>jit.window</o> object to display everything. We'll refer to it in our JavaScript code by the variable <i>mywindow</i>. Just as in a Max patch, the <o>jit.window</o> needs a name ("ListenWindow") that must match the OpenGL drawing context we're using. We've turned off the <m>depthbuffer</m> and turned on the <m>idlemouse</m> attribute, which allows the <o>jit.window</o> object to track mouse events in the window regardless of whether we've clicked our mouse down or not.</p>


<p><pre><code language="javascript">// create a [jit.gl.render] object for drawing into our window:
var myrender = new JitterObject("jit.gl.render","ListenWindow");
// use a 2-dimensional projection:
myrender.ortho = 2;
// set background to black with full erase opacity (no trails):
myrender.erase_color = [0,0,0,1];</code></pre></p>

<p>Our <o>jit.gl.render</o> object (assigned to the variable <i>myrender</i>) defines a drawing context called "ListenWindow". The <o>jit.window</o> object (above) and the <o>jit.gl.gridshape</o> objects (below) share this name. We've decided to use an <i>orthographic</i> projection (by setting the <m>ortho</m> attribute to <m>2</m>). This means that the <i>z</i> axis of our drawing context is ignored in terms of sizing objects based on their distance from the virtual camera. This essentially creates a 2-dimensional rendering of our scene. We've set the background to black (with a full erase between successive drawing) by setting our <m>erase_color</m> to <m>0 0 0 1</m>.</p>


<p><pre><code language="javascript">// create a [jit.gl.gridshape] object for use to control with the mouse
var mywidget = new JitterObject("jit.gl.gridshape","ListenWindow");
mywidget.shape = "sphere";
mywidget.lighting_enable = 1;
mywidget.smooth_shading = 1;
mywidget.scale = [0.1,0.1,0.1];
mywidget.color = [1,1,1,0.5] ;
mywidget.blend_enable = 1;
mywidget.position = [0,0]; // no z necessary in orthographic projection</code></pre></p>

<p>The first <o>jit.gl.gridshape</o> object we create (assigned to the variable <i>mywidget</i>) corresponds to the large sphere moved by our mouse in the <o>jit.window</o>. After creating it, we set all the relevant attributes we want the sphere to have, just as we would in a Max patcher. Note that in setting the <m>position</m> attribute we only use two arguments (<i>x</i> and <i>y</i>). In an orthographic projection the <i>z</i> axis is irrelevant to how the shapes are drawn.</p>


<p><pre><code language="javascript">// create an array of [jit.gl.gridshape] objects
// randomly arrayed across the window
var mysphere = new Array(OBJECT_COUNT);</code></pre></p>

<p>Rather than naming our smaller spheres individually, we're treating them as an Array (called <i>mysphere</i>). Each element in this array will then be a separate <o>jit.gl.gridshape</o> object that we can access by array notation (e.g. <i>mysphere[5]</i> will be the <i>sixth</i> sphere, counting up from 0).</p>


<p><pre><code language="javascript">// initialize our little spheres with random colors and positions (x,y)
for(var i=0;i&lt;OBJECT_COUNT;i++) {
  mysphere[i] = new JitterObject("jit.gl.gridshape","ListenWindow");
  mysphere[i].shape = "sphere";
  mysphere[i].lighting_enable = 1;
  mysphere[i].smooth_shading = 1;
  mysphere[i].scale = [0.05,0.05,0.05];
  mysphere[i].color = [Math.random(),Math.random(),Math.random(),0.5] ;
  mysphere[i].position = [Math.random()*2.-1, Math.random()*2.-1];
  mysphere[i].blend_enable = 1;
}</code></pre></p>

<p>This code actually creates the individual <o>jit.gl.gridshape</o> objects as individual JitterObjects that are members of the Array <i>mysphere</i>. We use a JavaScript for() loop to set the initial attributes of all these objects in one block of code. We give them random initial <m>color</m> and <m>position</m> attributes, scattering them over the screen and coloring them all differently.</p>


<p><pre><code language="javascript">// create a JitterListener for our [jit.window] object
var mylistener = new JitterListener(mywindow.getregisteredname(), thecallback);</code></pre></p>


<p>Finally, we create a variable called <i>mylistener</i> that we assign to be a JitterListener object. JitterListener objects take two arguments: the <i>object</i> that they listen to, and the <i>function</i> that will be called when the object triggers an event. Our JitterListener object is set to listen to our <o>jit.window</o> object (<i>mywindow</i>). The getregisteredname() property of a JitterObject object returns the <m>name</m> by which that object can be accessed by the JitterListener (in the case of <o>jit.window</o> objects, this will be the same as name of the drawing context). Whenever our <o>jit.window</o> object generates an event, a function called thecallback() will be triggered in our JavaScript code. Now that we've instantiated a JitterListener, we can (in most cases) leave it alone and simply deal with the mechanics of the callback function it triggers in response to an event from the object it listens to.</p>

<bullet>Back in the Tutorial patcher, click the <o>message</o> box labeled <m>randomize</m> or hit the <i>spacebar</i> on your computer keyboard. The small spheres should scatter and change colors. Look at the code for the randomize() function in our <o>js</o> file.</bullet>

<p><pre><code language="javascript">function randomize() // reorient the little spheres
{
  for(var i=0;i&lt;32;i++) {
   mysphere[i].color = [Math.random(),Math.random(),Math.random(),0.5];
   mysphere[i].position = [Math.random()*2.-1, Math.random()*2.-1];
  }
}</code></pre></p>


<p>Our randomize() function takes our little spheres and scatters them randomly, changing their colors. This allows us to basically restart our simulation whenever we like.</p>

<h2>The callback function</h2>
<p>The <o>jit.window</o> object responds to a variety of mouse events. When the <m>idlemouse</m> attribute is set to <m>1</m> (as it is in our code) the <o>jit.window</o> object outputs mouse information (the <m>mouseidle</m> message) when you drag the pointer over the window. It also tells us when the pointer has left the window area (the <m>mouseidleout</m> message). Regardless of the setting of the <m>idlemouse</m> attribute, the <o>jit.window</o> object also responds to mouse clicks inside the window (the <m>mouse</m> message).</p>

<bullet>In the Tutorial patcher, move the pointer into the <o>jit.window</o> and click the mouse. The white sphere will turn into a green torus. Release the mouse and the torus will turn into a red sphere. Moving the pointer will turn the sphere white again.</bullet>
<illustration><img src="images/jitterchapter47c.png"/><i>How our sphere responds to mouse click events (mouse down and mouse up).</i></illustration>
<bullet>Look at the code for the function called thecallback() in our JavaScript code. This code executes whenever our JitterListener object receives an event from our <o>jit.window</o> object.</bullet>

<p><pre><code language="javascript">
function thecallback(event)
// callback function to handle events triggered by mousing
// in our [jit.window]
{
	var x,y,button; // some local variables for the callback function
  </code></pre></p>


<p>The <i>event</i> constructor stores the message sent by the <o>jit.window</o> object to the JitterListener object in our patch. We also declare a few local variables (<i>x</i>, <i>y</i>, and <i>button</i>) to store information about the pointer derived from the <i>event</i> message's arguments.</p>

<p>We then use JavaScript if() statements based on the <m>eventname</m> property of the <i>event</i> that triggered the callback function. The <m>eventname</m> property will contain the name of the message (<m>mouse</m>, <m>mouseidle</m>, etc.) that triggered the function.</p>


<p><pre><code language="javascript">if (event.eventname="="mouse")" {
// we're entering, dragging within, or leaving a "mouse click" event</code></pre></p>

<p>This part of the code handles a mouse click event (a click down, dragging of the mouse, and the release of a click).</p>


<p><pre><code language="javascript">// arguments are (x,y,button,cmd,shift,capslock,option,ctrl)...
// we only care about the first three
x = event.args[0];
y = event.args[1];
button = event.args[2];</code></pre></p>


<p>The first three arguments to the <m>mouse</m> event contain the position of the mouse (x and y) and a flag telling us whether the mouse button is down (<m>1</m>) or up (<m>0</m>). We store these settings into variables (<i>x</i>, <i>y</i>, and <i>button</i>) for use later on.</p>


<p><pre><code language="javascript">   if (button) // we're clicked down
   {
      mywidget.color = [0,1,0,1]; // color our control object green
      mywidget.shape = "torus"; // change it to a donut shape
   }
   else // we've just unclicked
   {
      mywidget.color = [1,0,0,1]; // color our object red
      mywidget.shape = "sphere"; // change back to a sphere
   }
   // move our control object to the drawing context's
   // equivalent of where our mouse event occurred:
   mywidget.position = myrender.screentoworld(x,y);
}</code></pre></p>


<p>If our button is down, we turn our <o>jit.gl.gridshape</o> object <i>mywidget</i> from a white sphere into a green torus. When we release the mouse, we turn it into a red sphere.</p>
<p>Finally, we update the position of the <o>jit.gl.gridshape</o> object controlled by our mouse by updating the <m>position</m> attribute of the JitterObject object <i>mywidget</i>. Because our drawing context works in OpenGL world coordinates (where the default center of the space is (0, 0) and positions are expressed in decimal values), we need to convert our <i>x</i> and <i>y</i> values into numbers that make sense for our drawing context. The screentoworld() method to a <o>jit.gl.render</o> object will convert those values from pixel coordinates on the display to world coordinates for the rendering.</p>

<p><pre><code language="javascript">else if (event.eventname="="mouseidle")" {
   // we're mousing over the window with the mouse up
   x = event.args[0];
   y = event.args[1];
   mywidget.color = [1,1,1,1] ; // color our object white
   mywidget.position = myrender.screentoworld(x,y);
}</code></pre></p>

<p>This code executes whenever we drag our pointer across the <o>jit.window</o> object without clicking the pointer. First we store the variables <i>x</i> and <i>y</i> based on the pointer position, we turn our <o>jit.gl.gridshape</o> object (<i>mywidget</i>) white, in case the previous callback had turned it a different color, and again we reposition mywidget.</p>



<p><pre><code language="javascript">else if (event.eventname="="mouseidleout")" {
   // we're no longer mousing over the window
   mywidget.color = [1,1,1,0.5] ; // make our object translucent
}</code></pre></p>

<p>When our pointer leaves the <o>jit.window</o>, the <m>eventname</m> property of our callback will be "mouseidleout". All we do is change the alpha to 0.5, leaving the sphere where it was.</p>



<p><pre><code language="javascript">
}
// don't allow this function to be called from Max
thecallback.local = 1;</code></pre></p>


<p>Because our thecallback() function is intended to be executed by our JitterListener object, we set its <m>local</m> property to <m>1</m> to prevent it from being executed directly by a Max message sent to the <o>js</o> object.</p>

<h2>Drawing the scene</h2>
<p>Now that we've seen how to respond to mouse events and update our <i>mywidget</i> object's position, color, and shape accordingly, we need to look at how we perform the actual rendering of our scene in response to a <m>bang</m> message from the <o>qmetro</o> object in our Max patcher. The bang() function in our JavaScript code handles the drawing as well as the animation of the little spheres in response to the new position of our large sphere.</p>

<bullet>Look at the code for the bang() function.</bullet>
<p>The majority of our bang() function iterates through the positions of all the little spheres and compares them to the position of the large one. If the distance between them is small enough that the spheres would overlap when drawn, we move the little sphere away the minimum amount necessary to have the spheres touch. This type of processing is known as <i>collision detection</i> and is a ubiquitous technique in the field of computer animation.</p>


<p><pre><code language="javascript">function bang()
// main drawing loop... figure out which little spheres to move
// and drive the renderer
{
  // collision detection block. we need to iterate through
  // the little spheres and check their distance from the control
  // object. if we're touching we move the little sphere away
  // along the correct angle of contact.
  for(var i = 0;i&lt;OBJECT_COUNT;i++) {</code></pre></p>

<p>We enter a JavaScript for() loop to check the position of our large sphere against every small sphere, one at a time.</p>


<p><pre><code language="javascript">// cartesian distance along the x and y axis
var distx = mywidget.position[0]-mysphere[i].position[0];
var disty = mywidget.position[1]-mysphere[i].position[1];

// polar distance between the two objects
var r = Math.sqrt(distx*distx+disty*disty);
// angle of little sphere around control object
var theta = Math.atan2(disty,distx);</code></pre></p>

<p>By subtracting the <i>x</i> and <i>y</i> positions of the two spheres (large and small) from one another, we get their Cartesian distance. We can convert this to polar (absolute) distance by applying the Pythagorean theorem to derive the hypotenuse (stored in the variable <i>r</i>). We then derive the angle of the small sphere around the large one by taking the arctangent of the rise (<i>x</i>) over the run (<i>y</i>).</p>


<p><pre><code language="javascript">// check for collision...
if(r&lt;0.15)
// control object is size 0.1, little spheres are 0.05,
// so less than 0.15 and it's a hit...
{</code></pre></p>

<p>Because our large sphere has a <m>scale</m> attribute of <m>0.1 0.1 0.1</m> and our small spheres have <m>scale</m> attributes of <m>0.05 0.05 0.05</m>, we can infer that the objects are overlapping if the distance between them is less than 0.15. This triggers a block of code that deals with the collision.</p>


<p><pre><code language="javascript">   // convert polar-&gt;cartesian to figure out x and y displacement
   var movex = (0.15-r)*Math.cos(theta);
   var movey = (0.15-r)*Math.sin(theta);

   // offset the little sphere to the new position,
   // which should be just beyond touching at the
   // angle of contact we had before. the result
   // should look like we've "pushed" it along...
   mysphere[i].position = [mysphere[i].position[0]-movex, mysphere[i].position[1]-movey];
}</code></pre></p>


<p>We use the polar distance and angle, combined with the minimum allowable distance between the objects (0.15), to derive how far we need to nudge the little sphere along the <i>x</i> and <i>y</i> axes to stop it from overlapping the large sphere. We figure out these values by converting the polar coordinates back into Cartesian values stored in the variables <i>movex</i> and <i>movey</i>. We then subtract these two variables' values from the current position of the small sphere, pushing it out of the way.</p>


<p><pre><code language="javascript">  // rendering block...
  myrender.erase(); // erase the drawing context
  myrender.drawclients(); // draw the client objects
  myrender.swap(); // swap in the new drawing
}</code></pre></p>

<p>This last block of code does the actual rendering. Just as you would when working with Jitter OpenGL objects in a Max patcher, you send an <m>erase</m> message to the <o>jit.gl.render</o> object (<i>myrender</i>). The drawclients() method to <o>jit.gl.render</o> collects all the relevant information from the OpenGL objects attached to our drawing context and draws them; any OpenGL objects with an <m>automatic</m> attribute set to <m>0</m> will have to be drawn manually here. The swap() method then replaces the old rendering with the new one in the <o>jit.window</o> object, showing us the updated scene. The drawclients() and swap() method are combined into one operation when you send a <m>bang</m> message to a <o>jit.gl.render</o> object in a Max patcher.</p>

<bullet>Back in the Tutorial patcher, click the <o>toggle</o> box attached to the <o>message</o> box labeled <m>fullscreen $1</m> (or hit the <i>escape</i> key on your computer keyboard). The <o>jit.window</o> object will fill the screen. Notice that the coordinate conversion that allows you to move the large sphere around the screen with the mouse still works fine. You can take the <o>jit.window</o> object out of fullscreen mode by pressing the <i>escape</i> key on your keyboard. In the JavaScript code, look at the fullscreen() function:</bullet>
<p> </p>

<p><pre><code language="javascript">function fullscreen(v)
// function to send the [jit.window] into fullscreen mode
{
  mywindow.fullscreen = v;
}</code></pre></p>

<p>The fullscreen() attribute of a <o>jit.window</o> JitterObject object behaves just as the <m>fullscreen</m> message sent to a <o>jit.window</o> object in a Max patcher.</p>

<h2>Summary</h2>
<p>An entire OpenGL Jitter patch can be encapsulated in JavaScript by instantiating <o>jit.gl.render</o>, <o>jit.window</o>, and other OpenGL objects within procedural code written for the <o>js</o> object. These objects have all their messages and attributes exposed as corresponding methods and properties. You can use a JitterListener object to respond to events triggered by a Jitter object within JavaScript. The JitterListener then executes a callback function, passing the calling message to it as its argument. This allows you to write JavaScript functions to respond to mouse interactivity in a <o>jit.window</o> object, file reading in a <o>jit.movie</o> object, and other situations where you would want to respond to an event triggered by a message sent by a Jitter object out its status outlet in a Max patcher.</p>

<h2>Code Listing</h2>

<p><pre><code language="javascript">// 47jMarbles.js
//
// Demonstrates how to set up a JitterListener object to listen
// to the output of a Jitter object instantiated within [js].
//
// rld, 7.05
//

var OBJECT_COUNT = 32; // number of little spheres

// create a [jit.window] object for our display
// (this is the object we'll "listen" to):
var mywindow = new JitterObject("jit.window","ListenWindow");
// turn off depth testing... we're using blending instead:
mywindow.depthbuffer = 0;
// turn ON idlemousing... we want to listen for it:
mywindow.idlemouse = 1;

// create a [jit.gl.render] object for drawing into our window:
var myrender = new JitterObject("jit.gl.render","ListenWindow");
// use a 2-dimensional projection:
myrender.ortho = 2;
// set background to black with full erase opacity (no trails):
myrender.erase_color = [0,0,0,1];

// create a [jit.gl.gridshape] object for use to control with the mouse
var mywidget = new JitterObject("jit.gl.gridshape","ListenWindow");
mywidget.shape = "sphere";
mywidget.lighting_enable = 1;
mywidget.smooth_shading = 1;
mywidget.scale = [0.1,0.1,0.1];
mywidget.color = [1,1,1,0.5] ;
mywidget.blend_enable = 1;
mywidget.position = [0,0]; // no z necessary in orthographic projection

// create an array of [jit.gl.gridshape] objects randomly arrayed across the window
var mysphere = new Array(OBJECT_COUNT);

// initialize our little spheres with random colors and positions (x,y)
for(var i=0;i&lt;OBJECT_COUNT;i++) {
  mysphere[i] = new JitterObject("jit.gl.gridshape","ListenWindow");
  mysphere[i].shape = "sphere";
  mysphere[i].lighting_enable = 1;
  mysphere[i].smooth_shading = 1;
  mysphere[i].scale = [0.05,0.05,0.05];
  mysphere[i].color = [Math.random(),Math.random(),Math.random(),0.5] ;
  mysphere[i].position = [Math.random()*2.-1, Math.random()*2.-1];
  mysphere[i].blend_enable = 1;
}

// create a JitterListener for our [jit.window] object
var mylistener = new JitterListener(mywindow.getregisteredname(), thecallback);

function randomize() // reorient the little spheres
{
  for(var i=0;i&lt;32;i++) {
   mysphere[i].color = [Math.random(),Math.random(),Math.random(),0.5] ;
   mysphere[i].position = [Math.random()*2.-1, Math.random()*2.-1];
  }
}


function thecallback(event)
// callback function to handle events triggered by mousing
// in our [jit.window]
{

  var x,y,button; // some local variables for thecallback
  if (event.eventname="="mouse")" {
  // we're entering, dragging within, or leaving a "mouse click" event

   // arguments are (x,y,button,cmd,shift,capslock,option,ctrl)...
   // we only care about the first three
   x = event.args[0];
   y = event.args[1];
   button = event.args[2];
   if (button) // we're clicked down
   {
      mywidget.color = [0,1,0,1]; // color our control object green
      mywidget.shape = "torus"; // change it to a donut shape
   }
   else // we've just unclicked
   {
      mywidget.color = [1,0,0,1]; // color our object red
      mywidget.shape = "sphere"; // change back to a sphere
   }
   // move our control object to the drawing context's
   // equivalent of where our mouse event occurred:
   mywidget.position = myrender.screentoworld(x,y);
  }
  else if (event.eventname="="mouseidle")" {
  // we're mousing over the window with the mouse up
   x = event.args[0];
   y = event.args[1];
   mywidget.color = [1,1,1,1] ; // color our object white
   // move our control object to the drawing context's
   // equivalent of where our mouse event occurred:
   mywidget.position = myrender.screentoworld(x,y);
  }
  else if (event.eventname="="mouseidleout")" {
  // we're no longer mousing over the window
   mywidget.color = [1,1,1,0.5] ; // make our object translucent
  }


}
// don't allow this function to be called from Max
thecallback.local = 1;

function bang()
// main drawing loop... figure out which little spheres to move
// and drive the renderer
{
  // collision detection block. we need to iterate through
  // the little spheres and check their distance from the control
  // object. if we're touching we move the little sphere away
  // along the correct angle of contact.
  for(var i = 0;i&lt;OBJECT_COUNT;i++) {
   // cartesian distance along the x and y axis
   var distx = mywidget.position[0]-mysphere[i].position[0];
   var disty = mywidget.position[1]-mysphere[i].position[1];

   // polar distance between the two objects
   var r = Math.sqrt(distx*distx+disty*disty);
   // angle of little sphere around control object
   var theta = Math.atan2(disty,distx);

   // check for collision...
   if(r&lt;0.15)
   // control object is size 0.1, little spheres are 0.05,
   // so less than 0.15 and it's a hit...
   {
      // convert polar-&gt;cartesian to figure out x and y displacement
      var movex = (0.15-r)*Math.cos(theta);
      var movey = (0.15-r)*Math.sin(theta);

      // offset the little sphere to the new position,
      // which should be just beyond touching at the
      // angle of contact we had before. the result
      // should look like we've "pushed" it along...
      mysphere[i].position = [mysphere[i].position[0]-movex, mysphere[i].position[1]-movey];
   }
  }

  // rendering block...
  myrender.erase(); // erase the drawing context
  myrender.drawclients(); // draw the client objects
  myrender.swap(); // swap in the new drawing
}

function fullscreen(v)
// function to send the [jit.window] into fullscreen mode
{
  mywindow.fullscreen = v;
}</code></pre></p>


   <seealsolist>
      <seealso name="jit.gl.gridshape">Generate simple geometric shapes as a connected grid</seealso>
      <seealso name="jit.gl.render">Render Open GL</seealso>
      <seealso name="jit.window">Display data in a Window</seealso>
      <seealso name="js">Javascript in Max</seealso>
   </seealsolist>
   </chapter>
