plib/doc/ssg/branches.html

320 lines
13 KiB
HTML

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<META http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<TITLE>A Simple Scene Graph API for OpenGL.</TITLE>
</HEAD>
<BODY text="#B5A642" link="#8FFF8F" vlink="#18A515" alink="#20336B"
bgcolor="#005000" background="../marble.png">
<H2><code>class ssgBranch</code> - A basic branch node.</H2>
The basic ssgBranch node simply handles a node in the tree,
with zero or more child nodes which can be any kind of ssgEntity
except ssgRoot.
<p>
There are a rich set of functions for adding, deleting and
replacing child nodes:
<pre>
class ssgBranch : public ssgEntity
{
int getNumKids (void) ;
ssgEntity *getKid ( int n ) ;
ssgEntity *getNextKid (void) ;
int searchForKid ( ssgEntity *entity ) ;
void addKid ( ssgEntity *entity ) ;
void removeKid ( int n ) ;
void removeKid ( ssgEntity *entity ) ;
void removeAllKids (void) ;
void replaceKid ( ssgEntity *old_entity, ssgEntity *new_entity ) ;
} ;
</pre>
Most of these are pretty self-explanatory.
<code>ssgBranch::getNumKids()</code> returns the number of child nodes
beneath this branch.
<code>ssgBranch::getKid(n)</code> returns the address of the n'th child ssgEntity.
<code>ssgBranch::getNextKid()</code> returns the address of the child entity following
the last one returned by getKid or getNextKid - returning NULL when all child nodes
have been exhausted.
<code>ssgBranch::searchForKid(entity)</code> searches for the specified entity
in the list of child nodes and returns it's index (ie the inverse of getKid).
<code>ssgBranch::addKid(entity)</code> adds the specified entity to the list of
child nodes - the new node is added at the end of the list and will therefore
have the highest numbered index.
<code>ssgBranch::removeKid(n)</code> removes the n'th child node and renumbers
any higher numbered children so there are never any gaps in the number range.
<code>ssgBranch::removeKid(entity)</code> same as removeKid(searchForKid(entity)).
<code>ssgBranch::removeAllKids()</code> remove ALL child entities.
<code>ssgBranch::replaceKid(old, new)</code> replaces <code>old</code> with <code>new</code>.
If the entity removed by any of these commands has a ref count of
zero, it will be deleted.
<H2><code>class ssgInvisible</code> - Invisible parts of a Scene Graph.</H2>
It's sometimes useful to have sections of the scene graph that are never
rendered to the screen. These are frequently used for collision detection
and other non-graphical operations.
<H2><code>class ssgRoot</code> - The Root of the Scene Graph,</H2>
The node at the root of the scene graph is special. At present,
it resembles an ssgBranch externally.
<pre>
class ssgRoot : public ssgBranch
{
} ;
</pre>
<H2><code>class ssgTweenController</code> - A morph controller,</H2>
This is essentially identical to an ssgBranch - but adds API to
set the current 'bank' settings of all ssgTween leaf nodes beneath it.
<p>
An ssgTween is a leaf node that can hold multiple geometric
representations that it smoothly interpolates between.
<pre>
ssgTweenController::selectBank ( float b ) ;
float ssgTweenController::getCurrBank () ;
</pre>
This allows you to set which of the banks of it's daughter ssgTweens
will be rendered. That's a "float" quantity - so if you selectBank(2.4)
then the ssgTweens will render their vertices in a position (colour, etc)
that's 40% of the way between the bank 2 and bank 3.
<p>
You can also set the behaviour when the selected bank number is larger
than the number of banks in the model. This tends to happen when you
simply add some amount of to the bank selector each frame in order
to keep the animation running forever:
<pre>
ssgTweenController::setMode ( int mode ) ;
</pre>
'mode' can either be SSGTWEEN_STOP_AT_END or SSGTWEEN_REPEAT.
The default is STOP_AT_END - where anytime the bank selector
is larger than the actual number of banks in the ssgTween node,
it is clamped to the largest possible number. If you choose
REPEAT, then the bank number will be taken modulo the number of
banks.
<H2><code>class ssgSelector</code> - A switch point,</H2>
Most ssgBranch nodes represent a collection of objects that
are all present in the scene at the same time. ssgSelector
nodes (and derived classes) typically represent a single
object that can be represented in more than one way.
<p>
A selector contains up to 32 daughter objects and a
32 bit unsigned integer mask. Where there is a one bit
in the mask, that child object will be drawn, where
there is a zero, it will not.
<p>
<code>ssgSelector::select(mask)</code> sets the mask,
<code>ssgSelector::getSelect()</code> returns the current
state of the mask, <code>ssgSelector::selectStep(n)</code>
sets the n'th mask bit and zeroes out all the others - effectively
causing only the n'th child object to be displayed.
<p>
It is quite common to have an ssgSelector with just one
child object that can be enabled with select(1) and disabled
with select(0).
<H2><code>class ssgTimedSelector</code> - An animation node,</H2>
This is a selector in which the selection is made as a function
of the amount of time elapsed.
<p>
SSG will draw each of the child objects in turn for some amount
of time before going onto the next node in the sequence. You
set the time for each child using:
<pre>
ssgTimedSelector::setDuration ( float time, int which_child ) ;
</pre>
...or you can set the same time for each of the child nodes using:
<pre>
ssgTimedSelector::setDuration ( float time ) ;
</pre>
(At present, times are measured in SSG update cycles - ultimately,
there will be an option to set the times in seconds - but until
I have a reasonably accurate portable timer library, I can't
easily implement this).
<p>
The animation doesn't have to start at the first child node and
end at the last. It is sometimes useful to be able to replay
just a subset of them.
<pre>
ssgTimedSelector::setLimits ( int start_child, int end_child ) ;
</pre>
You can also choose between a number of animation algorithms:
<pre>
ssgTimedSelector::setMode ( ssgAnimDirection mode ) ;
Where mode is one of:
SSG_ANIM_ONESHOT, SSG_ANIM_SHUTTLE, SSG_ANIM_SWING
</pre>
<ul>
<li>In SSG_ANIM_ONESHOT mode, the animation starts at the first child
you specified with setLimits and ends at the last child you
specified. Once the last child has been displayed, the animation
will automatically go into STOP mode and continue to display
that last object until the application intervenes.
<li>In SSG_ANIM_SHUTTLE mode, the animation goes from the start
child to the end child - but unlike SSG_ANIM_ONESHOT, when
the animation has finished displaying the last child object,
it resets to the start child and does it all over again.
SSG_ANIM_SHUTTLE animations don't stop running unless the
application stops them.
<li>In SSG_ANIM_SWING mode, the animation goes from the start
child to the end child - but when the end is reached, the
animation reverses direction and heads back to the start
again. The animation oscillates like a swing until the
application stops it.
</ul>
<p>
When all this preparation is done, the application must
control the animation:
<pre>
ssgTimedSelector::control ( ssgAnimEnum cntrl ) ;
Where 'cntrl' is one of:
SSG_ANIM_START, SSG_ANIM_STOP,
SSG_ANIM_PAUSE, SSG_ANIM_RESUME
</pre>
These controls work just like you'd expect. Start, Stop,
Pause, Resume. SSG_ANIM_START resets the animation to
the 'start' child and lets it rip. SSG_ANIM_STOP causes
it to stop wherever it is and continue to display that
child node indefinitely. SSG_ANIM_PAUSE pauses the
animation wherever it is right now and SSG_ANIM_RESUME
allows it to continue from whatever point it was paused.
<p>
When the animation is in SSG_ANIM_STOP mode, you can
use this node just like a normal ssgSelector node
using the ssgSelector API.
<p>
If you need to know which child object is currently being
displayed, you cannot call ssgSelector::getSelect() because
SSG computes the animation step only if the node is actually
on-screen. Instead call ssgTimedSelector::getStep() which
returns the currently selected child node.
<H2><code>class ssgRangeSelector</code> - A level of detail node,</H2>
This is a selector in which the selection is made automatically
based on the range to the object. This is principally used to
allow you to save time by drawing simpler versions of objects
at long ranges and more complex ones close up.
<p>
Since an <code>ssgRangeSelector</code> is a kind of
<code>ssgSelector</code>, you can find
out which version of the object was most recently drawn using
<code>getSelect()</code>. However, if the object was not drawn recently, that
may not be a very useful thing to know. Mostly, it's useful in
the post-cull callback.
<p>
You set the ranges at which each daughter object will be drawn
by passing an array of lengths to
<code>ssgRangeSelector::setRanges(float *ranges,int nranges)</code>.
The first parameter is an array of ranges and the second is the
number of elements in that array. Note that element N of the
array is the range beyond which child object N will be drawn.
The array should contain one more range than there are child
objects - and beyond the last range, nothing will be drawn.
setRanges takes a copy of your array so you can delete it after
the call. If nranges is less than the number required, the
remaining ranges will be set to infinity. You can query the
current range array with <code>float getRange(int n)</code> which
returns the n'th range in the array.
<p>
In some cases, you'd like to build several complete versions
of an object such that just one of those versions will be
drawn - and that is the default behaviour. In other cases,
you'd like some basic object to be rendered at long range
and for additional parts to be added to it at shorter ranges.
This is called 'additive' mode and it is set using
<code>setAdditive(int additive)</code>
and queried with <code>isAdditive()</code>.
<H2><code>class ssgBaseTransform</code> - Nodes with transformations.</H2>
It is common to wish to move objects around in the scene, scale and rotate
them, move their texture maps, etc. All of these operations entail
manipulating a matrix associated with the branch node and the
ssgBaseTransform contains the functionality to store and manipulate
that matrix. Applications use one of the derived classes of ssgBaseTransform
to actually do something with that matrix.
<pre>
class ssgBaseTransform : ssgBranch
{
void getTransform ( sgMat4 xform ) ;
virtual void setTransform ( sgVec3 xyz ) ;
virtual void setTransform ( sgCoord *xform ) ;
virtual void setTransform ( sgCoord *xform, float sx, float sy, float sz ) ;
virtual void setTransform ( sgMat4 xform ) ;
} ;
</pre>
You can set up the transformation matrix using <code>ssgBaseTransform::setTransform()</code>
which has versions that allow you to pass either a full-blown
4x4 matrix, a simple translation, an 'sgCoord' (which is an xyz translation
and a hpr rotation) or an sgCoord and scale factors in each of X, Y and Z
directions.
<p>
<code>ssgBaseTransform::getTransform(matrix)</code> copies the current
transform into the matrix that you provide.
<H2><code>class ssgTransform</code> - Nodes with spatial transformations.</H2>
An ssgTransform is derived from ssgBaseTransform and uses the base classes'
transform to transform all the spatial vertices and normals of it's
child nodes. This is done by applying the current transform to the
GL_MODELVIEW stack each frame.
<H2><code>class ssgTexTrans</code> - Nodes with moving texture</H2>
ssgTexTrans nodes are just like ssgTransform nodes except that the
resulting matrix is applied to the GL_TEXTURE stack rather than
the modelview stack. Hence, altering the transform moves the texture
map(s) on the descendent leaf nodes.
<H2><code>class ssgCutout</code> - turn-to-face-the-viewer nodes.</H2>
Cutout nodes will normally contain only leaf nodes that are
modelled with polygons in the X/Z plane. The ssgCutout will rotate
those polygons such that they turn to continually face the viewer.
<p>
There are actually two distinct forms of ssgCutout - depending on
what value is passed as a parameter to the constructor function.
ssgCutout(TRUE) produces an object that rotates around it's
origin such as to keep the X/Z plane parallel to the screen and
ssgCutout(FALSE) produces one that tries to stay parallel to the
screen - but which is only allowed to rotate about the Z axis.
The latter form is useful for objects with cylindrical symmetry
and the former for those with spherical symmetry.
<hr>
<table width="100%">
<tr>
<td width="33%" align="left"><a href="ssgLeaf.html">&lt;= previous =</a></td>
<td width="34%" align="center"><a href="index.html">Return to SSG Index</a></td>
<td width="33%" align="right"><a href="state.html">= next =&gt;</a></td>
</tr>
</table>
<hr>
<table>
<tr>
<td>
<a href="http://validator.w3.org/check/referer"><img border="0" src="../valid-html40.png" alt="Valid HTML 4.0!" height="31" width="88"></a>
<td>
<ADDRESS>
<A HREF="http://www.sjbaker.org">
Steve J. Baker.</A>
&lt;<A HREF="mailto:sjbaker1@airmail.net">sjbaker1@airmail.net</A>&gt;
</ADDRESS>
</table>
</BODY>
</HTML>