ConstructorBeta/Docs/SimpleBoxToolPlugin

From TDN

Contents


SimpleBox Tool Plug-in

This page breaks down the SimpleBox example tool plug-in that is included with Constructor starting with Beta 5.


Introduction

The SimpleBox example tool plug-in may be found in constructor\client\plug-ins starting with Beta 5. It is fairly well internally commented and this page will expand upon these comments. To activate this tool (or any 3rd party tool starting with Beta 5) look under the Tools->User Plug-ins menu. This is a temporary location until the plug-in system is complete.


Header

Starting at the top of the plug-in.

// simplebox.cs
//
// Defines the SimpleBox tool plug-in to create a bare-bones cube.
//
// The static ScriptObject makes use of the following dynamic fields:
// init     - If 'true' indicates that the static has been initialized (needs to be done once)
// size[]   - Defines the xyz size of the cube as a 3 element array
// center[] - Defines the xyz center point of the cube as a 3 element array
// uscale	   - Texture scale along the 'u' axis
// vscale	   - Texture scale along the 'v' axis
// uoffset  - Texture offset along the 'u' axis
// voffset  - Texture offset along the 'v' axis
//
// The cube instance makes use of the following dynamic fields:
// static       - Points to the static ScriptObject
// handlepos[9] - Defines the xzy center point of the nine user controlable handles, each as a 3 element array. 0=center handle, 1-8=sizing corner handles
// dirty        - Flag to indicate that the tool needs to be refreshed on screen
// active       - Flag to indicate that the tool is active, draw its handles, and interact with the user
// update       - Store a value to be returned to Constructor when asked about the tool's edit state, such as do nothing or update with new settings, etc.
// changeCenter - Flag to indicate that the tool's center (origin) position has changed
// changeSize   - Flag to indicate that the tool's bounding box size has changed
//
// Revision History:
// July 13, 2005		David Wyand		Created script file
//

When I build plug-ins I usually provide the pertinent information at the top of the file. This provides a list of all the important variables and any other notes at-a-glance. This is all optional for your own plug-ins of course.

package SimpleBox
{

All plug-ins are Torque Script packages that are activated when the tool is made active. The plug-in simply overrides the methods from a generic Plugin class that provides default functionality when the plug-in doesn't specifically define a method. This also requires that only one plug-in is active at a time which is taken care of by Constructor.


Activate() Method

   //************************************************************************************
   // Activate()
   //
   // Called when the tool is activated.  %version holds the current version of this
   // tool type in Constructor to allow the tool to step down features if required.
   // %inst is actually a ScriptObject behind the scenes that allows for the tool's
   // instance to be attached to it -- which is typically a ScriptObject itself.
   // %static is a ScriptObject that allows anything to be attached to it that will
   // presist across tool instances.
   // Return a Tool Return Function to indicate success of the tool's activation.

   function Plugin::Activate(%this, %version, %inst, %static)
   {
      //error("SimpleBox: Activate(" @ %version @ "," @ %inst @ "," @ %static @ ")");

All plug-ins must have an Activate method. It is the main entry point when the tool is made the current one and defines how the plug-in is set up for the Tool Manager. The comments in the code above describe each of the passed parameters.

      //*** Check for a valid version
      if(%version != 1)
      {
         return tool.FUNC_BADVERSION();
      }

It is usually a good idea to check the currently supported version for this type of plug-in. When the plug-in is registered the Tool Manager is told what version of the plug-in interface is expected. Usually this same version is passed back through Activate()'s %version parameter although it is not guaranteed. The user may be running an older version of Constructor or a newer version that cannot support previous plug-in interface versions. If we find that the user is running an older version of Constructor it is up to us to decide if we fall back or simply error out. In this case we've decided to only work with the version 1 plug-in interface.

      //*** Has the static been set up?
      if(!%static.init)
      {
         SimpleBox_InitStatic(%static);
      }
 

The static object is used to store information that will persist beyond this particular instance of the plug-in. This is where you could store properties the user has set up that you'd like to present the next time the tool is activated. ie: a texture scale that will automatically be used the next time the tool is used unless the user changes it. In the code above the static data is only initialized the first time the tool is activated. Otherwise the static data would be reset for each tool instance and would defeat the purpose of it being static.

      //*** Build the tool's instance
      %cube = new ScriptObject();
      
      //*** Attach the static object to the cube.  This is to share some properties
      //*** such as the cube's centre and size
      %cube.static = %static;

The tool's instance object is specific to the lifetime of a tool's activation through deactivation. Anything that needs to be kept track of for a particular run may be stored here. Examples for the SimpleBox tool are 3D View handle positions and dirty flags. It is also handy to store a pointer to the static data in case we need to retrieve and manipulate it.

      //*** Setup the standard bounding box based on the default values
      ToolBB::rebuildBoundingBox(%cube, %static);

The SimpleBox tool makes use of the standard bound box helper functions. These take the drudgery out of taking care of the handles and drawing the box. It does impose some requirements on your tool such as specific static and instanced parameter names. The use of these helper functions will be covered in another article. Above we're simply passing along pointers to our instance and static data to allow the bounding box routine to do its thing.

      //*** Setup some additional attributes for the cube instance
      %cube.dirty = tool.DIRTY_NONE();
      %cube.active = false;
      %cube.update = tool.EDIT_DONOTHING();
      %cube.changeCenter = false;
      %cube.changeSize = false;
      
      //*** Pass along the instance
      %inst.instance = %cube;
      %inst.flagsInterface = tool.IFLAG_STANDARDGEOMETRY() + tool.IFLAG_DRAWALLAXISSAME(); // Set up the tool with the standard geometry creation GUI
      %inst.flagsApply = tool.AFLAG_STANDARDGEOMETRY();     // Set up the tool with the standard geometry creation post apply selections
      
      //*** Return that everything is OK
      return tool.FUNC_OK();
   }


Done() Method

   //************************************************************************************
   // Done()
   //
   // Called when the user is finished with the tool.  Typically any allocated
   // memory is freed here.  %inst and %static are the same as those in the
   // activation function.  This function does not return a value.
   function Plugin::Done(%this, %inst, %static)
   {
      //error("SimpleBox: Done(" @ %inst @ "," @ %static @ ")");

      %cube = %inst.instance;
      
      if(%cube)
      {         
         //*** Delete our instance
         %cube.delete();
         %inst.instance = 0;
      }
   }


MouseDown() Method

   //************************************************************************************
   // MouseDown()
   //
   // This function is called allow the tool to process a mouse down event.  Returning
   // false indicates that the handles should be used rather than raw mouse handling.
   function Plugin::MouseDown(%this, %inst, %event)
   {
      //error("SimpleBox: MouseDown(" @ %inst @ "," @ %event @ ")");

      //*** We only use handles so return 'false'
      return false;
   }


HandleCount() Method

   //************************************************************************************
   // HandleCount()
   //
   // Returns the number of user controlable handles.  These allow the user to
   // graphically interact with the tool.  If this function returns 0, then
   // the HandleInit() function will be called to set the initial
   // handle points.
   function Plugin::HandleCount(%this, %inst, %event)
   {
      //error("SimpleBox: HandleCount(" @ %inst @ "," @ %event @ ")");

      %cube = %inst.instance;

      //*** If we're not yet active, return 0 to have the handles initialized by
      //*** HandleInit().  Otherwise, return the number of handles the user may
      //*** interact with.  We're using the bounding box helper exclusively here
      //*** so allow it to return the number of handles.
      return %cube.active ? ToolBB::getHandleCount() : 0;      
   }


HandleInit() Method

   //************************************************************************************
   // HandleInit()
   //
   // Called when the HandleCount() function returns 0 and the mouse
   // button has just been depressed.  %event will contain the particulars of where
   // the mouse button was pressed to allow for the tool to set itself up for the
   // first time.  The value returned is the (zero-based) index of the handle that is now
   // active and will be dragged by the user until the mouse button is released.
   function Plugin::HandleInit(%this, %inst, %event)
   {
      //error("SimpleBox: HandleInit(" @ %inst @ "," @ %event @ ")");

      %cube = %inst.instance;

      //*** Make the tool active
      if(!%cube.active)
      {
         %cube.active = true;
      }
      
      //*** Allow the bounding box helper to set up the handles
      return ToolBB::initHandles(%cube, %cube.static, %event);
   }


Handle() Method

   //************************************************************************************
   // Handle()
   //
   // This function is called under a couple of different circumstances.  The first is
   // when the mouse button is held down and the mouse dragged.  In this case %hindex
   // contains the index to the handle that is being manipulated by the user.  This
   // function is also called right after the mouse button has been pressed for all of
   // the handles (as defined in HandleCount()) for the system to determine
   // which handle has been selected.  In both cases, %info is a ScriptObject that
   // contains the .pos[3] fields that are to be filled in with the requested handle's
   // position.  This function returns the priority of the handle, the higher the number
   // the higher the priority.  This is used to determine which handle should be selected
   // when two or more handles overlap on the screen.  If -1 is returned, then the handle
   // is considered disabled and will not take part in user selections (and %info.pos[3]
   // need not be filled in).
   function Plugin::Handle(%this, %inst, %event, %hindex, %info)
   {
      //error("SimpleBox: Handle(" @ %inst @ "," @ %event @ "," @ %hindex @ "," @ %info @ ")");

      %cube = %inst.instance;
      
      //*** Fill in the handle's position and return its priority
      return ToolBB::getHandle(%cube, %event, %hindex, %info);
   }


HandleMoved() Method

   //************************************************************************************
   // HandleMoved()
   //
   // This function is called when the mouse moves and a handle is being dragged.  The
   // %hindex is the (zero-based) index of the handle that is being adjusted.  The value
   // returned is the index of the handle that should continue being moved -- usually this
   // is the same as %hindex.
   function Plugin::HandleMoved(%this, %inst, %event, %hindex)
   {
      //error("SimpleBox: HandleMoved(" @ %inst @ "," @ %event @ "," @ %hindex @ ")");

      %cube = %inst.instance;
      
      //*** Move the appropriate bounding box handle.
      %returnHandle = ToolBB::moveHandle(%cube, %cube.static, %event, %hindex);
      
      //*** Notify that we need to redraw the plugin as well as geometry
      %cube.dirty = tool.DIRTY_APPEARANCE();
      %cube.update = tool.EDIT_UPDATE();
      
      return %returnHandle;
   }


Dirty() Method

   //************************************************************************************
   // Dirty()
   //
   // This function is called to determine if the tool needs to be redrawn.  Return a
   // combination of the tool.DIRTY_* flags added together to indicate that the tool's
   // features (but not geometry) should be redrawn.
   function Plugin::Dirty(%this, %inst)
   {
      //error("SimpleBox: Dirty(" @ %inst @ ")");

      %cube = %inst.instance;
      
      return %cube.dirty ? tool.DIRTY_APPEARANCE() : tool.DIRTY_NONE();
   }


Draw() Method

   //************************************************************************************
   // Draw()
   //
   // This function is called to draw the tool itself.  Geometry is not built here but
   // in BuildGeometry().  The %draw parameter points to the ToolDrawing class
   // and is used to build up the tool's wireframe.  Just before this function is called,
   // Constructor will clear the draw buffer, so the tool is responsible for recreating
   // the tool's appearance.  This function may be called multiple times, once for each
   // view type.  The %draw.getView(); function returns the current view type.  The tool
   // is not required to do anything different for each view type and may send the same drawing
   // commands on each call to this function, although it may be wise to treat the UV view
   // as a special case.  Draw() does not return a value.
   function Plugin::Draw(%this, %inst, %draw)
   {
      //error("SimpleBox: Draw(" @ %inst @ "," @ %draw @ ")");

      %cube = %inst.instance;
      
      //*** If the tool is not active, then don't draw it
      if(!%cube.active)
         return;

      //*** Draw the standard bounding box
      ToolBB::draw(%cube, %cube.static, %draw);

      //*** Indicate that we've drawn the tool
      %cube.dirty = tool.DIRTY_NONE();
   }


CheckEditAction() Method

   //************************************************************************************
   // CheckEditAction()
   //
   // This function is called to determine how to handle the tool's geometry.  Return
   // one of the tool.EDIT_* flags to indicate how to modify the geometry based on the
   // latest change.
   function Plugin::CheckEditAction(%this, %inst)
   {
      //error("SimpleBox: CheckEditAction(" @ %inst @ ")");

      %cube = %inst.instance;
      
      return %cube.update;
   }


EndEditAction() Method

   //************************************************************************************
   // EndEditAction()
   //
   // This function is called after the completion of a mouse down to mouse drag to mouse
   // up sequence.  This may be called a number of times.  The %keep parameter is set
   // based on what is returned from the CheckEditAction() function.  This function
   // does not return a value.
   function Plugin::EndEditAction(%this, %inst, %keep)
   {
      //error("SimpleBox: EndEditAction(" @ %inst @ "," @ %keep @ ")");

      %cube = %inst.instance;
      
      %cube.update = tool.EDIT_DONOTHING();
      %cube.active = false;
      %cube.changeSize = false;
      %cube.changeCenter = false;
   }


BuildGeometry() Method

   //************************************************************************************
   // BuildGeometry()
   //
   // This function is called to build/edit the tool's actual geometry.  %edit points to
   // the geometry edit operation structure.  Return a Tool Return Function to indicate
   // success of the tool's operation on the geometry.
   function Plugin::BuildGeometry(%this, %inst, %edit)
   {
      //error("SimpleBox: BuildGeometry(" @ %inst @ "," @ %edit @ ")");

      %cube = %inst.instance;
      
      // Work on the actual geometry.
      SimpleBox_MakeCubeGeometry(%cube, %edit);
      
      //*** As we've now worked on the geometry, set the edit update indicator to do nothing.
      %cube.update = tool.EDIT_DONOTHING();
      
      return tool.FUNC_OK();
   }


UserEvent() Method

   //************************************************************************************
   // UserEvent()
   //
   // This function is called when the user does something to the tool, such as activate
   // it or reset it.  %userevent is the event that the user caused.  This function does
   // not return a value.
   function Plugin::UserEvent(%this, %inst, %userevent)
   {
      //error("SimpleBox: UserEvent(" @ %inst @ "," @ %userevent @ ")");

      %cube = %inst.instance;
      
      switch(%userevent)
      {
         //*** User activated the tool such that we should continue to use the current
         //*** settings (ie: same centre and size).  This is different from the user
         //*** clicking in the 3D interface to draw a new cube.
         case tool.EVENT_ACTIVATE():
            %cube.update = tool.EDIT_UPDATE();
            %cube.active = true;
            %cube.dirty = tool.DIRTY_APPEARANCE();
            %cube.changeSize = true;
            %cube.changeCenter = true;
            
         //*** The user has asked that the tool be reset back to its default values/settings.
         case tool.EVENT_RESET():
            SimpleBox_DefaultValues(%cube.static);
            ToolBB::rebuildBoundingBox(%cube, %cube.static);
            %cube.update = tool.EDIT_UPDATE();
            %cube.active = true;
            %cube.dirty = tool.DIRTY_APPEARANCE();
            %cube.changeSize = true;
            %cube.changeCenter = true;
         
         //*** The user has deactivated the tool.  If the tool is active, then we tell
         //*** Constructor to reject any interactive action that is partly complete.  This
         //*** will discard any geometry the tool has created.
         case tool.EVENT_DEACTIVATE():
            if(%cube.active)
            {
               %cube.update = tool.EDIT_REJECT();
            }
            %cube.dirty = tool.DIRTY_APPEARANCE();
         
         //*** The user has change the currently active texture.  If the tool is active, then
         //*** we tell Constructor to update our geometry.
         case tool.EVENT_TEXTURECHANGE():
            if(%cube.active)
            {
               %cube.update = tool.EDIT_UPDATE();
            }
      }
   }


Interface() Method

   //************************************************************************************
   // Interface()
   //
   // This function sets up the GUI for the tool to allow the user to change the tool's
   // parameters.  %form points to the interface construction class that this function
   // makes calls to when building the interface.  This function does not return a value.
   function Plugin::Interface(%this, %inst, %form)
   {
      //error("SimpleBox: Interface(" @ %inst @ "," @ %form @ ")");

      %cube = %inst.instance;

      //*** Provide a title
      %form.defineTitle("Simple Box");

      //*** Add our fields to the form in the order we wish them displayed.  A field
      //*** with an ID of -1 will not have a value get/set.
      %form.addField( 0, "Center"   ,"distance3");
      %form.addField( 1, "Size"     ,"distance3");
      %form.addField( -1, "Texturing" ,"divider");
      %form.addField( 2, "U Scale"  ,"numeric");
      %form.addField( 3, "V Scale"  ,"numeric");
      %form.addField( 4, "U Offset" ,"numeric");
      %form.addField( 5, "V Offset" ,"numeric");
   }


InterfaceGet() Method

   //************************************************************************************
   // InterfaceGet()
   //
   // This function is called to retrieve a value from the tool given the field's ID
   // in %id.  The value of the field is then returned.
   function Plugin::InterfaceGet(%this, %inst, %id)
   {
      //error("SimpleBox: InterfaceGet(" @ %inst @ "," @ %id @ ")");

      %cube = %inst.instance;
      
      switch(%id)
      {
         //*** Handle the 'Center' field
         case 0:
            %value = %cube.static.center[0] SPC %cube.static.center[1] SPC %cube.static.center[2];
            return %value;
      
         //*** Handle the 'Size' field
         case 1:
            %value = %cube.static.size[0] SPC %cube.static.size[1] SPC %cube.static.size[2];
            return %value;
      
         //*** Handle the 'U Scale' field
         case 2:
            %value = %cube.static.uscale;
            return %value;
      
         //*** Handle the 'V Scale' field
         case 3:
            %value = %cube.static.vscale;
            return %value;
      
         //*** Handle the 'U Offset' field
         case 4:
            %value = %cube.static.uoffset;
            return %value;
      
         //*** Handle the 'V Offset' field
         case 5:
            %value = %cube.static.voffset;
            return %value;
      }
      
      return 0;
   }


InterfaceSet() Method

   //************************************************************************************
   // InterfaceSet()
   //
   // This function is called to set a value for the tool given the field's ID
   // in %id, and the value to set to in %value.  This function returns tool.FUNC_OK();
   // if the value was accepted.  Otherwise it returns tool.FUNC_BADVALUE(); to indicate
   // that the given value is invalid and the correct value should be retrieved from the
   // tool once again.
   function Plugin::InterfaceSet(%this, %inst, %id, %value)
   {
      //error("SimpleBox: InterfaceSet(" @ %inst @ "," @ %id @ "," @ %value @")");

      %cube = %inst.instance;
      
      switch(%id)
      {
         //*** Handle the 'Center' field
         case 0:
            for(%i=0; %i<3; %i++)
            {
               %cube.static.center[%i] = getWord(%value, %i);
            }
            %cube.changeCenter = true;
      
         //*** Handle the 'Size' field
         case 1:
            for(%i=0; %i<3; %i++)
            {
               %cube.static.size[%i] = getWord(%value, %i);
            }
            %cube.changeSize = true;
      
         //*** Handle the 'U Scale' field
         case 2:
            %cube.static.uscale = %value;
            %cube.changeSize = true;
      
         //*** Handle the 'V Scale' field
         case 3:
            %cube.static.vscale = %value;
            %cube.changeSize = true;
      
         //*** Handle the 'U Offset' field
         case 4:
            %cube.static.uoffset = %value;
            %cube.changeSize = true;
      
         //*** Handle the 'V Offset' field
         case 5:
            %cube.static.voffset = %value;
            %cube.changeSize = true;
      }

      //*** If we're not yet active, make it as if an EVENT_ACTIVATE has been received
      if(!%cube.active)
      {
         %cube.active = true;
         %cube.changeSize = true;
         %cube.changeCenter = true;
      }
      
      //*** Indicate that everything needs to be redrawn
      %cube.update = tool.EDIT_UPDATE();
      %cube.dirty = tool.DIRTY_APPEARANCE();
      ToolBB::rebuildBoundingBox(%cube, %cube.static);
      
      return tool.FUNC_OK();
   }


SimpleBox Specific Functions

These are some helper functions built for the SimpleBox tool. They do not form the core of a plug-in's interface and could be integrated with the methods above.


SimpleBox_DefaultValue() Function

   //*** Reset the given object to default values
   function SimpleBox_DefaultValues(%obj)
   {
      %obj.center[0] = 0.0; // x
      %obj.center[1] = 0.0; // y
      %obj.center[2] = 0.0; // z
      
      %obj.size[0] = 1.0; // x
      %obj.size[1] = 1.0; // y
      %obj.size[2] = 1.0; // z
      
      %obj.uscale = 1.0;
      %obj.vscale = 1.0;
      %obj.uoffset = 0.0;
      %obj.voffset = 0.0;
   }


SimpleBox_InitStatic() Function

   //*** Init the static object
   function SimpleBox_InitStatic(%static)
   {
      //*** Setup default values
      SimpleBox_DefaultValues(%static);
      
      //*** Signal we're all setup.
      %static.init = true;
   }


SimpleBox_ResetCube() Function

   //*** Reset the cube instance to default values
   function SimpleBox_ResetCube(%cube)
   {
      //*** Retrieve a pointer to the static data
      %static = %cube.static;
      
      //*** Setup default values
      SimpleBox_DefaultValues(%static);
      ToolBB::rebuildBoundingBox(%cube, %cube.static);
   }


SimpleBox_MakeCubeGeometry() Function

   //*** Build/modify the actual geometry
   function SimpleBox_MakeCubeGeometry(%cube, %edit)
   {
      //*** If we're not active, don't create geometry
      if(!%cube.active)
         return;
         
      //*** Check if there has already been a brush created.  If not, then we'll
      //*** build one here.
      %count = %edit.getEditBrushCount();
      if(%count == 0)
      {
         %brush = new MapBrush();
         
      } else
      {
         %brush = %edit.getEditBrush(0);
      }
   
      //*** Work on the sizing of the brush, if appropriate
      if(%cube.changeSize == true)
      {
         //*** Clear all planes on the brush to rebuild them.
         %brush.clearAllPlanes();
         
         //*** Define the cube's origin
         %center = %cube.static.center[0] SPC %cube.static.center[1] SPC %cube.static.center[2];
         %brush.setOrigin(%center);

         //*** Setup texture parameters
         %brush.setTextureOffset(%cube.static.uoffset, %cube.static.voffset);
         %brush.setTextureScale(%cube.static.uscale, %cube.static.vscale);
         
         //*** Prepare for texturing
         %tx = %cube.static.size[0] * 0.5;
         %ty = %cube.static.size[1] * 0.5;
         %tz = %cube.static.size[2] * 0.5;

         //*** Now build the main six planes.
         %brush.setTexturePlanesByPoints(%tx SPC -(%ty) SPC -(%tz*2), %tx SPC -(%ty) SPC -(%tz), %tx SPC %ty SPC -(%tz), 0.0, 0.0);
         %brush.addPlane("1 0 0 " @ -1.0*(%cube.static.center[0] + (%cube.static.size[0] * 0.5)));

         %brush.setTexturePlanesByPoints(-(%tx) SPC %ty SPC -(%tz*2), -(%tx) SPC %ty SPC -(%tz), -(%tx) SPC -(%ty) SPC -(%tz), 0.0, 0.0);
         %brush.addPlane("-1 0 0 " @ (%cube.static.center[0] - (%cube.static.size[0] * 0.5)));

         %brush.setTexturePlanesByPoints(%tx SPC %ty SPC -(%tz*2), %tx SPC %ty SPC -(%tz), -(%tx) SPC %ty SPC -(%tz), 0.0, 0.0);
         %brush.addPlane("0 1 0 " @ -1.0*(%cube.static.center[1] + (%cube.static.size[1] * 0.5)));
            
         %brush.setTexturePlanesByPoints(-(%tx) SPC -(%ty) SPC -(%tz*2), -(%tx) SPC -(%ty) SPC -(%tz), %tx SPC -(%ty) SPC -(%tz), 0.0, 0.0);
         %brush.addPlane("0 -1 0 " @ (%cube.static.center[1] - (%cube.static.size[1] * 0.5)));

         %brush.setTexturePlanesByPoints(-(%tx) SPC -(%ty*2) SPC %tz, -(%tx) SPC -(%ty) SPC %tz, %tx SPC -(%ty) SPC %tz, 0.0, 0.0);
         %brush.addPlane("0 0 1 " @ -1.0*(%cube.static.center[2] + (%cube.static.size[2] * 0.5)));
            
         %brush.setTexturePlanesByPoints(%tx SPC -(%ty*2) SPC -(%tz), %tx SPC -(%ty) SPC -(%tz), -(%tx) SPC -(%ty) SPC -(%tz), 0.0, 0.0);
         %brush.addPlane("0 0 -1 " @ (%cube.static.center[2] - (%cube.static.size[2] * 0.5)));
      }
   
      //*** Work on the position of the brush, if appropriate
      if(%cube.changeCenter == true)
      {
         %id = %brush.getBrushID();
         //*** Check if his brush has not yet been added to the map.  In this case, the building
         //*** of the planes using the change in size above will put it in the correct
         //*** location.
         if(%id != -1)
         {
            %edit.setBrushPosition(%id, %cube.static.center[0] SPC %cube.static.center[1] SPC %cube.static.center[2]);
         }
      }
         
      //*** Notify the edit operation of the new brush or change in an existing brush.
      %edit.updateBrush(%brush);
   }


End of Tool Package

};

Tool Registration

tool.register("SimpleBox", tool.typeInteractive(), tool.RFLAG_NONE(), "Simple Box" );