PLIB 1.8.5+ r2173 from http://plib.svn.sourceforge.net/svnroot/plib/trunk
This commit is contained in:
315
doc/ssg/LoaderWriter.html
Normal file
315
doc/ssg/LoaderWriter.html
Normal file
@@ -0,0 +1,315 @@
|
||||
<!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>How to write plib-loaders and writers</H2>
|
||||
|
||||
<H2>1.1 Introduction</H2>
|
||||
|
||||
This page is intended for those who wish to write loaders and writers
|
||||
for plib. If you just use plib (using the included loaders and writers), you don't
|
||||
really need to read this.
|
||||
|
||||
It is quite easy to adapt 3D-file-loaders and writers to be used by ssg. Plib
|
||||
already has many loaders and writers that may be used as examples.<p>
|
||||
|
||||
A brief note on cross platform compilation: Plib comes with
|
||||
both Makefiles (for Unix and for the CygWin-system under Windows)
|
||||
and workspace/project-files for Micro$oft Visual C++. If you
|
||||
have both, please update, test and commit both.
|
||||
Otherwise, when committing, please tell the people that something is
|
||||
missing (for example: you didn't update the workspace files) and that some
|
||||
kind soul should do so.
|
||||
<p>
|
||||
|
||||
Both loaders and writers convert between ssg's internal geometry
|
||||
representation and that of the file format. One key difference is that when
|
||||
loading, you should support all possibile
|
||||
geometry-representations of the file format. This is to ensure that
|
||||
plib can handle all the possible variations of a file format that may be generated
|
||||
by the tools that export to it. On the other hand, when writing a format, you can
|
||||
pretty safely only write to one geometry format (unless you need features peculiar
|
||||
to more than one geometry representation), because you have the final say on how the
|
||||
data is to be written.
|
||||
<p>
|
||||
|
||||
Regarding plib's geometry-representations: there are only two on the highest
|
||||
level: <code>ssgVtxTable</code> and <code>ssgVtxArray</code>. Actually, there is also
|
||||
ssgVTable, but that is deprecated.
|
||||
|
||||
<code>ssgVtxArray</code> is newer, is derived
|
||||
from ssgVtxTable and uses a index-list. Apart from that they are quite
|
||||
similar, and both have an interface <code>getNumTriangles () ; </code> and
|
||||
<code>getTriangle ( i, ...); </code>
|
||||
For this reasons, it is easier to write a writer than a loader.
|
||||
|
||||
|
||||
For both ssgVtxTable and ssgVtxArray you need to choose a
|
||||
GL-type. Currently ssgLoaderWriterMesh (more on this in the
|
||||
next section) uses <code>GL_TRIANGLES</code>.
|
||||
|
||||
|
||||
<H2>1.2 class ssgLoaderWriterMesh - an overview</H2>
|
||||
|
||||
The two main parts of writing a loader are writing the actual parser (coding
|
||||
the syntax of the format) and transferring the contents
|
||||
to ssg. The second task is fairly trivial if your contents
|
||||
obey the restrictions of ssg (which follow from OpenGL).
|
||||
<BR><BR>
|
||||
These are:
|
||||
<BR><BR>
|
||||
|
||||
1. Each ssg-node can (currently) have only one texture.
|
||||
<BR>
|
||||
2. Only one polygon or strip or fan per node. So you can't have a 3-, a 4- and a 5-sided
|
||||
poly inside one node (without subdividing the polys into triangles)
|
||||
<BR>
|
||||
3. Currently, you may have only one texture coordinate per vertex.
|
||||
<BR>
|
||||
4. You may have only one normal per vertex.
|
||||
<BR><BR>
|
||||
To modularize the two steps parsing the format and transfering it to ssg
|
||||
and to reduce redundant work, there is an intermediatory structure, the class
|
||||
ssgLoaderWriterMesh. For example, this has a member function
|
||||
<pre>
|
||||
void ssgLoaderWriterMesh::addFaceFromIntegerArray( int numVertices, int *vertices );
|
||||
</pre>
|
||||
With several calls, you can add several n-sided polys to one mesh ("one node").
|
||||
When you are done constructing the mesh from the file, you call
|
||||
<pre>
|
||||
void ssgLoaderWriterMesh::addToSSG(
|
||||
class ssgSimpleState *currentState,
|
||||
class ssgLoaderOptions* current_options,
|
||||
class ssgBranch *curr_branch_)
|
||||
</pre>
|
||||
and the class adds the information into the scene graph. It handles
|
||||
ssgs' restrictions. For example, if the polygons of the mesh use
|
||||
5 textures then at least 5 nodes will be added to the scene graph.<p>
|
||||
|
||||
Unfortunately, this class isn't completely finished. As of this
|
||||
writing, Wolfram Kuss (w_kuss@rz-online.de) has implemented those
|
||||
parts that were needed for the loaders he has finished thus far. Hopefully
|
||||
people will contribute more features as time goes on.<p>
|
||||
|
||||
If you are writing a new loader for a file format that doesn't hold to
|
||||
all restrictions of ssg (and virtually none do), you are urged to use this class.
|
||||
Your loader will be more consistent and easier to maintain and read.<p>
|
||||
|
||||
Further, there are many optimizations that can be done (For example: "If the state is
|
||||
different, but not the texture, do we need several nodes?" or "When we have multitexturing,
|
||||
can we use that?" or "Is there an optimal strip length?" or "How do I subdivide polys into
|
||||
triangles so that the stripifier will work well?"-- the list goes on
|
||||
forever). Once we have good answers to these questions (and the will
|
||||
to implement them), it will be easier to do them once in the ssgLoaderWriterMesh than in all the
|
||||
loaders seperately. It is noteable that most loaders written before
|
||||
ssgLoaderWriterMesh have had some sort of intermediatory mesh
|
||||
structure.<p>
|
||||
|
||||
In the future, ssgLoaderWriterMesh should also be used for writers, doing the opposite
|
||||
job: It takes the information from ssg with the restrictions and then looks whether
|
||||
it can optimize (for example merging nodes) by relaxing the restrictions.
|
||||
|
||||
<H2>1.3 The Class ssgLoaderWriterMesh - A Deeper Look</H2>
|
||||
At the start of your loader, you create a new <code>ssgLoaderWriterMesh</code>
|
||||
or do a <code>reInit()</code>. To insert the data into the <code>ssgLoaderWriterMesh</code>,
|
||||
you have to add vertices, faces, materials, materialindexes (saying what face uses what material)
|
||||
and, if applicable texture coordinates. For all of these, you <B>can</B> say in advance how many you have.
|
||||
If you know that you have 3712 vertices, call <code>createVertices(3712)</code> and everything is allocated
|
||||
at once and <code>addVertex</code> will be very fast. If you don't know in advance how many you have, you
|
||||
still have to call <code>createVertices()</code>, as this also allocates the vertices. In this case, a
|
||||
certain amount of vertices will be reserved and the list will dynamically grow as more are added.<p>
|
||||
|
||||
Vertices are simply sgVec3s. Faces are simply lists/arrays of vertex indexes.
|
||||
For adding faces, use <code>addFace</code> if you already have a <code>ssgIndexArray</code> or use
|
||||
<code>addFaceFromIntegerArray</code> if you have the vertex indexes in a C(++) array.
|
||||
You need to add at least one material (<code>ssgSimpleState</code>). For each face, you tell
|
||||
ssg which material to use via <code>addMaterialIndex</code>. Here is code from ssgLoadOFF, which tells
|
||||
ssg to use the <code>ssgSimpleState</code> ss for all faces:
|
||||
|
||||
<BR>
|
||||
<pre>
|
||||
|
||||
theMesh.createMaterials( 1 );
|
||||
theMesh.addMaterial( &ss );
|
||||
theMesh.createMaterialIndices( _ssgNoFacesToRead ) ;
|
||||
for(i=0;i<_ssgNoFacesToRead ;i++)
|
||||
theMesh.addMaterialIndex ( 0 ) ;
|
||||
</pre>
|
||||
<BR>
|
||||
If the file format has texture coordinates, you have to find out whether it has them
|
||||
per vertex or per vertex and face. If you look at a "straight forward" cube,
|
||||
having texture coordinates per vertex means you can have 8, but if you have
|
||||
texture coordinates per vertex and face, you can have 24 (each vertex is part of 3 faces).
|
||||
The two functions corresponding to these cases are:
|
||||
<pre>
|
||||
void createPerFaceAndVertexTextureCoordinates2( int numReservedTextureCoordinate2Lists = 3 );
|
||||
void addPerFaceAndVertexTextureCoordinate2( ssgTexCoordArray **textureCoordinateArray );
|
||||
</pre>
|
||||
or
|
||||
<pre>
|
||||
void createPerVertexTextureCoordinates2( int numReservedTextureCoordinates2 = 3 );
|
||||
void addPerVertexTextureCoordinate2( sgVec2 textureCoordinate );
|
||||
</pre>
|
||||
|
||||
|
||||
<H2>2. Loaders</H2>
|
||||
|
||||
|
||||
<H2>2.1 class ssgLoaderOptions</H2>
|
||||
|
||||
ssgLoaderOptions is a class that is defined in ssg.h.
|
||||
It is used to tell the loader some options.
|
||||
It is NOT used for user-setable options, although
|
||||
this may be nice to have at some point. For example,
|
||||
one COULD create a member-variable in it
|
||||
telling the unit that one wants. The loader would then
|
||||
be responsible to scale the object in such a way that
|
||||
the sizes are in that unit (for example: meter, millimeter, etc).
|
||||
|
||||
<BR>
|
||||
<BR>
|
||||
Regarding the reason for the callbacks in ssgLoaderOptions, Steve
|
||||
wrote:
|
||||
<BR>
|
||||
<BR>
|
||||
<blockquote>
|
||||
<i>"Whenever a branch node is created. The deal is that most file formats
|
||||
are
|
||||
missing important features at the Branch level - but many support
|
||||
comment
|
||||
fields - or long ASCII name strings or something. The idea was to allow the artists to attach an ARBITARY comment string
|
||||
in their modeller - and to have the loader trap these strings and pass
|
||||
them on to the application.</i><p>
|
||||
|
||||
<i>Hence, if the hook function is defined then when a branch node needs
|
||||
to
|
||||
be created, we call the application's callback with the ASCII string
|
||||
that was embedded in the file and let the application construct the
|
||||
ssgBranch
|
||||
node. Hence, you could put the string "~LOD: RANGE=100 meters"
|
||||
into the comment field in (say) the AC3D modeller. (AC3D calls this a
|
||||
"Data"
|
||||
field)...the application could then say to itself: "Any comment that
|
||||
starts
|
||||
with a tilde ('~') is a command to the loader" and parse such
|
||||
'comments'
|
||||
as commands. In this case, it would construct an ssgRangeSelector and
|
||||
set
|
||||
the transition range to 100m and return the application back to the
|
||||
loader.</i><p>
|
||||
|
||||
<i>Check the <a href="http://tuxkart.sf.net">Tux Kart</a> sources to see this in action."</i>
|
||||
</blockquote>
|
||||
|
||||
So much for the quote from Steve.
|
||||
<p>
|
||||
|
||||
As of this writing, the ssgLoaderOptions code has been copied from
|
||||
another loader into ssgLoaderWriterMesh.
|
||||
|
||||
|
||||
<H2>2.2 ASCII file formats</H2>
|
||||
A lexical analyzer for ascii-files is available in ssgParser.cxx and
|
||||
ssgParser.h. It converts the file into a stream of tokens and
|
||||
handles comments. In a way, it has two APIs.
|
||||
One hides the line structure from the loader. The loader just has
|
||||
to say "getNextToken".
|
||||
The other API operates in terms of exact line structure.
|
||||
You do a getLine which reads all the tokens of that line into a
|
||||
buffer and then you do a parseToken to get each token.<p>
|
||||
|
||||
The formats which currently use the parser are .X (which uses the
|
||||
line-independant API), .ase, .scenery and .off (which use the
|
||||
line-by-line-API).<p>
|
||||
Some functions are used by both APIs. For example:<p>
|
||||
|
||||
<pre>
|
||||
void openFile( const char* fname, const _ssgParserSpec* spec = 0 );
|
||||
</pre><p>
|
||||
|
||||
In ssgParserSpec, you give the parser the specification of the format.
|
||||
You say which characters start a comment, which characters are skipable,
|
||||
which characters are used for braces (which are used to determine the
|
||||
parser's level-- useful for parser's which work recursively).
|
||||
Most important are the delimiters. These determine where one token ends and the
|
||||
next one begins. For example, the first token of the line
|
||||
|
||||
<pre>
|
||||
1234,567
|
||||
</pre>
|
||||
|
||||
is <code>1234</code> if <code>","</code> is a delimiter and
|
||||
<code>1234,567</code> otherwise.
|
||||
The parser differentiates between skipable delimiters that
|
||||
are "swallowed" by the parser and non-skipable ones that are
|
||||
passed to the loader. So, regarding the example-line there
|
||||
are three possibilities:
|
||||
<BR>
|
||||
<code>","</code> is not a delimiter => The line contains one token, namely
|
||||
<code>"1234,567"</code>
|
||||
<BR>
|
||||
<code>","</code> is a skipable delimiter => The line contains two tokens, namely
|
||||
<code>"1234"</code> and <code>"567"</code>
|
||||
<BR>
|
||||
<code>","</code> is a non-skipable delimiter => The line contains three tokens,
|
||||
namely <code>"1234"</code>, <code>","</code> and <code>"567"</code>
|
||||
<BR>
|
||||
|
||||
|
||||
<H2>3. Writers</H2>
|
||||
For an example how to write out geometry and material, look at
|
||||
ssgSaveASE.
|
||||
|
||||
For an easy example (geometry only), look at <code>ssgSaveDXF</code> or <code>ssgSaveTRI</code>.
|
||||
The function
|
||||
|
||||
<pre>
|
||||
int ssgSaveXYZ ( const char *filename, ssgEntity *ent )
|
||||
</pre>
|
||||
|
||||
normally calls a function
|
||||
|
||||
<pre>
|
||||
static void save_entities ( ssgEntity *e )
|
||||
</pre>
|
||||
|
||||
which just recursively walks the scene graph.
|
||||
You should be able to use this function and just
|
||||
write a
|
||||
|
||||
<pre>
|
||||
static void save_vtx_table ( ssgVtxTable *vt )
|
||||
</pre>
|
||||
|
||||
which writes a <code>ssgVtxTable</code>.<p>
|
||||
|
||||
|
||||
|
||||
<hr>
|
||||
<table width="100%">
|
||||
<tr>
|
||||
<td width="33%" align="left"><a href="non_class.html"><= previous =</a></td>
|
||||
<td width="34%" align="center"><a href="index.html">Return to SSG Index</a></td>
|
||||
<td width="33%" align="right"></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>
|
||||
<<A HREF="mailto:sjbaker1@airmail.net">sjbaker1@airmail.net</A>>
|
||||
</ADDRESS>
|
||||
</table>
|
||||
</BODY>
|
||||
</HTML>
|
||||
|
||||
319
doc/ssg/branches.html
Normal file
319
doc/ssg/branches.html
Normal file
@@ -0,0 +1,319 @@
|
||||
<!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"><= 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 =></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>
|
||||
<<A HREF="mailto:sjbaker1@airmail.net">sjbaker1@airmail.net</A>>
|
||||
</ADDRESS>
|
||||
</table>
|
||||
</BODY>
|
||||
</HTML>
|
||||
|
||||
157
doc/ssg/index.html
Normal file
157
doc/ssg/index.html
Normal file
@@ -0,0 +1,157 @@
|
||||
<!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">
|
||||
|
||||
<center>
|
||||
<H1>SSG: A Simple Scene Graph API</H1>
|
||||
<H1>for OpenGL</H1>
|
||||
by Steve Baker
|
||||
</center>
|
||||
<H2>Introduction</H2>
|
||||
Simple Scene Graph (SSG) is intended to be a really simple,
|
||||
low-impact, scene graph API that layers nicely on top
|
||||
of OpenGL using C++ and which works with or without GLUT.
|
||||
<p>
|
||||
SSG is a part of <A HREF="../index.html">PLIB</A>.
|
||||
<p>
|
||||
This document assumes a certain degree of knowledge of
|
||||
OpenGL.
|
||||
<p>
|
||||
SSG includes a subsidiary library of simple matix and vector
|
||||
math with support for some intersection testing, field-of-view
|
||||
culling and such like. This is called
|
||||
<A HREF="../sg/index.html">'Simple Geometry' (SG)</A>.
|
||||
SG is used extensively by SSG - but is also useful as a
|
||||
standalone library.
|
||||
<p>
|
||||
A Scene Graph is essentially just a tree-structured database
|
||||
containing a hierarchy of branches - and a bunch of leaf nodes.
|
||||
Each leaf node does some OpenGL rendering - the branch nodes
|
||||
are intended to manage things like: field of view (FOV) culling,
|
||||
level of detail (LOD) management, transformations, and animation.
|
||||
<p>
|
||||
In addition, each leaf node has a structure tacked on to it
|
||||
to encapsulate OpenGL state information - and that in turn
|
||||
may optionally have a texture applied to it.
|
||||
<p>
|
||||
In addition to managing the scene graph, SSG contains code
|
||||
to manage the positions of cameras, lights and other rendering
|
||||
aspects of OpenGL.
|
||||
<H2>Symbol Conventions.</H2>
|
||||
Both SSG an SG follow conventions for symbols and tokens that
|
||||
are the conventions used by OpenGL and GLUT.
|
||||
<p>
|
||||
Hence, all SSG symbols for classes and functions start with <code>ssg</code>
|
||||
and all <code>#define</code> tokens start with <code>SSG</code>. Functions and symbols
|
||||
that belong to the SG library similarly start with <code>sg</code> or <code>SG</code>.
|
||||
<p>
|
||||
Words within a class or function name are Capitalised and NOT
|
||||
separated with underscores. Words within <code>#define</code> tokens may
|
||||
be separated with underscores to make them readable.
|
||||
<H2>Initialisation.</H2>
|
||||
The first SSG call in any program must always be ssgInit(). Call
|
||||
ssgInit only after you have obtained an OpenGL rendering context
|
||||
(or called glutInit() and created a rendering window if you are
|
||||
using glut).
|
||||
<H2>Classes</H2>
|
||||
The following class hierarchy makes up the core package - which
|
||||
can be extended to add functionality or to change some underlying
|
||||
mechanisms.
|
||||
<pre>
|
||||
|
||||
class ssgBase
|
||||
|__ class ssgSimpleList
|
||||
| |
|
||||
| |__ class ssgVertexArray
|
||||
| |__ class ssgNormalArray
|
||||
| |__ class ssgTexCoordArray
|
||||
| |__ class ssgColourArray
|
||||
| |__ class ssgIndexArray
|
||||
|
|
||||
|__ class ssgEntity
|
||||
| |
|
||||
| |__ class ssgLeaf
|
||||
| | |__ class ssgVTable (deprecated)
|
||||
| | |__ class ssgVtxTable
|
||||
| | |__ class ssgTween
|
||||
| | |__ class ssgVtxArray
|
||||
| |
|
||||
| |__ class ssgBranch
|
||||
| |__ class ssgRoot
|
||||
| |__ class ssgInvisible
|
||||
| |__ class ssgSelector
|
||||
| | |__ class ssgTimedSelector
|
||||
| | |__ class ssgRangeSelector
|
||||
| |
|
||||
| |__ class ssgBaseTransform
|
||||
| | |__ class ssgTransform
|
||||
| | |__ class ssgTexTrans
|
||||
| |
|
||||
| |__ class ssgCutout
|
||||
| |__ class ssgTweenController
|
||||
|
|
||||
|___ class ssgState
|
||||
| |__ class ssgSimpleState
|
||||
| |__ class ssgStateSelector
|
||||
|
|
||||
|___ class ssgTexture
|
||||
|
||||
</pre>
|
||||
The general idea is that, all geometry is contained in ssgLeaf classes,
|
||||
all data heirarchy is in a ssgBranch classes and all OpenGL state information
|
||||
is in ssgStates.
|
||||
<p>
|
||||
You may not declare instances of ssgBase, ssgEntity, ssgBaseTransform,
|
||||
ssgLeaf or ssgState since they are all abstract classes.
|
||||
<p>
|
||||
It is presumed that applications will add new kinds of leaves, branches,
|
||||
states and textures to customise SSG to their needs.
|
||||
<BR><BR>
|
||||
Here are the further chapters:
|
||||
<BR><BR>
|
||||
<A HREF="ssgBase.html">The base class</A>
|
||||
<BR>
|
||||
<A HREF="ssgEntity.html">An entity of the graph</A>
|
||||
<BR>
|
||||
<A HREF="ssgLeaf.html">A leaf of the graph</A>
|
||||
<BR>
|
||||
<A HREF="branches.html">A branch of the graph</A>
|
||||
<BR>
|
||||
<A HREF="state.html">States (material etc)</A>
|
||||
<BR>
|
||||
<A HREF="ssgContext.html">ssgContext</A>
|
||||
<BR>
|
||||
<A HREF="non_class.html">Non-class functions: Loading, saving and optimizing databases</A>
|
||||
<BR>
|
||||
<A HREF="LoaderWriter.html">How to write plib-loaders and writers</A>
|
||||
<BR><BR>
|
||||
You can go through all the SSG-documentation by clicking on the "= next =>"-links at the bottom of each page.
|
||||
<BR><BR>
|
||||
<hr>
|
||||
<table width="100%">
|
||||
<tr>
|
||||
<td width="33%" align="left"></td>
|
||||
<td width="34%" align="center"></td>
|
||||
<td width="33%" align="right"><a href="ssgBase.html">= next =></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>
|
||||
<<A HREF="mailto:sjbaker1@airmail.net">sjbaker1@airmail.net</A>>
|
||||
</ADDRESS>
|
||||
</table>
|
||||
</BODY>
|
||||
</HTML>
|
||||
|
||||
936
doc/ssg/non_class.html
Normal file
936
doc/ssg/non_class.html
Normal file
@@ -0,0 +1,936 @@
|
||||
<!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>Non-class Functions.</H2>
|
||||
So, with the class functions described above, it is
|
||||
fairly simple to construct a scene graph. So, now that
|
||||
you have one, what can you do with it?
|
||||
<pre>
|
||||
void ssgCullAndDraw ( ssgRoot *root ) ;
|
||||
</pre>
|
||||
This call deals with the entire process of rendering the database.
|
||||
Your application need only call ssgInit(), build a database,
|
||||
create a current context and call ssgCullAndDraw using the root node
|
||||
of that database.
|
||||
<H3>Intersection Testing.</H3>
|
||||
Most applications need to test the scenery to see if moving
|
||||
objects have collided with it - there are several ways to do
|
||||
that - but they all share the same mechanisms:
|
||||
<pre>
|
||||
|
||||
int ssgIsect ( ssgRoot *root, sgSphere *s, sgMat4 m, ssgHit **results ) ;
|
||||
int ssgHOT ( ssgRoot *root, sgVec3 s, sgMat4 m, ssgHit **results ) ;
|
||||
int ssgLOS ( ssgRoot *root, sgVec3 s, sgMat4 m, ssgHit **results ) ;
|
||||
|
||||
</pre>
|
||||
These three calls implement various ways to test the database for collisions,
|
||||
weapon impacts and such like. In each case, the search for a collision
|
||||
starts at 'root', and the database is transformed by the matrix 'm'
|
||||
before the test is evaluated - hence, 'm' is ususally the inverse of
|
||||
the matrix describing the test object's location.
|
||||
<ul>
|
||||
<li>ssgIsect intersects a sphere against the scene.
|
||||
<li>ssgHOT intersects a vertical line starting at the point 's' (remember,
|
||||
in SSG, positive Z is 'up'). This is often used to compute
|
||||
the Height-of-Terrain - hence the name 'HOT'.
|
||||
<li>ssgLOS intersects an arbitary vector whose direction is defined by 's'.
|
||||
</ul>
|
||||
The result in either case is an integer telling
|
||||
you how many triangles impacted the sphere/vector. If you need to know more
|
||||
about these intersections, pass the address of a ssgHit * variable as
|
||||
the last parameter and it will be returned pointing at a STATIC array
|
||||
of ssgHit structures. Thats a confusing explanation - and an example
|
||||
will help:
|
||||
<pre>
|
||||
|
||||
ie:
|
||||
|
||||
ssgHit *results ;
|
||||
|
||||
int num_hits = ssgIsect ( root, &sphere, mat, &results ) ;
|
||||
|
||||
for ( int i = 0 ; i < num_hits ; i++ )
|
||||
{
|
||||
ssgHit *h = &(results [ i ]) ;
|
||||
|
||||
/* Do something with 'h' */
|
||||
}
|
||||
|
||||
</pre>
|
||||
Remember, you must finish using the results array before you do
|
||||
another ssgIsect/ssgHOT/ssgLOS because all three functions share
|
||||
the same results array.
|
||||
<p>
|
||||
By default, these functions only detect collisions with the front face
|
||||
of polygons. You can make them detect only the back faces using:
|
||||
<pre>
|
||||
|
||||
void ssgSetBackFaceCollisions ( bool b ) ;
|
||||
|
||||
</pre>
|
||||
<p>
|
||||
An ssgHit looks like this:
|
||||
<pre>
|
||||
|
||||
class ssgHit
|
||||
{
|
||||
ssgLeaf *leaf ;
|
||||
int triangle ;
|
||||
sgVec4 plane ;
|
||||
sgMat4 matrix ;
|
||||
|
||||
ssgHit ()
|
||||
int getNumPathEntries () ;
|
||||
ssgEntity *getPathEntry ( int i ) ;
|
||||
} ;
|
||||
|
||||
</pre>
|
||||
The 'leaf' member points at the leaf node that impacted the sphere.
|
||||
The 'triangle' member tells you which triangle within the leaf
|
||||
did the impacting. The 'plane' member contains the plane equation
|
||||
of the impacting triangle and the 'matrix' element tells you
|
||||
the net result of concatenating all the transform nodes from
|
||||
the root to the leaf to the matrix you provided in the ssgIsect call.
|
||||
<p>
|
||||
It's possible for there to be multiple paths through the
|
||||
scene graph to the leaf node. Sometimes you'll need to
|
||||
look back up the tree to see nodes above the one that we actually
|
||||
impacted with. Hence, you can read all the ssgEntities that were
|
||||
traversed on the path from the root down to the leaf. Calling
|
||||
the 'getNumPathEntries' function to find the number of nodes
|
||||
along the path - and then 'getPathEntry(n)' to get the n'th entry
|
||||
in the path. The 'root' node will always be the zeroth entry
|
||||
in the path - and the leaf node will always be the last.
|
||||
<H3>Lights.</H3>
|
||||
SSG supports the eight standard OpenGL light sources as class 'ssgLight'.
|
||||
Since there are only a finite number of these, they all exist all the
|
||||
time - you just call:
|
||||
<pre>
|
||||
|
||||
ssgLight *ssgGetLight ( int i ) ;
|
||||
|
||||
</pre>
|
||||
...to get the i'th light should you need to manipulate it.
|
||||
<pre>
|
||||
|
||||
class ssgLight
|
||||
{
|
||||
int isOn () ;
|
||||
void on () ;
|
||||
void off () ;
|
||||
|
||||
void setPosition ( const sgVec3 pos ) ;
|
||||
void setPosition ( float x, float y, float z ) ;
|
||||
|
||||
void setColour ( GLenum which , const sgVec4 colour ) ;
|
||||
void setColour ( GLenum which , float r, float g, float b ) ;
|
||||
|
||||
void setHeadlight ( int head ) ;
|
||||
int isHeadlight () ;
|
||||
|
||||
void setSpotlight ( int spot ) ;
|
||||
int isSpotlight () ;
|
||||
|
||||
void setSpotDirection ( const sgVec3 dir ) ;
|
||||
void setSpotDirection ( float x, float y, float z ) ;
|
||||
void setSpotDiffusion ( float exponent, float cutoff = 90.0f ) ;
|
||||
void setSpotAttenuation ( float constant, float linear, float quadratic ) ;
|
||||
} ;
|
||||
|
||||
</pre>
|
||||
Each light can be turned on or off - or tested to see if it's on or off.
|
||||
<p>
|
||||
Lights are positioned with 'setPosition()' - which can be relative
|
||||
to the origin of the world - or relative to the SSG camera (in 'headlight'
|
||||
mode).
|
||||
<p>
|
||||
If the 'spotlight' mode is enabled,
|
||||
then the light intensity has a certain distribution and attenuation.
|
||||
These parameters can be set with the 'setSpotXxx' methods.
|
||||
Otherwise, the light source is considered to be directional,
|
||||
or infinitely far away (in the direction of its position).
|
||||
The 'spotlight' mode is initially disabled.
|
||||
|
||||
<H3>Miscellany.</H3>
|
||||
It's convenient to find out how much texture memory has been
|
||||
consumed:
|
||||
<pre>
|
||||
|
||||
int ssgGetNumTexelsLoaded () ;
|
||||
|
||||
</pre>
|
||||
(Bear in mind that a texel could be 16 or 32 bits depending on
|
||||
the hardware - and with MIPmapping enabled, 25% of the texels
|
||||
will be in the MIPmaps - so ssgGetNumTexelsLoaded will return
|
||||
a larger number than the total of the sizes of the input images
|
||||
might suggest.
|
||||
<H3>Loading Database Files.</H3>
|
||||
To load a model file into SSG, you can either call a loader
|
||||
function that is specific to the format of the file you
|
||||
wish to load - or you can call 'ssgLoad' - which parses
|
||||
the filename extension and calls the appropriate format-specific
|
||||
loader.
|
||||
<p>
|
||||
At time or writing, there are MANY loaders for SSG:
|
||||
<ul>
|
||||
<li> ssgLoadSSG - for '.ssg' files - the 'native' SSG format.
|
||||
<li> ssgLoadAC - for '.ac' files - a somewhat obscure format produced
|
||||
by the 'AC3D' modelling tool - reasonably well tried
|
||||
and tested.
|
||||
<li> ssgLoad3ds - for '.3ds' files as produced by 3DStudio.
|
||||
<li> ssgLoadASE - 3DSMAX ASCII EXPORT Version 2.00, well tested
|
||||
<li> ssgLoadDXF - AutoCADs famous DXF format. well tested
|
||||
<li> ssgLoadFLT - OpenFlight. Works for OpenFlight files generated by
|
||||
recent versions of MultiGen - but not for those generated by some other
|
||||
tools such as Designers' Workbench.
|
||||
<li> ssgLoadMD2 - Quake MD2
|
||||
<li> ssgLoadOBJ - Wavefront, works well
|
||||
<li> ssgLoadTRI - simple Tri format from "Andy Colbournes Editor".
|
||||
<li> ssgLoadX - Microsofts DirectX-Format. Most features work.
|
||||
<li> ssgLoadOFF - Geomview's OFF
|
||||
<li> ssgLoadM - ???
|
||||
<li> ssgLoadATG - Ascii TerraGear. Used by Flight Gear Flight Sim.
|
||||
<li> ssgLoadVRML1 - VRML1 format, only partially implemented.
|
||||
<li> ssgLoadIV - Inventor format, only partially implemented.
|
||||
<li> ssgLoadStrip - The format of a stripifier.
|
||||
</ul>
|
||||
|
||||
<pre>
|
||||
|
||||
typedef ssgBranch *(*ssgHookFunc)(char *) ;
|
||||
|
||||
ssgEntity *ssgLoad ( const char *fname, const ssgLoaderOptions *options = NULL ) ;
|
||||
|
||||
ssgEntity *ssgLoadSSG ( const char *fname, const ssgLoaderOptions *options = NULL ) ;
|
||||
ssgEntity *ssgLoadAC ( const char *fname, const ssgLoaderOptions *options = NULL ) ;
|
||||
ssgEntity *ssgLoad3ds ( const char *fname, const ssgLoaderOptions *options = NULL ) ;
|
||||
...etc...
|
||||
|
||||
</pre>
|
||||
Minimally, all you need to do is to call ssgLoadAC/ssgLoad3ds with the
|
||||
name of the file to load. However, most file formats (AC3D's
|
||||
and 3Dstudio's included) lack many desirable features, and it is also often
|
||||
necessary to store application-specific information in the
|
||||
file.
|
||||
<p>
|
||||
SSG's loaders will decode the comment fields found in the
|
||||
nodes of many common file formats and pass these onto the
|
||||
application via 'hookfunc'. This function should decode
|
||||
the string and construct whatever kind of SSG node it
|
||||
considers appropriate.
|
||||
<p>
|
||||
Similarly, the application may wish to embellish the
|
||||
ssgState of a loaded node - and since state information
|
||||
rarely has a comment field in most file formats, we
|
||||
pass the texture filename instead and expect the application
|
||||
to construct the entire ssgState:
|
||||
<pre>
|
||||
|
||||
void ssgSetAppStateCallback ( ssgState *(*cb)(char *) ) ;
|
||||
|
||||
</pre>
|
||||
One common problem with file loaders is that it's
|
||||
often possible to refer to a second file from inside
|
||||
the first - but the <b>path</b> to that file is often
|
||||
not adequately defined by the original file. Hence,
|
||||
the application can specify a file path to be prepended
|
||||
to all model or texture file names.
|
||||
<pre>
|
||||
|
||||
void ssgModelPath ( char *path ) ;
|
||||
void ssgTexturePath ( char *path ) ;
|
||||
|
||||
</pre>
|
||||
You can only supply one path. If you need additional features, use the
|
||||
function <code>ulFindFile</code> (for more see util-library-doc).
|
||||
|
||||
The last three functions simply set values in the _ssgCurrentOptions
|
||||
(type ssgLoaderOptions), for example:
|
||||
|
||||
<pre>
|
||||
inline void ssgModelPath ( const char *path )
|
||||
{
|
||||
_ssgCurrentOptions -> setModelDir ( path ) ;
|
||||
}
|
||||
</pre>
|
||||
|
||||
For more on ssgLoaderOptions see also the next page of this doc.
|
||||
|
||||
<p>
|
||||
|
||||
Some loaders for file formats that use texture formats not
|
||||
supported by ssg use this functions to find textures:
|
||||
<pre>
|
||||
void ssgFindOptConvertTexture( char * filepath, char * tfname )
|
||||
</pre>
|
||||
It finds and optionally (= if necessary) converts the texture.
|
||||
This is only really implemented for Windo$ :-(, for all others it
|
||||
should just be the two lines you will find in the comment. I didn't
|
||||
test it, that's the reason I commented it out. But it will warn you
|
||||
when you have to convert something, so even for non-Windo$-users the
|
||||
new function is already a step forward.
|
||||
For the actual conversion, at first I wanted to use GIMP. So, in Deja,
|
||||
I looked for "+gimp +convert +batch" and similar strings. I found
|
||||
several people asking, but almost all the answer were to use
|
||||
ImageMagick instead. ImageMagick is free as in beer. Also, the docs I
|
||||
got with the newest gimp is extremely sparse :-(. Therefore, I tried
|
||||
ImageMagick and this worked straight away. You should find ImageMagick
|
||||
under
|
||||
<p>
|
||||
http://www.wizards.dupont.com/cristy/ImageMagick.html
|
||||
<p>
|
||||
Plib uses the ImageMagick application "convert". Since there are other
|
||||
convert.exe-programs on my computer, I had to copy the ImageMagick
|
||||
stuff into the directory of my plib-application, so that it uses the correct
|
||||
convert.exe.
|
||||
<p>
|
||||
|
||||
|
||||
Most file formats contain considerable numbers of redundant
|
||||
nodes (because of the way people build using these tools).
|
||||
This function walks a database sub-tree multiplying
|
||||
out any ssgTransform nodes and replacing them with
|
||||
ssgBranch'ed - unless they have userdata associated with them.
|
||||
Any branch nodes with zero kids are deleted - any with just
|
||||
one kid are eliminated and the child node pushed up one level.
|
||||
<pre>
|
||||
|
||||
void ssgFlatten ( ssgEntity *ent ) ;
|
||||
|
||||
</pre>
|
||||
It's important for 3D performance to optimise
|
||||
triangles into triangle strips or fans. Since most
|
||||
file formats don't record strip/fan information,
|
||||
it's useful to call:
|
||||
<pre>
|
||||
|
||||
void ssgStripify ( ssgEntity *ent ) ;
|
||||
|
||||
</pre>
|
||||
<H3>Saving Database Files.</H3>
|
||||
Most SSG programs will simply load a file and display it in
|
||||
some way - but occasionally, it's useful to be able to write
|
||||
a file back out again.
|
||||
<p>
|
||||
To write a model file from SSG, you can either call a writer
|
||||
function that is specific to the format of the file you
|
||||
wish to save - or you can call 'ssgSave' - which parses
|
||||
the filename extension and calls the appropriate format-specific
|
||||
writer.
|
||||
<p>
|
||||
Saving into ssg-format is done with these functions:
|
||||
<ul>
|
||||
<li> ssgSaveSSG - for '.ssg' files - the 'native' SSG format.
|
||||
</ul>
|
||||
<pre>
|
||||
|
||||
int ssgSave ( char *fname, ssgEntity *ent ) ;
|
||||
int ssgSaveSSG ( char *fname, ssgEntity *ent ) ;
|
||||
|
||||
</pre>
|
||||
This returns TRUE if the operation worked - FALSE if it failed.
|
||||
You will also find writers for the 3DS, AC, ASE, ATG, DXF, M, OBJ, OFF, QHI, TRI and
|
||||
X formats.
|
||||
|
||||
<H3>Features of the file formats and status of the loaders/writers</H3>
|
||||
|
||||
Here comes a table of the features of all the file formats and loaders and writers.
|
||||
VRML doesn't really work, so you won't find it here.
|
||||
The "QHI" (QHull Input - a format used by a toll to create convex hulls)
|
||||
writer only writes a point cloud and suppoorts no other features, so I also didn't add it to the table.
|
||||
BTW, if you want to create convex hulls of existing geometry, you just need a few lines. Look
|
||||
into PPE (prettypoly editor, on SourceForge as well), into the file ppeCoreFuncs.cxx,
|
||||
function addConvexHull.
|
||||
The SSG loaders/writers support all
|
||||
features of the ssg-lib, so missing features mean they miss in the library (normaly because they miss in OpenGL)
|
||||
The letters mean:
|
||||
<BR><BR>
|
||||
A = feature not in file format
|
||||
<BR>
|
||||
B = feature in file format and not implemented, not planned.
|
||||
<BR>
|
||||
C = feature in file format and not implemented, but planned.
|
||||
<BR>
|
||||
D = feature in file format and partly implemented or not tested.
|
||||
<BR>
|
||||
E = feature in file format and implemented.
|
||||
<BR><BR>
|
||||
And here are the features with some explanaitions:
|
||||
<BR><BR>
|
||||
|
||||
<ul>
|
||||
<li>Filled polys - Planar polygons. In the ssg-lib, this is the only primitive you can use to make "solid" looking models. This is a 2D primitive; it has no volume but an area.
|
||||
<li># sides - No of sides per poly. This is of course equal to number of vertices per poly. Some formats support only triangles, some
|
||||
also quads and some support n-sided polys, that is they have no restrictions.
|
||||
<li>Lines - for example used for high voltage lines in a flight simulator.
|
||||
This is a 1D primitive; it has no area but a length.
|
||||
<li>Points - for example used for small lights.
|
||||
This is a "0D" primitive; it has no length.
|
||||
<li>Sub objects - The complete model may consist of several sub models.
|
||||
There are several reasons one wants this, for example to make the structure of the model
|
||||
clearer to humans, to easily enable humans or programs to move, colour, texture, animate etc
|
||||
one part, for example one wheel of the complete model.
|
||||
<li>Hierarchie - You not only have sub objects, but there is a parent-kid relation between some,
|
||||
for example, the upper arm of a human model may be "under" the body and the lower arm "under" the upper arm etc.
|
||||
<li>DAG - direct acyclic graph means that the hierarchie may not only be a tree where
|
||||
each node has exactly one parent (apart from the root, which has zero parents), but that nodes may have more than one parent.
|
||||
Used for example in cars to have the wheel geometry only once. If the one wheel-node has four parents, this means
|
||||
it will be rendered four times when the scene is drawn.
|
||||
<li>Colours - Things can have a colour. Uncoloured objects are always white.
|
||||
<li>Textures - Texture things with 2D bitmaps.
|
||||
<li>Texture coordinates - The texture mapping is arbitrary.
|
||||
<li>Texture coord. per face AND vertex - If a vertex is part of three faces, then this feature
|
||||
allows it to have three texture coordinates. For example, a cube may have 18 texture coordinates, even if it has much fewer vertices.
|
||||
<li>Texture per face - each face may have another texture bitmap. Formats (and the ssg lib) that
|
||||
don't have this have to increase the number of nodes to get this effect.
|
||||
<li>Transparency - Some polys may be partially or completely transparent.
|
||||
<li>Animation - There may be many different sorts of animation.
|
||||
<li>Billboards - geometry that automatically rotates so it always faces the viewer. Normaly flat.
|
||||
As an example, can be used to model trees in a driving simulator.
|
||||
<li>LOD - stands for "Level of Detail" and means there can be geometries of varying
|
||||
complexity for the model, so for example, if it is near the viewer you use many polys
|
||||
and if it is far away you use few polys so that the impact on rendering speed is low.
|
||||
<li>Other switches - switch means you can switch the visibility of some nodes on and off.
|
||||
<li>Ascii or Binary - A stands for Ascii, B for Binary files.
|
||||
</ul>
|
||||
|
||||
<table width="100%" border="1" cellspacing="0" cellpadding="0">
|
||||
<tr>
|
||||
<td> Feature</td>
|
||||
<td> 3DS<BR>load</td>
|
||||
<td> AC<BR>load/<BR>save</td>
|
||||
<td> ASC<BR>save</td>
|
||||
<td> ASE<BR>load/<BR>save</td>
|
||||
<td> ATG<BR>load/<BR>save</td>
|
||||
<td> DXF<BR>load</td>
|
||||
<td> DXF<BR>save</td>
|
||||
<td> FLT<BR>load</td>
|
||||
<td> M<BR>load/<BR>save</td>
|
||||
<td> MD2<BR>load</td>
|
||||
<td> OBJ<BR>load</td>
|
||||
<td> OBJ<BR>save</td>
|
||||
<td> OFF<BR>load/<BR>save</td>
|
||||
<td> SSG<BR>load/<BR>save</td>
|
||||
<td> Strip<BR>load</td>
|
||||
<td> TRI<BR>load/<BR>save</td>
|
||||
<td> X<BR>load</td>
|
||||
<td> IV<BR>load</td>
|
||||
<td> VRML1<BR>load</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> Filled polys</td>
|
||||
<td> E</td>
|
||||
<td> E</td>
|
||||
<td> E</td>
|
||||
<td> E</td>
|
||||
<td> E</td>
|
||||
<td> E</td>
|
||||
<td> E(5)</td>
|
||||
<td> E</td>
|
||||
<td> E/D</td>
|
||||
<td> ?</td>
|
||||
<td> E</td>
|
||||
<td> E</td>
|
||||
<td> E</td>
|
||||
<td> E</td>
|
||||
<td> E</td>
|
||||
<td> </td>
|
||||
<td> E</td>
|
||||
<td> E</td>
|
||||
<td> E</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> # sides</td>
|
||||
<td> </td>
|
||||
<td> n/3</td>
|
||||
<td> 3</td>
|
||||
<td> 3</td>
|
||||
<td> n</td>
|
||||
<td> 3,4(4)</td>
|
||||
<td> 3</td>
|
||||
<td> n</td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> n?</td>
|
||||
<td> 3</td>
|
||||
<td> n</td>
|
||||
<td> n(4)</td>
|
||||
<td> </td>
|
||||
<td> 3?</td>
|
||||
<td> n</td>
|
||||
<td> 3,4</td>
|
||||
<td> 3,4</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> Lines</td>
|
||||
<td> A</td>
|
||||
<td> D/C</td>
|
||||
<td> C</td>
|
||||
<td> E</td>
|
||||
<td> A(?)</td>
|
||||
<td> E</td>
|
||||
<td> E</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> ?</td>
|
||||
<td> E</td>
|
||||
<td> E</td>
|
||||
<td> A?</td>
|
||||
<td> E</td>
|
||||
<td> A</td>
|
||||
<td> </td>
|
||||
<td> A</td>
|
||||
<td> B</td>
|
||||
<td> B</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> Points</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> E</td>
|
||||
<td> C</td>
|
||||
<td> A(?)</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> B</td>
|
||||
<td> A</td>
|
||||
<td> ?</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> E</td>
|
||||
<td> A</td>
|
||||
<td> </td>
|
||||
<td> A</td>
|
||||
<td> B</td>
|
||||
<td> B</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> Sub objects</td>
|
||||
<td> E</td>
|
||||
<td> E/D</td>
|
||||
<td> E</td>
|
||||
<td> E</td>
|
||||
<td> A(?)</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> E</td>
|
||||
<td> A</td>
|
||||
<td> ?</td>
|
||||
<td> C-D</td>
|
||||
<td> C-D</td>
|
||||
<td> A</td>
|
||||
<td> E</td>
|
||||
<td> A</td>
|
||||
<td> </td>
|
||||
<td> E</td>
|
||||
<td> E</td>
|
||||
<td> E</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> Hierarchie</td>
|
||||
<td> A</td>
|
||||
<td> E/D</td>
|
||||
<td> E?</td>
|
||||
<td> E</td>
|
||||
<td> A(?)</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> E</td>
|
||||
<td> A</td>
|
||||
<td> ?</td>
|
||||
<td> C</td>
|
||||
<td> C</td>
|
||||
<td> A</td>
|
||||
<td> E</td>
|
||||
<td> A</td>
|
||||
<td> </td>
|
||||
<td> C</td>
|
||||
<td> E</td>
|
||||
<td> E</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> DAG</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> A(?)</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> E</td>
|
||||
<td> A</td>
|
||||
<td> ?</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> E</td>
|
||||
<td> A</td>
|
||||
<td> </td>
|
||||
<td> A(?)</td>
|
||||
<td> E</td>
|
||||
<td> E</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> Colours</td>
|
||||
<td> E</td>
|
||||
<td> E/D</td>
|
||||
<td> E?</td>
|
||||
<td> E</td>
|
||||
<td> ?</td>
|
||||
<td> E</td>
|
||||
<td> E</td>
|
||||
<td> D(1)</td>
|
||||
<td> A</td>
|
||||
<td> ?</td>
|
||||
<td> D</td>
|
||||
<td> C</td>
|
||||
<td> A</td>
|
||||
<td> E</td>
|
||||
<td> A</td>
|
||||
<td> </td>
|
||||
<td> E</td>
|
||||
<td> B</td>
|
||||
<td> B</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> Textures</td>
|
||||
<td> D</td>
|
||||
<td> E/D</td>
|
||||
<td> E</td>
|
||||
<td> E</td>
|
||||
<td> E</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> E</td>
|
||||
<td> A</td>
|
||||
<td> ?</td>
|
||||
<td> D</td>
|
||||
<td> C</td>
|
||||
<td> B</td>
|
||||
<td> E</td>
|
||||
<td> A</td>
|
||||
<td> </td>
|
||||
<td> E</td>
|
||||
<td> E</td>
|
||||
<td> E</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> Texture coord.</td>
|
||||
<td> D</td>
|
||||
<td> E</td>
|
||||
<td> E</td>
|
||||
<td> E</td>
|
||||
<td> E</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> E</td>
|
||||
<td> A</td>
|
||||
<td> ?</td>
|
||||
<td> E</td>
|
||||
<td> C</td>
|
||||
<td> B</td>
|
||||
<td> E</td>
|
||||
<td> A</td>
|
||||
<td> </td>
|
||||
<td> E</td>
|
||||
<td> E</td>
|
||||
<td> E</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> Texture coord.<BR>per face<BR>AND vertex</td>
|
||||
<td> D(?)</td>
|
||||
<td> D(?)</td>
|
||||
<td> A</td>
|
||||
<td> E</td>
|
||||
<td> E</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> ?</td>
|
||||
<td> E</td>
|
||||
<td> C</td>
|
||||
<td> B(?)</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> </td>
|
||||
<td> C</td>
|
||||
<td> E</td>
|
||||
<td> E</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> Texture per face</td>
|
||||
<td> </td>
|
||||
<td> D(?)/-</td>
|
||||
<td> C</td>
|
||||
<td> A</td>
|
||||
<td> E</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> E</td>
|
||||
<td> A</td>
|
||||
<td> ?</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> B(?)</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> </td>
|
||||
<td> C</td>
|
||||
<td> B</td>
|
||||
<td> A</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> Transparency</td>
|
||||
<td> D</td>
|
||||
<td> D</td>
|
||||
<td> D</td>
|
||||
<td> D</td>
|
||||
<td> A(?)</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> E</td>
|
||||
<td> A</td>
|
||||
<td> ?</td>
|
||||
<td> A?</td>
|
||||
<td> A?</td>
|
||||
<td> B(?)</td>
|
||||
<td> E</td>
|
||||
<td> A</td>
|
||||
<td> </td>
|
||||
<td> E</td>
|
||||
<td> B</td>
|
||||
<td> B</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> Animation</td>
|
||||
<td> B</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> E</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> B(2)</td>
|
||||
<td> A</td>
|
||||
<td> ?</td>
|
||||
<td> A?</td>
|
||||
<td> A?</td>
|
||||
<td> A</td>
|
||||
<td> E</td>
|
||||
<td> A</td>
|
||||
<td> </td>
|
||||
<td> B or C</td>
|
||||
<td> B</td>
|
||||
<td> A</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> Billboards</td>
|
||||
<td> </td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> E</td>
|
||||
<td> A</td>
|
||||
<td> ?</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> E</td>
|
||||
<td> A</td>
|
||||
<td> </td>
|
||||
<td> A</td>
|
||||
<td> B</td>
|
||||
<td> A</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> LOD</td>
|
||||
<td> </td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> E</td>
|
||||
<td> A</td>
|
||||
<td> ?</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> E</td>
|
||||
<td> A</td>
|
||||
<td> </td>
|
||||
<td> A</td>
|
||||
<td> B</td>
|
||||
<td> B</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> Other switches</td>
|
||||
<td> </td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> D</td>
|
||||
<td> A</td>
|
||||
<td> ?</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> E</td>
|
||||
<td> A</td>
|
||||
<td> </td>
|
||||
<td> A</td>
|
||||
<td> D</td>
|
||||
<td> D</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> A=Ascii or<BR>B=Binary</td>
|
||||
<td> B</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> B</td>
|
||||
<td> A</td>
|
||||
<td> B</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
<td> B</td>
|
||||
<td> ?</td>
|
||||
<td> A</td>
|
||||
<td> A+B(3)</td>
|
||||
<td> A</td>
|
||||
<td> A</td>
|
||||
</tr>
|
||||
</table>
|
||||
footnotes:
|
||||
<BR><BR>
|
||||
(1) problematic for ancient files
|
||||
<BR>
|
||||
(2) DOFs are not implemented
|
||||
<BR>
|
||||
(3) There is an ascii- and a binary X-file-format.
|
||||
I only implemented the ascii-one and probably wont implement the
|
||||
binary one. There is a free (as in beer) converter by Microsoft
|
||||
running under Windo$.
|
||||
<BR>
|
||||
(4) It is possible to have polys with an arbitrary number of vertices in ssg.
|
||||
But then you may only use one poly per node. Also, you can not mix 3 and 4 sided polys in one node.
|
||||
<BR>
|
||||
(5) Some OpenGL modes, like for example Quads, are ignored. This means some parts of the model
|
||||
may dissappear when saving into DXF files.
|
||||
<BR><BR>
|
||||
Additional info on some formats:
|
||||
|
||||
<BR><BR>
|
||||
ATG:
|
||||
<BR>
|
||||
ATG stands for ascii TerraGear. Loading of TriStrips and TriFans not implemented yet.
|
||||
Untextured parts are lost, for example when you save and load
|
||||
Steve Bakers Tuxedo, you will loose the feet, since they are not
|
||||
textured.
|
||||
The files written are not optimal, they use no strips/fans,
|
||||
only have triangles etc.
|
||||
Also, one vertex that needs several texture coords is written out several
|
||||
times.
|
||||
|
||||
|
||||
<BR><BR>
|
||||
3ds-writer:
|
||||
<BR>
|
||||
I (Per) have one basicly working, but since there seems to be so much else to do
|
||||
with plib right now, I'm a bit reluctant to put my energy into it. Also, the
|
||||
only 3ds-loader I've tested files written by it with is the one in ssg :-)
|
||||
|
||||
|
||||
<BR><BR>
|
||||
OFF loader:
|
||||
<BR>
|
||||
Warning: There are two formats called OFF! We support the OFF from GeomView,
|
||||
not the one from DEC.
|
||||
We support 2D and 3D, but no higher dimensions.
|
||||
|
||||
<BR><BR>
|
||||
.SSG file loader/writer:
|
||||
<BR>
|
||||
We number .SSG file formats so that for example the loaders knows
|
||||
what to expect. Until now, there is
|
||||
<BR>
|
||||
format "0" - Used by plib 1.2.0, 1.3.x
|
||||
<BR>
|
||||
format "1" - Will be used by 1.4.0
|
||||
<BR>
|
||||
Currently, we are between "0" and "1". Normally, we want to keep at least our loader
|
||||
compatible, but the changes from zero to one would bloat the code so much and it seems
|
||||
.SSG file version zero were only used by people for temporary files, so we decided to make an incompatible break.
|
||||
If you need to read or write version zero, either get plib from SVN with the date 14.1.2001, or, if you are a Windo$ person, get
|
||||
<a href="prettypoly.sourceforge.net/download/ppewinbin_ssg_version_zero.zip">prettypoly.sourceforge.net/download/ppewinbin_ssg_version_zero.zip</a>
|
||||
This allows you to save and load .ssg version zero.
|
||||
<BR>
|
||||
One of the new features in format "1" might be worth mentioning.
|
||||
It is now possible to load and save *any* class derived from ssgBase (notably
|
||||
the ssgAux node types).
|
||||
All that is needed for saving to work is an implementation of the virtual save() method.
|
||||
Loading requires the corresponing load() method, and also means for creating
|
||||
an instance of the class, which is accomplished
|
||||
by a call to ssgRegisterType().
|
||||
See the ssgAux implementation for example usage;
|
||||
the convenience function ssgaInit() registers the ssgAux classes.
|
||||
<BR><BR>
|
||||
.X file writer:
|
||||
<BR>
|
||||
Planned.
|
||||
<BR><BR>
|
||||
.X file loader:
|
||||
<BR>
|
||||
The .X-entity "Frame" is not yet implemented.
|
||||
If you convert files into .X with "3D Exploration", you can check the
|
||||
option "without frames".
|
||||
|
||||
<BR><BR>
|
||||
VRML1/IV file loaders:
|
||||
<BR>
|
||||
These are only partially implemented, and are useful primarily for
|
||||
mesh-based models (textured or untextured). It would be useful to add
|
||||
material support to these loaders, as well as explicit normal definition.
|
||||
|
||||
<hr>
|
||||
<table width="100%">
|
||||
<tr>
|
||||
<td width="33%" align="left"><a href="ssgContext.html"><= 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="LoaderWriter.html">= next =></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>
|
||||
<<A HREF="mailto:sjbaker1@airmail.net">sjbaker1@airmail.net</A>>
|
||||
</ADDRESS>
|
||||
</table>
|
||||
</BODY>
|
||||
</HTML>
|
||||
|
||||
233
doc/ssg/ssgBase.html
Normal file
233
doc/ssg/ssgBase.html
Normal file
@@ -0,0 +1,233 @@
|
||||
<!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 ssgBase</code> - The Universal Abstract Base Class.</H2>
|
||||
All significant SSG classes are derived from ssgBase - which offers a type testing
|
||||
mechanism and a means to print out the tree hierarchy in human-readable form,
|
||||
or to save/load it to/from disk.
|
||||
<pre>
|
||||
|
||||
class ssgBase
|
||||
{
|
||||
void ref () ;
|
||||
void deRef () ;
|
||||
int getRef () ;
|
||||
|
||||
int isA ( int ty ) ;
|
||||
int isAKindOf ( int ty ) ;
|
||||
|
||||
int getType (void) ;
|
||||
virtual char *getTypeName(void) ;
|
||||
|
||||
ssgBase *getUserData () ;
|
||||
void setUserData ( ssgBase *user_data ) ;
|
||||
|
||||
void setName ( char *nm ) ;
|
||||
char *getName () ;
|
||||
const char *getPrintableName () ;
|
||||
|
||||
virtual void print ( FILE *fd = stderr, char *indent = "", int how_much = 2 ) ;
|
||||
virtual int load ( FILE *fd ) ;
|
||||
virtual int save ( FILE *fd = stderr ) ;
|
||||
|
||||
ssgBase *clone ( int clone_flags ) ;
|
||||
} ;
|
||||
|
||||
</pre>
|
||||
|
||||
<H3>Reference Counting.</H3>
|
||||
All SSG classes are reference counted - that means that whenever you
|
||||
connect a node into the scene graph with <code>ssgBranch::addKid()</code>, we
|
||||
increment its reference count and each time we remove a node from
|
||||
the graph with <code>ssgBranch::removeKid()</code>, we decrement the count -
|
||||
and if it's zero, we'll delete the node to recover memory.
|
||||
<p>
|
||||
Sometimes, you need a node to stay in memory even though it may be
|
||||
be disconnected from the scene graph. You can achieve that by
|
||||
calling <code>ssgBase::ref()</code> to increment the reference count.
|
||||
If you later find you don't need that node anymore then you may
|
||||
<code>ssgBase::deRef()</code> it. If you <code>ssgBase::deRef()</code>
|
||||
a node to zero, SSG won't automatically delete it - you still need to use
|
||||
<code>delete</code> to do that. Since such deletions are recursive,
|
||||
you may delete an entire sub-branch with a single call.
|
||||
<p>
|
||||
Instead of using <code>ssgBase::deRef()</code> directly, you should use
|
||||
<code>ssgDeRefDelete()</code> which automatically deletes the node if
|
||||
the reference count drops to zero.
|
||||
<p>
|
||||
You can read the current ref count for a node
|
||||
using <code>ssgBase::getRef()</code>.
|
||||
<H3>Names.</H3>
|
||||
It's often useful to attach an ASCII name to a node in the
|
||||
scene graph - this is often derived from a name field in
|
||||
whatever modelling tool was used to create the object.
|
||||
<code>ssgBase::setName(s)</code> sets the name,
|
||||
<code>ssgBase::getName()</code> returns it.
|
||||
|
||||
<H3>User Data</H3>
|
||||
Although one can derive a new C++ class from an SSG class and thereby customise
|
||||
it's behavior, it's often more convenient to simply attach application-specific
|
||||
data structures to a basic entity. Two functions are provided:
|
||||
<code>ssgBase::getUserData()</code> and <code>ssgBase::setUserData(data)</code>.
|
||||
<p>
|
||||
Notice that user data is of class ssgBase - which means that user data
|
||||
can be named, ref-counted - and can in turn have user data of it's own.
|
||||
This allows user data to be formed into linked lists when multiple
|
||||
user data items need to be attached to a single node.
|
||||
|
||||
<H3>Destructor Functions</H3>
|
||||
When an SSG entity is NOT connected into the scene graph in any
|
||||
way, then the correct way to get rid of it and free up memory
|
||||
is to call it's destructor function. However, when the entity
|
||||
is included into the scene graph, you should disconnect it
|
||||
from the tree and let the reference count mechanism take care
|
||||
of the cleanup.
|
||||
<H3>Type Names</H3>
|
||||
SSG frequently needs to know what kind of an object an ssgBase is.
|
||||
Since C++ programs may create new classes that inherit from SSG
|
||||
classes, we provide several functions to make run time type determination
|
||||
possible. There is an external function for each type that
|
||||
returns the type token for that type:
|
||||
<pre>
|
||||
|
||||
int ssgTypeBase () ;
|
||||
int ssgTypeEntity () ;
|
||||
int ssgTypeLeaf () ;
|
||||
int ssgTypeVTable () ;
|
||||
int ssgTypeVtxTable () ;
|
||||
int ssgTypeDisplayList() ;
|
||||
int ssgTypeBranch () ;
|
||||
int ssgTypeBaseTransform ();
|
||||
int ssgTypeTransform () ;
|
||||
int ssgTypeTexTrans () ;
|
||||
int ssgTypeSelector () ;
|
||||
int ssgTypeTimedSelector () ;
|
||||
int ssgTypeRangeSelector () ;
|
||||
int ssgTypeRoot () ;
|
||||
int ssgTypeCutout () ;
|
||||
|
||||
</pre>
|
||||
Now, you can use the <code>ssgBase::isA(type)</code> or <code>ssgBase::isAKindOf</code>
|
||||
to test the type of the node. For example, if you want to test
|
||||
whether a node is a Leaf node or a Branch node, you can do this:
|
||||
<pre>
|
||||
|
||||
if ( mynode -> isAKindOf ( ssgTypeLeaf() ) )
|
||||
printf ( "Leaf node\n" ) ;
|
||||
else
|
||||
if ( mynode -> isAKindOf ( ssgTypeBranch() ) )
|
||||
printf ( "Branch node\n" ) ;
|
||||
else
|
||||
printf ( "Something else\n" ) ;
|
||||
|
||||
</pre>
|
||||
Notice that if you ran that code on (say) an ssgSelector, then it'll
|
||||
print "Branch node" since the Selector class is derived from the Branch
|
||||
class. If you wanted to tell if a node was *exactly* a Branch node -
|
||||
and not from a derived class, then you could use:
|
||||
<pre>
|
||||
|
||||
if ( mynode -> isA ( ssgTypeBranch() ) )
|
||||
printf ( "Branch node\n" ) ;
|
||||
|
||||
</pre>
|
||||
Finally, you can actually read the type of a node - either as a
|
||||
token (using <code>ssgBase::getType()</code>) or as an ASCII string
|
||||
(using <code>ssgBase::getTypeName()</code>). The latter is very useful
|
||||
for debug routines:
|
||||
<pre>
|
||||
|
||||
printf ( "ERROR - something wrong with my '%s' node.\n",
|
||||
mynode -> getTypeName () ) ;
|
||||
|
||||
</pre>
|
||||
|
||||
<H3>Printing</H3>
|
||||
It's sometimes useful during debug to print a section of the
|
||||
scene graph so you can examine it. <code>ssgBase::print(fd, indent, how_much)</code>
|
||||
does that for you - it prints out the node itself - and anything
|
||||
connected beneath it in the scene graph. <code>fd</code> is the
|
||||
file descriptor to print to (defaults to stderr) and
|
||||
<code>indent</code> is a string that will prefix all output lines
|
||||
- and is used internally within SSG to make printout of tree
|
||||
structures more legible by indenting them.
|
||||
<p>
|
||||
The values for the parameter <code>how_much</code> may be 0,1,2,3 or 4
|
||||
and determine how much is printed, with 0 meaning little
|
||||
and 4 meaning much.
|
||||
<BR>
|
||||
For how_much = 0, basic information of the branches is printed
|
||||
<BR>
|
||||
For 1, additionally there is: basic leaf info, state pointers
|
||||
<BR>
|
||||
For 2, additionally there is: states, user data, number of parents,
|
||||
bSphere
|
||||
<BR>
|
||||
For 3, additionally there is: Reference count
|
||||
<BR>
|
||||
For 4, additionally there is: contents of vertex-, normal-, colour-,
|
||||
texCoord- and index-arrays
|
||||
<BR>
|
||||
Experience tells that for <code>how_much = 0</code> you get very little
|
||||
out put, with 1, 2 and 3 a manageable amount and with 4 a huge amount,
|
||||
up to 100 MB for a medium sized model.
|
||||
|
||||
|
||||
<p>
|
||||
It would be unwise
|
||||
to attempt to parse the output of <code>ssgBase::print</code> into another
|
||||
program since it is only intended for human consumption and the
|
||||
format may change dramatically between revisions of SSG.
|
||||
|
||||
<H3>Cloning:</H3>
|
||||
All classes derived from ssgBase have a member function
|
||||
<code>ssgBase *clone(int clone_flags)</code> which new's a
|
||||
new object of that class as a copy of the calling object.
|
||||
<p>
|
||||
The 'clone_flags' is a set of tokens that you 'OR' together to
|
||||
specify how 'deep' you want the cloning to go. By default
|
||||
(with clone_flags==0), only the object itself is cloned and
|
||||
the clone will simply point to the same child structures as
|
||||
the original object. However, if you OR in 'SSG_CLONE_RECURSIVE',
|
||||
then all ssgEntities beneath this one will also be cloned.
|
||||
ORing in SSG_CLONE_GEOMETRY will cause all the per-vertex data
|
||||
at the leaf nodes to also be cloned. SSG_CLONE_STATE causes
|
||||
ssgState objects to be cloned also, SSG_CLONE_STATE_RECURSIVE
|
||||
also causes states pointed to by other states to be copied,
|
||||
SSG_CLONE_USERDATA causes user data attached to
|
||||
the original node to be referenced (NOT copied) by the clone -
|
||||
otherwise, user data for the clone is set to NULL. Finally,
|
||||
SSG_CLONE_TEXTURE causes texture maps to be replicated also.
|
||||
<p>
|
||||
Most copy operations will typically use either zero, SSG_CLONE_RECURSIVE
|
||||
or (SSG_CLONE_RECURSIVE | SSG_CLONE_GEOMETRY)
|
||||
|
||||
<hr>
|
||||
<table width="100%">
|
||||
<tr>
|
||||
<td width="33%" align="left"><a href="index.html"><= 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="ssgEntity.html">= next =></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>
|
||||
<<A HREF="mailto:sjbaker1@airmail.net">sjbaker1@airmail.net</A>>
|
||||
</ADDRESS>
|
||||
</table>
|
||||
</BODY>
|
||||
</HTML>
|
||||
|
||||
183
doc/ssg/ssgContext.html
Normal file
183
doc/ssg/ssgContext.html
Normal file
@@ -0,0 +1,183 @@
|
||||
<!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>ssgContext</H2>
|
||||
A 'context' is a set of parameters that relate to rendering
|
||||
one SSG image. It contains the camera parameters and some
|
||||
default state information.
|
||||
<pre>
|
||||
|
||||
class ssgContext
|
||||
{
|
||||
ssgContext () ;
|
||||
void forceBasicState () { basicState -> force () ; }
|
||||
|
||||
void makeCurrent () ;
|
||||
int isCurrent () ;
|
||||
|
||||
void overrideTexture ( int on_off ) ;
|
||||
void overrideCullface ( int on_off ) ;
|
||||
int textureOverridden () { return ovTexture ; }
|
||||
int cullfaceOverridden () { return ovCullface ; }
|
||||
void setCullface ( int on_off ) { cullFace = on_off ; }
|
||||
int cullfaceIsEnabled () { return cullFace ; }
|
||||
|
||||
sgFrustum *getFrustum () { return frustum ; }
|
||||
|
||||
void getNearFar ( float *n, float *f ) ;
|
||||
void getFOV ( float *w, float *h ) ;
|
||||
void getOrtho ( float *w, float *h ) ;
|
||||
void setNearFar ( float n, float f ) ;
|
||||
void setOrtho ( float w, float h ) ;
|
||||
void setFOV ( float w, float h ) ;
|
||||
|
||||
int isOrtho () { return orthographic ; }
|
||||
|
||||
void getCameraPosition ( sgVec3 pos ) ;
|
||||
void setCamera ( sgMat4 mat ) ;
|
||||
void setCamera ( sgCoord *coord ) ;
|
||||
|
||||
void loadProjectionMatrix () ;
|
||||
void loadModelviewMatrix () ;
|
||||
|
||||
void getProjectionMatrix ( sgMat4 dst ) ;
|
||||
void getModelviewMatrix ( sgMat4 dst ) ;
|
||||
|
||||
void clrClipPlane ( int i ) ;
|
||||
void setClipPlane ( int i, sgVec4 plane ) ;
|
||||
int isSetClipPlane ( int i ) ;
|
||||
float *getClipPlane ( int i ) ;
|
||||
} ;
|
||||
|
||||
</pre>
|
||||
In all 3D rendering, you need the concept of a virtual camera - or
|
||||
eyepoint. This is set up in SSG with the following calls:
|
||||
<pre>
|
||||
|
||||
void ssgContext::setFOV ( float w, float h ) ;
|
||||
void ssgContext::setNearFar( float n, float f ) ;
|
||||
void ssgContext::setCamera ( sgCoord *coord ) ;
|
||||
|
||||
</pre>
|
||||
The setFOV call sets up the vertical and horizontal fields
|
||||
of view (in degrees), setNearFar sets the near and far
|
||||
clip planes (in whatever units your model is built in).
|
||||
Finally, you can position the virtual camera relative to
|
||||
the database origin using setCamera.
|
||||
<p>
|
||||
Very often, an SSG program contains other non-SSG routines that
|
||||
are accessing OpenGL state. Even a menu drawn using PUI or an
|
||||
overlay in raw OpenGL or using FNT will change the current
|
||||
state of OpenGL. Since SSG does 'lazy' state changes (only
|
||||
updating those states that need to be changed) - it will be
|
||||
fooled into no setting some things that some ssgLeaf nodes
|
||||
really need.
|
||||
<p>
|
||||
This isn't a problem so long as the application doesn't change states
|
||||
DURING ssgCullAndDraw (by using derived class member functions, callbacks,
|
||||
etc). If you need to do that then be sure to call forceBasicState()
|
||||
before you return to SSG.
|
||||
<pre>
|
||||
|
||||
void ssgContext::forceBasicState ( void ) ;
|
||||
|
||||
</pre>
|
||||
<p>
|
||||
During testing, you sometimes need to disable texture rendering,
|
||||
or backface culling:
|
||||
<pre>
|
||||
|
||||
void ssgContext::overrideTexture ( int on_off ) ;
|
||||
void ssgContext::overrideCullface ( int on_off ) ;
|
||||
|
||||
</pre>
|
||||
The six standard OpenGL user-defined clipping planes
|
||||
can be setup and managed automatically using these
|
||||
calls:
|
||||
<pre>
|
||||
|
||||
void clrClipPlane ( int i ) ;
|
||||
void setClipPlane ( int i, sgVec4 plane ) ;
|
||||
int isSetClipPlane ( int i ) ;
|
||||
float *getClipPlane ( int i ) ;
|
||||
|
||||
</pre>
|
||||
setClipPlane takes the number of the plane (0 through 5) and
|
||||
a plane equation which will be applied at the next cull/draw
|
||||
cycle. clrClipPlane removes a clip plane. isSetClipPlane inquires
|
||||
about whether the i'th plane is turned on and getClipPlane returns
|
||||
the plane that's currently set as the i'th plane.
|
||||
<p>
|
||||
Once you have your context set up as you'd like, you have to
|
||||
make it become the 'current' context.
|
||||
<pre>
|
||||
|
||||
void ssgContext::makeCurrent () ;
|
||||
|
||||
</pre>
|
||||
There is a non-class function:
|
||||
<pre>
|
||||
|
||||
ssgContext *ssgGetCurrentContext() ;
|
||||
|
||||
</pre>
|
||||
...which returns the current context.
|
||||
<p>
|
||||
The 'ssgContext' class was not present in PLIB 1.0.xx, so (for
|
||||
backwards compatibility) there is an initial context assigned
|
||||
inside ssgInit(). In addition to the member functions of ssgContext,
|
||||
there are a number of equivelent global functions that are
|
||||
equivelent to ssgGetCurrentContext()->member_function(). These
|
||||
functions are deprecated for new code:
|
||||
<pre>
|
||||
|
||||
inline void ssgForceBasicState () ;
|
||||
inline void ssgGetCameraPosition ( sgVec3 pos ) ;
|
||||
inline void ssgOverrideTexture ( int on_off ) ;
|
||||
inline void ssgOverrideCullface ( int on_off ) ;
|
||||
inline void ssgGetNearFar ( float *n, float *f ) ;
|
||||
inline void ssgGetFOV ( float *w, float *h ) ;
|
||||
inline void ssgSetFOV ( float w, float h ) ;
|
||||
inline void ssgSetOrtho ( float w, float h ) ;
|
||||
inline void ssgSetNearFar ( float n, float f ) ;
|
||||
inline void ssgSetCamera ( sgMat4 mat ) ;
|
||||
inline void ssgSetCamera ( sgCoord *coord ) ;
|
||||
inline void ssgLoadProjectionMatrix () ;
|
||||
inline void ssgLoadProjectionMatrix ( sgFrustum *f ) ;
|
||||
inline void ssgGetProjectionMatrix ( sgMat4 dst ) ;
|
||||
inline void ssgGetModelviewMatrix ( sgMat4 dst ) ;
|
||||
inline void ssgLoadModelviewMatrix () ;
|
||||
inline void ssgLoadModelviewMatrix ( sgMat4 mat ) ;
|
||||
|
||||
</pre>
|
||||
|
||||
|
||||
<hr>
|
||||
<table width="100%">
|
||||
<tr>
|
||||
<td width="33%" align="left"><a href="state.html"><= 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="non_class.html">= next =></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>
|
||||
<<A HREF="mailto:sjbaker1@airmail.net">sjbaker1@airmail.net</A>>
|
||||
</ADDRESS>
|
||||
</table>
|
||||
</BODY>
|
||||
</HTML>
|
||||
|
||||
146
doc/ssg/ssgEntity.html
Normal file
146
doc/ssg/ssgEntity.html
Normal file
@@ -0,0 +1,146 @@
|
||||
<!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 ssgEntity</code> - A Node in the Tree.</H2>
|
||||
All nodes in the SSG scene graph are ssgEntities.
|
||||
<pre>
|
||||
|
||||
clas ssgEntity : public ssgBase
|
||||
{
|
||||
public:
|
||||
|
||||
ssgEntity (void) ;
|
||||
virtual ~ssgEntity (void) ;
|
||||
|
||||
int getTraversalMask () ;
|
||||
void setTraversalMask ( int t ) ;
|
||||
void setTraversalMaskBits ( int t ) ;
|
||||
void clrTraversalMaskBits ( int t ) ;
|
||||
|
||||
virtual void recalcBSphere (void) ;
|
||||
int isDirtyBSphere (void) ;
|
||||
void dirtyBSphere () ;
|
||||
sgSphere *getBSphere () ;
|
||||
|
||||
virtual int getNumKids (void) ;
|
||||
int getNumParents () ;
|
||||
ssgBranch *getParent ( int p ) ;
|
||||
ssgBranch *getNextParent () ;
|
||||
|
||||
virtual void cull ( sgFrustum *f, sgMat4 m, int test_needed ) ;
|
||||
virtual void isect ( sgSphere *s, sgMat4 m, int test_needed ) ;
|
||||
virtual void hot ( sgVec3 s, sgMat4 m, int test_needed ) ;
|
||||
} ;
|
||||
|
||||
</pre>
|
||||
|
||||
<H3>The tree structure.</H3>
|
||||
Every entity has a list of parent entities and (conceptually), a list of
|
||||
child entities ("kids"). In practice, ssgRoot nodes never have parents
|
||||
and ssgLeaf nodes never have kids.
|
||||
<p>
|
||||
The structure of the scene graph permits the same node to be inserted
|
||||
into the graph in multiple locations. This is useful for saving
|
||||
space when the same object is needed many times in the scene.
|
||||
Hence, any given node may have more than one parent node.
|
||||
<p>
|
||||
You can traverse the list of parent nodes
|
||||
using <code>ssgEntity::getNumParents()</code> to find out the number
|
||||
of parents this node has and
|
||||
<code>ssgEntity::getParent(n)</code> to locate the n'th parent.
|
||||
<p>
|
||||
Alternatively, after calling getParent, you can call getNextParent
|
||||
to get the N+1'th parent node - it returns NULL when no more parents
|
||||
are available.
|
||||
<p>
|
||||
As a convenience for general tree-walking routines, there is a
|
||||
<code>ssgEntity::getNumKids()</code> call - which will always
|
||||
return zero on leaf nodes. You cannot actually get kid nodes unless
|
||||
the node is some kind of ssgBranch.
|
||||
|
||||
<H3>Traversals</H3>
|
||||
Much of the work done on an SSG scene graph entails 'traversing'
|
||||
the tree structure. This is done most commonly to display the
|
||||
scene using OpenGL - but is also done when doing intersection
|
||||
testing and other operations.
|
||||
<p>
|
||||
It's quite useful to be able to limit the traversal so that
|
||||
certain nodes do not get tested. This can save time - or
|
||||
prevent undesirable side-effects.
|
||||
<p>
|
||||
Each entity has a 'traveral mask' - which is a simple integer
|
||||
with one bit per kind of traversal. At present, there are
|
||||
three kinds of traversal:
|
||||
<pre>
|
||||
|
||||
SSGTRAV_CULL -- Culling to the field of view.
|
||||
SSGTRAV_ISECT -- General intersection testing.
|
||||
SSGTRAV_HOT -- Height-over-terrain testing.
|
||||
|
||||
</pre>
|
||||
You can directly set or get the traversal mask with <code>ssgEntity::setTraversalMask(m)</code>
|
||||
<code>ssgEntity::getTraversalMask()</code>. You can set an individual traversal bit using
|
||||
<code>ssgEntity::setTraversalMaskBits(m)</code> or clear one using
|
||||
<code>ssgEntity::clrTraversalMaskBits(m)</code>.
|
||||
|
||||
<H3>Bounding Sphere</H3>
|
||||
Quite a few graphics algorithms can be accellerated using a
|
||||
bounding sphere. The standard ssgEntity uses bounding
|
||||
spheres to do field-of-view and intersection testing.
|
||||
<p>
|
||||
Clearly one does not want to recompute the bounding sphere
|
||||
every frame - just some objects do change their size over
|
||||
time. Hence, the bounding sphere is lazily evaluated.
|
||||
<p>
|
||||
Whenever you do something to change the size or shape of an entity,
|
||||
you should call <code>ssgEntity::dirtyBSphere()</code>. This will
|
||||
mark this entity's sphere as invalid ("dirty") and also, walk
|
||||
backwards up the scene graph tree making all the nodes above
|
||||
this one dirty too. The next time SSG needs to know the bounding
|
||||
sphere size, it'll recompute it.
|
||||
<p>
|
||||
If you'd prefer for the bounding sphere recalculation to be
|
||||
done immediately, then you can call <code>ssgEntity::recalcBSphere()</code>
|
||||
and it will be done immediately. Branch nodes like ssgTransforms will
|
||||
automatically dirty their bounding spheres when necessary. Leaf nodes
|
||||
generally do not.
|
||||
<p>
|
||||
When anyone needs to know the bounding sphere size for a node,
|
||||
they'll call <code>ssgEntity::getBSphere()</code> - which will
|
||||
recaclulate the Bsphere if it needs to.
|
||||
|
||||
<H3>Culling and Drawing</H3>
|
||||
The actual tree-traversal, culling and rendering is handled by
|
||||
a virtual function <code>ssgEntity::cull()</code> - calling
|
||||
this on the root node in the scene graph causes the entire
|
||||
scene to be rendered in an efficient manner.
|
||||
|
||||
<hr>
|
||||
<table width="100%">
|
||||
<tr>
|
||||
<td width="33%" align="left"><a href="ssgBase.html"><= 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="ssgLeaf.html">= next =></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>
|
||||
<<A HREF="mailto:sjbaker1@airmail.net">sjbaker1@airmail.net</A>>
|
||||
</ADDRESS>
|
||||
</table>
|
||||
</BODY>
|
||||
</HTML>
|
||||
|
||||
305
doc/ssg/ssgLeaf.html
Normal file
305
doc/ssg/ssgLeaf.html
Normal file
@@ -0,0 +1,305 @@
|
||||
<!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 ssgLeaf</code> - Leaf nodes.</h2>
|
||||
Leaf nodes are those that actually make OpenGL calls
|
||||
or take other 'rendering' actions - they contain
|
||||
all of the geometric information in the scene.
|
||||
<pre>
|
||||
|
||||
class ssgLeaf : public ssgEntity
|
||||
{
|
||||
public:
|
||||
int getExternalPropertyIndex ()
|
||||
int isTranslucent ()
|
||||
int hasState ()
|
||||
ssgState *getState ()
|
||||
void setState ( ssgState *st )
|
||||
|
||||
virtual float *getVertex ( int i )
|
||||
virtual float *getNormal ( int i )
|
||||
virtual float *getColour ( int i )
|
||||
virtual float *getTexCoord ( int i )
|
||||
|
||||
virtual int getNumTriangles() ;
|
||||
virtual void getTriangle ( int n, short *v1, short *v2, short *v3 )
|
||||
|
||||
virtual int getNumLines () ;
|
||||
virtual void getLine ( int n, short *v1, short *v2 ) ;
|
||||
|
||||
int getNumLines () ;
|
||||
void getLine ( int n, short *v1, short *v2 ) ;
|
||||
|
||||
virtual void transform ( sgMat4 m )
|
||||
|
||||
void setCullFace ( int cf )
|
||||
int getCullFace ()
|
||||
|
||||
void makeDList () ;
|
||||
void deleteDList () ;
|
||||
GLuint getDListIndex () ;
|
||||
} ;
|
||||
|
||||
</pre>
|
||||
|
||||
<H3>Pre- and Post-Draw Callbacks.</H3>
|
||||
It's frequently useful to have an application function called
|
||||
just before and/or just after a leaf node is rendered.
|
||||
<pre>
|
||||
|
||||
typedef int (*ssgCallback)( ssgEntity * ) ;
|
||||
ssgCallback getCallback ( int which ) ;
|
||||
void setCallback ( int which, ssgCallback cb ) ;
|
||||
|
||||
</pre>
|
||||
(Where 'which' is either SSG_CALLBACK_PREDRAW for a function that's
|
||||
to be called before the node is drawn or SSG_CALLBACK_POSTDRAW for
|
||||
one that's called after rendering.) In both cases, the function will
|
||||
be passed a pointer to the leaf node that's about to be drawn, and
|
||||
(in the case of PREDRAW callbacks), may return FALSE to prevent the
|
||||
node from being drawn, or TRUE to have it draw normally.
|
||||
<H3>Display Lists</H3>
|
||||
A leaf node is normally rendered in 'immediate' mode in OpenGL,
|
||||
so that changes you make to the leaf will be reflected on the
|
||||
screen on the next occasion that it's drawn. However, on some
|
||||
graphics hardware, it's more efficient to create an OpenGL
|
||||
display list for each leaf node. This can be managed by
|
||||
calling <code>ssgLeaf::makeDList()</code>. If you want to
|
||||
make changes to the Leaf, you'll have to call makeDList again
|
||||
since OpenGL does not support the editing of display lists.
|
||||
<p>
|
||||
You can call <code>ssgLeaf::deleteDList()</code> to stop
|
||||
this leaf from being display listed from now on and to
|
||||
free up the display list memory.
|
||||
<code>ssgLeaf::getDListIndex()</code> returns the OpenGL
|
||||
display list handle - or zero if no display list exists
|
||||
for this leaf.
|
||||
<p>
|
||||
If you change a leaf node's geometry when it has an
|
||||
active display list without calling either deleteDList
|
||||
or makeDList again, then any subsequent operation
|
||||
involving rendering this node could fail.
|
||||
|
||||
<H3>Face Culling.</H3>
|
||||
By default, ssgLeaf nodes are back-face culled, you can change
|
||||
that for any given node using <code>ssgLeaf::setCullFace(cf)</code>
|
||||
where <code>cf</code> is TRUE to enable backface culling,
|
||||
FALSE to disable it. You can test the state of face culling
|
||||
using <code>ssgLeaf::getCullFace()</code>.
|
||||
<H3>State Management.</H3>
|
||||
OpenGL supports a wide selection of state information - things like
|
||||
texture, materials and such. All of this information is held in a
|
||||
separate SSG class hierarchy: 'ssgState'. Each leaf has a state
|
||||
which it sets up before drawing the geometry that the leaf contains.
|
||||
<p>
|
||||
Nodes may also be stateless - but that isn't useful for any
|
||||
of the existing SSG leaf node types.
|
||||
<p>
|
||||
You can set the state for a node using <code>ssgLeaf::setState(state)</code>
|
||||
and query it using <code>ssgLeaf::getState()</code>. You can ask if
|
||||
a node has state information attached using <code>ssgLeaf::hasState()</code>.
|
||||
<p>
|
||||
Since OpenGL does not render translucent object well when Z-buffering
|
||||
is enabled, it's often useful to know if an object is translucent.
|
||||
<code>ssgLeaf::isTranslucent()</code> handles that test.
|
||||
<p>
|
||||
It is often useful to tag ssgState's with external properties - and
|
||||
you can retrieve the property of a leaf's state using
|
||||
<code>ssgLeaf::getExternalPropertyIndex()</code>.
|
||||
<H3>Querying Geometry</H3>
|
||||
The actual storage format for geometry in classes derived from
|
||||
ssgLeaf varies from class to class. However, it's very useful
|
||||
to be able to query the geometry in an implementation-independent
|
||||
manner.
|
||||
<p>
|
||||
Although classes derived from ssgLeaf are entitled to store their
|
||||
geometry in any form, all of them are required to respond to
|
||||
queries about basic triangle primitives.
|
||||
<p>
|
||||
Firstly, you can get a count of the number of triangles in this
|
||||
leaf using <code>ssgLeaf::getNumTriangles()</code>. Each triangle
|
||||
has an index number for each vertex which can be queried using
|
||||
<code>ssgLeaf::getTriangle(n,&v1,&v2,&v3)</code> which copies
|
||||
the 'short' indices for the n'th triangle's three vertices into
|
||||
v1, v2 and v3.
|
||||
<p>
|
||||
Once you know the indices of a triangle's vertices, you can ask for
|
||||
more information about that vertex using
|
||||
<code>ssgLeaf::getVertex(i)</code>,
|
||||
<code>ssgLeaf::getNormal(i)</code>,
|
||||
<code>ssgLeaf::getColour(i)</code>, and
|
||||
<code>ssgLeaf::getTexCoord(i)</code>. These calls allow you to
|
||||
retrieve the i'th vertex, normal, colour or texture coordinate as
|
||||
a short floating point array. (3 elements for Vertex and Normal,
|
||||
4 elements for Colour (RGBA) and two elements for a texture coordinate.
|
||||
<p>
|
||||
Analogous to getting the triangles,
|
||||
you may use <code>ssgLeaf::getNumLines ()</code>
|
||||
and <code>ssgLeaf::getLine ( int n, short *v1, short *v2 ) ;</code>
|
||||
to get the number of lines and to get the n. line.
|
||||
|
||||
<p>
|
||||
You can transform all the vertices of a leaf each frame by placing
|
||||
an ssgTransform node above the leaf in the scene graph - but for
|
||||
transformations that never change, it's more efficient to pre-transform
|
||||
the vertices in the leaf node.
|
||||
<code>ssgLeaf::transform(matrix)</code> permenantly transforms all
|
||||
the vertices and normals of this leaf by multiplying them by the
|
||||
matrix. (In the case of the normals, the translation part of the
|
||||
matrix is ignored).
|
||||
<p>
|
||||
It's inadvisable to repeatedly transform a leaf using <code>transform</code>
|
||||
since roundoff error will be accumulated with bad consequences (eventually).
|
||||
In those cases, use an ssgTransform node.
|
||||
|
||||
<H2><code>class ssgVtxTable</code> - A Vertex-table leaf node.</H2>
|
||||
This class allows one to represent leaf geometry as arrays of vertex,
|
||||
normal, texture coordinate and colour data. As a derived class of
|
||||
ssgLeaf, Vertex Tables add a constructor function to take the
|
||||
pre-computed vertex data:
|
||||
<pre>
|
||||
|
||||
ssgVtxTable ( GLenum ty, ssgVertexArray *vl,
|
||||
ssgNormalArray *nl,
|
||||
ssgTexCoordArray *tl,
|
||||
ssgColourArray *cl ) ;
|
||||
|
||||
</pre>
|
||||
'ty' is an OpenGL primitive type (such as one might pass to glBegin):
|
||||
<pre>
|
||||
|
||||
GL_POLYGON
|
||||
GL_TRIANGLE_FAN
|
||||
GL_TRIANGLES
|
||||
GL_TRIANGLE_STRIP
|
||||
GL_QUAD_STRIP
|
||||
GL_QUADS
|
||||
|
||||
</pre>
|
||||
the remaining arguments are lists of (x,y,z) vertices, (nx,ny,nz)
|
||||
normals, (s,t) texture coordinates and (r,g,b,a) colours.
|
||||
<H2><code>class ssgVertexArray/ssgNormalArray/ssgTexCoordArray/ssgColourArray</code> - Vertex data storage classes.</H2>
|
||||
These four classes are used for storing vertex data for ssgVtxTable nodes.
|
||||
Each class implements an extensible array that grows as you add data to
|
||||
it.
|
||||
<pre>
|
||||
|
||||
ssg*Array::ssg*Array ( int init = 3 ) ;
|
||||
|
||||
</pre>
|
||||
When you construct the array, you may specify an initial size for it,
|
||||
the default is three elements. If you don't know how big the array
|
||||
is, don't worry about it - but if you do know, there are time and
|
||||
storage space advantages to telling the class the exact number.
|
||||
<pre>
|
||||
|
||||
void ssgVertexArray ::add ( sgVec3 data ) ;
|
||||
void ssgNormalArray ::add ( sgVec3 data ) ;
|
||||
void ssgTexCoordArray::add ( sgVec2 data ) ;
|
||||
void ssgColourArray ::add ( sgVec4 data ) ;
|
||||
|
||||
</pre>
|
||||
These functions tack another data element onto the end of the array.
|
||||
<pre>
|
||||
|
||||
float *ssg*Array::get ( int i ) ;
|
||||
|
||||
</pre>
|
||||
Returns the address of the i'th element of the array.
|
||||
<pre>
|
||||
|
||||
int ssg*Array::getNum () ;
|
||||
|
||||
</pre>
|
||||
Returns the number of data elements currently stored in the array.
|
||||
<pre>
|
||||
|
||||
void ssg*Array::removeAll () ;
|
||||
|
||||
</pre>
|
||||
Empties the array.
|
||||
<H2><code>class ssgTween</code> - A Vertex-table morphing node.</H2>
|
||||
This node is derived from ssgVtxTable. Where VtxTable can retain
|
||||
a set of arrays, one each for Vertex coordinates, Normals, Texture
|
||||
Coordinates and Colours, the ssgTween node can store an unlimited
|
||||
number of 'banks' of these arrays.
|
||||
<p>
|
||||
Hence, one constructs an ssgTween by specifying it's OpenGL primitive
|
||||
type:
|
||||
<pre>
|
||||
|
||||
ssgTween::ssgTween ( GLenum ty ) ;
|
||||
|
||||
</pre>
|
||||
And then create some number of 'banks' of data arrays by calling:
|
||||
<pre>
|
||||
|
||||
int ssgTween::newBank ( ssgVertexArray *vl,
|
||||
ssgNormalArray *nl,
|
||||
ssgTexCoordArray *tl,
|
||||
ssgColourArray *cl ) ;
|
||||
|
||||
</pre>
|
||||
...once for each bank. All other ssgVtxTable calls operate ONLY
|
||||
on the 'current bank' - which is either the most recent one you
|
||||
created with newBank - or you can go back to an older bank by
|
||||
calling:
|
||||
<pre>
|
||||
|
||||
void ssgTween::setBank ( int bankID ) ;
|
||||
int ssgTween::getBank () ;
|
||||
|
||||
</pre>
|
||||
(newBank returns the number of the bank it created in case you
|
||||
lose count!).
|
||||
<p>
|
||||
ssgTween's idea of the 'current bank' is reset to zero after
|
||||
rendering it...so be sure to always call setBank immediately
|
||||
before working on it's component arrays.
|
||||
<p>
|
||||
When the ssgTween node is rendered, it works cooperatively
|
||||
with whichever ssgTweenController node is above it in the
|
||||
scene graph. See the section on ssgTweenController for more
|
||||
details.
|
||||
<p>
|
||||
IMPORTANT NOTE: There must be an identical number of vertices,
|
||||
normals, etc in each bank. If you get that wrong, SSG will
|
||||
exit with an 'abort'. Note that there is a specific optimisation
|
||||
in ssgTween that avoids the computational cost of interpolating
|
||||
between two sets of vertex data if EITHER:
|
||||
<ul>
|
||||
<li>The ssgTweenController's selected bank number happens to
|
||||
be an integer.
|
||||
<li>The previous and next banks have the same ssg*Array pointer.
|
||||
Since one generally doesn't wish to interpolate normals, colours
|
||||
or texture coordinates, it's important to pay attention to this.
|
||||
</ul>
|
||||
<hr>
|
||||
<table width="100%">
|
||||
<tr>
|
||||
<td width="33%" align="left"><a href="ssgEntity.html"><= 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="branches.html">= next =></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>
|
||||
<<A HREF="mailto:sjbaker1@airmail.net">sjbaker1@airmail.net</A>>
|
||||
</ADDRESS>
|
||||
</table>
|
||||
</BODY>
|
||||
</HTML>
|
||||
|
||||
255
doc/ssg/state.html
Normal file
255
doc/ssg/state.html
Normal file
@@ -0,0 +1,255 @@
|
||||
<!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 ssgState</code> - OpenGL state representation.</H2>
|
||||
Each leaf node will have some kind of ssgState node associated
|
||||
with it that contains all relevent OpenGL state information.
|
||||
<p>
|
||||
There can (in principal) be a number of different ways to represent
|
||||
OpenGL state - but all must be derived from an ssgState:
|
||||
<pre>
|
||||
|
||||
class ssgState : public ssgBase
|
||||
{
|
||||
int getExternalPropertyIndex () ;
|
||||
void setExternalPropertyIndex ( int i ) ;
|
||||
|
||||
ssgStateCallback getStateCallback ( int cb_type ) ;
|
||||
void setStateCallback ( int cb_type, ssgStateCallback cb ) ;
|
||||
|
||||
virtual void force () ;
|
||||
virtual void apply () ;
|
||||
} ;
|
||||
|
||||
</pre>
|
||||
<H3>Callbacks.</H3>
|
||||
States are 'applied' immediately before the geometry they are attached
|
||||
to is rendered. Applying the state causes all of it's properties to
|
||||
be set up in OpenGL.
|
||||
<p>
|
||||
Each state has three optional callback function hooks. The application
|
||||
program can have a function called before the state is applied, after
|
||||
it is applied (but before the geometry is drawn) and another after the
|
||||
geometry is rendered - immediately before the next state is applied.
|
||||
<p>
|
||||
You can set those three callbacks with setStateCallback - passing
|
||||
either SSG_CALLBACK_PREAPPLY, SSG_CALLBACK_PREDRAW or SSG_CALLBACK_POSTDRAW
|
||||
as the first parameter and the address of your function as the second.
|
||||
<H3>External Properties.</H3>
|
||||
Each state entity can have an external property - which is a simple
|
||||
integer that can be set using <code>ssgState::setExternalPropertyIndex(i)</code>
|
||||
or queried using <code>ssgState::getExternalPropertyIndex()</code>.
|
||||
External properties are of use to certain sorts of applications programs,
|
||||
for example, a game might want to encode the set of OpenGL state information
|
||||
that represents Lava as something that is hot and Ice as something that
|
||||
is cold by encoding the temperature of the material in the External
|
||||
property field. Most applications will probably use this field as an
|
||||
index into a table of material properties inside the application itself.
|
||||
<H3>Applying a State.</H3>
|
||||
Whilst it's rare for an application to need to deal with an ssgState
|
||||
once it has been defined, there may be occasions when the application
|
||||
wishes to draw objects of it's own without using SSG's scene graph.
|
||||
This often is the case with on-screeen symbology.
|
||||
<p>
|
||||
In such cases, it is important to bear in mind that SSG changes the
|
||||
OpenGL state as little as possible - in order to save time. Hence,
|
||||
when a leaf node has just been drawn with one set of state information,
|
||||
and another leaf node is about to be drawn using another, SSG carefully
|
||||
compares the two states to see how they differ and arranges to make
|
||||
only the fewest possible OpenGL state change calls. If the application
|
||||
goes in "behind SSG's back" and changes state then SSG will be confused.
|
||||
<p>
|
||||
There are two ways to achive this. One is to use SSG state classes to
|
||||
change the state by calling <code>ssgState::apply()</code>. That call
|
||||
will ensure that OpenGL's state matches the desired state using the
|
||||
minimum of calls. However, if your application absolutely MUST make
|
||||
it's own state calls then you should call <code>ssgState::force()</code>
|
||||
to force all aspects of a specified state to be set in OpenGL so that
|
||||
SSG can be certain about how things are set up.
|
||||
<H2><code>class ssgSimpleState</code> - Simple State class.</H2>
|
||||
ssgSimpleState is currently the only concrete class derived from
|
||||
ssgState. It has so far proved adequate for all state management.
|
||||
<pre>
|
||||
class ssgSimpleState : ssgState
|
||||
{
|
||||
void disable ( GLenum mode ) ;
|
||||
void enable ( GLenum mode ) ;
|
||||
void set ( GLenum mode, int val ) { val ? enable(mode) : disable(mode) ; }
|
||||
|
||||
void setTexture ( char *fname, int wrapu = TRUE, int wrapv = TRUE )
|
||||
void setTexture ( ssgTexture *tex )
|
||||
void setTexture ( GLuint tex )
|
||||
void setColourMaterial ( GLenum which )
|
||||
void setMaterial ( GLenum which, float r, float g, float b, float a = 1.0f )
|
||||
void setMaterial ( GLenum which, sgVec4 rgba )
|
||||
void setShininess ( float sh )
|
||||
void setShadeModel ( GLenum model )
|
||||
void setAlphaClamp ( float clamp )
|
||||
} ;
|
||||
</pre>
|
||||
These calls mostly correspond to similarly named OpenGL functions.
|
||||
<H3>Enable and Disable calls:</H3>
|
||||
<code>ssgSimpleState:: disable ( mode )</code>,
|
||||
<code>ssgSimpleState:: enable ( mode )</code> and
|
||||
<code>ssgSimpleState:: set ( mode, val )</code> provide
|
||||
the same services as glEnable and glDisable ('set' is a convenience function
|
||||
that is a 'disable' if 'val' is FALSE, 'enable' otherwise). The 'mode'
|
||||
parameter uses tokens that are similarly named to those in OpenGL:
|
||||
<pre>
|
||||
|
||||
SSG_GL_TEXTURE_EN
|
||||
SSG_GL_CULL_FACE_EN
|
||||
SSG_GL_COLOR_MATERIAL_EN
|
||||
SSG_GL_BLEND_EN
|
||||
SSG_GL_ALPHA_TEST_EN
|
||||
SSG_GL_LIGHTING_EN
|
||||
|
||||
</pre>
|
||||
<H3>Texture states.</H3>
|
||||
There are three ways to attach a texture to an ssgSimpleState:
|
||||
<code>ssgSimpleState::setTexture ( fname, wrapu, wrapv )</code>,
|
||||
<code>ssgSimpleState::setTexture ( ssgtexture )</code>, and
|
||||
<code>ssgSimpleState::setTexture ( texture_handle )</code>.
|
||||
In the form that takes a filename, U-axis wrap and V-axis wrap flags, the
|
||||
texture is loaded from a texture file on disk (see ssgTexture
|
||||
below for details on how this is done). The map will be MIPmapped and set with
|
||||
a texture environment that is GL_LINEAR_MIPMAP_LINEAR and GL_MODULATE.
|
||||
<p>
|
||||
If you need something fancier, then declare an 'ssgTexture' class and
|
||||
pass that to the setTexture function. You can also load your own
|
||||
texture and pass the OpenGL glBindTexture handle to setTexture.
|
||||
<p> If you need the texture file name, first check that
|
||||
isEnabled ( GL_TEXTURE_2D ) returns true, then you may call
|
||||
getTextureFilename(). But you should still check the return value for NULL and for "".
|
||||
|
||||
<H3>Materials.</H3>
|
||||
These calls are all very similar to OpenGL calls - and take the same
|
||||
parameters:
|
||||
<code>ssgSimpleState::setColourMaterial(which)</code>
|
||||
<code>ssgSimpleState::setMaterial(which,r,g,b,a)</code>
|
||||
<code>ssgSimpleState::setMaterial(which,rgba)</code>
|
||||
<code>ssgSimpleState::setShininess(sh)</code>
|
||||
<code>ssgSimpleState::setShadeModel(model)</code>
|
||||
<code>ssgSimpleState::setAlphaClamp(clamp)</code>
|
||||
<H2><code>class ssgTexture</code> - Storing texture maps.</H2>
|
||||
An ssgTexture loads a texture map for you with the minimum possible
|
||||
fuss - but offers less flexibility than if you did so yourself.
|
||||
<p>
|
||||
The ssgTexture constructor function
|
||||
<code>ssgTexture::ssgTexture( char *fname,
|
||||
int wrapu = TRUE, int wrapv = TRUE )</code> does all the work,
|
||||
presuming that you require GL_LINEAR_MIPMAP_LINEAR filtering and a
|
||||
GL_MODULATE texture environment.
|
||||
<p>
|
||||
You can obtain the OpenGL glBindTexture handle for the texture
|
||||
using <code>ssgTexture::getHandle()</code>.
|
||||
<p>
|
||||
When ssgTexture loads a map from disk, it uses the filename
|
||||
extension to determine which image format the file is in.
|
||||
<p>
|
||||
Currently, only SGI format and <strong>uncompressed</strong>
|
||||
8 or 24 bit BMP images are supported - but more
|
||||
formats are planned for the future. Filenames ending with
|
||||
'.rgb', '.rgba', '.int', '.inta', '.bw' are assumed to be
|
||||
SGI formatted files, '.bmp' are in Microsoft's BMP format
|
||||
and '.png' are in Portable Network Graphics format.
|
||||
<p>
|
||||
If for any reason ssgTexture cannot load the requested file,
|
||||
it creates a 2x2 texel red and white chequerboard map to
|
||||
enable the program to continue running. This is often very
|
||||
useful for debugging and to enable program development to
|
||||
continue when texture maps are not yet painted.
|
||||
<H2><code>class ssgStateSelector</code> - Switchable State class.</H2>
|
||||
There are cases where you would like to be able to switch between a
|
||||
number of different states for a given leaf node.
|
||||
<pre>
|
||||
class ssgStateSelector : ssgSimpleState
|
||||
{
|
||||
ssgStateSelector ( int nstates ) ;
|
||||
|
||||
void selectStep ( unsigned int s ) ;
|
||||
int getSelectStep (void) ;
|
||||
ssgSimpleState *getCurrentStep (void) ;
|
||||
void setStep ( int i, ssgSimpleState *step ) ;
|
||||
ssgSimpleState *getStep ( int i ) ;
|
||||
} ;
|
||||
</pre>
|
||||
This class is used to switch between some number of <code>ssgSimpleStates</code>.
|
||||
You could (for example) draw the ground for your game as either
|
||||
grass or snow - depending on the season. Construct objects of this
|
||||
class with the number of alternative representations you will require
|
||||
as it's parameter, then create a number of <code>ssgSimpleState</code>s - passing
|
||||
them to <code>ssgStateSelector::setStep()</code>. You can then select which
|
||||
step you wish to render using <code>ssgStateSelector::selectStep()</code>.
|
||||
<p>
|
||||
<code>ssgStateSelector::getSelectStep()</code> returns the number of the currently
|
||||
selected step. <code>ssgStateSelector::getCurrentStep()</code> returns a pointer to
|
||||
the currently selected <code>ssgSimpleState</code>. <code>ssgStateSelector::getStep()</code>
|
||||
returns a pointer to the i'th <code>ssgSimpleState</code>.
|
||||
<p>
|
||||
Since <code>ssgStateSelector</code> is derived from <code>ssgSimpleState</code>,
|
||||
all the other <code>ssgSimpleState</code> calls work - and the effect is to
|
||||
operate on the currently selected <code>ssgSimpleState</code>.
|
||||
<p>
|
||||
Example:
|
||||
<pre>
|
||||
|
||||
ssgStateSelector *s = new ssgStateSelector ( 2 ) ;
|
||||
ssgSimpleState *grass = new ssgSimpleState () ;
|
||||
ssgSimpleState *snow = new ssgSimpleState () ;
|
||||
|
||||
...set up grass and snow states appropriately...
|
||||
|
||||
s -> setStep ( 0, grass ) ;
|
||||
s -> setStep ( 1, snow ) ;
|
||||
|
||||
leafnode1 -> setState ( s ) ;
|
||||
leafnode2 -> setState ( s ) ;
|
||||
leafnode3 -> setState ( s ) ;
|
||||
|
||||
...choose grass or snow...
|
||||
|
||||
if ( ! winter )
|
||||
s -> selectStep ( 0 ) ;
|
||||
else
|
||||
s -> selectStep ( 1 ) ;
|
||||
|
||||
...render the scene...
|
||||
|
||||
</pre>
|
||||
Notice that one selectStep call changes the material on all
|
||||
leaf nodes that use that ssgStateSelector.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<hr>
|
||||
<table width="100%">
|
||||
<tr>
|
||||
<td width="33%" align="left"><a href="branches.html"><= 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="ssgContext.html">= next =></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>
|
||||
<<A HREF="mailto:sjbaker1@airmail.net">sjbaker1@airmail.net</A>>
|
||||
</ADDRESS>
|
||||
</table>
|
||||
</BODY>
|
||||
</HTML>
|
||||
|
||||
Reference in New Issue
Block a user