Open Inventor Release 2024.2.0
 
Loading...
Searching...
No Matches
JumpingJackKit

This section describes one more new class of node kit, JumpingJackKit. It is a stick figure of a man that responds to mouse events by moving his arms and legs back and forth. Catalog Diagram for JumpingJackKit shows a diagram of Jack's catalog.

All parts of the body (“head,” “body,” “leftArm,” “rightArm,” “leftLeg,” “rightLeg”) are of type SoShapeKit, so that users can replace them with any shape they want.

An SoEventCallback node is added as a child of the “callbackList” part. When the mouse goes down over Jack, this node's callback animates the body by editing the transforms of the arm and leg body parts.

Catalog Diagram for JumpingJackKit

JumpingJackKit.h shows the header file for JumpingJackKit.

Example : JumpingJackKit.h

#include <Inventor/nodekits/SoBaseKit.h>
class SoEventCallback;
class JumpingJackKit : public SoBaseKit
{
SO_KIT_HEADER( JumpingJackKit );
SO_KIT_CATALOG_ENTRY_HEADER( body );
SO_KIT_CATALOG_ENTRY_HEADER( head );
SO_KIT_CATALOG_ENTRY_HEADER( leftArm );
SO_KIT_CATALOG_ENTRY_HEADER( rightArm );
SO_KIT_CATALOG_ENTRY_HEADER( leftLeg );
SO_KIT_CATALOG_ENTRY_HEADER( rightLeg );
public:
JumpingJackKit();
// Overrides default method. All the parts are shapeKits,
// so this node will not affect the state.
virtual SbBool affectsState() const;
static void initClass();
static void exitClass();
private:
// Constructor calls to build and set up parts.
void createInitialJack();
// An SoEventCallback will be inserted into the
// "callbackList" (inherited from SoBaseKit) as the part
// "callbackList[0]". This routine jumpJackJump() will be
// set as the callback function for that part. It is this
// routine which changes the angles in the joints.
static void jumpJackJump( void* userData, SoEventCallback* eventCB );
virtual ~JumpingJackKit();
};

The constructor for JumpingJackKit calls createInitialJack(). This routine, shown in JumpingJackKit.c++ , constructs the man, moves the parts to a starting position, and creates an SoEventCallback node, which it installs as “callbackList[0].” The constructor also creates the node-kit catalog and performs other standard construction tasks.

The callback is called “jumpJackJump.” Basically, it sees if the mouse-down event occurred over the object. If so, then the limbs are rotated.

Example : JumpingJackKit.c++

#include <Inventor/SoPickedPoint.h>
#include <Inventor/events/SoMouseButtonEvent.h>
#include <Inventor/nodekits/SoShapeKit.h>
#include <Inventor/nodes/SoCube.h>
#include <Inventor/nodes/SoCylinder.h>
#include <Inventor/nodes/SoEventCallback.h>
#include <Inventor/nodes/SoSphere.h>
#include <Inventor/nodes/SoTransform.h>
#include "JumpingJackKit.h"
SO_KIT_SOURCE( JumpingJackKit );
void
JumpingJackKit::initClass()
{
SO_KIT_INIT_CLASS( JumpingJackKit, SoBaseKit, "BaseKit" );
}
void
JumpingJackKit::exitClass()
{
SO__KIT_EXIT_CLASS( JumpingJackKit );
}
JumpingJackKit::JumpingJackKit()
{
SO_KIT_CONSTRUCTOR( JumpingJackKit );
// Add the body parts to the catalog...
SO_KIT_ADD_CATALOG_ENTRY( body, SoShapeKit, TRUE, this, "", TRUE );
SO_KIT_ADD_CATALOG_ENTRY( head, SoShapeKit, TRUE, this, "", TRUE );
SO_KIT_ADD_CATALOG_ENTRY( leftArm, SoShapeKit, TRUE, this, "", TRUE );
SO_KIT_ADD_CATALOG_ENTRY( rightArm, SoShapeKit, TRUE, this, "", TRUE );
SO_KIT_ADD_CATALOG_ENTRY( leftLeg, SoShapeKit, TRUE, this, "", TRUE );
SO_KIT_ADD_CATALOG_ENTRY( rightLeg, SoShapeKit, TRUE, this, "", TRUE );
SO_KIT_INIT_INSTANCE();
createInitialJack();
}
JumpingJackKit::~JumpingJackKit() {}
// This kit is made up entirely of SoShapeKits.
// Since SoShapeKits do not affect state, neither does this.
SbBool
JumpingJackKit::affectsState() const
{
return FALSE;
}
// Set up parts for default configuration of the jumping jack
void
JumpingJackKit::createInitialJack()
{
// Create the head.
SoSphere* headSphere = new SoSphere;
setPart( "head.shape", headSphere );
// Create the body.
SoCube* bodyCube = new SoCube;
setPart( "body.shape", bodyCube );
// Create the limbs
SoCylinder* limbCylinder = new SoCylinder;
setPart( "leftLeg.shape", limbCylinder );
setPart( "leftArm.shape", limbCylinder );
setPart( "rightLeg.shape", limbCylinder );
setPart( "rightArm.shape", limbCylinder );
// Place the body and head
set( "body.transform", "scaleFactor 1 2 1" );
set( "head.transform", "translation 0 3 0" );
// Place the limbs
set( "leftArm.transform", "scaleFactor 0.5 1.5 0.5" );
set( "leftLeg.transform", "scaleFactor 0.5 1.5 0.5" );
set( "rightArm.transform", "scaleFactor 0.5 1.5 0.5" );
set( "rightLeg.transform", "scaleFactor 0.5 1.5 0.5" );
set( "leftArm.transform", "center 0 1 0" );
set( "leftLeg.transform", "center 0 1 0" );
set( "rightArm.transform", "center 0 1 0" );
set( "rightLeg.transform", "center 0 1 0" );
set( "leftArm.transform", "translation -1 1 0.5" );
set( "leftLeg.transform", "translation -1 -2.5 0.5" );
set( "rightArm.transform", "translation 1 1 0.5" );
set( "rightLeg.transform", "translation 1 -2.5 0.5" );
// Create the Event Callback to make jack jump.
// When it receives a mouse button event, it will
// call the method jumpJackJump.
SoEventCallback* myEventCB = new SoEventCallback;
myEventCB->addEventCallback( SoMouseButtonEvent::getClassTypeId(), JumpingJackKit::jumpJackJump, this );
setPart( "callbackList[0]", myEventCB );
}
// Animates the jumping jack (called by the "eventCallback[0]"
// part when a left mouse button press occurs).
void
JumpingJackKit::jumpJackJump( void* userData, SoEventCallback* myEventCB )
{
const SoEvent* myEvent = myEventCB->getEvent();
// See if it's a left mouse down event
if ( SO_MOUSE_PRESS_EVENT( myEvent, BUTTON1 ) )
{
JumpingJackKit* myJack = ( JumpingJackKit* )userData;
// See if the jumping jack was picked.
const SoPickedPoint* myPickedPoint;
myPickedPoint = myEventCB->getPickedPoint();
if ( myPickedPoint && myPickedPoint->getPath() && myPickedPoint->getPath()->containsNode( myJack ) )
{
// The jumping jack was picked. Make it jump!
SoTransform* myXf;
SbVec3f zAxis( 0, 0, 1 );
SbRotation noRot = SbRotation::identity();
myXf = SO_GET_PART( myJack, "leftArm.transform", SoTransform );
if ( myXf->rotation.getValue() == noRot )
myXf->rotation.setValue( zAxis, -1.6 );
else
myXf->rotation.setValue( noRot );
myXf = SO_GET_PART( myJack, "leftLeg.transform", SoTransform );
if ( myXf->rotation.getValue() == noRot )
myXf->rotation.setValue( zAxis, -1.2 );
else
myXf->rotation.setValue( noRot );
myXf = SO_GET_PART( myJack, "rightArm.transform", SoTransform );
if ( myXf->rotation.getValue() == noRot )
myXf->rotation.setValue( zAxis, 1.6 );
else
myXf->rotation.setValue( noRot );
myXf = SO_GET_PART( myJack, "rightLeg.transform", SoTransform );
if ( myXf->rotation.getValue() == noRot )
myXf->rotation.setValue( zAxis, 1.2 );
else
myXf->rotation.setValue( noRot );
myEventCB->setHandled();
}
}
}

JumpingJackTest.c++ shows a short program to create a jumping jack that responds to user events. Notice how it calls

initClass() for JumpingJackKit before it creates an instance of this new node-kit class.

Example : JumpingJackTest.c++

#include <Inventor/Xt/SoXt.h>
#include <Inventor/Xt/viewers/SoXtExaminerViewer.h>
// Header files for new node class
#include "JumpingJackKit.h"
main( int, char** argv )
{
// Initialize Inventor and Xt
Widget myWindow = SoXt::init( argv[0] );
if ( myWindow == NULL )
exit( 1 );
// Initialize the new node class
JumpingJackKit::initClass();
JumpingJackKit* jackyBaby = new JumpingJackKit;
jackyBaby->ref();
SoXtExaminerViewer* viewer = new SoXtExaminerViewer( myWindow );
viewer->setSceneGraph( jackyBaby );
viewer->setTitle( "JumpingJackKit" );
viewer->show();
viewer->viewAll();
SoXt::show( myWindow );
SoXt::mainLoop();
}