This commit is contained in:
Alexander Deynichenko
2013-02-25 07:23:44 +04:00
parent 35ff18a6a1
commit 03b62f3315
809 changed files with 211135 additions and 0 deletions

BIN
doc/FDS_logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

BIN
doc/FNT.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
doc/JS.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
doc/MinigolfManiacs.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

BIN
doc/NET.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
doc/PSL.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
doc/PUI.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
doc/PW.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
doc/SG.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
doc/SL.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
doc/SSG.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
doc/UL.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

55
doc/auxlibs/index.html Normal file
View File

@@ -0,0 +1,55 @@
<!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>Auxiliary Libraries for PLIB.</TITLE>
</HEAD>
<BODY text="#B5A642" link="#8FFF8F" vlink="#18A515" alink="#20336B"
bgcolor="#005000" background="../marble.png">
<TABLE>
<TR>
<TD>
<H1>Auxiliary Libraries for PLIB.</H1>
</TD>
</TR>
<TR>
<TD>
by Steve Baker
</TD>
</TR>
</TABLE>
<H2>Introduction</H2>
PLIB/AUX is a suite of auxiliary libraries that build
higher level classes on top of the basic PLIB libraries.
<p>
These will be installed and named with the same
conventions as the base PLIB libraries, eg:
<pre>
/usr/include/plib/auxXXX.h
/usr/lib/libplibauxXXX.a
</pre>
...where 'XXX' is the name of the aux library.
<p>
PLIB/AUX functions, classes and constants are all
named after the base PLIB library that they logically
belong with, hence enhancements to SSG will share the
'ssg' prefix but add a 'u':
<pre>
eg
class ssguParticleSystem ;
class puuFileBrowser ;
</pre>
<hr>
<ADDRESS>
<A HREF="http://www.sjbaker.org">
Steve J. Baker.</A>
&lt;<A HREF="mailto:sjbaker1@airmail.net">sjbaker1@airmail.net</A>&gt;
</ADDRESS>
</BODY>
</HTML>

114
doc/contacts.html Normal file
View File

@@ -0,0 +1,114 @@
<!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>PLIB: Contacting Us.</TITLE>
</HEAD>
<BODY text="#B5A642" link="#8FFF8F" vlink="#18A515" alink="#20336B"
bgcolor="#005000" background="marble.png">
<TABLE>
<TR>
<TD>
<IMG SRC="plib_logo.png" ALT="PLIB Logo" width=256 height=245>
<br>
</TD>
<TD>
<center>
<H1>
<FONT SIZE=9>S</FONT><FONT SIZE=5>TEVE'S</FONT>
<FONT SIZE=9>P</FONT><FONT SIZE=5>ORTABLE</FONT>
<FONT SIZE=9>G</FONT><FONT SIZE=5>AME</FONT>
<FONT SIZE=9>L</FONT><FONT SIZE=5>IBRARY.</FONT>
</H1>
</center>
</TD>
<TD>
<ul>
And Lo, the Lion and the Sheep shall lie down together - but the Sheep won't
get much Sleep.
<br>
-- Woody Allen
</ul>
<center>
<A href="http://sf.net">
<IMG src="http://sf.net/sflogo.php?group_id=382&type=1" width="88" height="31" border="0" ALT="Sourceforge Logo"></A>
</center>
</TD>
</TR>
</TABLE>
<TABLE>
<TR>
<TD valign=top align=left>
<A HREF="index.html"><IMG SRC="home.png" ALT="HOME" BORDER="0" width=150 height=50></A><br>
<A HREF="whats_inside.html"><IMG SRC="whats_inside.png" ALT="WHAT'S INSIDE" BORDER="0" width=150 height=50></A><br>
<A HREF="license.html"><IMG SRC="license.png" ALT="LICENSE" BORDER="0" width=150 height=50></A><br>
<A HREF="contacts.html"><IMG SRC="contacts.png" ALT="CONTACTS" BORDER="0" width=150 height=50></A><br>
<A HREF="requirements.html"><IMG SRC="requirements.png" ALT="REQUIREMENTS" BORDER="0" width=150 height=50></A><br>
<A HREF="gallery.html"><IMG SRC="gallery.png" ALT="GALLERY" BORDER="0" width=150 height=50></A><br>
<A HREF="download.html"><IMG SRC="download.png" ALT="DOWNLOAD & INSTALL" BORDER="0" width=150 height=50></A><br>
<A HREF="examples.html"><IMG SRC="examples.png" ALT="EXAMPLES" BORDER="0" width=150 height=50></A><br>
<A HREF="sg/index.html"><IMG SRC="SG.png" ALT="SG" BORDER="0" width=75 height=25></A>
<A HREF="ssg/index.html"><IMG SRC="SSG.png" ALT="SSG" BORDER="0" width=75 height=25></A><br>
<A HREF="ssgAux/index.html"><IMG SRC="ssgAux.png" ALT="SSGAUX" BORDER="0" width=75 height=25></A>
<A HREF="fnt/index.html"><IMG SRC="FNT.png" ALT="FNT" BORDER="0" width=75 height=25></A><br>
<A HREF="pui/index.html"><IMG SRC="PUI.png" ALT="PUI" BORDER="0" width=75 height=25></A>
<A HREF="psl/index.html"><IMG SRC="PSL.png" ALT="PSL" BORDER="0" width=75 height=25></A>
<A HREF="util/index.html"><IMG SRC="UL.png" ALT="UL" BORDER="0" width=75 height=25></A>
<A HREF="js/index.html"><IMG SRC="JS.png" ALT="JS" BORDER="0" width=75 height=25></A><br>
<A HREF="net/index.html"><IMG SRC="NET.png" ALT="NET" BORDER="0" width=75 height=25></A>
<A HREF="sl/index.html"><IMG SRC="SL.png" ALT="SL" BORDER="0" width=75 height=25></A><br>
<A HREF="pw/index.html"><IMG SRC="PW.png" ALT="PW" BORDER="0" width=75 height=25></A>
<A HREF="puAux/index.html"><IMG SRC="puAux.png" ALT="PUAUX" BORDER="0" width=75 height=25></A><br>
</TD>
<TD>
<H2>Contacting Us - and Contributing to PLIB.</H2>
There are three PLIB mailing lists:
In order to keep the spam off the lists, it's set up so you have
to subscribe in order to send mail. To do that, visit:
<ul>
<li>
<A HREF="http://lists.sf.net/mailman/listinfo/plib-announce">
http://lists.sf.net/mailman/listinfo/plib-announce</A><br>
A very low traffic, heavily moderated list where I'll announce new versions
of PLIB - you may not post to 'plib-announce'.<p>
<li>
<A HREF="http://lists.sf.net/mailman/listinfo/plib-users">
http://lists.sf.net/mailman/listinfo/plib-users</A><br>
A list for PLIB users - this would be the correct place
to ask questions, report bugs and generally hang out with
fellow sufferers.<p>
<li>
<A HREF="http://lists.sf.net/mailman/listinfo/plib-devel">
http://lists.sf.net/mailman/listinfo/plib-devel</A><br>
A list for people who wish to contribute to the development
of PLIB - this list will have a high technical content and we'll
try to keep discussions there focussed and on-topic.<p>
</ul>
<p>
Please do not send me personal mail in situations when one of
the public mailing lists would be an appropriate forum - I hate
it when people do that and I'll usually ignore you.
<p>
The mailing list is set up to prohibit large attachments. HTML mail
and other non-ASCII forms of posting are NOT welcome.
</TD>
</TR>
</TABLE>
<hr>
<ADDRESS>
<A HREF="http://www.sjbaker.org">
Steve J. Baker.</A>
&lt;<A HREF="mailto:sjbaker1@airmail.net">sjbaker1@airmail.net</A>&gt;
</ADDRESS>
</BODY>
</HTML>

BIN
doc/contacts.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

225
doc/download.html Normal file
View File

@@ -0,0 +1,225 @@
<!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>PLIB: Downloading and Installing PLIB.</TITLE>
</HEAD>
<BODY text="#B5A642" link="#8FFF8F" vlink="#18A515" alink="#20336B"
bgcolor="#005000" background="marble.png">
<TABLE>
<TR>
<TD>
<IMG SRC="plib_logo.png" ALT="PLIB Logo" width=256 height=245>
<br>
</TD>
<TD>
<center>
<H1>
<FONT SIZE=9>S</FONT><FONT SIZE=5>TEVE'S</FONT>
<FONT SIZE=9>P</FONT><FONT SIZE=5>ORTABLE</FONT>
<FONT SIZE=9>G</FONT><FONT SIZE=5>AME</FONT>
<FONT SIZE=9>L</FONT><FONT SIZE=5>IBRARY.</FONT>
</H1>
</center>
</TD>
<TD>
<ul>
And Lo, the Lion and the Sheep shall lie down together - but the Sheep won't
get much Sleep.
<br>
-- Woody Allen
</ul>
<center>
<A href="http://sf.net">
<IMG src="http://sf.net/sflogo.php?group_id=382&type=1" width="88" height="31" border="0" ALT="Sourceforge Logo"></A>
</center>
</TD>
</TR>
</TABLE>
<TABLE>
<TR>
<TD valign=top align=left>
<A HREF="index.html"><IMG SRC="home.png" ALT="HOME" BORDER="0" width=150 height=50></A><br>
<A HREF="whats_inside.html"><IMG SRC="whats_inside.png" ALT="WHAT'S INSIDE" BORDER="0" width=150 height=50></A><br>
<A HREF="license.html"><IMG SRC="license.png" ALT="LICENSE" BORDER="0" width=150 height=50></A><br>
<A HREF="contacts.html"><IMG SRC="contacts.png" ALT="CONTACTS" BORDER="0" width=150 height=50></A><br>
<A HREF="requirements.html"><IMG SRC="requirements.png" ALT="REQUIREMENTS" BORDER="0" width=150 height=50></A><br>
<A HREF="gallery.html"><IMG SRC="gallery.png" ALT="GALLERY" BORDER="0" width=150 height=50></A><br>
<A HREF="download.html"><IMG SRC="download.png" ALT="DOWNLOAD & INSTALL" BORDER="0" width=150 height=50></A><br>
<A HREF="examples.html"><IMG SRC="examples.png" ALT="EXAMPLES" BORDER="0" width=150 height=50></A><br>
<A HREF="sg/index.html"><IMG SRC="SG.png" ALT="SG" BORDER="0" width=75 height=25></A>
<A HREF="ssg/index.html"><IMG SRC="SSG.png" ALT="SSG" BORDER="0" width=75 height=25></A><br>
<A HREF="ssgAux/index.html"><IMG SRC="ssgAux.png" ALT="SSGAUX" BORDER="0" width=75 height=25></A>
<A HREF="fnt/index.html"><IMG SRC="FNT.png" ALT="FNT" BORDER="0" width=75 height=25></A><br>
<A HREF="pui/index.html"><IMG SRC="PUI.png" ALT="PUI" BORDER="0" width=75 height=25></A>
<A HREF="psl/index.html"><IMG SRC="PSL.png" ALT="PSL" BORDER="0" width=75 height=25></A>
<A HREF="util/index.html"><IMG SRC="UL.png" ALT="UL" BORDER="0" width=75 height=25></A>
<A HREF="js/index.html"><IMG SRC="JS.png" ALT="JS" BORDER="0" width=75 height=25></A><br>
<A HREF="net/index.html"><IMG SRC="NET.png" ALT="NET" BORDER="0" width=75 height=25></A>
<A HREF="sl/index.html"><IMG SRC="SL.png" ALT="SL" BORDER="0" width=75 height=25></A><br>
<A HREF="pw/index.html"><IMG SRC="PW.png" ALT="PW" BORDER="0" width=75 height=25></A>
<A HREF="puAux/index.html"><IMG SRC="puAux.png" ALT="PUAUX" BORDER="0" width=75 height=25></A><br>
</TD>
<TD>
<H1>Downloading and Installing PLIB.</H1>
<H2>The Short Answer (for Linux and CygWin users):</H2>
Make sure you have OpenGL installed.<br>
Download this: <A HREF="dist/plib-1.8.4.tar.gz"> PLIB - Version 1.8.4</A>
<br>
Run this (as 'root'):
<pre>
tar xzf plib-1.8.4.tar.gz
cd plib-1.8.4
./configure ; make install
</pre>
Tadaaaa!
<p>
<H2>The Long Answer: Downloading PLIB.</H2>
You can get PLIB in various versions here. We follow the common Linux
convention where the second digit in the version number is EVEN for
stable versions and ODD for unstable and/or experimental versions.
<p>
End users should generally download the latest stable version but
application developers may wish to periodically compile their code
against the odd-numbered version so as to keep abreast of developments
in PLIB.
<p>
<ul>
<li><A HREF="dist/plib-1.8.4.tar.gz"> PLIB - Version 1.8.4 -- Current Stable</A>
<li><A HREF="dist/"> PLIB - Other versions</A>
<li><A HREF="http://sf.net/project/?group_id=382"> PLIB - Latest development version (from SVN)</A>
<li><A HREF="dist/current.tgz"> PLIB - Latest development version (tarball)</A>
</ul>
Download this using your browser by right-clicking on the name. If you
have InternetExplorer, you'll probably fall victim to it's stupid bug
where it unzips the file automatically - but forgets to
rename it to lose the '.gz' off the end. Just rename it yourself
before you try to un-tar it and all will be well.
<p>
PLIB documentation, example programs, fonts, etc are separated from
PLIB itself to minimise your download time.
<p>
The <b>online</b> documentation attempts to always track the latest stable
version of PLIB. If you are using some other version, you may want to
download the documentation appropriate to that release which comes with
the plib_examples tarball.
<A NAME="EXAMPLES"></A>
<ul>
<li><A HREF="dist/plib_examples-1.8.4.tar.gz">
Example programs and Documentation for PLIB-1.8.4 or later.</A>
<li><A HREF="dist/">PLIB_examples - Older versions</A>
</ul>
Un-tar this into a separate directory from PLIB itself - or else
all the configuration and makefiles will clash. Many of the example programs
require the GLUT library (or 'freeglut') - some other use SDL and FLTK.
<p>
<A NAME="DEMOS"></A>
More extensive PLIB demonstration programs are also separated from
PLIB itself and are individually tarballed with their own version
numbers. Generally, they'll run with the most recent stable version
of PLIB - but occasionally they'll rely on something in the latest
PLIB beta.
<p>
<ul>
<li><A HREF="dist/exposer-0.2.0.tar.gz">
A character animation tool.</A>
<li><A HREF="dist/p-guide-0.0.1.tar.gz">
A tool for designing PUI interface panels.</A>
<li><A HREF="dist/ttt3d-0.2.0.tar.gz">
A complete TicTacToe game - played in 3 dimensions!</A>
<li><A HREF="dist/">PLIB Demos - Older versions</A>
</ul>
Un-tar these into a separate directory from PLIB itself - or else
all the configuration and makefiles will clash.
<H2>The Long Answer: Installing PLIB.</H2>
On most Linux and other UNIX-like OS's, it's simply a matter of
unpacking the tar-ball, changing directory into the plib_x.y.z
directory that this creates and typing:
<pre>
./configure
make install
</pre>
You'll need to
be 'root' to perform the last step. At the end of that process,
you should have a set of header files in /usr/include/plib
and a set of corresponding libraries in /usr/lib. There
are some example programs in the 'plib-x.y.z/examples' subdirectory.
<p>
WARNING: If you are using 'Mesa' instead of an 'Official' OpenGL,
please make sure you followed the instructions in the Mesa installation
notes that tell you to symbolically link /usr/lib/libGL.so
and /usr/lib/libGLU.so to their Mesa equivelents. More modern
versions of Mesa may install directly into that location - but
make sure that one way or another, /usr/lib/libGL.so points to your
current OpenGL/Mesa library.
<p>
Some Linux distro's install OpenGL/Mesa in /usr/X11R6/lib - that
is now officially deprecated - if your OpenGL/Mesa is installed
there then I suggest you add symbolic links to make the
files appear to be in /usr/lib.
<p>
If you are running some non-UNIX OS, (eg MS-Windows) there may be
instructions on how to build PLIB in README.{OS name}. If you
have problems - or can offer to streamline the
process, then please pass on your knowledge via the mailing list.
In general, it isn't complicated to install - you usually just have
to compile all of the source files in each directory and link
each subdirectory into a separate library. Don't try to make
PLIB into a M$ '.DLL' - it's not worth the effort!
<p>
If you have the Microsoft Visual C++ suite, you'll find a set
of project files - one in each source directory - plus a master
workspace at the top of the tree.
<p>
If you have all the Cygnus (CygWin) compiler/tools, then use
the UNIX build instructions.
<p>
There is now a README.mac for Macintosh users.
<H2> Where Does PLIB Install Itself? </H2>
This is always a controversial topic. In order to maintain
our own sanity, we expect PLIB to be installed in one place
and in one place only.
<pre>
Libraries are in: /usr/lib/libplibXXX.a
Headers are in: /usr/include/plib/XXX.h
</pre>
(Where 'XXX' is the short acronym for the PLIB library in question -
in lowercase).
<p>
The now *VERY* obsolete PLIB 1.0.* used to install itself
into /usr/local/plib, but from version 1.1.0 onwards, the
modern location was adopted following discussions with
several Linux distributors.
<p>
Please don't even <b>think</b> about arguing about this decision,
it has been the topic of long and arduous discussion and it's
NEVER going to change!
</TD>
</TR>
</TABLE>
<hr>
<ADDRESS>
<A HREF="http://www.sjbaker.org">
Steve J. Baker.</A>
&lt;<A HREF="mailto:sjbaker1@airmail.net">sjbaker1@airmail.net</A>&gt;
</ADDRESS>
</BODY>
</HTML>

BIN
doc/download.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

191
doc/examples.html Normal file
View File

@@ -0,0 +1,191 @@
<!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>PLIB: A Portable Games Library.</TITLE>
</HEAD>
<BODY text="#B5A642" link="#8FFF8F" vlink="#18A515" alink="#20336B"
bgcolor="#005000" background="marble.png">
<TABLE>
<TR>
<TD>
<IMG SRC="plib_logo.png" ALT="PLIB Logo" width=256 height=245>
<br>
</TD>
<TD>
<center>
<H1>
<FONT SIZE=9>S</FONT><FONT SIZE=5>TEVE'S</FONT>
<FONT SIZE=9>P</FONT><FONT SIZE=5>ORTABLE</FONT>
<FONT SIZE=9>G</FONT><FONT SIZE=5>AME</FONT>
<FONT SIZE=9>L</FONT><FONT SIZE=5>IBRARY.</FONT>
</H1>
</center>
</TD>
<TD>
<ul>
And Lo, the Lion and the Sheep shall lie down together - but the Sheep won't
get much Sleep.
<br>
-- Woody Allen
</ul>
<center>
<A href="http://sf.net">
<IMG src="http://sf.net/sflogo.php?group_id=382&type=1" width="88" height="31" border="0" ALT="Sourceforge Logo"></A>
</center>
</TD>
</TR>
</TABLE>
<TABLE>
<TR>
<TD valign=top align=left>
<A HREF="index.html"><IMG SRC="home.png" ALT="HOME" BORDER="0" width=150 height=50></A><br>
<A HREF="whats_inside.html"><IMG SRC="whats_inside.png" ALT="WHAT'S INSIDE" BORDER="0" width=150 height=50></A><br>
<A HREF="license.html"><IMG SRC="license.png" ALT="LICENSE" BORDER="0" width=150 height=50></A><br>
<A HREF="contacts.html"><IMG SRC="contacts.png" ALT="CONTACTS" BORDER="0" width=150 height=50></A><br>
<A HREF="requirements.html"><IMG SRC="requirements.png" ALT="REQUIREMENTS" BORDER="0" width=150 height=50></A><br>
<A HREF="gallery.html"><IMG SRC="gallery.png" ALT="GALLERY" BORDER="0" width=150 height=50></A><br>
<A HREF="download.html"><IMG SRC="download.png" ALT="DOWNLOAD & INSTALL" BORDER="0" width=150 height=50></A><br>
<A HREF="examples.html"><IMG SRC="examples.png" ALT="EXAMPLES" BORDER="0" width=150 height=50></A><br>
<A HREF="sg/index.html"><IMG SRC="SG.png" ALT="SG" BORDER="0" width=75 height=25></A>
<A HREF="ssg/index.html"><IMG SRC="SSG.png" ALT="SSG" BORDER="0" width=75 height=25></A><br>
<A HREF="ssgAux/index.html"><IMG SRC="ssgAux.png" ALT="SSGAUX" BORDER="0" width=75 height=25></A>
<A HREF="fnt/index.html"><IMG SRC="FNT.png" ALT="FNT" BORDER="0" width=75 height=25></A><br>
<A HREF="pui/index.html"><IMG SRC="PUI.png" ALT="PUI" BORDER="0" width=75 height=25></A>
<A HREF="psl/index.html"><IMG SRC="PSL.png" ALT="PSL" BORDER="0" width=75 height=25></A>
<A HREF="util/index.html"><IMG SRC="UL.png" ALT="UL" BORDER="0" width=75 height=25></A>
<A HREF="js/index.html"><IMG SRC="JS.png" ALT="JS" BORDER="0" width=75 height=25></A><br>
<A HREF="net/index.html"><IMG SRC="NET.png" ALT="NET" BORDER="0" width=75 height=25></A>
<A HREF="sl/index.html"><IMG SRC="SL.png" ALT="SL" BORDER="0" width=75 height=25></A><br>
<A HREF="pw/index.html"><IMG SRC="PW.png" ALT="PW" BORDER="0" width=75 height=25></A>
<A HREF="puAux/index.html"><IMG SRC="puAux.png" ALT="PUAUX" BORDER="0" width=75 height=25></A><br>
</TD>
<TD>
<H1>PLIB: Example Programs and Demonstrations.</H1>
PLIB has three sources of sample programs to learn from.
<ul>
<li> EXAMPLES: There is a bundle of small programs that each show
off one or two small aspects of PLIB and which are
not generally all that useful by themselves.
<li> DEMOS: These are fully worked out demonstration programs
that use a wide range of PLIB features to create complete
and useful programs that are still small enough to understand
quite easily.
<li> APPLICATIONS: Because many PLIB applications are OpenSourced,
there are a large number of complex programs that you can
look at to see how large games, simulations and interactive
tools can be built using this technology.
</ul>
<H2> EXAMPLES </H2>
The PLIB example programs are distributed in <A HREF="download.html#EXAMPLES">
a separate tarball</A> from the main PLIB distribution - and generally, it
is updated less often - but following the same version numbers as the
main PLIB library.
<p>
When you install that package, you'll see that the 'src' directory is
split into sections for each PLIB component library - with one or two
different examples for each library.
<p>
All of the examples are licensed under GPL as bundle and are maintained
under the PLIB SVN archive.
<ul>
<li>FNT:<ul>
<li> fnt_test - a basic TXF font browser.
<li> slideshow - a way to present a simple slide-show driven
from an ASCII text file. Who needs PowerPoint
when you have 'vi'? :-)
<li> data - this directory contains 20 different TXF fonts.
</ul>
<li>JS:<ul>
<li> js_demo - a program that shows the current output from
whatever joysticks it can detect. Useful for
testing out which buttons set which bits and
which axes are which.
</ul>
<li>NET:<ul>
<li> client-server -
<li> http_get -
<li> net_echo -
</ul>
<li>PUI:<ul>
<li> simple - the "Hello World" of PUI programs.
<li> complex - a fairly pointless program that shows how
to control a spinning OpenGL cube, and use
a variety of PUI widgets.
<li> widget_list - draws every kind of PUI widget each
in a separate window. This is what we used
to make the screenshots for the PUI manual.
</ul>
<li>SG:<ul>
<li> sg_quat_test - tests the SG quaternions...unsuccessfully
I think!
</ul>
<li>SL:<ul>
<li> example - plays a number of annoying sounds.
<li> mod_demo - plays a MOD format music file.
</ul>
<li>SSG:<ul>
<li> load_save - Load a 3D model - then just save it again.
<li> majik - A test (originally written to help the Majik3D
project) that shows Tux walking around on some
auto-generated terrain.
<li> state_test - Exercises some ssgSimpleState settings.
<li> tux - A model of Tux the Penguin spins around on a
pedestal encrusted in golden Herring.
<li> tween_test - Demonstrated the 'tween' effect.
<li> water - Demonstrates the ssgAux library - water/fire/lensflare/particles plus basic shapes, cube, teapot.
<li> viewer - A program to allow you to view any 3D model
and spin it around using the mouse.
</ul>
<li>UTIL:<ul>
<li> test_dir - tests some of the directory handling features.
</ul>
</ul>
<H2> DEMONSTRATIONS </H2>
The PLIB demonstration programs are distributed in <A HREF="download.html#DEMOS">
their own separate tarballs</A> - each has it's own version number and it's
own license conditions (although all of them must fall within the SourceForge
definition for OpenSourced software in order to reside on the SourceForge
server). All of the demonstrations are maintained under the PLIB SVN
archive.
<ul>
<li> ExPoser - A program to allow you to animate characters for your
games using 'Skin and Bones' animation techniques.
ExPoser needs PLIB 1.5.1 or later.
<li> TTT3D - A complete 3D TicTacToe game played on a 4x4x4 board.
It's theoretically possible to beat it - <b>theoretically</b>.
TTT3D needs PLIB 1.4.0 or later.
</ul>
<H2> APPLICATIONS </H2>
PLIB applications do not reside on the PLIB web site - but you can find
links to many of them in <A HREF="gallery.html">our image gallery</A>.
</TD>
</TR>
</TABLE>
<hr>
<ADDRESS>
<A HREF="http://www.sjbaker.org">
Steve J. Baker.</A>
&lt;<A HREF="mailto:sjbaker1@airmail.net">sjbaker1@airmail.net</A>&gt;
</ADDRESS>
</BODY>
</HTML>

BIN
doc/examples.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

BIN
doc/fgfs.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

385
doc/fnt/index.html Normal file
View File

@@ -0,0 +1,385 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<META http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<META name="keywords" content="FNT, PLIB, OpenGL, font, library, portable, rendering, text, texture, map, glyph, TXF">
<META name="description" content="The PLIB FNT Library allows you to produce text using texture maps instead of bitmaps because the latter are typically very slow on consumer-grade 3D hardware.">
<TITLE>A Font Library for OpenGL.</TITLE>
</HEAD>
<BODY text="#B5A642" link="#8FFF8F" vlink="#18A515" alink="#20336B"
bgcolor="#005000" background="../marble.png">
<TABLE>
<TR>
<TD>
<H1>A Font Library for OpenGL</H1>
</TD>
</TR>
<TR>
<TD>
by Steve Baker
</TD>
</TR>
</TABLE>
<H2>Introduction</H2>
The FNT library was originally written to allow PUI programs to
produce text using texture maps instead of bitmaps because the
latter are typically very slow on consumer-grade 3D hardware.
<H2>An Example.</H2>
This example program is probably all you need in the
way of documentation - so it's the first thing we'll talk
about:
<pre>
/* Declarations */
fntRenderer texout ;
/* Load some fonts */
fntTexFont TimesRoman ( "times_roman.txf" ) ;
fntTexFont Courier ( "courier.txf" ) ;
/* Select a font and pointsize to render with... */
texout . setFont ( & TimesRoman ) ;
texout . setPointSize ( 24 ) ;
/* Print "Hello" and "World" */
texout . begin () ;
texout . start2f ( 50.0f, 80.0f ) ;
texout . puts ( "Hello" ) ;
texout . start2f ( 50.0f, 50.0f ) ;
texout . puts ( "World" ) ;
texout . end () ;
</pre>
<H2>fntInit</H2>
All programs that use the FNT library should call 'fntInit()' sometime
after they have established a valid OpenGL rendering context and
before they make any other FNT library calls.
<H2>The Classes</H2>
There are three external classes used in FNT:
<pre>
class fntFont -- An abstract base class from which all
kinds of font representations could be
derived.
class fntTexFont -- A fntFont that uses texture mapping.
class fntRenderer -- A class that draws text using a fntFont.
</pre>
<H3>class fntFont</H3>
Classes derived from the <code>fntFont</code> class all describe fonts.
This is an abstract base class from which <code>fntTexFont</code> is derived.
Other <code>fntFont</code> sub-classes could also be derived in the future.
(This means that you cannot declare a fntFont - but all classes derived
from fntFont will obey this description.)
<p>
This class appears quite complex since constructing and/or
querying the contents of a texture font is a complicated
business - and consequently, there is a lot of API to
support your ability to do that. Fortunately, most FNT
applications will just load a font from disk and use
<code>fntFont::begin()</code>/
<code>fntFont::puts()</code>/
<code>fntFont::end()</code>
functionality.
<pre>
class fntFont
{
public:
fntFont () ;
~fntFont () ;
void putch ( sgVec3 curpos, float pointsize, float slant, char c ) ;
void puts ( sgVec3 curpos, float pointsize, float slant, char *s ) ;
void begin () ;
void end () ;
void getBBox ( char *s, float pointsize, float slant,
float *left, float *right,
float *bot , float *top ) ;
int load ( char *fname, GLenum mag = GL_NEAREST,
GLenum min = GL_LINEAR_MIPMAP_LINEAR ) ;
void setFixedPitch ( int fix ) ;
int isFixedPitch () ;
void setWidth ( float w ) ;
void setGap ( float g ) ;
float getWidth () ;
float getGap () ;
int hasGlyph ( char c ) ;
} ;
</pre>
<code>fntFont::getBBox()</code> returns the top, bottom, left and
right extents (in OpenGL units) of the string 's' if it were drawn at the
specified pointsize and slant. This routine knows how to deal with
newline characters.
<p>
<code>fntFont::putch()</code> draws the character 'c' at the
cursor position specified be 'curpos' (with the specified pointsize and slant)
and advances the cursor
to the right hand edge of the character it just rendered.
<p>
<code>fntFont::puts()</code> draws the entire string 's' at the
cursor position specified be 'curpos'
(with the specified pointsize and slant) and advances the cursor
to the right hand edge of the last character it rendered.
<p>
Both putch and puts will automatically switch the case of letters
from upper to lower or vice versa if the required character is
not present in the font but the letter with the reverse case
is present. Other missing characters will simply generate no
output and won't update the cursor position. If a space character
is not defined in the font, then a half-pointsize gap will be
generated instead.
<p>
puts (but NOT putch) knows how to deal with newline characters,
it drops the text down to the next line - leaving a one-third
pointsize gap between lines.
<p>
<code>fntFont::begin()/end()</code> since redundant mode changes are
costly in OpenGL, applications may optionally call <code>fntFont::begin()</code>
before rendering some text using a specified font and call <code>fntFont::end()</code>
at the end. Just like a <code>glBegin()</code>/<code>glEnd()</code> pair,
there are some fairly restrictive rules about what you can do between
a <code>fntFont::begin()</code> and a <code>fntFont::end()</code>:
<ul>
<li>The only OpenGL calls that are permitted are those that
are allowed between a <code>glBegin()</code>/<code>glEnd()</code>.
<li>You may not make calls to other member functions of other
<code>fntFont</code> objects or to <code>fntRenderer</code> objects.
<li>You may not call <code>fntFont::begin()</code> between another
<code>fntFont::begin()</code>/<code>fntFont::end()</code> pair.
</ul>
<p>
You may call <code>fntFont::putch()</code> and/or
<code>fntFont::puts()</code> without
entering a <code>fntFont::begin()</code>/<code>fntFont::end()</code>
state - but if you do that, each call will result in
OpenGL state switching - which may well be redundant.
<p>
<code>int load ( char *filename )</code> loads a font from disk,
returns TRUE on success, FALSE for failure.
<p>
<code>int load ( char *filename, GLenum mag = GL_NEAREST,
GLenum min = GL_LINEAR_MIPMAP_LINEAR )</code>...you can optionally
specify the OpenGL texture magnification and minification filters
- this is sometimes necessary to get the clearest possible text
at certain point sizes. Experiment!
<p>
<code>void setFixedPitch ( int fixed )</code> if 'fixed' is TRUE, forces
the font to be fixed-pitch (so each letter or 'Glyph' is a standard width),
if 'fixed' is false then variable character widths are possible.
<p>
<code>void setWidth ( float w )</code> For a fixed width font, this
sets the width of each character. If the actual characters are wider
than this, they will overlap, if they are narrower then there will be
a gap.
<p>
<code>void setGap ( float g )</code> Set the gap between letters, can be
negative or positive.
<p>
The following routines allow you to query the font's setup:
<pre>
int isFixedPitch ()
float getWidth ()
float getGap ()
</pre>
<code>int hasGlyph()</code> returns TRUE if the font contains a
glyph (graphic image) for a given ASCII character, FALSE otherwise.
Fonts that have only uppercase (or only lowercase) letters will still
return TRUE for corresponding characters of the opposite case because
the putch and puts routines will automatically case-convert in that
case.
<H3>class fntTexFont</H3>
<code>fntTexFont</code> is inherited from <code>fntFont</code>.
All functions of a fntFont are implemented in fntTextFont using
a texture map.
<pre>
class fntTexFont
{
public:
fntTexFont () ;
fntTexFont ( char *fname,
GLenum mag = GL_NEAREST,
GLenum min = GL_LINEAR_MIPMAP_LINEAR ) ;
~fntTexFont () ;
void putch ( sgVec3 curpos, float pointsize, float slant, char c ) ;
void puts ( sgVec3 curpos, float pointsize, float slant, char *s ) ;
void begin () ;
void end () ;
void getBBox ( char *s, float pointsize, float slant,
float *left, float *right,
float *bot , float *top ) ;
int load ( char *fname,
GLenum mag = GL_NEAREST,
GLenum min = GL_LINEAR_MIPMAP_LINEAR ) ;
void setFixedPitch ( int fix ) ;
int isFixedPitch () ;
void setWidth ( float w ) ;
void setGap ( float g ) ;
float getWidth () ;
float getGap () ;
void setGlyph ( char c,
float tex_left, float tex_right,
float tex_bot , float tex_top ,
float vtx_left, float vtx_right,
float vtx_bot , float vtx_top ) ;
int getGlyph ( char c,
float *tex_left = NULL, float *tex_right = NULL,
float *tex_bot = NULL, float *tex_top = NULL,
float *vtx_left = NULL, float *vtx_right = NULL,
float *vtx_bot = NULL, float *vtx_top = NULL) ;
} ;
</pre>
<p>
<code>int load ( char *filename )</code> loads a font from disk
using the extension of the filename to determine what format it is
stored in. Currently, the only supported format is Mark Kilgards 'texfont'
format - which has the '.txf' filename extension. Returns TRUE for
success, FALSE for failure.
Details of the TXF file format can be found in
<A HREF="http://www.opengl.org/resources/code/rendering/mjktips/TexFont/TexFont.html">
Marks's document about Textured Fonts</A>
<p>
Just as with all fntFont derived classes, you can optionally specify
the OpenGL texture filter options for the loaded texture.
<p>
Each font is made up of zero or more 'Glyphs' (character shapes) packed
into a single texture map. If you didn't use 'load' to load the font
from disk, you'll have to define where each one lies on the map and
how big the quadrilateral it is to be drawn on is:
<pre>
void setGlyph ( char c,
float tex_left, float tex_right,
float tex_bot , float tex_top ,
float vtx_left, float vtx_right,
float vtx_bot , float vtx_top ) ;
</pre>
Where 'c' is the character we are defining, 'tex_*' is the
left, right, top and bottom of the image of that character
in the texture map. Since texture coordinates are in the
range 0..1, these will typically be quite small numbers.
'vtx_*' is the left, right, top and bottom of the character's
rectangle in a coordinate system that has (0,0) at the
baseline of the character cell, and (1,1) at the top-right
corner of the tallest, widest character in the font. Hence,
a lower-case 'y' would have a negative 'vtx_bot'.
<p>
You can also query all this information:
<pre>
int getGlyph ( char c,
float *tex_left, float *tex_right,
float *tex_bot , float *tex_top ,
float *vtx_left, float *vtx_right,
float *vtx_bot , float *vtx_top ) ;
</pre>
<code>fntFont::getGlyph()</code> returns TRUE if the character has
been defined in this font, FALSE otherwise.
<H3>class fntRenderer</H3>
This class is the one most people are going to be using
to render text in FNT. Most applications will declare
a single <code>fntRenderer</code> class for all their text needs.
<pre>
class fntRenderer
{
public:
fntRenderer ()
void start3fv ( sgVec3 pos ) ;
void start2fv ( sgVec2 pos ) ;
void start2f ( float x, float y ) ;
void start3f ( float x, float y, float z ) ;
void getCursor ( float *x, float *y, float *z )
fntFont *getFont () ;
void setFont ( fntFont *f ) ;
void begin () ;
void end () ;
void putch ( char c ) ;
void puts ( char *s ) ;
} ;
</pre>
<code>fntRenderer::setFont()</code> is used to tell the renderer which
font is current. <code>fntRenderer::getFont()</code> lets you find out
which font it is. You may not call <code>fntRenderer::setFont()</code>
between a <code>fntRenderer::begin()</code> and <code>fntRenderer::end()</code>
pair.
<p>
By default, uppercase characters of all fonts are one OpenGL unit high.
You can make characters larger or smaller by setting
<code>fntRenderer::setPointSize()</code>. You can also slant the characters
to form italic or oublique fonts using <code>fntRenderer::setSlant()</code>.
(The slant measures by how many OpenGL units the tops of uppercase
characters are sloped to the right). You can call either setPointSize or
setSlant between <code>fntRenderer::begin()</code> and
<code>fntRenderer::end()</code>.
<p>
The various kinds of <code>fntRendered::start*()</code> calls are
akin to the OpenGL <code>glVertex*</code> commands and they determine where
the next chunk of text will be drawn. Since this coordinate is
updated as text is drawn, you'll need to call
<code>fntRenderer::getCursor()</code> to
find out where the next chunk of text will be drawn. You can
call <code>fntRenderer::start*()</code>,
<code>fntRenderer::putch()</code> and
<code>fntRenderer::puts()</code> between
<code>fntRenderer::begin()</code>/<code>fntRenderer::end()</code>
calls.
<H2>Making New TXF Fonts.</H2>
The '.txf' font format was designed by Mark Kilgard - who
also produced some tools for dealing with them.
<p>
Check <A HREF="http://www.opengl.org/resources/code/rendering/mjktips/TexFont/TexFont.html">
Marks's document about Textured Fonts</A> for further information.
Of particular interest is Mark's "gentexfont" program that can
create a TXF format font from an X-windows font.
<p>
You can find out which X-fonts are stored on your machine using
the <code>/usr/X11/bin/xlsfonts</code> program.
<p>
There are over a dozen sample TXF fonts stored
in <code>examples/src/fnt/data</code>.
<hr>
<table>
<tr>
<td>
<a href="http://validator.w3.org/check/referer"><img border="0" src="../valid-html40.png" alt="Valid HTML 4.0!" height="31" width="88"></a>
<td>
<ADDRESS>
<A HREF="http://www.sjbaker.org">
Steve J. Baker.</A>
&lt;<A HREF="mailto:sjbaker1@airmail.net">sjbaker1@airmail.net</A>&gt;
</ADDRESS>
</table>
</BODY>
</HTML>

188
doc/gallery.html Normal file
View File

@@ -0,0 +1,188 @@
<!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>PLIB: Gallery.</TITLE>
</HEAD>
<BODY text="#B5A642" link="#8FFF8F" vlink="#18A515" alink="#20336B"
bgcolor="#005000" background="marble.png">
<TABLE>
<TR>
<TD>
<IMG SRC="plib_logo.png" ALT="PLIB Logo" width=256 height=245>
<br>
</TD>
<TD>
<center>
<H1>
<FONT SIZE=9>S</FONT><FONT SIZE=5>TEVE'S</FONT>
<FONT SIZE=9>P</FONT><FONT SIZE=5>ORTABLE</FONT>
<FONT SIZE=9>G</FONT><FONT SIZE=5>AME</FONT>
<FONT SIZE=9>L</FONT><FONT SIZE=5>IBRARY.</FONT>
</H1>
</center>
</TD>
<TD>
<ul>
And Lo, the Lion and the Sheep shall lie down together - but the Sheep won't
get much Sleep.
<br>
-- Woody Allen
</ul>
<center>
<A href="http://sf.net">
<IMG src="http://sf.net/sflogo.php?group_id=382&type=1" width="88" height="31" border="0" ALT="Sourceforge Logo"></A>
</center>
</TD>
</TR>
</TABLE>
<TABLE>
<TR>
<TD valign=top align=left>
<A HREF="index.html"><IMG SRC="home.png" ALT="HOME" BORDER="0" width=150 height=50></A><br>
<A HREF="whats_inside.html"><IMG SRC="whats_inside.png" ALT="WHAT'S INSIDE" BORDER="0" width=150 height=50></A><br>
<A HREF="license.html"><IMG SRC="license.png" ALT="LICENSE" BORDER="0" width=150 height=50></A><br>
<A HREF="contacts.html"><IMG SRC="contacts.png" ALT="CONTACTS" BORDER="0" width=150 height=50></A><br>
<A HREF="requirements.html"><IMG SRC="requirements.png" ALT="REQUIREMENTS" BORDER="0" width=150 height=50></A><br>
<A HREF="gallery.html"><IMG SRC="gallery.png" ALT="GALLERY" BORDER="0" width=150 height=50></A><br>
<A HREF="download.html"><IMG SRC="download.png" ALT="DOWNLOAD & INSTALL" BORDER="0" width=150 height=50></A><br>
<A HREF="examples.html"><IMG SRC="examples.png" ALT="EXAMPLES" BORDER="0" width=150 height=50></A><br>
<A HREF="sg/index.html"><IMG SRC="SG.png" ALT="SG" BORDER="0" width=75 height=25></A>
<A HREF="ssg/index.html"><IMG SRC="SSG.png" ALT="SSG" BORDER="0" width=75 height=25></A><br>
<A HREF="ssgAux/index.html"><IMG SRC="ssgAux.png" ALT="SSGAUX" BORDER="0" width=75 height=25></A>
<A HREF="fnt/index.html"><IMG SRC="FNT.png" ALT="FNT" BORDER="0" width=75 height=25></A><br>
<A HREF="pui/index.html"><IMG SRC="PUI.png" ALT="PUI" BORDER="0" width=75 height=25></A>
<A HREF="psl/index.html"><IMG SRC="PSL.png" ALT="PSL" BORDER="0" width=75 height=25></A>
<A HREF="util/index.html"><IMG SRC="UL.png" ALT="UL" BORDER="0" width=75 height=25></A>
<A HREF="js/index.html"><IMG SRC="JS.png" ALT="JS" BORDER="0" width=75 height=25></A><br>
<A HREF="net/index.html"><IMG SRC="NET.png" ALT="NET" BORDER="0" width=75 height=25></A>
<A HREF="sl/index.html"><IMG SRC="SL.png" ALT="SL" BORDER="0" width=75 height=25></A><br>
<A HREF="pw/index.html"><IMG SRC="PW.png" ALT="PW" BORDER="0" width=75 height=25></A>
<A HREF="puAux/index.html"><IMG SRC="puAux.png" ALT="PUAUX" BORDER="0" width=75 height=25></A><br>
</TD>
<TD>
<H1>ScreenShot Gallery.</H1>
These images come from a wide variety of PLIB applications - some OpenSourced,
some commercial. Click on the thumbnail image for more detail and links to further
information.
<TABLE>
<TR><TD>
<H2>The FlightGear Flight Simulator.</H2>
</TD>
<TD>
<A HREF="http://plib.sourceforge.net/gallery/fgfs.html">
<IMG WIDTH=270 HEIGHT=183 SRC="http://plib.sourceforge.net/gallery/fgfs_small.png" BORDER="0" ALT="FlightGear"></A><br>
</TD></TR>
<TR><TD>
<H2>The Chronicles of the Evil Overlord.</H2>
</TD>
<TD>
<A HREF="http://plib.sourceforge.net/gallery/evilo.html">
<IMG WIDTH=280 HEIGHT=219 SRC="http://plib.sourceforge.net/gallery/evilo_thumbnail.png" BORDER="0" ALT="Chronicles of the Evil Overlord"></A><br>
</TD></TR>
<TR><TD>
<H2>The ExPoser Animation Tool.</H2>
</TD>
<TD>
<A HREF="http://plib.sourceforge.net/gallery/exposer.html">
<IMG WIDTH=280 HEIGHT=210 SRC="http://plib.sourceforge.net/gallery/exposer_thumbnail.png" BORDER="0" ALT="ExPoser"></A><br>
</TD></TR>
<TR><TD>
<H2>HardBall.</H2>
</TD>
<TD>
<A HREF="http://plib.sourceforge.net/gallery/hardball.html">
<IMG WIDTH=280 HEIGHT=225 SRC="http://plib.sourceforge.net/gallery/hardball_thumbnail.png" BORDER="0" ALT="HardBall"></A><br>
</TD></TR>
<TR><TD>
<H2>MOTE.</H2>
</TD>
<TD>
<A HREF="http://plib.sourceforge.net/gallery/mote.html">
<IMG WIDTH=280 HEIGHT=202 SRC="http://plib.sourceforge.net/gallery/mote_thumbnail.png" BORDER="0" ALT="MOTE"></A><br>
</TD></TR>
<TR><TD>
<H2>The PrettyPoly Modeller.</H2>
</TD>
<TD>
<A HREF="http://plib.sourceforge.net/gallery/prettypoly.html">
<IMG WIDTH=280 HEIGHT=234 SRC="http://plib.sourceforge.net/gallery/prettypoly_thumbnail.png" BORDER="0" ALT="PrettyPoly Modeller"></A><br>
</TD></TR>
<TR><TD>
<H2>TicTacToe 3D.</H2>
</TD>
<TD>
<A HREF="http://plib.sourceforge.net/gallery/ttt3d.html">
<IMG WIDTH=280 HEIGHT=210 SRC="http://plib.sourceforge.net/gallery/ttt3d_thumbnail.png" BORDER="0" ALT="TicTacToe 3D"></A><br>
</TD></TR>
<TR><TD>
<H2>TORCS Car Racing Simulator.</H2>
</TD>
<TD>
<A HREF="http://plib.sourceforge.net/gallery/torcs.html">
<IMG WIDTH=280 HEIGHT=210 SRC="http://plib.sourceforge.net/gallery/torcs_thumbnail.png" BORDER="0" ALT="TORCS"></A><br>
</TD></TR>
<TR><TD>
<H2>Tuxedo T. Penguin - A Quest for Herring.</H2>
</TD>
<TD>
<A HREF="http://plib.sourceforge.net/gallery/tuxaqfh.html">
<IMG WIDTH=280 HEIGHT=210 SRC="http://plib.sourceforge.net/gallery/tuxaqfh_thumbnail.png" BORDER="0" ALT="A Quest for Herring"></A><br>
</TD></TR>
<TR><TD>
<H2>TuxKart.</H2>
</TD>
<TD>
<A HREF="http://plib.sourceforge.net/gallery/tuxkart.html">
<IMG WIDTH=280 HEIGHT=210 SRC="http://plib.sourceforge.net/gallery/tuxkart_thumbnail.png" BORDER="0" ALT="TuxKart"></A><br>
</TD></TR>
<TR><TD>
<H2>TuxFleet.</H2>
</TD>
<TD>
<A HREF="http://plib.sourceforge.net/gallery/tuxfleet.html">
<IMG WIDTH=280 HEIGHT=210 SRC="http://plib.sourceforge.net/gallery/tuxfleet_thumbnail.png" BORDER="0" ALT="TuxFleet"></A><br>
</TD></TR>
<TR><TD>
<H2>Wizz.</H2>
</TD>
<TD>
<A HREF="http://plib.sourceforge.net/gallery/wizz.html">
<IMG WIDTH=280 HEIGHT=210 SRC="http://plib.sourceforge.net/gallery/wizz_thumbnail.png" BORDER="0" ALT="Wizz"></A><br>
</TD></TR>
<TR><TD>
<H2>Atlas Map Maker.</H2>
</TD>
<TD>
<A HREF="http://plib.sourceforge.net/gallery/atlas.html">
<IMG WIDTH=280 HEIGHT=210 SRC="http://plib.sourceforge.net/gallery/atlas_thumbnail.png" BORDER="0" ALT="Atlas Map Maker"></A><br>
</TD></TR>
<TR><TD>
<H2>Flight Dynamics Simulator.</H2>
</TD>
<TD>
<A HREF="http://plib.sourceforge.net/gallery/FDS.html">
<IMG WIDTH=280 HEIGHT=210 SRC="http://plib.sourceforge.net/gallery/FDS_thumbnail.png" BORDER="0" ALT="Flight Dynamics Simulator"></A><br>
</TD></TR>
</TABLE>
</TD></TR>
</TABLE>
<hr>
<ADDRESS>
<A HREF="http://www.sjbaker.org">
Steve J. Baker.</A>
&lt;<A HREF="mailto:sjbaker1@airmail.net">sjbaker1@airmail.net</A>&gt;
</ADDRESS>
</BODY>
</HTML>

BIN
doc/gallery.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

BIN
doc/home.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

203
doc/index.html Normal file
View File

@@ -0,0 +1,203 @@
<!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>PLIB: A Portable Games Library.</TITLE>
</HEAD>
<BODY text="#B5A642" link="#8FFF8F" vlink="#18A515" alink="#20336B"
bgcolor="#005000" background="marble.png">
<TABLE>
<TR>
<TD>
<IMG SRC="plib_logo.png" ALT="PLIB Logo" width=256 height=245>
<br>
</TD>
<TD>
<center>
<H1>
<FONT SIZE=9>S</FONT><FONT SIZE=5>TEVE'S</FONT>
<FONT SIZE=9>P</FONT><FONT SIZE=5>ORTABLE</FONT>
<FONT SIZE=9>G</FONT><FONT SIZE=5>AME</FONT>
<FONT SIZE=9>L</FONT><FONT SIZE=5>IBRARY.</FONT>
</H1>
</center>
</TD>
<TD>
<ul>
And Lo, the Lion and the Sheep shall lie down together - but the Sheep won't
get much Sleep.
<br>
-- Woody Allen
</ul>
<center>
<A href="http://sf.net">
<IMG src="http://sf.net/sflogo.php?group_id=382&type=1" width="88" height="31" border="0" ALT="Sourceforge Logo"></A>
</center>
</TD>
</TR>
</TABLE>
<TABLE>
<TR>
<TD valign=top align=left>
<A HREF="index.html"><IMG SRC="home.png" ALT="HOME" BORDER="0" width=150 height=50></A><br>
<A HREF="whats_inside.html"><IMG SRC="whats_inside.png" ALT="WHAT'S INSIDE" BORDER="0" width=150 height=50></A><br>
<A HREF="license.html"><IMG SRC="license.png" ALT="LICENSE" BORDER="0" width=150 height=50></A><br>
<A HREF="contacts.html"><IMG SRC="contacts.png" ALT="CONTACTS" BORDER="0" width=150 height=50></A><br>
<A HREF="requirements.html"><IMG SRC="requirements.png" ALT="REQUIREMENTS" BORDER="0" width=150 height=50></A><br>
<A HREF="gallery.html"><IMG SRC="gallery.png" ALT="GALLERY" BORDER="0" width=150 height=50></A><br>
<A HREF="download.html"><IMG SRC="download.png" ALT="DOWNLOAD & INSTALL" BORDER="0" width=150 height=50></A><br>
<A HREF="examples.html"><IMG SRC="examples.png" ALT="EXAMPLES" BORDER="0" width=150 height=50></A><br>
<A HREF="sg/index.html"><IMG SRC="SG.png" ALT="SG" BORDER="0" width=75 height=25></A>
<A HREF="ssg/index.html"><IMG SRC="SSG.png" ALT="SSG" BORDER="0" width=75 height=25></A><br>
<A HREF="ssgAux/index.html"><IMG SRC="ssgAux.png" ALT="SSGAUX" BORDER="0" width=75 height=25></A>
<A HREF="fnt/index.html"><IMG SRC="FNT.png" ALT="FNT" BORDER="0" width=75 height=25></A><br>
<A HREF="pui/index.html"><IMG SRC="PUI.png" ALT="PUI" BORDER="0" width=75 height=25></A>
<A HREF="psl/index.html"><IMG SRC="PSL.png" ALT="PSL" BORDER="0" width=75 height=25></A>
<A HREF="util/index.html"><IMG SRC="UL.png" ALT="UL" BORDER="0" width=75 height=25></A>
<A HREF="js/index.html"><IMG SRC="JS.png" ALT="JS" BORDER="0" width=75 height=25></A><br>
<A HREF="net/index.html"><IMG SRC="NET.png" ALT="NET" BORDER="0" width=75 height=25></A>
<A HREF="sl/index.html"><IMG SRC="SL.png" ALT="SL" BORDER="0" width=75 height=25></A><br>
<A HREF="pw/index.html"><IMG SRC="PW.png" ALT="PW" BORDER="0" width=75 height=25></A>
<A HREF="puAux/index.html"><IMG SRC="puAux.png" ALT="PUAUX" BORDER="0" width=75 height=25></A><br>
</TD>
<TD>
<H1>PLIB: A Suite of Portable Game Libraries.</H1>
I (and an ever increasing band of helpers) have been spending
time to build a set of OpenSource (LGPL) libraries that will
permit programmers to write games and other realtime interactive
applications that are 100% portable across a wide range of hardware and
operating systems.
<p>
PLIB includes sound effects, music, a complete 3D engine, font
rendering, a simple Windowing library, a game scripting language,
a GUI, networking, 3D math library and a
collection of handy utility functions. All are 100% portable
across nearly all modern computing platforms. What's more, it's
all available on line - and completely free. Each library component
is fairly independent of the others - so if you want to use SDL,
GTK, GLUT, or FLTK instead of PLIB's 'PW' windowing library, you can.
<p>
The latest stable version of PLIB is 1.8.4 - go to the
<A HREF="download.html">DOWNLOAD</A> section to get a
copy - go to the <A HREF="whats_inside.html">WHAT'S INSIDE</A>
section for documentation and a more detailed description of
what PLIB contains.
<p>
If you are looking at other games libraries (and there are a LOT
to choose from) - ask yourself how many games have been written
for that library by people outside the group that wrote it. That
is the acid test of usability and PLIB passes with flying colours.
<p>
PLIB is used by many projects (not all games - and not all
OpenSourced), here are some of the more prominent ones - there
are at least a hundred others:
<center>
<TABLE>
<TR>
<TD><center><A HREF="http://tuxaqfh.sf.net">
<IMG BORDER=0 SRC="tux_aqfh.png" ALT="Tux_AQFH Logo" width=99 height=77></A><br>
<A HREF="http://tuxaqfh.sf.net">Tux the Penguin -
<br>A Quest for herring.</A></center></TD>
<TD><center><A HREF="http://tuxkart.sf.net">TuxKart</A><br>
<A HREF="http://tuxkart.sf.net">
<IMG BORDER=0 SRC="tuxkart_logo.png" ALT="TuxKart Logo" width=101 height=78></A></center></TD>
<TD><center><A HREF="http://www.flightgear.org">
<IMG BORDER=0 SRC="fgfs.png" ALT="FlightGear Logo" width=111 height=58></A><br>
<A HREF="http://www.flightgear.org">FlightGear</A></center></TD>
<TD><center><A HREF="http://www.majik3d.org">Majik3D</A><br>
<A HREF="http://www.majik3d.org">
<IMG BORDER=0 SRC="majik3d.png" ALT="Majik3D Logo" width=83 height=80></A></center></TD>
</TR>
<TR>
<TD><center><A HREF="http://prettypoly.sf.net">
<IMG BORDER=0 SRC="ppe_logo_1.png" ALT="PrettyPoly Logo" width=98 height=54></A><br>
<A HREF="http://prettypoly.sf.net">
PrettyPoly Editor</A></center></TD>
<TD><center><A HREF="http://tuxfleet.sf.net">TuxFleet</A><br>
<A HREF="http://tuxfleet.sf.net">
<IMG BORDER=0 SRC="tuxfleet_logo.png" ALT="TuxFleet Logo" width=92 height=72></A></center></TD>
<TD><center><A HREF="http://www.torcs.org">TORCS</A><br>
<A HREF="http://www.torcs.org">
<IMG BORDER=0 SRC="torcs_logo.png" ALT="TORCS Logo" width=100 height=84></A></center></TD>
<TD><center><A HREF="http://www.minigolfmaniacs.com">
<IMG BORDER=0 SRC="MinigolfManiacs.png" ALT="Minigolf Maniacs Logo" width=120 height=47></A><br>
<A HREF="http://www.minigolfmaniacs.com">
Minigolf Maniacs</A></center></TD>
</TR>
</TABLE>
</center>
<center>
<TABLE>
<TR>
<TD><center><A HREF="http://www.flight-dynamic-simulator.de">
<IMG BORDER=0 SRC="FDS_logo.png" ALT="FDS Logo" width=110 height=90></A><br>
<A HREF="http://www.flight-dynamic-simulator.de">
Flight Dynamics Simulator</A></center></TD>
<TD><center><A HREF="http://mote-project.org">
<IMG BORDER=0 SRC="mote.png" ALT="MOTE Logo" width=123 height=33></A><br>
<A HREF="http://mote-project.org">
MOTE</A></center></TD>
<TD><center>
<A HREF="http://www.spacething.org">
<IMG BORDER=0 SRC="spacething-small.png" ALT="Spacething Logo" width=200 height=33></A><br>
<A HREF="http://www.spacething.org">Spacething</A></center></TD>
</TR>
</TABLE>
</center>
<p>
Unlike the many similar libraries, PLIB is easy to learn and
use - and has an object-oriented C++ interface. It's built
as a set of component libraries that you can pick and choose
between if (for example) you don't want to use PLIB's GUI but
you do want to use it's scene graph API.
<p>
If you are reading this document from the source distribution on
your local disk, you can find the most up to date version of PLIB
here:
<ul>
<A HREF="http://plib.sf.net">
http://plib.sf.net</A>
</ul>
PLIB's web presence is currently hosted on SourceForge (with thanks to
VA Linux Inc for providing this free service), and the
project summary page is here:
<ul>
<A HREF="http://sf.net/projects/plib">
http://sf.net/projects/plib</A>
</ul>
</TD>
</TR>
</TABLE>
<hr>
<ADDRESS>
<A HREF="http://www.sjbaker.org">
Steve J. Baker.</A>
&lt;<A HREF="mailto:sjbaker1@airmail.net">sjbaker1@airmail.net</A>&gt;
</ADDRESS>
</BODY>
</HTML>

187
doc/js/index.html Normal file
View File

@@ -0,0 +1,187 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<META http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<META name="keywords" content="JS, PLIB, OpenGL, joystick, library, portable, interface, games, Baker, Steve, jsJoystick">
<META name="description" content="The PLIB Joystick Library (JS) is a portable interface that has no inherent restrictions over the number and type of joysticks it supports. It is a wrapper to make the various underlying OS mechanisms look the same to application code.">
<TITLE>A Joystick Library.</TITLE>
</HEAD>
<BODY text="#B5A642" link="#8FFF8F" vlink="#18A515" alink="#20336B"
bgcolor="#005000" background="../marble.png">
<TABLE>
<TR>
<TD>
<H1>A Joystick Library.</H1>
</TD>
</TR>
<TR>
<TD>
by Steve Baker
</TD>
</TR>
</TABLE>
<H2>Introduction</H2>
JS is now just one component of <A HREF="../index.html">PLIB</A>.
<p>
This Joystick Library (JS) is a portable interface that
has no inherent restrictions over the number and type
of joysticks it supports - although in actuality, most
implementations will simply sit on top of an underlying
driver provided by the Operating System.
<p>
You should include the JS header file '/usr/include/plib/js.h'
and link to the JS library '/usr/lib/libjs.a'.
<p>
Before using any JS functions, you should initialise the
library by calling:
<pre>
jsInit () ;
</pre>
JS is essentially just a wrapper to make the various
underlying OS mechanisms look the same to application code.
<pre>
class jsJoystick
{
jsJoystick ( int id = 0 ) ;
~jsJoystick () ;
const char* getName () const ;
int getNumAxes () const ;
int getNumButtons () const ;
int notWorking () const ;
void setError () ;
float getDeadBand ( int axis ) const ;
void setDeadBand ( int axis, float db ) ;
float getSaturation ( int axis ) const ;
void setSaturation ( int axis, float st ) ;
void setMinRange ( float *axes ) ;
void setMaxRange ( float *axes ) ;
void setCenter ( float *axes ) ;
void getMinRange ( float *axes ) const ;
void getMaxRange ( float *axes ) const ;
void getCenter ( float *axes ) const ;
void read ( int *buttons, float *axes ) ;
void rawRead ( int *buttons, float *axes ) ;
}
</pre>
You pass the identifier (0..n) of the joystick you wish to
open into the constructor function. If you leave the number
off, it'll grab the first joystick available.
<p>
If the joystick is unavailable, not working, not installed or
otherwise bad, the package will return zero for all the axes
and all the buttons will appear to be up. If you need to
check for the existance of a particular stick, you can
call <code>notWorking()</code> which returns JS_TRUE if
there is some problem with that stick, JS_FALSE otherwise.
<p>
<code>getName()</code> tells you the device name of the
joystick, if available through API calls in your OS. A
typical value is "CH PRODUCTS CH PRO PEDALS USB ". If no
name is available, this method will return the empty string.
<p>
<code>getNumAxes()</code> tells you how many axes the stick
has. Note that it is NOT safe to assume that all sticks have
the same number of axes - or that they all have a maximum of
three or something. When you pass axis data into and out of
JS, your arrays MUST be sized large enough for that stick.
<p>
When you are testing joystick code, you need to be sure your
program does the right thing when no joystick is installed.
Since it's inconvenient to do keep uninstalling your stick
to do that, we provide <code>setError()</code> which causes
that stick to react exactly as if it were not installed.
<p>
To read the joystick, just call <code>read(&amp;buttons,axes)</code>
where 'buttons' is an integer and 'axes' is an array of
floating point numbers. The buttons variable will be populated
with a number that has one bit per button (0==Not Pressed, 1==Pressed)
and the elements of the axis array will be scaled from an idealized
-1.0 to +1.0 range. (In practice, your stick may not reach those
limits - or it may marginally exceed them).
<p>
For a basic two axis stick, axis zero is Left/Right with left being
negative and right positive. Axis one is North/South with north being
negative and right positive (this is counter-intuitive - but that's
what they do).
<p>
M$-Windows letters its stick axes X,Y,Z,R,U,V. These correspond
to JS axes 0,1,2,3,4,5,6.
<H2>Buttons</H2>
One continually annoying thing about PC joysticks is the lack of
standards for their names. Most sticks have at least two buttons -
mine has six (maybe some have still more). The problem is to know
how to name them. My game pad has buttons labelled A,B,C,D,R,L
corresponding to bits 0,1,2,3,4,5 in the 'buttons' variable.
<p>
Anyway, some joysticks have features that operate by setting
two or more button bits at once. This is quite easy to catch by
masking multiple bits from the 'buttons' word.
<H2>Demo Program</H2>
The demo program that comes with JS is quite useful for finding out
which buttons set which bits and which axes are which - and in
which direction they operate.
<H2>Calibration</H2>
Since most joysticks are analog devices (and fairly cheap, nasty ones
at that), you will not generally get numbers that are accurately
in the range -1..1 with exactly zero being returned when the joystick
is centered on it's springs. This means that you may wish to calibrate
your joystick. The <code>rawRead</code> routine bypasses all the scaling and
offsetting to return RAW data directly from the OS that you can use during
calibration.
<p>
For each axis of the joystick, you should provide a maximum number
(that you wish to correspond to 1.0 returned by <code>read()</code>),
a minimum number (corresponding to -1.0) and a center point number
(corresponding to 0.0) by calling
<code>setMaxRange()/setMinRange()/setCenter()</code> as appropriate.
<p>
However, even with calibration, you should expect the joystick to
drift somewhat over time due to the position of the cable, the
temperature of the potentiometers and probably, the phase of the moon.
This drift is typically not serious at the max and min limits - but
in some applications, the user will expect (for example) for his
character in a game to stop moving completely when he releases the
stick. Since we cannot guarantee to get the same exact number out
of the stick when he does this, you'll need to implement a 'dead band'
in the middle of the stick's travel. This is done with
<code>setDeadBand(axis,amount)</code> where 'axis' is the number of the
axis you wish to have a dead band implemented on - and 'amount' is the
amount of dead band either side of 0.0.
<p>
There are corresponding 'get' routines for each 'set'.
<p>
The <code>read</code> routine is auto-calibrated when you create
the joystick class - so if the joystick is not centered at that
moment, you will get bad data from that point onwards. This is
quite common in games - so don't feel too badly about it. Just
arrange to 'new' all your joysticks early on in the program - when
your user's hands are likely to still be on the keyboard or mouse -
and provide a hot-key to pause the game and recalibrate the stick
on demand.
<hr>
<table>
<tr>
<td>
<a href="http://validator.w3.org/check/referer"><img border="0" src="../valid-html40.png" alt="Valid HTML 4.0!" height="31" width="88"></a>
<td>
<ADDRESS>
<A HREF="http://www.sjbaker.org">
Steve J. Baker.</A>
&lt;<A HREF="mailto:sjbaker1@airmail.net">sjbaker1@airmail.net</A>&gt;
</ADDRESS>
</table>
</BODY>
</HTML>

112
doc/license.html Normal file
View File

@@ -0,0 +1,112 @@
<!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>PLIB: Licensing.</TITLE>
</HEAD>
<BODY text="#B5A642" link="#8FFF8F" vlink="#18A515" alink="#20336B"
bgcolor="#005000" background="marble.png">
<TABLE>
<TR>
<TD>
<IMG SRC="plib_logo.png" ALT="PLIB Logo" width=256 height=245>
<br>
</TD>
<TD>
<center>
<H1>
<FONT SIZE=9>S</FONT><FONT SIZE=5>TEVE'S</FONT>
<FONT SIZE=9>P</FONT><FONT SIZE=5>ORTABLE</FONT>
<FONT SIZE=9>G</FONT><FONT SIZE=5>AME</FONT>
<FONT SIZE=9>L</FONT><FONT SIZE=5>IBRARY.</FONT>
</H1>
</center>
</TD>
<TD>
<ul>
And Lo, the Lion and the Sheep shall lie down together - but the Sheep won't
get much Sleep.
<br>
-- Woody Allen
</ul>
<center>
<A href="http://sf.net">
<IMG src="http://sf.net/sflogo.php?group_id=382&type=1" width="88" height="31" border="0" ALT="Sourceforge Logo"></A>
</center>
</TD>
</TR>
</TABLE>
<TABLE>
<TR>
<TD valign=top align=left>
<A HREF="index.html"><IMG SRC="home.png" ALT="HOME" BORDER="0" width=150 height=50></A><br>
<A HREF="whats_inside.html"><IMG SRC="whats_inside.png" ALT="WHAT'S INSIDE" BORDER="0" width=150 height=50></A><br>
<A HREF="license.html"><IMG SRC="license.png" ALT="LICENSE" BORDER="0" width=150 height=50></A><br>
<A HREF="contacts.html"><IMG SRC="contacts.png" ALT="CONTACTS" BORDER="0" width=150 height=50></A><br>
<A HREF="requirements.html"><IMG SRC="requirements.png" ALT="REQUIREMENTS" BORDER="0" width=150 height=50></A><br>
<A HREF="gallery.html"><IMG SRC="gallery.png" ALT="GALLERY" BORDER="0" width=150 height=50></A><br>
<A HREF="download.html"><IMG SRC="download.png" ALT="DOWNLOAD & INSTALL" BORDER="0" width=150 height=50></A><br>
<A HREF="examples.html"><IMG SRC="examples.png" ALT="EXAMPLES" BORDER="0" width=150 height=50></A><br>
<A HREF="sg/index.html"><IMG SRC="SG.png" ALT="SG" BORDER="0" width=75 height=25></A>
<A HREF="ssg/index.html"><IMG SRC="SSG.png" ALT="SSG" BORDER="0" width=75 height=25></A><br>
<A HREF="ssgAux/index.html"><IMG SRC="ssgAux.png" ALT="SSGAUX" BORDER="0" width=75 height=25></A>
<A HREF="fnt/index.html"><IMG SRC="FNT.png" ALT="FNT" BORDER="0" width=75 height=25></A><br>
<A HREF="pui/index.html"><IMG SRC="PUI.png" ALT="PUI" BORDER="0" width=75 height=25></A>
<A HREF="psl/index.html"><IMG SRC="PSL.png" ALT="PSL" BORDER="0" width=75 height=25></A>
<A HREF="util/index.html"><IMG SRC="UL.png" ALT="UL" BORDER="0" width=75 height=25></A>
<A HREF="js/index.html"><IMG SRC="JS.png" ALT="JS" BORDER="0" width=75 height=25></A><br>
<A HREF="net/index.html"><IMG SRC="NET.png" ALT="NET" BORDER="0" width=75 height=25></A>
<A HREF="sl/index.html"><IMG SRC="SL.png" ALT="SL" BORDER="0" width=75 height=25></A><br>
<A HREF="pw/index.html"><IMG SRC="PW.png" ALT="PW" BORDER="0" width=75 height=25></A>
<A HREF="puAux/index.html"><IMG SRC="puAux.png" ALT="PUAUX" BORDER="0" width=75 height=25></A><br>
</TD>
<TD>
<H2>PLIB Licensing.</H2>
PLIB is licensed under the <A HREF="http://www.gnu.org/copyleft/library.html">Library GNU Public License</A> (LGPL).
<p>
Whilst this permits closed-source applications to use PLIB, you
are bound by certain restrictions under LGPL. Please be sure
to read and understant the 'LICENSE' file in the PLIB distribution
directory before you distribute any work based around or upon PLIB.
<p>
The PLIB example programs (being complete programs) are licensed
under the GNU General Public License (GPL).
<p>
Each of the demonstration programs has it's own license - but
they are all 'OpenSource' of one kind or another (as defined by
the SourceForge rules for OpenSourced software. Check the
distribution directory for each one for a LICENSE file describing
how it's licensed.
<H2>Polite Request to Distributors.</H2>
If you are a Linux or other OpenSource software distributor,
please do us the courtesy of only releasing stable versions
of PLIB and NOT versions labelled 'unstable' - or (especially)
any snapshot you may take from SVN. We are aware that legally,
you are entitled to do either of these things - but we ask
that you do not because it makes supporting PLIB that much
more difficult.
<p>
We would also appreciate being notified of which versions
you plan to ship - and approximately when so that we may
coordinate with you as to the best version to take.
</TD>
</TR>
</TABLE>
<hr>
<ADDRESS>
<A HREF="http://www.sjbaker.org">
Steve J. Baker.</A>
&lt;<A HREF="mailto:sjbaker1@airmail.net">sjbaker1@airmail.net</A>&gt;
</ADDRESS>
</BODY>
</HTML>

BIN
doc/license.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

BIN
doc/majik3d.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

BIN
doc/marble.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

BIN
doc/mote.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

354
doc/net/index.html Normal file
View File

@@ -0,0 +1,354 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<META http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<META name="keywords" content="NET, PLIB, Pegasus, network, library, portable, games, medusa, client, server, socket, TCP, IP, netAddress, netBuffer, netMessage, netGuid, netSocket, netChannel, netBufferChannel, netChat, netMessageChannel, netMonitorServer">
<META name="description" content="The Pegasus Network Library is C++ library for making networked games. Pegasus is based on Medusa and it is a part of PLIB. Pegasus, like Medusa, multiplexes I/O with its various client and server connections within a single process/thread. Pegasus is supported on many platforms, including Win32, Linux, and a majority of Unix implementations.">
<TITLE>Pegasus Network Library</TITLE>
</HEAD>
<BODY text="#B5A642" link="#8FFF8F" vlink="#18A515" alink="#20336B"
bgcolor="#005000" background="../marble.png">
<center>
<H1>Pegasus Network Library</H1>
</center>
<H2>Introduction</H2>
Pegasus is a C++ library for making networked games. Pegasus is based on
<a href="http://www.nightmare.com/medusa/medusa.html">Medusa</a>
and is part of <A HREF="../index.html">PLIB</A>.
Pegasus, like Medusa, runs as a single process, multiplexing I/O with its various
client and server connections within a single process/thread. Pegasus is supported
on any platform that includes a socket implementation with the select() function.
This includes Win32, Linux, and a majority of Unix implementations.
<p>
This document assumes a certain degree of knowledge of
TCP/IP and socket programming.
<p>
To use the NET library, you'll need to '#include <plib/net.h>' and
link to libplibnet.a
<H2>Symbol Conventions.</H2>
Pegasus follows the same conventions for symbols and tokens that
are used by OpenGL and GLUT. All Pegasus symbols for classes and
functions start with <code>net</code> and all <code>#define</code>
tokens start with <code>NET</code>. 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 NET call in any program must always be netInit().
<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 netAddress
class netBuffer
|__ class netMessage
class netGuid
class netSocket
|__ class netChannel
|__ class netBufferChannel
| |__ class netChat
| |__ class netMessageChannel
|
|__ class netMonitorServer
</pre>
<H2><code>class netBuffer</code></h2>
A simple buffer class.
<pre>
class netBuffer
{
public:
netBuffer ( int max_length ) ;
~netBuffer () ;
int getLength() const ;
int getMaxLength() const ;
char* getData() ;
void remove () ;
void remove (int pos, int n) ;
bool append (const char* s, int n) ;
bool append (int n) ;
} ;
</pre>
<H2><code>class netMessage</code></h2>
A message buffer used to transfer binary data and handle byte swapping.
<pre>
class netMessage : public netBuffer
{
public:
netMessage ( const char* s, int n ) ;
netMessage ( int type, int to_id, int from_id ) ;
int getType () const ;
int getToID () const ;
int getFromID () const ;
void geta ( void* a, int n ) const ; // a=array; array should already be serialized
void puta ( const void* a, int n ) ;
int getch () const ;
void putch ( int c ) ;
bool getb () const ;
void putb ( bool b ) ;
int getw () const ;
void putw ( int i ) ;
int geti () const ;
void puti ( int i ) ;
void gets ( char* s, int n ) const ;
void puts ( const char* s ) ;
void print ( FILE *fd = stderr ) const ;
};
</pre>
<H2><code>class netAddress</code></h2>
This is the representation of an Internet-style machine address.
<pre>
class netAddress
{
public:
netAddress () ;
netAddress ( const char* host, int port ) ;
void set ( const char* host, int port ) ;
const char* getHost () const ;
int getPort () const ;
static const char* getLocalHost () ;
bool getBroadcast () const ;
} ;
</pre>
When reading from the network using one of the higher level classes,
you can use a netAddress with an empty string as the 'host' to mean
"accept data from any host". When writing to the network, the
reserved host name '&lt;broadcast&gt;' (the &lt; and &gt; are literally
there) will cause the message to be broadcast to all machines on your
subnet.
<p>
Otherwise, use either the machines' network name - or it's IP address
(as an ASCII string).
<H2><code>class netSocket</code></h2>
netSocket is the low-level socket class.
<pre>
class netSocket
{
public:
netSocket () ;
virtual ~netSocket () ;
int getHandle () const ;
void setHandle (int handle) ;
bool open ( bool stream=true ) ;
int bind ( cchar* host, int port ) ;
int listen ( int backlog ) ;
int accept ( netAddress* addr ) ;
int connect ( cchar* host, int port ) ;
int send ( const void * buffer, int size, int flags = 0 ) ;
int sendto ( const void * buffer, int size, int flags, const netAddress* to ) ;
int recv ( void * buffer, int size, int flags = 0 ) ;
int recvfrom ( void * buffer, int size, int flags, netAddress* from ) ;
void close ( void ) ;
void setBlocking ( bool blocking ) ;
} ;
</pre>
<H3>Example:</H3>
This example is stripped of error checking for clarity:
<TABLE>
<TR>
<TD>
<H4>Sender:</H4>
<pre>
netInit () ;
netSocket *sock = new netSocket () ;
sock -> open ( false ) ;
sock -> setBlocking ( false ) ;
sock -> connect ( host, port ) ;
while ( !done )
sock -> send ( msg, len, 0 );
sock -> close () ;
</pre>
</TD>
<TD>
<H4>Reciever:</H4>
<pre>
netInit () ;
netSocket *sock = new netSocket () ;
sock -> open ( false ) ;
sock -> setBlocking ( false ) ;
sock -> bind ( host, port ) ;
while ( !done )
if ( (len = sock -> recv(msg, maxlen, 0)) >= 0 )
...use the data...
sock -> close () ;
</pre>
</TD>
</TR>
</TABLE>
This code produces a 'Datagram' connection - which is fast but unreliable
(using UDP protocol). Passing a 'true' to sock->open() would produce a
'Stream' connection (using TCP).
<H2><code>class netChannel</code></h2>
netChannel adds event-handling to the low-level
netSocket class. Otherwise, it can be treated as
a normal non-blocking socket object.
The direct interface between the poll loop and
the channel object are the handleReadEvent and
handleWriteEvent methods. These are called
whenever a channel object 'fires' that event.
The firing of these low-level events can tell us whether
certain higher-level events have taken place, depending on
the timing and state of the connection.
<pre>
class netChannel : public netSocket
{
public:
netChannel () ;
virtual ~netChannel () ;
void setHandle (int s, bool is_connected = true);
bool isConnected () const ;
bool isClosed () const ;
void shouldDelete () ;
// --------------------------------------------------
// socket methods
// --------------------------------------------------
bool open ( bool stream=true ) ;
int listen ( int backlog ) ;
int connect ( cchar* host, int port ) ;
int send ( const void * buf, int size, int flags = 0 ) ;
int recv ( void * buf, int size, int flags = 0 ) ;
void close ( void ) ;
// poll() eligibility predicates
virtual bool readable (void) ;
virtual bool writable (void) ;
// --------------------------------------------------
// event handlers
// --------------------------------------------------
void handleReadEvent (void);
void handleWriteEvent (void);
// These are meant to be overridden.
virtual void handleConnect (void) ;
virtual void handleRead (void) ;
virtual void handleWrite (void) ;
virtual void handleClose (void) ;
virtual void handleAccept (void) ;
virtual void handleError (int error) ;
static bool poll (u32 timeout = 0 ) ;
static void loop (u32 timeout = 0 ) ;
};
</pre>
<H2><code>class netBufferChannel</code></h2>
netBufferChannel is a netChannel with I/O buffering.
Clients and servers built on top of netBufferChannel
automatically support pipelining where you can send
multiple commands without waiting for the response
to each command before you send the next.
<pre>
class netBufferChannel : public netChannel
{
public:
netBufferChannel (int in_buffer_size = 512, int out_buffer_size = 4096) ;
void closeWhenDone (void) ;
virtual bool bufferSend (const char* msg, int msg_len) ;
virtual void handleBufferRead (netBuffer& buffer) ;
};
</pre>
<H2><code>class netChat</code></h2>
netChat adds support for 'chat' style protocols -
where one side sends a 'command', and the other sends
a response (examples would be the common internet
protocols - smtp, nntp, ftp, etc..).
<p>
The handle_buffer_read() method looks at the input
stream for the current 'terminator' (usually '\r\n'
for single-line responses, '\r\n.\r\n' for multi-line
<pre>
class netChat : public netBufferChannel
{
public:
netChat () ;
void setTerminator (const char* t);
const char* getTerminator (void);
bool push (const char* s) ;
virtual void collectIncomingData (const char* s, int n) ;
virtual void foundTerminator (void) ;
};
</pre>
<H2><code>class netMessageChannel</code></h2>
A channel for binary messages. Takes care of packing and unpacking them in/out of the buffers.
<pre>
class netMessageChannel : public netBufferChannel
{
public:
netMessageChannel () ;
bool sendMessage ( const netMessage& msg ) ;
virtual void handleMessage ( const netMessage& msg ) ;
};
</pre>
<H2><code>class netMonitorServer</code></h2>
The monitor server gives you remote, 'back-door' access to your server while it is running. netMonitor is a telnet command port with
password authorization. It can be paired with and used to remotely admin another server.
Once connected via any telnet client to the monitor, you can issue commands. The monitor can be hooked up to a python interpreter for added power. Since an ordinary telnet session is not secure, the password could be intercepted, but that level of security is usually not needed for games.
<pre>
class netMonitorServer : public netChannel
{
public:
netMonitorServer( cchar* _name, int port ) ;
~netMonitorServer() ;
cchar* getPassword () const ;
void setPassword ( cchar* string ) ;
void setPrompt ( cchar* string ) ;
void setCommandFunc ( void (*func)(cchar*, netMonitorChannel*) ) ;
} ;
</pre>
<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://mcdave.cjb.net">
Dave McClurg</A>
&lt;<A HREF="mailto:dpm@efn.org">dpm@efn.org</A>&gt;
</ADDRESS>
</table>
</BODY>
</HTML>

BIN
doc/plib_logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
doc/ppe_logo_1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

430
doc/psl/appl_guide.html Normal file
View File

@@ -0,0 +1,430 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="keywords" content="PSL, PLIB, OpenGL, portable, script, language, Baker, Steve">
<meta name="description" content="The PLIB Scripting Language (PSL) Library is a lightweight scripting language that is well suited for games or other interactive programs.">
<title>The PLIB Scripting Language: Applications Guide.</title>
</head>
<body text="#B5A642" bgcolor="#005000" link="#8FFF8F" vlink="#18A515" alink="#20336B" background="../marble.png">
&nbsp;
<table>
<tr>
<td>
<center>
<h1>The PSL Application Programmer's Guide.</h1></center>
<center>By Steve Baker</center>
</td>
</tr>
</table>
<H1>Introduction</H1>
This document is to help people writing C++ applications to include
scripting abilities using the PSL interpreter.
<p>
To include PSL scripts into your application requires that you:
<pre>
#include &lt;plib/psl.h&gt;
</pre>
...and link with '<code>-lplibpsl</code>'
<p>
Then, sometime before you call any other PSL functions, you must call:
<pre>
pslInit () ;
</pre>
Each PSL script is represented by an object of class <code>pslProgram</code>
<H1>Example Application</H1>
This is the simplest possible PSL application, it
loads a script called "test.psl", compiles and runs it.
<pre>
#include &lt;plib/psl.h&gt;
void main ()
{
pslInit () ;
pslExtension extensions [] = { { NULL, 0, NULL } } ;
pslProgram *prog = new pslProgram ( extensions, "Program1" ) ;
prog -&gt; compile ( "test.psl" ) ;
while ( prog -&gt; step () != PSL_PROGRAM_END ) /* Nothing */ ;
}
</pre>
Here is a line-by-line explanation:
<p>
<center>
<TABLE border="1">
<tr><td><code> pslInit () ;</code></td><td>
Initialise PSL - this must be the first thing you do.</td></tr>
<tr><td><code> pslExtension extensions [] ...</code></td><td>
Make a list of PSL extension functions.<br>
This program doesn't have any. </td></tr>
<tr><td><code> pslProgram *prog = new pslProgram...</code> </td><td>
Declare a program (called "MyProgram").</td></tr>
<tr><td><code> prog -&gt; compile ( "test.psl" ) ;</code></td><td>
Compile the program to bytecode.</td></tr>
<tr><td><code> while ( prog -&gt; step () != PSL_PROGRAM_END )...</code>
</td><td>
Tell the PSL program to execute one 'step'
<br>Keep doing that until we reach the end of the program.
</td></tr>
</TABLE>
</center>
<p>
Easy!
<p>
Now let's look at <code>class pslProgram</code> in more detail.
<H1><code>class pslProgram</code></H1>
Each PSL script is represented by an object of class <code>pslProgram</code>.
<pre>
class pslProgram
{
public:
pslProgram ( const pslExtension *extns, const char *name ) ;
pslProgram ( pslProgram *prog, const char *name ) ;
void setUserData ( void *data ) ;
void *getUserData () const ;
void setProgName ( const char *name ) ;
char *getProgName () const ;
void dump () const ;
void reset () ;
pslResult step () ;
pslResult trace () ;
int compile ( const char *memptr, const char *fname ) ;
int compile ( const char *fname ) ;
int compile ( FILE *fd ) ;
} ;
</pre>
<H1><code>pslProgram::pslProgram</code></H1>
There are two constructor functions to choose from. The first
takes an array of 'extension functions' and the name by which
this program will be known (for error messages and such). The
second constructor takes an existing, compiled PSL program and
makes a copy of it - it too needs a program name.
<p>
The second version of the constructor is especially efficient
because this enables the script to be compiled just once - and
run multiple times in parallel. The second and subsequent
copies of the program consume much less RAM than the first
copy because they share the 'code' part of the script.
<p>
For example, you can run two copies of a script in parallel
like this:
<pre>
pslInit () ;
pslProgram *prog_1 = new pslProgram ( extensions, "code1" ) ;
prog_1 -&gt; compile ( "data/test.psl" ) ;
pslProgram *prog_2 = new pslProgram ( prog_1, "code2" ) ;
while ( prog_1 -&gt; step () != PSL_PROGRAM_END &&
prog_2 -&gt; step () != PSL_PROGRAM_END )
/* NOTHING */ ;
</pre>
<H1><code>pslProgram::compile</code></H1>
When you compile a PSL program, any errors or warnings are reported
to stderr (by default) and the number of fatal compilation errors
is returned as the result of the 'compile' function. Programs may
choose to ignore any compilation errors - but executing the resulting
program will immediately produce a PSL_PROGRAM_END.
<p>
You can pass to the compiler either:
<ol>
<li> The filename of the file containing the PSL source code...or...
<li> A 'FILE *' descriptor for the file containing the PSL source...or...
<li> The address of a null terminated string containing the
program source PLUS a name to use for the program when reporting
errors, etc.
</ol>
If you pass the filename (1) or the address of the source with a name (3),
then error messages from PSL will refer to that name. But if you pass a
file destriptor then the program name that you passed to the constructor
function will be reported.
<p>
Applications that would like to report scripting errors in a more elegant
way, may register a callback function that will be called whenever there
is a problem within PSL:
<pre>
void pslSetErrorCallback ( void (*CB) ( pslProgram *, int, char *,
int, char * ) ) ;
</pre>
Your function will be called with five parameters:
<pre>
void myErrorCB ( pslProgram *prog, int severity,
char *progname, int lineno, char *message ) ) ;
</pre>
<ul>
<li> The 'prog' parameter is a pointer to the pslProgram that had the
problem.
<li> The 'severity' parameter is the error type and severity:
<ul>
<li> PSL_COMPILETIME_WARNING - A problem was found while
compiling the PSL program - but it may not be serious enough
to prevent it from running.
<li> PSL_COMPILETIME_ERROR - A serious problem was found while
compiling the PSL program - it won't run correctly.
<li> PSL_RUNTIME_WARNING - A problem was found while running
the PSL program - but it wasn't serious enough to prevent
the program from continuing to execute.
<li> PSL_RUNTIME_ERROR - The PSL program 'crashed' while being
executed.
</ul>
<li> The 'progname' parameter is the name of the program.
<li> The 'lineno' parameter is the line number at which the problem
occurred (if compiling) or the byte-code address at which it
failed (if at runtime). The latter isn't much use unless you
are a developer of the PSL interpreter.
<li> The 'message' parameter is the actual text of the error message.
</ul>
Notice that at compiletime, the 'progname' parameter is the name of the
file or string being compiled (if that's known to the compiler). Since it's
possible for one PSL source file to '#include' another, you should
always use the 'progName' parameter in your error messages in preference
to <code>prog-&gt;getProgName()</code> member function.
<H1><code>pslExtension</code></H1>
We have not yet talked about this mysterious 'extensions' array that's passed
into the pslProgram constructor function.
<p>
It's important that your PSL scripts are able to interact with your C++
program - and this is done by creating a number of C++ functions that
can be called by the PSL program as it executes. These are called
'extensions' because they extend the functionality of PSL.
<p>
The extension parameter to the pslProgram constructor is an array of
pslExtension structures:
<pre>
class pslExtension
{
public:
const char *symbol ;
int argc ;
pslValue (*func) ( int, pslValue *, pslProgram *p ) ;
} ;
</pre>
<ul>
<li>The 'symbol' field is the name of the extension function AS IT APPEARS INSIDE
PSL PROGRAMS. This doesn't have to be the same as the actual name of
your C++ function.
<li>The 'argc' field is the number of parameters the function expects. You can
set 'argc' to -1 to allow any number of parameters to be passed - so that you
can create functions that work like 'printf' does.
<li>The 'func' field is a pointer to your C++ function.
</ul>
The list of pslExtensions is terminated by a <code>{ NULL, 0, NULL}</code>
entry.
<p>
The C++ function has to look like this:
<pre>
pslValue my_func ( int argc, pslValue *argv, pslProgram *p )
</pre>
<ul>
<li>The 'argc' parameter to the C++ function is the number of
PSL parameters that were passed to it. It's useful to know this
number when your pslExtension had 'argc' set to -1.
<p>
<li>The 'argv' parameter is an array containing the parameters
that PSL is passing to this function. Each element is a 'pslValue'
class which could contain any of the PSL variable types.
<p>
<li>The 'p' parameter is a pointer to the pslProgram that was
running at the time this function was called. Notice that pslProgram's
can have user data associated with them - so this gives you quite a
bit of scope for accessing script-specific data structures.
<p>
<li>When your script has finished doing it's job, it has to return
some kind of result. This is another one of those 'pslValue'
class objects.
</ul>
<H3>Example Extension Function</H3>
This C++ function prints it's arguments to stdout and returns the
value 123.456.
<pre>
pslValue print ( int argc, pslValue *argv, pslProgram *p )
{
for ( int i = 0 ; i &lt; argc ; i++ )
{
switch ( argv[i].getType () )
{
case PSL_INT : printf ( "%d ", argv[i].getInt () ) ; break ;
case PSL_FLOAT : printf ( "%f ", argv[i].getFloat () ) ; break ;
case PSL_STRING : printf ( "%s ", argv[i].getString () ) ; break ;
case PSL_VOID : printf ( "(void) " ) ; break ;
default : printf ( "Illegal parameter passed to 'print'." ) ; break ;
}
}
pslValue ret ;
ret.set ( 123.456f ) ;
return ret ;
}
</pre>
Adding this to the example program above, requires only that you
change the declaration of 'extensions' as follows:
<pre>
pslExtension extensions [] =
{
{ "print", -1, print },
{ NULL, 0, NULL }
} ;
</pre>
Now, now you can write "Hello World" in PSL script:
<pre>
int main ()
{
print ( "Hello World.\n" ) ;
}
</pre>
...and your C++ function 'print' will be called with one parameter
that'll contain the string value "Hello World.\n".
<H3><code>pslValue</code></H3>
The 'pslValue' class is used to pass numbers into and out of extension
functions. It contains the type and value of a number or string in PSL
and it looks like this:
<pre>
class pslValue
{
public:
pslType getType () const ;
int getInt () const ;
float getFloat () const ;
char *getString () const ;
void set () ;
void set ( int v ) ;
void set ( float v ) ;
void set ( const char *v ) ;
void set ( const pslNumber *v ) ;
} ;
</pre>
Setting <b>nothing</b> into your pslValue ("my_value-&gt;set()") is used to
return a 'void' result from your extension function - that is the default
type for a pslValue.
<p>
The 'getType' call returns the type of this value - currently,
it can be: PSL_INT, PSL_FLOAT, PSL_STRING or PSL_VOID. If you 'set' the
pslValue, it automatically changes it's 'getType' result to match.
<p>
Doing a 'get' for a type that DOESN'T match the 'getType' of the pslValue
causes it to try to convert to that type. However, a 'getString' on a
non-string pslValue will return NULL. Doing a 'getInt' or 'getFloat'
on a PSL_STRING will perform an atoi() or atof() (respectively) in an
attempt to get a number from the string.
<H1>Running, Tracing, Debugging.</H1>
You run the PSL program one byte-code instruction at a time by calling the
<code>pslProgram::step()</code> function. A byte-code
instruction is rather like the 'machine code' of a physical computer and
it typically takes several byte-code instructions to implement each line
of PSL source code.
<p>
The 'step' function returns one of three possible results:
<ul>
<li> PSL_PROGRAM_CONTINUE -- The PSL program is running normally.
<li> PSL_PROGRAM_END -- The PSL program has finished running. This
could be because it simply ended normally - but it could also
be because it 'crashed' with a fatal runtime problem of some kind.
<li> PSL_PROGRAM_PAUSE -- There is a special 'pause' statement in PSL
and when that statement is executed, it causes 'step' to return
this value.
</ul>
The PSL_PROGRAM_PAUSE return is intended to cope with the specific
case when PSL is being used in an interactive graphical application.
Typically, such applications will not want to run PSL scripts to
completion every frame - but instead run them up to the next 'pause'
statement.
<p>
A typical game might have dozens of PSL scripts running in parallel
and wish to run each of them until the script 'pause's.
<p>
So, your application's main loop might look something like this:
<pre>
read_the_joystick () ;
for ( int i = 0 ; i &lt; num_scripts ; i++ )
while ( program [ i ] -&gt; step () == PSL_PROGRAM_CONTINUE )
/* Do Nothing */ ;
render_the_graphics () ;
swap_the_doublebuffer () ;
</pre>
Then, one of those scripts (to move a monster for example)
might look like this:
<pre>
int main ()
{
int i = getMyMonster () ;
while ( 1 )
{
moveMonster ( i ) ;
pause ;
}
}
</pre>
The 'pause' command indicates that this script has completed it's
work for this frame.
<p>
Alternatively, some applications may wish to run the scripts for
fixed amounts of time, fixed numbers of byte-codes - or until
some other criterion is satisfied.
<H3> Resetting a Script </H3>
There is a <code>pslProgram::reset()</code> function that
restarts the PSL program from the beginning having first
reset all of its internal variables.
<H3> Debugging PSL scripts </H3>
For debugging PSL scripts, you may replace the 'step' call with
'trace' - which causes the byte-code for each instruction to be
printed to stderr as it's executed.
<p>
You can also call <code>pslProgram::dump()</code> to print out
all of the byte-code and the PSL symbol table for the program.
<H3> Include paths. </H3>
By default, PSL searches for files with relative pathnames in
the current directory - but you can override this by setting:
<pre>
pslScriptPath ( "directory" ) ;
</pre>
<hr>
<address>
<a href="http://www.sjbaker.org">Steve J. Baker.</a> &lt;<a href="mailto:sjbaker1@airmail.net">sjbaker1@airmail.net</a>&gt;</address>
</body>
</html>

463
doc/psl/impl_guide.html Normal file
View File

@@ -0,0 +1,463 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="keywords" content="PSL, PLIB, OpenGL, portable, script, language, Baker, Steve">
<meta name="description" content="The PLIB Scripting Language (PSL) Library is a lightweight scripting language that is well suited for games or other interactive programs.">
<title>The PLIB Scripting Language: Implementation Guide.</title>
</head>
<body text="#B5A642" bgcolor="#005000" link="#8FFF8F" vlink="#18A515" alink="#20336B" background="../marble.png">
&nbsp;
<table>
<tr>
<td>
<center>
<h1>The PSL Implementation Guide.</h1></center>
<center>By Steve Baker</center>
</td>
</tr>
</table>
<H1>Introduction</H1>
This document describes the virtual machine that the PSL byte code
interpreter implements.
<p>
The machine has 65536 bytes of instruction memory (and hence, 16 bit
code addresses) and 256 variables (and hence 8 bit data addresses).
Each variable can be a 32 bit integer, an IEEE single precision float
or a character string of arbitary length.
<p>
In addition, there is a 256 element stack - each entry of which can
contain any PSL data type.
<p>
The machine has just two registers - the Program Counter (PC) and
the Stack Pointer (SP) - neither of which are accessible to running
programs directly.
<H1>The Instruction Set</H1>
Each instruction consists of a one byte opcode and some number of
bytes of data.
<p>
The hex numbers for these opcodes are listed in plib/src/psl/pslOpcodes.h
<p>
<H3> OPCODE_BAD </H3>
INTRUCTION BYTES: 1<br>
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> Produces a 'Suspicious Opcode' error message and halts the program.<br>
Generally, programs
that run amok for some reason (eg an error in the compiler) will
hit a zero byte fairly soon afterwards. Hence instruction 0x00
is reserved to be the BAD instruction. Other unrecognised
instructions are also flagged as errors - but it's useful to
explicitly reserve opcode 0x00 for this function due to the
high probability of it being executed by broken programs.</td>
</tr>
</table>
<H3> OPCODE_LINE_NUMBER </H3>
INTRUCTION BYTES: 3
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> Updates the 'current line number' from the two bytes
embedded in the instruction.</td>
</tr>
</table>
<H3> OPCODE_PUSH_INT_CONSTANT </H3>
INTRUCTION BYTES: 5
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> Takes four bytes from the instruction and pushes them
onto the stack as an integer.</td>
</tr>
</table>
<H3> OPCODE_PUSH_FLOAT_CONSTANT </H3>
INTRUCTION BYTES: 5
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> Takes four bytes from the instruction and pushes them
onto the stack as a float.</td>
</tr>
</table>
<H3> OPCODE_PUSH_STRING_CONSTANT </H3>
INTRUCTION BYTES: 1 + strlen string + 1
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> Takes a null-terminated string from the instruction
stream and pushes it onto the stack.</td>
</tr>
</table>
<H3> OPCODE_GET_PARAMETER </H3>
INTRUCTION BYTES: 3
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> Fetches the value of a function's parameter from the
depths of the stack and puts it into a local variable.
<p>
The second byte of the instruction is the
index of the variable. The third byte is a small
integer offset - which is the number of the parameter
you want.
<p>
Look at the number two down from the top of the stack
(which should be
the number of parameters of a recently called
function).
<p>
Now copy the stack element at
<code> sp - ( nargs + 2 ) + offset </code>
into the variable.</td>
</tr>
</table>
<H3> OPCODE_POP </H3>
INTRUCTION BYTES: 1
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> Throws away the top element of the stack.</td>
</tr>
</table>
<H3> OPCODE_CALLEXT </H3>
INTRUCTION BYTES: 3
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> The second byte of the instruction is the index of
a PSL 'extension function', the third
is the number of arguments being passed to it.
<p>
Pop that number of values off the stack and pass them
to the extension function.
<p>
Call the extension function.
Push the result onto the stack.</td>
</tr>
</table>
<H3> OPCODE_CALL </H3>
INTRUCTION BYTES: 6
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> [The number of aguments will already have been pushed
onto the stack.]
<p>
The four bytes after the instruction is the function address.
The fifth byte is the number of arguments.
<p>
Push return address.<br>
PC = address of function.
<p>
popNumber ( &amp;result ) ;<br>
&nbsp;&nbsp;&nbsp;pc = popInt () ;<br>
&nbsp;&nbsp;&nbsp;nargs = popInt () ;<br>
&nbsp;&nbsp;&nbsp;popVoid ( nargs ) ;<br>
pushNumber ( &amp;result ) ;</td>
</tr>
</table>
<H3> OPCODE_STACK_DUPLICATE </H3>
INTRUCTION BYTES: 1
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> Duplicate the top element of the stack.</td>
</tr>
</table>
<H3> OPCODE_EXCHANGE </H3>
INTRUCTION BYTES: 1
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> Exchange the top two elements of the stack.</td>
</tr>
</table>
<H3> OPCODE_LESS </H3>
<H3> OPCODE_LESSEQUAL </H3>
<H3> OPCODE_GREATER </H3>
<H3> OPCODE_GREATEREQUAL </H3>
<H3> OPCODE_NOTEQUAL </H3>
<H3> OPCODE_EQUAL </H3>
<H3> OPCODE_ADD </H3>
<H3> OPCODE_SUB </H3>
<H3> OPCODE_SHIFTLEFT </H3>
<H3> OPCODE_SHIFTRIGHT </H3>
<H3> OPCODE_OROR </H3>
<H3> OPCODE_ANDAND </H3>
<H3> OPCODE_OR </H3>
<H3> OPCODE_AND </H3>
<H3> OPCODE_XOR </H3>
<H3> OPCODE_DIV </H3>
<H3> OPCODE_MOD </H3>
<H3> OPCODE_MULT </H3>
INTRUCTION BYTES: 1
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> Pop the top element from the stack and operate on it
and the next element down - leaving the result on
the stack in it's place. So (for example) if the
operation was 'SUB' (Subtract), and A is on top of
the stack and B is beneath it - then the result of
this operation would be to leave (B-A) on the stack
with no sign of either A or B.
<p>
The 'ADD' operator also works with strings by concatenating
them.</td>
</tr>
</table>
<H3> OPCODE_NOT </H3>
<H3> OPCODE_TWIDDLE </H3>
<H3> OPCODE_NEG </H3>
INTRUCTION BYTES: 1
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> Perform the C unary '!', '~' or '-' operator on the top
element of the stack.</td>
</tr>
</table>
<H3> OPCODE_PAUSE </H3>
INTRUCTION BYTES: 1
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> Informs application program that the script wishes
to be paused until next frame.</td>
</tr>
</table>
<H3> OPCODE_HALT </H3>
INTRUCTION BYTES: 1
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> Informs the application that the script wishes to halt.
Even if the application ignores this request, the script
will continue looping at this location for ever.</td>
</tr>
</table>
<H3> OPCODE_PEEK_JUMP_TRUE </H3>
<H3> OPCODE_PEEK_JUMP_FALSE </H3>
INTRUCTION BYTES: 3
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> The two bytes at the end of the instruction contain
an address. Inspect the number off the top of the stack
(without popping it) - and branch to the specified
instruction if the value is TRUE (or FALSE as applicable).</td>
</tr>
</table>
<H3> OPCODE_JUMP_TRUE </H3>
<H3> OPCODE_JUMP_FALSE </H3>
INTRUCTION BYTES: 3
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> The two bytes at the end of the instruction contain
an address. POP the number off the top of the stack
(without popping it) - and branch to the specified
instruction if the value is TRUE (or FALSE as applicable).</td>
</tr>
</table>
<H3> OPCODE_JUMP </H3>
INTRUCTION BYTES: 3
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> The two bytes at the end of the instruction contain
an address. Jump to that address.</td>
</tr>
</table>
<H3> OPCODE_PUSH_VARIABLE </H3>
INTRUCTION BYTES: 2
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> The second byte of the instruction is the index of
a variable. The value of that variable is pushed onto
the stack.</td>
</tr>
</table>
<H3> OPCODE_POP_ADD_VARIABLE </H3>
<H3> OPCODE_POP_SUB_VARIABLE </H3>
<H3> OPCODE_POP_MUL_VARIABLE </H3>
<H3> OPCODE_POP_MOD_VARIABLE </H3>
<H3> OPCODE_POP_DIV_VARIABLE </H3>
<H3> OPCODE_POP_AND_VARIABLE </H3>
<H3> OPCODE_POP_OR_VARIABLE </H3>
<H3> OPCODE_POP_XOR_VARIABLE </H3>
<H3> OPCODE_POP_SHL_VARIABLE </H3>
<H3> OPCODE_POP_SHR_VARIABLE </H3>
INTRUCTION BYTES: 1
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> Three things are on the stack when this function is called.<br>
The thing on top is the result of an expression evaluation.<br>
The thing beneath that is the index of a variable.<br>
The thing beneath that is the dimension of the variable.<br>
The value is added to/subtracted from/multiplied by/etc
the variable - and stored back into the variable.<br>
The new value of the variable is left on the stack.</td>
</tr>
</table>
<H3> OPCODE_POP_VARIABLE </H3>
INTRUCTION BYTES: 1
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> Three things are on the stack when this function is called.<br>
The thing on top is the result of an expression evaluation.<br>
The thing beneath that is the index of a variable.<br>
The thing beneath that is the dimension of the variable.<br>
The value is stored into the variable.<br>
The new value of the variable is left on the stack.</td>
</tr>
</table>
<H3> OPCODE_SET_INT_ARRAY </H3>
<H3> OPCODE_SET_FLOAT_ARRAY </H3>
<H3> OPCODE_SET_STRING_ARRAY </H3>
INTRUCTION BYTES: 2
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> The second byte of the instruction is the index of an array
variable.<br>
On the top of the stack is an integer.<br>
This instruction allocates that number of elements of storage to
the array.</td>
</tr>
</table>
<H3> OPCODE_SET_INT_VARIABLE </H3>
<H3> OPCODE_SET_FLOAT_VARIABLE </H3>
<H3> OPCODE_SET_STRING_VARIABLE </H3>
INTRUCTION BYTES: 2
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> The second byte of the instruction is the index of a variable.<br>
That variable is created, set to the appropriate type and
initialised appropriately.</td>
</tr>
</table>
<H3> OPCODE_FETCH </H3>
INTRUCTION BYTES: 1
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> The index of a variable is on top of the stack.<br>
The thing beneath that is the dimension of the variable.<br>
Replace those with the value of that variable.</td>
</tr>
</table>
<H3> OPCODE_INCREMENT_FETCH </H3>
<H3> OPCODE_DECREMENT_FETCH </H3>
INTRUCTION BYTES: 1
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> The index of a variable is on top of the stack.<br>
The thing beneath that is the dimension of the variable.<br>
Replace those
with the value of that variable. Post-increment/decrement the
variable.</td>
</tr>
</table>
<H3> OPCODE_INCREMENT_LVALUE </H3>
<H3> OPCODE_DECREMENT_LVALUE </H3>
INTRUCTION BYTES: 1
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> The index and dimension of a variable is on top of the stack.<br>
Increment/decrement the variable leaving the stack
contents undisturbed.</td>
</tr>
</table>
<hr>
<address>
<a href="http://www.sjbaker.org">Steve J. Baker.</a> &lt;<a href="mailto:sjbaker1@airmail.net">sjbaker1@airmail.net</a>&gt;</address>
</body>
</html>

55
doc/psl/index.html Normal file
View File

@@ -0,0 +1,55 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="keywords" content="PSL, PLIB, OpenGL, portable, script, language, Baker, Steve">
<meta name="description" content="The PLIB Scripting Language (PSL) Library is a lightweight scripting language that is well suited for games or other interactive programs.">
<title>The PLIB Scripting Language.</title>
</head>
<body text="#B5A642" bgcolor="#005000" link="#8FFF8F" vlink="#18A515" alink="#20336B" background="../marble.png">
&nbsp;
<table>
<tr>
<td>
<center>
<h1>PSL: PLIB's Scripting Language.</h1></center>
<center>By Steve Baker</center>
</td>
</tr>
</table>
<H1>Introduction</H1>
Whilst applications can use any suitable scripting
language (Python, PERL, Lua, etc) in conjunction with PLIB, there are
attractions to using PLIB's own scripting language: PSL.
<p>
In particular, in using PSL, you do not add any dependancies on
your application. If the end user has the correct version of PLIB
installed - then the scripting language is already there - for sure.
<p>
PSL is a very light-weight C-like language with some features borrowed
from C++. It's also 'stackless' and very friendly to games applications.
<p>
There are two PSL documents:
<ul>
<li><a href="appl_guide.html">The PSL-enabled Applications Guide.</a>
-- If you are planning on including a PSL interpreter into your program,
(making it 'PSL-enabled') then you should read the Applications Guide.
<li><a href="prog_guide.html">The PSL Programmers Guide.</a>
-- If you are writing scripts for a PSL-enabled application, then you'll
only need to read the Programmer's Guide.
<li><a href="impl_guide.html">The PSL Implementation Guide.</a>
-- Explains some of PSL's internals, especially, the byte-code
virtual machine.
</ul>
<p>
Each application can extend PSL by providing additional built-in
functions - so if you are a PSL programer then you'll probably need to
read the documentation for whatever PSL-enabled application
you are writing for. If you are writing a PSL-enabled application, then
you'd better sit down and WRITE that document!
<hr>
<address>
<a href="http://www.sjbaker.org">Steve J. Baker.</a> &lt;<a href="mailto:sjbaker1@airmail.net">sjbaker1@airmail.net</a>&gt;</address>
</body>
</html>

209
doc/psl/prog_guide.html Normal file
View File

@@ -0,0 +1,209 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="keywords" content="PSL, PLIB, OpenGL, portable, script, language, Baker, Steve">
<meta name="description" content="The PLIB Scripting Language (PSL) Library is a lightweight scripting language that is well suited for games or other interactive programs.">
<title>The PLIB Scripting Language: Programming Guide.</title>
</head>
<body text="#B5A642" bgcolor="#005000" link="#8FFF8F" vlink="#18A515" alink="#20336B" background="../marble.png">
&nbsp;
<table>
<tr>
<td>
<center>
<h1>The PLIB Scripting Language Programming Guide </h1></center>
<center>By Steve Baker</center>
</td>
</tr>
</table>
<H1>Introduction</H1>
This document explains how to write PSL programs.
<p>
How you actually run those programs depends on which PSL-enabled
application you are running. There is a stand-alone PSL interpreter
in plib/examples/src/psl/psl_demo - but it doesn't include any
application-specific language extensions - so a PSL program
that's written for a specific application may not run
on <code>psl_demo</code>.
<p>
However, psl_demo is great for learning to write PSL scripts.
<H1>The PSL Language</H1>
PSL is designed to be as close to the C Programming
Language - although we
cut a few corners - we extended the language in a few places - and
we consciously omitted other features that are dangerous in a
scripting language.
<p>
The following C features are implemented much as you'd expect:
<ul>
<li> Types 'void', 'int' and 'float' (and arrays of those things).
<li> Function definitions.
<li> Global variable definitions.
<li> Statement types:
<ul>
<li> Local variable definitions.
<li> Static variable definitions.
<li> "return"
<li> "break"
<li> "continue"
<li> "for"
<li> "do/while"
<li> "switch/case/default"
<li> "while"
<li> "if"
<li> "if/else"
<li> "{}" compound statements.
<li> Assignment statements.
<li> Procedure calls.
</ul>
<li> Most Arithmetic operators.
<li> Comments '/*' '*/'.
<li> C preprocessor directives:
<ul>
<li> "#include"
<li> "#define" without parameters.
<li> "#undef"
<li> "#ifdef/#endif"
<li> "#ifdef/#else/#endif"
<li> "#ifndef/#endif"
<li> "#ifndef/#else/#endif"
</ul>
<li> Special characters in strings:
<ul>
<li> "\n"
<li> "\r"
<li> "\a"
<li> "\b"
<li> "\f"
<li> "\t"
<li> "\\"
<li> "\""
</ul>
<li> Recursion, etc.
</ul>
Some new features have been added that are not part of C:
<ul>
<li> "pause" -- Pause the program until next frame.
<li> "string" data type (and arrays of strings).
<li> Casts are unnecessary between compatible types.
<li> C++ style '//' comments.
<li> C++ style local variable declarations.
</ul>
Some features of C are NOT IMPLEMENTED in PSL:
<ul>
<li> Pointers.
<li> Casts.
<li> Dynamic Memory Allocation.
<li> ',' and '?:' operators in expressions.
<li> "static", "auto" and "register" storage class reserved words.
<li> "char", "short", "unsigned", "signed", "long", "double".
<li> "typedef"
<li> "enum", "union", bitfields.
<li> "goto".
<li> "#if"
<li> "#pragma"
<li> "#define" with parameters.
<li> 'f' and 'l' suffixes for float and long numbers.
<li> All preprocessor directives must have the '#' as the
very first character on the line - they cannot be
preceded with whitespace.
</ul>
The following features are "NOT IMPLEMENTED YET" - but will
hopefully arrive soon:
<ul>
<li> Multiple variable definitions like 'int i, j, k ;'
<li> Structs.
<li> '\' to escape the end-of-line character in strings and macro's.
<li> Parameter passing by name.
<li> Many of C's standard library functions are needed.
</ul>
<H1> Compatibility Notes: </H1>
<H3> C++ style local variables. </H3>
With PSL's C++ style locals, you can say things like this:
<pre>
for ( int i = 0 ; i < 10 ; i++ ) /* Do something */ ;
</pre>
In standard C++, the scope of the variable 'i' is from it's
declaration to the end of the 'for' loop. However, Microsoft's
Visual C++ uses an obsolete version of the C++ standard that
allows the scope of 'i' to continue to the end of the block
that contains the for loop. So:
<p>
WINDOWS USERS BEWARE: PSL IMPLEMENTS THIS CORRECTLY - *NOT* LIKE
MSVC.
<H1>Hard Limits</H1>
Currently there are hard limits in many places - the number of
variables, the size of the program, the depth of nesting, etc.
These limits will gradually be removed as PSL is developed.
<H1>Debugging PSL Programs</H1>
Specific PSL-enabled applications may have their own
special features to assist with debugging - but all
PSL-enabled applications support several 'shell variables'
that enable certain debugging features.
<p>
When using a command line shell, you can set these
variables using one of the following commands before
you run your application:
<pre>
setenv VARIABLE value -- csh or tcsh
export VARIABLE=value -- bash or sh
set VARIABLE=value -- DOS shell
</pre>
<H3> Byte-Code Dump </H3>
It's possible to view the byte code that PSL generated
by setting the shell variable 'PSL_DUMP' to either:
<ul>
<li> <b>never</b> (the default) -- Never produce a dump unless
the application demands it.
<li> <b>on_error</b> -- Produce a dump whenever the PSL program
fails to compile for whatever reason.
<li> <b>always</b> -- Always produce a dump after the PSL program
finishes compiling.
</ul>
<H3> Byte-Code Execution Trace </H3>
It's possible to view the byte code as it's executed
by setting the shell variable 'PSL_TRACE' to either:
<ul>
<li> <b>never</b> (the default) -- Never produce a trace unless
the application demands it.
<li> <b>always</b> -- Always produce a trace.
</ul>
When the execution trace is enabled, extra instructions will be
inserted into the byte code to enable the PSL interpreter to
produce debug indicating which lines of the source code are
being traced.
<H3> Byte-Code Stack Display </H3>
If you have PSL_TRACE turned on (either via the config variable or
by the application program), then the shell variable 'PSL_STACK'
can be set to display the contents of the top eight stack locations
as the program is traced. If PSL_TRACE is disabled then PSL_STACK
has no effect.
<ul>
<li> <b>never</b> (the default) -- Never produce stack dumps
within a trace.
<li> <b>always</b> -- Always produce a stack dump within trace.
</ul>
<hr>
<address>
<a href="http://www.sjbaker.org">Steve J. Baker.</a> &lt;<a href="mailto:sjbaker1@airmail.net">sjbaker1@airmail.net</a>&gt;</address>
</body>
</html>

BIN
doc/puAux.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

54
doc/puAux/index.html Normal file
View File

@@ -0,0 +1,54 @@
<!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>SSG Auxiliary Libraries.</TITLE>
</HEAD>
<BODY text="#B5A642" link="#8FFF8F" vlink="#18A515" alink="#20336B"
bgcolor="#005000" background="../marble.png">
<TABLE>
<TR>
<TD>
<H1>PUI Auxiliary Libraries.</H1>
</TD>
</TR>
<TR>
<TD>
by Steve Baker
</TD>
</TR>
</TABLE>
<H2>Introduction</H2>
<TABLE>
<TR>
<TD>
PLIB/puAux is a suite of auxiliary libraries that build
higher level classes on top of the basic PUI classes.
<p>
</TD>
</TR>
</TABLE>
<p>
<H2>Conventions</H2>
puAux is installed and named with the same
conventions as the base PLIB libraries.
<br>
ie:
<pre>
/usr/include/plib/puAux.h
/usr/lib/libplibpuaux.a
</pre>
<p>
PLIB/puAux functions, classes and constants are all
named with an 'pua' or 'PUA' prefix.
<br>
<ADDRESS>
<A HREF="http://www.sjbaker.org">
Steve J. Baker.</A>
&lt;<A HREF="mailto:sjbaker1@airmail.net">sjbaker1@airmail.net</A>&gt;
</ADDRESS>
</table>
</BODY>
</HTML>

636
doc/pui/BasicPUI.html Normal file
View File

@@ -0,0 +1,636 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="Author" content="John F. Fay">
<meta name="GENERATOR" content="Mozilla/4.75 [en] (Win98; U) [Netscape]">
<meta name="keywords" content="PUI, PLIB, OpenGL, UI, user, interface, library, portable, picoscopic, widget, GUI, fast, GLUT, introduction, callback, puButton, puButtonBox, puFrame, puInput, puMenuBar, puOneShot, puText, puInit">
<meta name="description" content="The PLIB Picoscopic User Interface (PUI) Library is designed to be a simple, easy-to-use graphical user interface. It is based on the OpenGL graphics language and requires a windowing system, either the OpenGL Utility Toolkit (GLUT) or another similar one. This document's purpose is to provide an introduction to the basics of PUI.">
<title>BasicPUI</title>
</head>
<body>
<center>
<h1>
Introduction to Using the Picoscopic User Interface</h1></center>
<center>
<h1>
John F. Fay</h1></center>
<center>
<h1>October 18, 2000</h1>
(Updated by <a href="mailto:ude@handshake.de">Sebastian Ude</a> on October 02, 2001)
</center>
<h2>
Contents</h2>
<table>
<tr>
<td>1.</td>
<td><a href="#Introduction: Graphical User Interfaces and">Introduction:&nbsp;
Graphical User Interfaces and Windowed Programs</a></td>
</tr>
<tr>
<td>2.</td>
<td><a href="#Elementary PUI">Elementary PUI</a></td>
</tr>
<tr><td></td>
<td>2.1 <a href="#Creating User Interface Widgets">Creating User Interface
Widgets</a></td>
</tr>
<tr><td></td>
<td>2.2 <a href="#Invoking PUI">Invoking PUI</a></td>
</tr>
<tr><td></td>
<td>2.3 <a href="#Widget Callbacks">Widget Callbacks</a></td>
</tr>
<tr>
<td>3.</td>
<td><a href="#Conclusion">Conclusion</a></td>
</tr>
</table>
<h2>
<a NAME="Introduction: Graphical User Interfaces and"></a>1.&nbsp; Introduction:&nbsp;
Graphical User Interfaces and Windowed Programs</h2>
The Picoscopic User Interface (PUI) is designed to be a simple, easy-to-use
graphical user interface.&nbsp; It is based on the OpenGL graphics language
and requires a windowing system, either the OpenGL Utility Toolkit (GLUT)
or another similar one.&nbsp; The gentle reader is assumed either to be
familiar with OpenGL and his windowing system or at least to have their
manuals at hand.
<p>Basic to a GUI is the idea of a widget.&nbsp; A widget is something
that appears on the computer screen and which transfers data from the user
to the program or from the program to the user.&nbsp; The user can activate
a widget by pressing a key, clicking a mouse button, or by using some other
input device.&nbsp; This lets the user send information to the program.&nbsp;
A widget can also display text or a graphic, allowing the program to transfer
information to the user.
<p>A windowing system requires a specific style of program which differs
from a text-based program in several fundamental ways.&nbsp; First, instead
of starting at the beginning of a problem and stopping at the end, a windowed
program starts by creating the windows and then enters an infinite loop
in which it responds to user inputs.&nbsp; Second, instead of having a
self-contained hierarchy of functions which call each other, a windowed
program is controlled by the windowing system which calls functions as
it sees fit.&nbsp; The following diagram shows the structure of a typical
windowed program.
<pre>
+------------------+
| Main Program | The application developer
| Set up window(s) | supplies this.
| and widget(s) |
+------------------+
|
V
+----------------+
| Window Manager | The window manager library
| (like GLUT) | supplies this.
+----------------+
|
+------+--------+---------------+---------------+----&gt; etc.
| | | |
V V V V
+----------+ +----------+ +----------+ +----------+
| Window | | Window | | Window | | Window | The application
| Mouse | | Keyboard | | Idle | | Display | developer
| Callback | | Callback | | Callback | | Callback | supplies these.
+----------+ +----------+ +----------+ +----------+
| | | |
V V V V
+----------+ +----------+ May call +----------+
| PUI | | PUI | PUI functions | PUI | PUI
| Mouse | | Keyboard | for default | Display | supplies
| Function | | Function | behaviors | Function | these.
+----------+ +----------+ +----------+
| |
+-------+-------+
|
+-------+-------+---------------+------&gt; etc.
| | |
V V V
+----------+ +----------+ +----------+
| Widget 1 | | Widget 2 | | Widget 3 | The application developer
| Callback | | Callback | | Callback | supplies these.
+----------+ +----------+ +----------+
</pre>
<p>The functions that the application developer supplies are called "callbacks"
because the windowing system or user interface system "calls back" into
the application.
<p>A windowed program with a user interface, then, consists of a main program
and a set of callbacks.&nbsp; The callbacks may invoke other function in
turn, but these are all arranged in hierarchical trees underneath the callbacks.
<p>A windowed program executes differently from a typical hierarchical
program as well.&nbsp; It begins with the main program setting up the window(s)
and the user interface.&nbsp; The main program then calls the window manager,
which contains an infinite loop and never returns control to the main program.&nbsp;
(GLUT in particular has this behavior; I cannot speak for all window managers.)&nbsp;
When the window manager needs to redraw the display that is shown on the
screen, it calls the application's Window Display Callback.&nbsp; When
the user moves the mouse or clicks a mouse button, the window manager calls
the application's Window Mouse Callback.&nbsp; When the user presses a
key on the keyboard, the window manager calls the application's Window
Keyboard Callback.&nbsp; Other input devices cause the window manager to
call other callbacks in the application.&nbsp; Finally, if the user hasn't
done anything for a while, the window manager will call the application's
Window Idle Callback.
<p>In building a window callback, the application developer must be sure
to call the appropriate PUI functions.&nbsp; The applications's Window
Mouse Callback, for example, must call the PUI mouse function "puMouse"
if the user interface is to process a mouse click.&nbsp; The application's
Window Display Callback, besides rendering any graphics in the window,
must also call the PUI display function "puDisplay" in order to display
the widgets in the user interface.
<p>When the application developer's window callback calls the appropriate
PUI function, PUI determines which (if any) widget the user has just activated
with his mouse, keyboard, or other input device.&nbsp; PUI then calls that
widget's callback function which the application developer must supply
and which provides the actual heart of the interface.&nbsp; The callback
for an input widget will probably read the text that the user has typed
there and pass it on to the application.&nbsp; The callback for a button
widget may turn something in the program on or off.&nbsp; What a callback
does is limited only by the application developer's imagination.
<h2>
<a NAME="Elementary PUI"></a>2.&nbsp; Elementary PUI</h2>
Using the Picoscopic User Interface on an elementary level requires three
things:&nbsp; setting up the user interface widgets, invoking PUI from
the window callbacks, and supplying the widget callbacks.
<p>PUI was written in C++, designed to be invoked from C++ programs.&nbsp;
The following text and examples will assume a program written in C++.
<h3>
<a NAME="Creating User Interface Widgets"></a>2.1 Creating User Interface
Widgets</h3>
Most (or all) widgets have certain properties in common.&nbsp; These are:
<ul>
<li>
position - the x- and y-coordinates, in pixels, of the lower left-hand
corner of the widget relative to the lower left-hand corner of the window</li>
<li>
size - the width and height of the widget, in pixels</li>
<li>
callback - the application program's function which is called when the
widget is activated</li>
<li>
value - a number or character string that is associated with the widget</li>
<li>
label - text that is printed next to the widget</li>
<li>
legend - text that is printed inside the widget (some widgets only)</li>
</ul>
PUI supports other widget properties, but these are enough to allow the
application developer to create a simple user interface.
<p>Each widget in the Picoscopic User Interface is an object in C++.&nbsp;
The application developer creates a widget by defining a variable to point
to the object and creating a new object:
<pre>
puButton *button = new puButton ( 10, 10, 100, 30 ) ;
</pre>
<p>To set the properties of a widget, the application developer calls methods
in the object:
<pre>
button->setPosition ( x, y ) ; // Sets the position of the widget to
(x, y)
button->setSize ( w, h ) ; // Sets the size of the widget to (w, h)
button->setCallback ( widget_cb ) ; // Sets the callback to
"void widget_cb ( puObject *ob )"
button->setLegend ( "Press Me" ) ; // Sets the legend
button->setLabel ( "A Button:" ) ; // Sets the label
button->setLabelPlace ( PUPLACE_LOWER_LEFT ) ; // Makes the label print on the button's
left
</pre>
<p>Other allowed values for the label position are:
<ul>
<li>PUPLACE_ABOVE_LEFT
<li>PUPLACE_ABOVE_RIGHT
<li>PUPLACE_TOP_LEFT
<li>PUPLACE_TOP_CENTERED
<li>PUPLACE_TOP_RIGHT
<li>PUPLACE_UPPER_LEFT
<li>PUPLACE_UPPER_RIGHT
<li>PUPLACE_CENTERED_LEFT
<li>PUPLACE_CENTERED_RIGHT
<li>PUPLACE_LOWER_LEFT
<li>PUPLACE_LOWER_RIGHT (default)
<li>PUPLACE_BOTTOM_LEFT
<li>PUPLACE_BOTTOM_CENTERED
<li>PUPLACE_BOTTOM_RIGHT
<li>PUPLACE_BELOW_LEFT
<li>PUPLACE_BELOW_RIGHT
</ul>
<p>For a detailed description of these have a look at the
<a href="http://plib.sf.net/pui/">PUI Programmers Guide</a>.
<p>All of these calls are optional.&nbsp; If the application developer
does not want to label a widget, he simply does not call "setLabel" or
"setLabelPlace".&nbsp; Similarly, if he has set the widget's position and
size while creating the widget, there is no need to call "setPosition"
or "setSize".
<p>The following subsections describe some of the widget types that PUI
supports.
<h4>
2.1.1 Button</h4>
The button ("puButton") is a rectangle, usually containing a legend, which
is activated when the user clicks the mouse on it.&nbsp; It has two possible
values, off and on; its actual value changes each time the user clicks
on it.
<p>The button has two possible methods of construction:
<ul>
<li>
puButton ( x1, y1, x2, y2 ) - creates a button with lower left-hand coordinates
of (x1, y1) and with upper right-hand coordinates of (x2, y2)</li>
<li>
puButton ( x1, y1, "text" ) - creates a button with lower left-hand coordinates
of (x1, y1) and containing the text "text".&nbsp; The size is set by the
size of the text.</li>
</ul>
<h4>
2.1.2 Button Box</h4>
The button box ("puButtonBox") is a large rectangle containing a set of
buttons, each with text next to it, which the user can select.&nbsp; It
is sometimes called a radio button.&nbsp; It is created by creating a null-terminated
list of labels and then by calling the constructor function:
<pre>
char **labels = { "Label1", "Label2", "This is Label3", "Four", NULL } ;
puButtonBox my_box = new puButtonBox ( x1, x2, y1, y2, labels, &lt;0|1&gt; ) ;
</pre>
<p>This creates a button box with lower left-hand coordinates of (x1, y1)
and upper right-hand coordinates (x2, y2).&nbsp; The number of buttons
is specified by the number of entries in the "labels" array; each string
before the NULL gets a button.&nbsp; The final argument in the constructor
specifies whether the user can select multiple buttons (0) or whether selecting
a new button will deactivate the previously-selected button (1).
<p>The button box should not be given a legend.
<h4>
2.1.3 Frame</h4>
The frame ("puFrame") is a rectangular area that provides a background
for other widgets.&nbsp; It should be defined before any other widgets
that go inside it or else it will cover them up.&nbsp; It is constructed
by the following function call:
<ul>
<li>
puFrame ( x1, y1, x2, y2 ) - creates a frame with lower left-hand coordinates
of (x1, y1) and with upper right-hand coordinates of (x2, y2)</li>
</ul>
The frame should not be given a legend.&nbsp; It does not support a callback
either.
<h4>
2.1.4 Input Box</h4>
The input box ("puInput") is a rectangular area into which the user can
type text.&nbsp; The user must first click the mouse inside the area and
then type the text.&nbsp; He concludes by pressing &lt;Enter&gt; or &lt;Tab&gt;
or by clicking the mouse outside the input box.
<p>An input box is constructed by the following function call:
<ul>
<li>
puInput ( x1, y1, x2, y2 ) - creates an input box with lower left-hand
coordinates of (x1, y1) and with upper right-hand coordinates of (x2, y2)</li>
</ul>
The input box should not be given a legend.
<h4>
2.1.5 Menu Bar</h4>
The menu bar ("puMenuBar") is easily the most complicated widget written
up here.&nbsp; It consists of a horizontal bar containing buttons which
the user can click on.&nbsp; The bar is always situated on the left-hand
edge of the window and is usually in the upper left-hand corner.&nbsp;
It is constructed by the following function call:
<br>
<ul>
<li>
puMenuBar *menu = puMenuBar ( y ) - creates a menu bar with the lower left-hand
corner "y" pixels above the lower left-hand corner of the window.&nbsp;
A value of -1 for "y" will put the menu bar in the upper left-hand corner
of the window.</li>
</ul>
<p><br>Once the menu bar has been constructed, it must be loaded with its
entries and submenus.&nbsp; A submenu is the list that drops down when
the user clicks on an entry in the menu.&nbsp; A typical menu bar will
have the entries "File", "Edit", "Search", and "Help".&nbsp; Under the
"File" entry is a submenu with entries "New", "Open", "Save", "Save As",
a separator, "Page Setup", "Print", another separator, and "Exit".&nbsp;
Each entry in the submenu has its own widget callback function.&nbsp; To
create a submenu, the application developer must first create two null-terminated
lists of character strings and callback functions:
<pre>
char *file_submenu [] = { "Exit", "-----", "Print", "Page Setup", "-----",
"Save As", "Save", "Open", "New", NULL } ;
puCallback file_submenu_cb[] = { exit_cb, NULL, print_cb, page_setup_cb, NULL,
save_as_cb, save_cb, open_cb, new_cb, NULL } ;
</pre>
<p>Notice here that the submenu entries are placed in the list from bottom
to top.&nbsp; After the last character string is a NULL entry; this tells
PUI that there aren't any more entries in the submenu.&nbsp; The callbacks
for the separators are also null, indicating that there is no callback
for the separator.&nbsp; The submenu is added to the menu bar with a call
to the "add_submenu" function:
<pre>
menu->add_submenu ( "File", file_submenu, file_submenu_cb ) ;
</pre>
<p>Further calls to "add_submenu" add the other submenus:
<pre>
char *edit_submenu [] = { "Select All", "-----", "Paste", "Copy", "Cut",
"-----", "Undo", NULL } ;
puCallback edit_submenu_cb[] = { select_all_cb, NULL, paste_cb, copy_cb, cut_cb,
NULL, undo_cb, NULL } ;
menu->add_submenu ( "Edit", edit_submenu, edit_submenu_cb ) ;
char *search_submenu [] = { "Find Next", "Find", NULL } ;
puCallback search_submenu_cb[] = { find_next_cb, find_cb, NULL } ;
menu->add_submenu ( "Search", search_submenu, search_submenu_cb ) ;
char *help_submenu [] = { "About", "Help", NULL } ;
puCallback help_submenu_cb[] = { about_cb, help_cb, NULL } ;
menu->add_submenu ( "Help", help_submenu, help_submenu_cb ) ;
</pre>
<p>When the last submenu has been added, the application developer must
close the menu bar:
<pre>
menu->close() ;
</pre>
<p>This is absolutely necessary or else PUI will think that any widgets
the application defines later are supposed to go into the menu bar.
<p>The menu bar does not support a legend.&nbsp; It does not support a
callback itself, although all the entries in the submenus certainly do
support callbacks.&nbsp; Repositioning and resizing a menu bar will be
problematic as well.&nbsp; There may be an occasion when a menu bar can
take a label, but this would be rare.
<h4>
2.1.6 One-Shot Button</h4>
The one-shot button ("puOneShot") is a button whose value is always reset
immediately to zero after it has been activated.&nbsp; In all other respects
it is the same as the regular button.&nbsp; It is created in the same way
as the button:
<ul>
<li>
puOneShot ( x1, y1, x2, y2 ) - creates a one-shot button with lower left-hand
coordinates of (x1, y1) and with upper right-hand coordinates of (x2, y2)</li>
<li>
puOneShot ( x1, y1, "text" ) - creates a one-shot button with lower left-hand
coordinates of (x1, y1) and containing the text "text".&nbsp; The size
is set by the size of the text.</li>
</ul>
<h4>
2.1.7 Text Box</h4>
The text box ("puText") is an output-only widget which displays a character
string.&nbsp; It is created by the following constructor:
<ul>
<li>
puText ( x, y ) - creates a text box at the point (x, y) in the window</li>
</ul>
The application actually adds the text by assigning a label and a label
place to the text box.&nbsp; The label place will determine where relative
to the position of the text box the text itself will appear.
<h3>
<a NAME="Invoking PUI"></a>2.2 Invoking PUI</h3>
The summary of invoking PUI is very simple:
<ul>
<li>
At the beginning of the program, before creating any widgets, the application
must call the function "puInit ()".</li>
<li>
If the application developer wants PUI to process a mouse click, he must
have the application call the function "puMouse ( button, updown, x, y
)".</li>
<li>
If the application developer wants PUI to process a mouse motion, he must
have the application call the function "puMouse ( x, y )".</li>
<li>
If the application developer wants PUI to process a key from the keyboard,
he must have the application call the function "puKeyboard ( key, updown
)".</li>
<li>
If the application developer wants PUI to display the user interface, he
must have the application call the function "puDisplay ()".</li>
</ul>
The application developer must create window callbacks for the window manager
to call when the user interacts with the computer.&nbsp; The following
are taken from GLUT, but another window manager will have similar callback
requirements.
<h4>
2.2.1 Main Program Code</h4>
In the main program, the application developer usually places the following
or similar statements:
<pre>
// Create the GLUT window and the OpenGL context
glutCreateWindow ( "PUI Application" ) ;
// Set up the GLUT window callbacks
glutDisplayFunc ( displayfn ) ; // display the window
glutMouseFunc ( mousefn ) ; // process mouse clicks
glutMotionFunc ( motionfn ) ; // process mouse moves
glutPassiveMotionFunc ( motionfn ) ;
glutKeyboardFunc ( keyboardfn ) ; // process key presses
glutIdleFunc ( displayfn ) ; // what to do when nothing's happening
// Initialize PUI
puInit () ;
// Set up the widgets here
</pre>
<h4>
2.2.2 Window Callbacks</h4>
The application's window callbacks should generally look like this.&nbsp;
Again, these are written assuming GLUT; other window managers should be
similar.
<pre>
void displayfn ( void )
{
// stuff to display any non-PUI drawings
// update any PUI widgets that update by themselves ... like a timer display
// redisplay PUI
puDisplay () ;
// Finish up
glutSwapBuffers () ;
glutPostRedisplay () ;
}
void mousefn ( int button, int updown, int x, int y )
{
// Invoke the PUI mouse function
puMouse ( button, updown, x, y ) ;
glutPostRedisplay () ;
}
void motionfn ( int x, int y )
{
// Invoke the PUI mouse motion function
puMouse ( x, y ) ;
glutPostRedisplay () ;
}
void keyboardfn ( unsigned char key, int, int )
{
// Invoke the PUI keyboard function
puKeyboard ( key, PU_DOWN ) ;
glutPostRedisplay () ;
}
</pre>
<h4>
2.2.3 Miscellaneous Other Tidbits</h4>
If the application developer wishes to delete a widget, he should not delete
the object directly.&nbsp; Instead he should call the PUI function "puDeleteObject
( ob )" with his widget pointer as the argument.
<h3>
<a NAME="Widget Callbacks"></a>2.3 Widget Callbacks</h3>
The final pieces to the puzzle are the widget callbacks.&nbsp; These are
of the form
<pre>
void widget_cb ( puObject *ob )
{
// code goes here
}
</pre>
<p>where "puObject" is the C++ type for a generic widget.&nbsp; When PUI
calls a widget callback, it passes to it the address of the widget whose
activation caused the callback.&nbsp; This is useful because it allows
a single callback for multiple widgets:
<pre>
void widget_cb ( puObject *ob )
{
if ( ob == button ) // the button from section 2.1
{
...
}
else if ( ob == my_box ) // the button box from section 2.1.2
{
...
}
else
{
printf ( "Error - unknown widget" ) ;
}
}
</pre>
<p>A widget callback needs to be either a regular function (global
or defined in the same file that contains the widget's definition) or a
static member function of a class.&nbsp; It cannot be a regular member
function of a class.
<h4>
2.3.1 Widget Values</h4>
It is frequently very useful in a callback to know the value of a widget.&nbsp;
A PUI widget has an integer value, a floating-point value, and a character
string value.&nbsp; These values are kept synchronized as much as possible.&nbsp;
For example, if the application assigns an integer value to a widget, the
floating-point value is set equal to the integer and the integer is printed
into the character string.
<p>An application program can use the following function to retrieve the
value of a PUI widget ("ob" is the pointer to the object):
<pre>
int ivalue1 = ob->getValue () ; // No argument, return the integer value
int ivalue2 ;
ob->getValue ( &amp;ivalue2 ) ; // Place the integer value in the argument
float fvalue ;
ob->getValue ( &amp;fvalue ) ; // Place the floating-point value in the argument
char svalue[PUSTRING_MAX] ; // Create a string
ob->getValue ( svalue ) ; // Copy the string value into the argument
// Note that the argument is of type "char *"
char *sptr ;
ob->getValue ( &amp;sptr ) ; // Have the pointer point to the string value
// Note that the argument is of type "char **"
</pre>
<p>The values of the various widgets have the following meanings:
<ul>
<li>
Button:&nbsp; 0 - turned off; 1 - turned on</li>
<li>
Button Box:&nbsp; If only one button can be activated at a time, the value
is the number of the button which is activated.&nbsp; If multiple buttons
can be activated at once, then the bits in the integer value corresponding
to the activated buttons are one and the bits corresponding to the inactive
buttons are zero.</li>
<li>
Frame:&nbsp; no value</li>
<li>
Input:&nbsp; the string value is the character string that the user has
typed in</li>
<li>
Menu Bar:&nbsp; no value</li>
<li>
One Shot Button:&nbsp; value is always zero</li>
<li>
Text:&nbsp; no value</li>
</ul>
<h2>
<a NAME="Conclusion"></a>3.&nbsp; Conclusion</h2>
This has been offered as an introduction to the Picoscopic User Interface.&nbsp;
It makes no warranty as to its accuracy although efforts have been made
to make it correct.&nbsp; It is offered in the hope that the gentle reader
will find it useful.
<p>The PUI has considerably greater capabilities than have been listed
here.&nbsp; There are well over a dozen additional types of widgets.&nbsp;
Additionally, the application developer can do many more things with this
widgets than have been described here.
<p>"As to more than these, my son, beware.&nbsp; Of the making of many
books there is no end, and in much study there is weariness for the flesh."
- Ecclesiastes 12:12
</body>
</html>

171
doc/pui/FAQ.html Normal file
View File

@@ -0,0 +1,171 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<META http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<META name="keywords" content="PUI, PLIB, OpenGL, UI, user, interface, library, portable, picoscopic, MUI, widget, GUI, fast, FAQ, Baker, Steve">
<META name="description" content="Here are some questions that have been asked about the PLIB Picoscopic User Interface library.">
<TITLE>The Picoscopic User Interface: FAQ list.</TITLE>
</HEAD>
<BODY text="#B5A642" link="#8FFF8F" vlink="#18A515" alink="#20336B"
bgcolor="#005000" background="../marble.png">
<TABLE>
<TR>
<TD>
<IMG SRC="pooh.png" ALT="Imagine Pooh Here" width=60 height=77>
</TD>
<TD>
<H1>PUI: A Picoscopic User Interface</H1>
<H1>Frequently Asked Questions List.</H1>
By Steve Baker
</TD>
</TR>
</TABLE>
Here are some questions that have been asked about PUI:
<ul>
<li><A HREF="#Q1">Q1: Can I build a Windoze DLL for PUI?</A>
<li><A HREF="#Q2">Q2: Which versions of OpenGL and GLUT will support PUI?</A>
<li><A HREF="#Q3">Q3: Which machines/operating systems can run PUI?</A>
<li><A HREF="#Q4">Q4: Is PUI stable? Are there known bugs?</A>
<li><A HREF="#Q5">Q5: What changes do you expect to make in future releases?</A>
<li><A HREF="#Q6">Q6: Where can I ask questions?</A>
<li><A HREF="#Q7">Q7: What's the difference between PUI and MUI?</A>
<li><A HREF="#Q8">Q8: Are there restrictions on using PUI?</A>
<li><A HREF="#Q9">Q9: Do I have to write in C++ to use PUI?</A>
</ul>
<p>
<hr>
<p>
<H2><A NAME="Q1">Q1: Can I build a Windoze DLL for PUI?</A></H2>
Not from the present sources. Some Windoze compilers
require an '_export' directive on functions or classes
that are to be exported from the DLL. This is ugly and
I refuse to add non-standard syntax to the library just
to pander to a disgusting Windoze-ism. PUI is a VERY
small library and there is really no need for it to
be a DLL anyway.
<H2><A NAME="Q2">Q2: Which versions of OpenGL and GLUT will support PUI?</A></H2>
In principal, any version of GLUT since 2.0 and any
reasonably compliant OpenGL (including Mesa) should
be happy to support PUI.
<H2><A NAME="Q3">Q3: Which machines/operating systems can run PUI?</A></H2>
AFAIK, any machine with C++, OpenGL (or Mesa) and
GLUT will run PUI programs without problems.
<H2><A NAME="Q4">Q4: Is PUI stable? Are there known bugs?</A></H2>
So far, there have only been a couple of bugs reported
in PUI - the most significant is that the menu bar doesn't
work properly after the GLUT window has been resized.
<p>
The 'complex' demo program seems to fail when a dialog
box is dismissed. This may be because the dialog object
is deleted inside a callback within a member function of
that object. This problem only appears under Microsoft
operating systems and so is hard for me to track down.
The simplest thing may be for me to change the demo
program so it just doesn't work that way.
<H2><A NAME="Q5">Q5: What changes do you expect to make in future releases?</A></H2>
I am generally unhappy about the somewhat inconsistant
set of constructor functions for the various widgets.
Some auto-size their widgets, some take the size directly,
others have both. This needs to be made much more consistant
across all the widget classes.
<p>
I want to write a cute interactive GUI designer program to
write C++ source code for the PUI constructor functions
automatically. Something along the lines of the XForms
'fdesign' or the FLTK 'fluid' programs.
<p>
If GLUT ever changes to allow applications to run without
calling 'glutMainLoop', I will greatly improve the Dialog
box API which sucks right now. It would also spur me on
to write a File Selector widget. The problem is that
you'd really like to be able to write things like:
<pre>
if ( ( fd = fopen ( "babble", "w" ) ) == NULL )
{
if ( puYesNoDialog ( "Can't open babble file",
"Do you want to continue?" ) )
return ;
else
exit ( 1 ) ;
}
</pre>
However, the 'puYesNoDialog' function can't get it's
graphics up on the screen without returning to GLUT's
main loop - and it can't do that since the call to
puYesNoDialog is in a GLUT callback function.
Look at the ugly code in 'complex' to see how to do
this kind of thing without this facility.
<p>
Finally, the appearance of PUI's widgets is somehow
not as neat as some other GUI's such as MUI and Motif.
This should be pretty easy to fix - and it's something
on the 'to do' list.
<H2><A NAME="Q6">Q6: Where can I ask questions?</A></H2>
Since PUI is now a part of <A HREF="../index.html">PLIB</A>,
all user level questions, development issues and announcements
are handled from the PLIB mailing list.
<H2><A NAME="Q7">Q7: What's the difference between PUI and MUI?</A></H2>
The main reason I wrote PUI was my disappointment
with MUI.
<p>
MUI has now been 'abandoned' by it's author (Tom Davis)
who none-the-less retains copyright over it. MUI has
several known bugs - and the only known documentation
was written by me - and I have never actually written
a real application using it!
<p>
The MUI library (distributed with GLUT) takes
over all of the GLUT callbacks - this makes it
very hard to write general purpose programs with
MUI.
<p>
In contrast, it is very easy to add PUI widgets to
an existing OpenGL/GLUT application with only a
couple of lines of code.
<p>
PUI also works quite well with 3D hardware such
as 3Dfx Voodoo that 'take over' the screen. Since
MUI and GLUT both create their menu's using the
underlying windowing system's GUI, these menu's
won't be visible on that kind of hardware. PUI
uses only OpenGL to do all kinds of widgets, so
portability onto 3Dfx hardware is assured.
<H2><A NAME="Q8">Q8: Are there restrictions on using PUI ?</A></H2>
PUI is OpenSource under the terms of LGPL. If for some reason,
you find LGPL too restrictive and if you wish to use it in some
major project then please talk to me about it - I can be flexible.
<H2><A NAME="#Q9">Q9: Do I have to write in C++ to use PUI?</A></H2>
Yes - there will never be a {insert favorite non-C++ language here}
version of PUI.
<hr>
<table>
<tr>
<td>
<a href="http://validator.w3.org/check/referer"><img border="0" src="../valid-html40.png" alt="Valid HTML 4.0!" height="31" width="88"></a>
<td>
<ADDRESS>
<A HREF="http://www.sjbaker.org">Steve J. Baker.</A> &lt;<A HREF="mailto:sjbaker1@airmail.net">sjbaker1@airmail.net</A>&gt;
</ADDRESS>
</table>
</BODY>
</HTML>

BIN
doc/pui/complex.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

2210
doc/pui/index.html Normal file

File diff suppressed because it is too large Load Diff

BIN
doc/pui/labelplaces.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
doc/pui/legendplaces.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
doc/pui/pooh.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

BIN
doc/pui/puArrowButton.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
doc/pui/puBiSlider.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
doc/pui/puButton.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

BIN
doc/pui/puButtonBox.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

BIN
doc/pui/puComboBox.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

BIN
doc/pui/puDial.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

BIN
doc/pui/puDialogBox.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
doc/pui/puFileSelector.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
doc/pui/puFrame.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

BIN
doc/pui/puInput.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
doc/pui/puLargeInput.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

BIN
doc/pui/puListBox.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

BIN
doc/pui/puMenuBar.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
doc/pui/puOneShot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
doc/pui/puPopupMenu.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
doc/pui/puSelectBox.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

BIN
doc/pui/puSlider.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
doc/pui/puText.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 609 B

BIN
doc/pui/puTriSlider.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
doc/pui/puVerticalMenu.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
doc/pui/simple.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

203
doc/pw/index.html Normal file
View File

@@ -0,0 +1,203 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<META http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<META name="keywords" content="PW, PLIB, OpenGL, window, library, portable, interface, games, Baker, Steve, pwInit">
<META name="description" content="The PLIB minimal Windowing Library (PW) is a portable interface that makes it as simple as possible to make an OpenGL application that can open a single window and read the mouse and keyboard. It is a wrapper to make the various underlying OS mechanisms look the same to application code.">
<TITLE>A PLIB Windowing Library.</TITLE>
</HEAD>
<BODY text="#B5A642" link="#8FFF8F" vlink="#18A515" alink="#20336B"
bgcolor="#005000" background="../marble.png">
<TABLE>
<TR>
<TD>
<H1>A PLIB Windowing Library.</H1>
</TD>
</TR>
<TR>
<TD>
by Steve Baker
</TD>
</TR>
</TABLE>
<H2>Introduction</H2>
PW is now just one component of <A HREF="../index.html">PLIB</A>.
<p>
The PLIB minimal Windowing Library (PW) is a portable interface that makes
it as simple as possible to make an OpenGL application that can open a
single window and read the mouse and keyboard. It is a wrapper to make the
various underlying OS mechanisms look the same to application code.
<p>
You should include the PW header file '/usr/include/plib/pw.h'
and link to the PW library '/usr/lib/libplibpw.a'.
<p>
Before using any other PW functions, you should initialise the
library by calling either:
<pre>
void pwInit ( int multisample, int num_samples ) ;
</pre>
...or:
<pre>
void pwInit ( int x, int y, int w, int h,
int multisample,
char *title, int border, int num_samples ) ;
</pre>
The first version creates a full-screen window with no borders,
titles, etc (or at least as close to that as your OS can manage).
The second version creates a window with it's origin at (x,y) of
dimensions w x h, with the specified title string, and optionally
with or without a border.
<p>
The window that's created will have the maximum number of colours
that your system supports - double-buffered plus a Z buffer.
<p>
Both forms allow you to specify whether you'd like multisampling
to be enabled or not - and if so, with how many samples. If your
system cannot produce the number of samples requested, pwInit will
fall back to the best it can do.
<p>
Then, initialise other PLIB components such as PUI. When initialisation
is complete, call this function:
<pre>
void pwCallbacks ( pwKeybdFunc *kb = NULL, pwMouseFunc *ms = NULL,
pwMousePosFunc *mp = NULL, pwResizeCB *rcb = NULL,
pwExitCB *ecb = NULL ) ;
</pre>
These parameters are callback functions for (repectively)
incoming keyboard keystrokes, incoming mouse button press or
release events, mouse movements, window resize events and finally,
a window close callback. (That's invoked by PW when the user attempts
to close the window by pressing the exit button on the window border.)
PW also calls the exit function when it detects a fatal error that
occurs after the window has been successfully opened.
<p>
Your application has to be prepared for these callbacks to be invoked
at any time after pwCallbacks. PW allows you to issue OpenGL calls
any time after pwInit().
<p>
The specifications of these various callbacks are:
<pre>
typedef void pwResizeCB ( int w, int h ) ;
typedef void pwExitCB () ;
typedef void pwKeybdFunc ( int key, int updown, int x, int y ) ;
typedef void pwMouseFunc ( int button, int updown, int x, int y ) ;
typedef void pwMousePosFunc ( int x, int y ) ;
</pre>
The 'updown' parameter is set to PW_DOWN when a key or mouse button
is pressed or to PW_UP when it's released. The 'key' parameter is
either an ASCII character or one of:
<pre>
PW_KEY_F1 PW_KEY_F2 PW_KEY_F3 PW_KEY_F4
PW_KEY_F5 PW_KEY_F6 PW_KEY_F7 PW_KEY_F8
PW_KEY_F9 PW_KEY_F10 PW_KEY_F11 PW_KEY_F12
PW_KEY_LEFT PW_KEY_UP PW_KEY_RIGHT PW_KEY_DOWN
PW_KEY_PAGE_UP PW_KEY_PAGE_DOWN
PW_KEY_HOME PW_KEY_END PW_KEY_INSERT
</pre>
The 'button' parameter is one of:
<pre>
PW_LEFT_BUTTON PW_MIDDLE_BUTTON PW_RIGHT_BUTTON
</pre>
These constants are chosen to be identical to the similarly named
constants used in the PLIB PUI library so that it's easy to connect
a PUI GUI to a PW window.
<p>
Once the window is initialised, you may call other PLIB graphics
initialisations (puInit, ssgInit, etc).
<p>
So now you have your window open, you only need to do one thing -
call this function once per frame:
<pre>
void pwSwapBuffers () ;
</pre>
This function swaps the double-buffers, collects keystrokes, mouse events
and resize events and calls whatever application-defined callbacks are
needed. It is NOT LEGAL to call pwSwapBuffers() from inside a PW callback
function.
<p>
When you wish to close the PW window, you should call:
<pre>
void pwCleanup () ;
</pre>
Some applications need to know when the shift/control/alt keys are being
held down by the user:
<pre>
int pwGetModifiers () ;
</pre>
This returns the state of those three keys as the OR of the three constants:
<pre>
PW_SHIFT PW_CTRL PW_ALT
</pre>
Note that the results are only valid inside of a callback called from
pwSwapBuffers().
<p>
By default, PW disallows auto-repeat of keyboard keys. This is generally what
you want for games. However, it's possible that you may want auto-repeat to
be enabled:
<pre>
void pwSetAutoRepeatKey ( bool enable ) ;
</pre>
If the user has told the windowing system that auto repeat should be off as
some kind of a global preference then pwSetAutoRepeatKey(true) won't turn
it back on again.
<p>
Finally, there are a number of functions for setting and getting the window
position and dimensions - also to set the current cursor shape:
<pre>
void pwGetSize ( int *w, int *h ) ;
void pwSetSizeOrigin ( int x, int y, int w, int h ) ;
void pwSetSize ( int x, int y ) ;
void pwSetOrigin ( int w, int h ) ;
void pwSetCursor ( int c ) ;
</pre>
The available cursor shapes for pwSetCursor are:
<pre>
PW_CURSOR_NONE 0
PW_CURSOR_RIGHT 1
PW_CURSOR_LEFT 2
PW_CURSOR_QUERY 3
PW_CURSOR_AIM 4
PW_CURSOR_CIRCLE 5
PW_CURSOR_WAIT 6
PW_CURSOR_CROSS 7
PW_CURSOR_CUSTOM 8
</pre>
<ADDRESS>
<A HREF="http://www.sjbaker.org">
Steve J. Baker.</A>
&lt;<A HREF="mailto:sjbaker1@airmail.net">sjbaker1@airmail.net</A>&gt;
</ADDRESS>
</table>
</BODY>
</HTML>

147
doc/requirements.html Normal file
View File

@@ -0,0 +1,147 @@
<!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>PLIB: Requirements & Portability.</TITLE>
</HEAD>
<BODY text="#B5A642" link="#8FFF8F" vlink="#18A515" alink="#20336B"
bgcolor="#005000" background="marble.png">
<TABLE>
<TR>
<TD>
<IMG SRC="plib_logo.png" ALT="PLIB Logo" width=256 height=245>
<br>
</TD>
<TD>
<center>
<H1>
<FONT SIZE=9>S</FONT><FONT SIZE=5>TEVE'S</FONT>
<FONT SIZE=9>P</FONT><FONT SIZE=5>ORTABLE</FONT>
<FONT SIZE=9>G</FONT><FONT SIZE=5>AME</FONT>
<FONT SIZE=9>L</FONT><FONT SIZE=5>IBRARY.</FONT>
</H1>
</center>
</TD>
<TD>
<ul>
And Lo, the Lion and the Sheep shall lie down together - but the Sheep won't
get much Sleep.
<br>
-- Woody Allen
</ul>
<center>
<A href="http://sf.net">
<IMG src="http://sf.net/sflogo.php?group_id=382&type=1" width="88" height="31" border="0" ALT="Sourceforge Logo"></A>
</center>
</TD>
</TR>
</TABLE>
<TABLE>
<TR>
<TD valign=top align=left>
<A HREF="index.html"><IMG SRC="home.png" ALT="HOME" BORDER="0" width=150 height=50></A><br>
<A HREF="whats_inside.html"><IMG SRC="whats_inside.png" ALT="WHAT'S INSIDE" BORDER="0" width=150 height=50></A><br>
<A HREF="license.html"><IMG SRC="license.png" ALT="LICENSE" BORDER="0" width=150 height=50></A><br>
<A HREF="contacts.html"><IMG SRC="contacts.png" ALT="CONTACTS" BORDER="0" width=150 height=50></A><br>
<A HREF="requirements.html"><IMG SRC="requirements.png" ALT="REQUIREMENTS" BORDER="0" width=150 height=50></A><br>
<A HREF="gallery.html"><IMG SRC="gallery.png" ALT="GALLERY" BORDER="0" width=150 height=50></A><br>
<A HREF="download.html"><IMG SRC="download.png" ALT="DOWNLOAD & INSTALL" BORDER="0" width=150 height=50></A><br>
<A HREF="examples.html"><IMG SRC="examples.png" ALT="EXAMPLES" BORDER="0" width=150 height=50></A><br>
<A HREF="sg/index.html"><IMG SRC="SG.png" ALT="SG" BORDER="0" width=75 height=25></A>
<A HREF="ssg/index.html"><IMG SRC="SSG.png" ALT="SSG" BORDER="0" width=75 height=25></A><br>
<A HREF="ssgAux/index.html"><IMG SRC="ssgAux.png" ALT="SSGAUX" BORDER="0" width=75 height=25></A>
<A HREF="fnt/index.html"><IMG SRC="FNT.png" ALT="FNT" BORDER="0" width=75 height=25></A><br>
<A HREF="pui/index.html"><IMG SRC="PUI.png" ALT="PUI" BORDER="0" width=75 height=25></A>
<A HREF="psl/index.html"><IMG SRC="PSL.png" ALT="PSL" BORDER="0" width=75 height=25></A>
<A HREF="util/index.html"><IMG SRC="UL.png" ALT="UL" BORDER="0" width=75 height=25></A>
<A HREF="js/index.html"><IMG SRC="JS.png" ALT="JS" BORDER="0" width=75 height=25></A><br>
<A HREF="net/index.html"><IMG SRC="NET.png" ALT="NET" BORDER="0" width=75 height=25></A>
<A HREF="sl/index.html"><IMG SRC="SL.png" ALT="SL" BORDER="0" width=75 height=25></A><br>
<A HREF="pw/index.html"><IMG SRC="PW.png" ALT="PW" BORDER="0" width=75 height=25></A>
<A HREF="puAux/index.html"><IMG SRC="puAux.png" ALT="PUAUX" BORDER="0" width=75 height=25></A><br>
</TD>
<TD>
<H2>Hardware Requirements for Running PLIB</H2>
To do good 3D graphics, you'll need an OpenGL-compatible 3D graphics
accellerator that your operating system supports. Most systems can
run OpenGL in software only - but performance is so poor as to be
unusable in the kinds of application for which PLIB is intended.
<p>
If you want to hear sound effects and music, you'll obviously
need a sound card and some speakers or headphones.
<H2>Software Requirements for Running PLIB</H2>
The PLIB team works hard to minimise our dependance on other
libraries to make it easy for end-users to install application
software without having to visit dozens of web sites to collect
the libraries they need.
<ul>
<li>3D/2D Graphics: OpenGL. If you aren't already set up to
run OpenGL, you should check:
<ul>
<li> <A HREF="http://www.opengl.org">The OpenGL ARB</A> site.
<li> Or download <A HREF="http://www.mesa3d.org">Mesa</A>
(which is an excellent OpenGL clone by Brian Paul).
<li> If you are a Linux user, you may wish to check the
<A HREF="http://www.linux3d.org">Linux3D Site</A>.
<li> If you are a Windoze or Macintosh user, you should have
had a copy of OpenGL delivered with your operating
system.
</ul>
<li>Windowing: From version 1.8.0, PLIB itself is completely independent of
any other windowing library. However, some of the demo and example
programs use <A HREF="http://freeglut.sf.net">freeglut</A> (or at a
pinch:
<A HREF="http://www.opengl.org/Documentation/GLUT.html">the original
GLUT</A> (GL Utility Toolkit by Mark Kilgard).
<A HREF="http://freeglut.sf.net">freeglut</A>
works very well with PLIB applications and is maintained by
many of the same people - so there is good continuity.
It's perfectly possible to write PLIB programs that don't use
either GLUT or freeglut - for example, you can use PLIB with
<a href="http://www.libsdl.org">SDL</a>).
</ul>
<H2>How Portable is PLIB?</H2>
VERY!
<ul>
<li> All flavors of Linux are supported - on any CPU platform that
supports Xfree86 and OpenGL.
<li> All flavors of Win32 are
supported, using either MSVC++ or CygWin for compilation.
Theoretically you could use Borland C++ also, but since there is little
user base these days, the necessary 'project' files to build PLIB
under Borland's IDE tend to get outdated.
<li> Most other UNIX-like systems (at least BSD, IRIX, Solaris, OS-X) providing
they support X-windows.
<li> MacOS-X is also reasonably well supported.
<li> MacOS-9 runs everything except the joystick library. However, it's getting
hard to find people to test this port - so it may have problems by the time
you come to use it.
<li> Support for BeOS is problematic - for some reason, people who are prepared
to help out with porting PLIB to BeOS are hard to find. However, since
BeOS (I'm told) has compatibility with X, OpenGL and OSS, it should
be easy to port to and may just work 'out of the box'.
</ul>
</TD>
</TR>
</TABLE>
<hr>
<ADDRESS>
<A HREF="http://www.sjbaker.org">
Steve J. Baker.</A>
&lt;<A HREF="mailto:sjbaker1@airmail.net">sjbaker1@airmail.net</A>&gt;
</ADDRESS>
</BODY>
</HTML>

BIN
doc/requirements.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

1107
doc/sg/index.html Normal file

File diff suppressed because it is too large Load Diff

BIN
doc/sg/triangle_params.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

71
doc/sl/index.html Normal file
View File

@@ -0,0 +1,71 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<META http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<META name="keywords" content="SL, SM, PLIB, OpenGL, sound, library, portable, games, sample, replay, mixer, OSS, Baker, Steve">
<META name="description" content="The PLIB SL Library is targetted towards producing sound effects for games and other realtime applications. The emphasis is on low CPU impact and low latency rather than high quality and fancy MIDI/MOD facilities. The PLIB SM Library controls the audio mixer on a PC sound card.">
<TITLE>The SL Sound and Mixer Libraries.</TITLE>
</HEAD>
<BODY text="#B5A642" link="#8FFF8F" vlink="#18A515" alink="#20336B"
bgcolor="#005000" background="../marble.png">
<H1>The SL Sound and Mixer Libraries.</H1>
By Steve Baker
<H2>Introduction.</H2>
The 'SL' sound library is primarily targetted towards producing sound
effects for games, and isn't really intended for playing music (although
you could certainly use it for doing that). The emphasis is on low
CPU impact and low latency rather than high quality and fancy MIDI/MOD
facilities.
<p>
SL is a part of <A HREF="../index.html">PLIB</A>.
<p>
The 'SL' sound library will eventually become a fully portable freeware
sound library that should run on all major platforms. Right now, SL
runs under:
<ul>
<li>Linux on systems with OSS (the Open Sound System) installed
(it's usually a standard part of the kernel).
<li>Windows NT, 95 and 98.
<li>OpenBSD.
<li>SGI's IRIX.
<li>Other UNIX systems using OSS (which should include Solaris, FreeBSD,
BSD/OS, SCO and others) should be able to run the Linux version of
SL by adding '-DSL_USING_OSS_AUDIO' to the compile command line.
</ul>
At present, there is no support for Apple's MacOS sound systems
- although it is hoped that these will be added in the near future.
<ul>
<li><A HREF="sl.html">The SL Library</A>
deals with all aspects of sample replay for games and
other realtime applications - it is designed such that it can be
ported to other operating systems by replacing just the slDSP
class.
<p>
<li><A HREF="sm.html">The SM Library</A>
controls the audio mixer on a PC sound card and
probably only works 100% correctly within OSS - and then probably
only on fairly 'vanilla' Soundblaster-compatible sound cards.
Portability of SM is patchy - regard it as a bonus.
</ul>
It is due to the relative non-portability of the SM routines
that these are in a separate library. For non-portable
applications, SL and SM can be considered as a single library.
<p>
<A HREF="http://www.4front-tech.com">Download the Open Sound System
drivers (previously known as VoxWare).</A>
<hr>
<table>
<tr>
<td>
<a href="http://validator.w3.org/check/referer"><img border="0" src="../valid-html40.png" alt="Valid HTML 4.0!" height="31" width="88"></a>
<td>
<ADDRESS>
<A HREF="http://www.sjbaker.org">
Steve J. Baker.</A>
&lt;<A HREF="mailto:sjbaker1@airmail.net">sjbaker1@airmail.net</A>&gt;
</ADDRESS>
</table>
</BODY>
</HTML>

BIN
doc/sl/mixer.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

1048
doc/sl/sl.html Normal file

File diff suppressed because it is too large Load Diff

BIN
doc/sl/sl.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

106
doc/sl/sm.html Normal file
View File

@@ -0,0 +1,106 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<META http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<META name="keywords" content="SM, PLIB, OpenGL, sound, library, mixer, OSS, Baker, Steve, smMixer">
<META name="description" content="The PLIB SM Library allows one to drive the mixer controls of most PC-style sound cards.">
<TITLE>The SL Mixer Library.</TITLE>
</HEAD>
<BODY text="#B5A642" link="#8FFF8F" vlink="#18A515" alink="#20336B"
bgcolor="#005000" background="../marble.png">
<TABLE>
<TR>
<TD><IMG SRC="mixer.png" ALT="Imagine kitchen mixers here" width=247 height=247></TD>
<TD>
<H1>The SL Mixer Library.</H1>
By Steve Baker
</TD>
</TR>
</TABLE>
<H2>Introduction.</H2>
This library allows one to drive the mixer controls of
most PC-style sound cards. It relies
on <A HREF="http://www.4front-tech.com">the Open Sound
System</A> drivers (formerly known as 'VoxWare')
- which are generally a standard part of the Linux Kernel - and
which is also available on some other UNIX platforms.
<p>
A port of SM to the Windows family of operating systems
is currently underway.
<p>
SM does not work under SGI's IRIX.
<H2>Using the Library.</H2>
To use this library, you must '#include "sm.h"' and link to
libsm.a or libsm.so.
<H2>class smMixer.</H2>
This library comprises a single class 'smMixer'.
<p>
Most programs will only ever create a single smMixer object.
<p>
Here are the member functions:
<pre>
class smMixer
{
public:
smMixer () ;
smMixer ( char *device ) ;
~smMixer () ;
int not_working () ;
/* Volume/Treble/Bass controls are in integer percentages */
void setTreble ( int treble ) ;
void setBass ( int bass ) ;
void setMasterVolume ( int volume ) ;
void setSynthVolume ( int volume ) ;
void setPCMVolume ( int volume ) ;
void setSpeakerVolume( int volume ) ;
void setLineVolume ( int volume ) ;
void setMicVolume ( int volume ) ;
void setCDVolume ( int volume ) ;
void setMasterVolume ( int left, int right ) ;
void setSynthVolume ( int left, int right ) ;
void setPCMVolume ( int left, int right ) ;
void setSpeakerVolume( int left, int right ) ;
void setLineVolume ( int left, int right ) ;
void setMicVolume ( int left, int right ) ;
void setCDVolume ( int left, int right ) ;
} ;
</pre>
Basically, each of the mixer devices can be driven with either
mono or stereo volume controls, each volume is a expressed as an
integer percentage of maximum.
<p>
By default, "/dev/mixer" is the device used by this class, but
an alternative device may be accessed if it's name is passed
into the constructor.
<p>
The 'not_working()' function returns TRUE if there is any kind of
problem with the driver. Mostly it returns TRUE if your system isn't
set up for audio.
<p>
The driver will not fail if you call it's member functions when
'not_working()' returns TRUE - so programs written for audio
should work OK even on Linux boxes with no audio support.
<hr>
<table>
<tr>
<td>
<a href="http://validator.w3.org/check/referer"><img border="0" src="../valid-html40.png" alt="Valid HTML 4.0!" height="31" width="88"></a>
<td>
<ADDRESS>
<A HREF="http://www.sjbaker.org">
Steve J. Baker.</A>
&lt;<A HREF="mailto:sjbaker1@airmail.net">sjbaker1@airmail.net</A>&gt;
</ADDRESS>
</table>
</BODY>
</HTML>

BIN
doc/spacething-small.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

315
doc/ssg/LoaderWriter.html Normal file
View 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( &amp;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">&lt;= 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>
&lt;<A HREF="mailto:sjbaker1@airmail.net">sjbaker1@airmail.net</A>&gt;
</ADDRESS>
</table>
</BODY>
</HTML>

319
doc/ssg/branches.html Normal file
View 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">&lt;= previous =</a></td>
<td width="34%" align="center"><a href="index.html">Return to SSG Index</a></td>
<td width="33%" align="right"><a href="state.html">= next =&gt;</a></td>
</tr>
</table>
<hr>
<table>
<tr>
<td>
<a href="http://validator.w3.org/check/referer"><img border="0" src="../valid-html40.png" alt="Valid HTML 4.0!" height="31" width="88"></a>
<td>
<ADDRESS>
<A HREF="http://www.sjbaker.org">
Steve J. Baker.</A>
&lt;<A HREF="mailto:sjbaker1@airmail.net">sjbaker1@airmail.net</A>&gt;
</ADDRESS>
</table>
</BODY>
</HTML>

157
doc/ssg/index.html Normal file
View 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 =&gt"-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 =&gt;</a></td>
</tr>
</table>
<hr>
<table>
<tr>
<td>
<a href="http://validator.w3.org/check/referer"><img border="0" src="../valid-html40.png" alt="Valid HTML 4.0!" height="31" width="88"></a>
<td>
<ADDRESS>
<A HREF="http://www.sjbaker.org">
Steve J. Baker.</A>
&lt;<A HREF="mailto:sjbaker1@airmail.net">sjbaker1@airmail.net</A>&gt;
</ADDRESS>
</table>
</BODY>
</HTML>

936
doc/ssg/non_class.html Normal file
View 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, &amp;sphere, mat, &amp;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>&nbsp;Feature</td>
<td>&nbsp;3DS<BR>load</td>
<td>&nbsp;AC<BR>load/<BR>save</td>
<td>&nbsp;ASC<BR>save</td>
<td>&nbsp;ASE<BR>load/<BR>save</td>
<td>&nbsp;ATG<BR>load/<BR>save</td>
<td>&nbsp;DXF<BR>load</td>
<td>&nbsp;DXF<BR>save</td>
<td>&nbsp;FLT<BR>load</td>
<td>&nbsp;M<BR>load/<BR>save</td>
<td>&nbsp;MD2<BR>load</td>
<td>&nbsp;OBJ<BR>load</td>
<td>&nbsp;OBJ<BR>save</td>
<td>&nbsp;OFF<BR>load/<BR>save</td>
<td>&nbsp;SSG<BR>load/<BR>save</td>
<td>&nbsp;Strip<BR>load</td>
<td>&nbsp;TRI<BR>load/<BR>save</td>
<td>&nbsp;X<BR>load</td>
<td>&nbsp;IV<BR>load</td>
<td>&nbsp;VRML1<BR>load</td>
</tr>
<tr>
<td>&nbsp;Filled polys</td>
<td>&nbsp;E</td>
<td>&nbsp;E</td>
<td>&nbsp;E</td>
<td>&nbsp;E</td>
<td>&nbsp;E</td>
<td>&nbsp;E</td>
<td>&nbsp;E(5)</td>
<td>&nbsp;E</td>
<td>&nbsp;E/D</td>
<td>&nbsp;?</td>
<td>&nbsp;E</td>
<td>&nbsp;E</td>
<td>&nbsp;E</td>
<td>&nbsp;E</td>
<td>&nbsp;E</td>
<td>&nbsp;</td>
<td>&nbsp;E</td>
<td>&nbsp;E</td>
<td>&nbsp;E</td>
</tr>
<tr>
<td>&nbsp;# sides</td>
<td>&nbsp;</td>
<td>&nbsp;n/3</td>
<td>&nbsp;3</td>
<td>&nbsp;3</td>
<td>&nbsp;n</td>
<td>&nbsp;3,4(4)</td>
<td>&nbsp;3</td>
<td>&nbsp;n</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;n?</td>
<td>&nbsp;3</td>
<td>&nbsp;n</td>
<td>&nbsp;n(4)</td>
<td>&nbsp;</td>
<td>&nbsp;3?</td>
<td>&nbsp;n</td>
<td>&nbsp;3,4</td>
<td>&nbsp;3,4</td>
</tr>
<tr>
<td>&nbsp;Lines</td>
<td>&nbsp;A</td>
<td>&nbsp;D/C</td>
<td>&nbsp;C</td>
<td>&nbsp;E</td>
<td>&nbsp;A(?)</td>
<td>&nbsp;E</td>
<td>&nbsp;E</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;?</td>
<td>&nbsp;E</td>
<td>&nbsp;E</td>
<td>&nbsp;A?</td>
<td>&nbsp;E</td>
<td>&nbsp;A</td>
<td>&nbsp;</td>
<td>&nbsp;A</td>
<td>&nbsp;B</td>
<td>&nbsp;B</td>
</tr>
<tr>
<td>&nbsp;Points</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;E</td>
<td>&nbsp;C</td>
<td>&nbsp;A(?)</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;B</td>
<td>&nbsp;A</td>
<td>&nbsp;?</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;E</td>
<td>&nbsp;A</td>
<td>&nbsp;</td>
<td>&nbsp;A</td>
<td>&nbsp;B</td>
<td>&nbsp;B</td>
</tr>
<tr>
<td>&nbsp;Sub objects</td>
<td>&nbsp;E</td>
<td>&nbsp;E/D</td>
<td>&nbsp;E</td>
<td>&nbsp;E</td>
<td>&nbsp;A(?)</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;E</td>
<td>&nbsp;A</td>
<td>&nbsp;?</td>
<td>&nbsp;C-D</td>
<td>&nbsp;C-D</td>
<td>&nbsp;A</td>
<td>&nbsp;E</td>
<td>&nbsp;A</td>
<td>&nbsp;</td>
<td>&nbsp;E</td>
<td>&nbsp;E</td>
<td>&nbsp;E</td>
</tr>
<tr>
<td>&nbsp;Hierarchie</td>
<td>&nbsp;A</td>
<td>&nbsp;E/D</td>
<td>&nbsp;E?</td>
<td>&nbsp;E</td>
<td>&nbsp;A(?)</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;E</td>
<td>&nbsp;A</td>
<td>&nbsp;?</td>
<td>&nbsp;C</td>
<td>&nbsp;C</td>
<td>&nbsp;A</td>
<td>&nbsp;E</td>
<td>&nbsp;A</td>
<td>&nbsp;</td>
<td>&nbsp;C</td>
<td>&nbsp;E</td>
<td>&nbsp;E</td>
</tr>
<tr>
<td>&nbsp;DAG</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;A(?)</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;E</td>
<td>&nbsp;A</td>
<td>&nbsp;?</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;E</td>
<td>&nbsp;A</td>
<td>&nbsp;</td>
<td>&nbsp;A(?)</td>
<td>&nbsp;E</td>
<td>&nbsp;E</td>
</tr>
<tr>
<td>&nbsp;Colours</td>
<td>&nbsp;E</td>
<td>&nbsp;E/D</td>
<td>&nbsp;E?</td>
<td>&nbsp;E</td>
<td>&nbsp;?</td>
<td>&nbsp;E</td>
<td>&nbsp;E</td>
<td>&nbsp;D(1)</td>
<td>&nbsp;A</td>
<td>&nbsp;?</td>
<td>&nbsp;D</td>
<td>&nbsp;C</td>
<td>&nbsp;A</td>
<td>&nbsp;E</td>
<td>&nbsp;A</td>
<td>&nbsp;</td>
<td>&nbsp;E</td>
<td>&nbsp;B</td>
<td>&nbsp;B</td>
</tr>
<tr>
<td>&nbsp;Textures</td>
<td>&nbsp;D</td>
<td>&nbsp;E/D</td>
<td>&nbsp;E</td>
<td>&nbsp;E</td>
<td>&nbsp;E</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;E</td>
<td>&nbsp;A</td>
<td>&nbsp;?</td>
<td>&nbsp;D</td>
<td>&nbsp;C</td>
<td>&nbsp;B</td>
<td>&nbsp;E</td>
<td>&nbsp;A</td>
<td>&nbsp;</td>
<td>&nbsp;E</td>
<td>&nbsp;E</td>
<td>&nbsp;E</td>
</tr>
<tr>
<td>&nbsp;Texture coord.</td>
<td>&nbsp;D</td>
<td>&nbsp;E</td>
<td>&nbsp;E</td>
<td>&nbsp;E</td>
<td>&nbsp;E</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;E</td>
<td>&nbsp;A</td>
<td>&nbsp;?</td>
<td>&nbsp;E</td>
<td>&nbsp;C</td>
<td>&nbsp;B</td>
<td>&nbsp;E</td>
<td>&nbsp;A</td>
<td>&nbsp;</td>
<td>&nbsp;E</td>
<td>&nbsp;E</td>
<td>&nbsp;E</td>
</tr>
<tr>
<td>&nbsp;Texture coord.<BR>per face<BR>AND vertex</td>
<td>&nbsp;D(?)</td>
<td>&nbsp;D(?)</td>
<td>&nbsp;A</td>
<td>&nbsp;E</td>
<td>&nbsp;E</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;?</td>
<td>&nbsp;E</td>
<td>&nbsp;C</td>
<td>&nbsp;B(?)</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;</td>
<td>&nbsp;C</td>
<td>&nbsp;E</td>
<td>&nbsp;E</td>
</tr>
<tr>
<td>&nbsp;Texture per face</td>
<td>&nbsp;</td>
<td>&nbsp;D(?)/-</td>
<td>&nbsp;C</td>
<td>&nbsp;A</td>
<td>&nbsp;E</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;E</td>
<td>&nbsp;A</td>
<td>&nbsp;?</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;B(?)</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;</td>
<td>&nbsp;C</td>
<td>&nbsp;B</td>
<td>&nbsp;A</td>
</tr>
<tr>
<td>&nbsp;Transparency</td>
<td>&nbsp;D</td>
<td>&nbsp;D</td>
<td>&nbsp;D</td>
<td>&nbsp;D</td>
<td>&nbsp;A(?)</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;E</td>
<td>&nbsp;A</td>
<td>&nbsp;?</td>
<td>&nbsp;A?</td>
<td>&nbsp;A?</td>
<td>&nbsp;B(?)</td>
<td>&nbsp;E</td>
<td>&nbsp;A</td>
<td>&nbsp;</td>
<td>&nbsp;E</td>
<td>&nbsp;B</td>
<td>&nbsp;B</td>
</tr>
<tr>
<td>&nbsp;Animation</td>
<td>&nbsp;B</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;E</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;B(2)</td>
<td>&nbsp;A</td>
<td>&nbsp;?</td>
<td>&nbsp;A?</td>
<td>&nbsp;A?</td>
<td>&nbsp;A</td>
<td>&nbsp;E</td>
<td>&nbsp;A</td>
<td>&nbsp;</td>
<td>&nbsp;B or C</td>
<td>&nbsp;B</td>
<td>&nbsp;A</td>
</tr>
<tr>
<td>&nbsp;Billboards</td>
<td>&nbsp;</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;E</td>
<td>&nbsp;A</td>
<td>&nbsp;?</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;E</td>
<td>&nbsp;A</td>
<td>&nbsp;</td>
<td>&nbsp;A</td>
<td>&nbsp;B</td>
<td>&nbsp;A</td>
</tr>
<tr>
<td>&nbsp;LOD</td>
<td>&nbsp;</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;E</td>
<td>&nbsp;A</td>
<td>&nbsp;?</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;E</td>
<td>&nbsp;A</td>
<td>&nbsp;</td>
<td>&nbsp;A</td>
<td>&nbsp;B</td>
<td>&nbsp;B</td>
</tr>
<tr>
<td>&nbsp;Other switches</td>
<td>&nbsp;</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;D</td>
<td>&nbsp;A</td>
<td>&nbsp;?</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;E</td>
<td>&nbsp;A</td>
<td>&nbsp;</td>
<td>&nbsp;A</td>
<td>&nbsp;D</td>
<td>&nbsp;D</td>
</tr>
<tr>
<td>&nbsp;A=Ascii or<BR>B=Binary</td>
<td>&nbsp;B</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;B</td>
<td>&nbsp;A</td>
<td>&nbsp;B</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;A</td>
<td>&nbsp;B</td>
<td>&nbsp;?</td>
<td>&nbsp;A</td>
<td>&nbsp;A+B(3)</td>
<td>&nbsp;A</td>
<td>&nbsp;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">&lt;= previous =</a></td>
<td width="34%" align="center"><a href="index.html">Return to SSG Index</a></td>
<td width="33%" align="right"><a href="LoaderWriter.html">= next =&gt;</a></td>
</tr>
</table>
<hr>
<table>
<tr>
<td>
<a href="http://validator.w3.org/check/referer"><img border="0" src="../valid-html40.png" alt="Valid HTML 4.0!" height="31" width="88"></a>
<td>
<ADDRESS>
<A HREF="http://www.sjbaker.org">
Steve J. Baker.</A>
&lt;<A HREF="mailto:sjbaker1@airmail.net">sjbaker1@airmail.net</A>&gt;
</ADDRESS>
</table>
</BODY>
</HTML>

233
doc/ssg/ssgBase.html Normal file
View 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">&lt;= previous =</a></td>
<td width="34%" align="center"><a href="index.html">Return to SSG Index</a></td>
<td width="33%" align="right"><a href="ssgEntity.html">= next =&gt;</a></td>
</tr>
</table>
<hr>
<table>
<tr>
<td>
<a href="http://validator.w3.org/check/referer"><img border="0" src="../valid-html40.png" alt="Valid HTML 4.0!" height="31" width="88"></a>
<td>
<ADDRESS>
<A HREF="http://www.sjbaker.org">
Steve J. Baker.</A>
&lt;<A HREF="mailto:sjbaker1@airmail.net">sjbaker1@airmail.net</A>&gt;
</ADDRESS>
</table>
</BODY>
</HTML>

183
doc/ssg/ssgContext.html Normal file
View 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">&lt;= previous =</a></td>
<td width="34%" align="center"><a href="index.html">Return to SSG Index</a></td>
<td width="33%" align="right"><a href="non_class.html">= next =&gt;</a></td>
</tr>
</table>
<hr>
<table>
<tr>
<td>
<a href="http://validator.w3.org/check/referer"><img border="0" src="../valid-html40.png" alt="Valid HTML 4.0!" height="31" width="88"></a>
<td>
<ADDRESS>
<A HREF="http://www.sjbaker.org">
Steve J. Baker.</A>
&lt;<A HREF="mailto:sjbaker1@airmail.net">sjbaker1@airmail.net</A>&gt;
</ADDRESS>
</table>
</BODY>
</HTML>

146
doc/ssg/ssgEntity.html Normal file
View 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">&lt;= previous =</a></td>
<td width="34%" align="center"><a href="index.html">Return to SSG Index</a></td>
<td width="33%" align="right"><a href="ssgLeaf.html">= next =&gt;</a></td>
</tr>
</table>
<hr>
<table>
<tr>
<td>
<a href="http://validator.w3.org/check/referer"><img border="0" src="../valid-html40.png" alt="Valid HTML 4.0!" height="31" width="88"></a>
<td>
<ADDRESS>
<A HREF="http://www.sjbaker.org">
Steve J. Baker.</A>
&lt;<A HREF="mailto:sjbaker1@airmail.net">sjbaker1@airmail.net</A>&gt;
</ADDRESS>
</table>
</BODY>
</HTML>

305
doc/ssg/ssgLeaf.html Normal file
View 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,&amp;v1,&amp;v2,&amp;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">&lt;= previous =</a></td>
<td width="34%" align="center"><a href="index.html">Return to SSG Index</a></td>
<td width="33%" align="right"><a href="branches.html">= next =&gt;</a></td>
</tr>
</table>
<hr>
<table>
<tr>
<td>
<a href="http://validator.w3.org/check/referer"><img border="0" src="../valid-html40.png" alt="Valid HTML 4.0!" height="31" width="88"></a>
<td>
<ADDRESS>
<A HREF="http://www.sjbaker.org">
Steve J. Baker.</A>
&lt;<A HREF="mailto:sjbaker1@airmail.net">sjbaker1@airmail.net</A>&gt;
</ADDRESS>
</table>
</BODY>
</HTML>

255
doc/ssg/state.html Normal file
View 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">&lt;= previous =</a></td>
<td width="34%" align="center"><a href="index.html">Return to SSG Index</a></td>
<td width="33%" align="right"><a href="ssgContext.html">= next =&gt;</a></td>
</tr>
</table>
<hr>
<table>
<tr>
<td>
<a href="http://validator.w3.org/check/referer"><img border="0" src="../valid-html40.png" alt="Valid HTML 4.0!" height="31" width="88"></a>
<td>
<ADDRESS>
<A HREF="http://www.sjbaker.org">
Steve J. Baker.</A>
&lt;<A HREF="mailto:sjbaker1@airmail.net">sjbaker1@airmail.net</A>&gt;
</ADDRESS>
</table>
</BODY>
</HTML>

BIN
doc/ssgAux.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

886
doc/ssgAux/index.html Normal file
View File

@@ -0,0 +1,886 @@
<!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>SSG Auxiliary Libraries.</TITLE>
</HEAD>
<BODY text="#B5A642" link="#8FFF8F" vlink="#18A515" alink="#20336B"
bgcolor="#005000" background="../marble.png">
<TABLE>
<TR>
<TD>
<H1>SSG Auxiliary Libraries.</H1>
</TD>
</TR>
<TR>
<TD>
by Steve Baker
</TD>
</TR>
</TABLE>
<H2>Introduction</H2>
<TABLE>
<TR>
<TD>
PLIB/ssgAux is a suite of auxiliary libraries that build
higher level classes on top of the basic SSG classes.
<p>
<ul>
<li><A HREF="#ssgaShape">ssgaShape - Abstract Base Class</A>
<li><A HREF="#ssgaCube">ssgaCube - Makes a cube.</A>
<li><A HREF="#ssgaPatch">ssgaPatch - Makes a Bezier patch.</A>
<li><A HREF="#ssgaTeapot">ssgaTeapot - Makes a Teapot.</A>
<li><A HREF="#ssgaSphere">ssgaSphere - Makes a Sphere.</A>
<li><A HREF="#ssgaCylinder">ssgaCylinder - Makes a Cylinder.</A>
<li><A HREF="#ssgaWaveSystem">ssgaWaveSystem - Simulates Water Waves</A>
<li><A HREF="#ssgaParticleSystem">ssgaParticleSystem - Implements a spray of particles</A>
<li><A HREF="#ssgaFire">ssgaFire - Simulates Fire</A>
<li><A HREF="#ssgaLensFlare">ssgaLensFlare - Simulates Lens Flare for drawing bright lights.</A>
<li><A HREF="#ssgaSky">ssgaSky - Model a sky with sun, moon, clouds, stars & planets.</A>
</ul>
</TD>
<TD>
<center>
<IMG SRC="snapshot.png" ALT="ssgAux screenshot" WIDTH=417 HEIGHT=309>
<br>
This image was created entirely from ssgAux primitives.
</center>
</TD>
</TR>
</TABLE>
<p>
<H2>Conventions</H2>
ssgAux is installed and named with the same
conventions as the base PLIB libraries.
<br>
ie:
<pre>
/usr/include/plib/ssgAux.h
/usr/lib/libplibssgaux.a
</pre>
<p>
PLIB/ssgAux functions, classes and constants are all
named with an 'ssga' or 'SSGA' prefix.
<br>
eg:
<pre>
class ssgaShape ;
SSGA_TYPE_CUBE
</pre>
<A NAME="ssgaShape"></A>
<H1>ssgaShape</H1>
This is an abstract base class for many of the more
complex classes in the ssgAux 'collection'. The idea
is that ssgaShape's are really ssgBranch nodes that create
their own child nodes - but they behave in such a way that
you are never concerned with the nodes they create beneath
themselves.
<pre>
class ssgaShape : public ssgBranch
{
ssgaShape (void) ;
ssgaShape ( int numtris ) ;
float *getCenter () { return center ; }
float *getSize () { return size ; }
int getNumTris () { return ntriangles ; }
void setColour ( sgVec4 c ) { sgCopyVec4 ( colour, c ) ; regenerate () ; }
void setCenter ( sgVec3 c ) { sgCopyVec3 ( center, c ) ; regenerate () ; }
void setSize ( sgVec3 s ) { sgCopyVec3 ( size , s ) ; regenerate () ; }
void setSize ( float s ) { sgSetVec3 ( size,s,s,s) ; regenerate () ; }
void setNumTris ( int ntri ) { ntriangles = ntri ; regenerate () ; }
void setKidState ( ssgState *s ) ;
void setKidCallback ( int cb_type, ssgCallback cb ) ;
virtual void regenerate () = 0 ;
}
</pre>
The constructor allows you to specify the approximate number of
triangles you'd like the shape to consume. For some shapes, this
will be ignored (eg the Cube has 12 triangles - no matter how many
you ask for) - for others, it's honored only approximately (eg the
Sphere can only generate certain specific numbers of triangles) -
and for others, it may be honored exactly.
<p>
You can also set the colour of all the polygons and the ssgState and
callbacks that are applied to all of the child nodes.
<p>
setCenter allows you to position the center point of the object in
3D space - and setSize lets you determine the overall dimensions of
the object (this too may also be approximate - the 'size' of a teapot
is hard to specify in any useful way). The version of 'setSize' that
takes an sgVec3 allow you to generate cuboids from cubes and sphereoids
from spheres...but not all shapes allow this.
<p>
The 'regenerate' call allows the complete child structure of the object
to be deleted and then recreated. This is occasionaly useful if (for
example) you have walked down into the child structures and modified
them - and you'd like the shape back into it's pristine conditions.
<A NAME="ssgaCube"></A>
<H1>ssgaCube</H1>
<pre>
class ssgaCube : public ssgaShape
{
ssgaCube (void) ;
ssgaCube ( int numtris ) ;
virtual void regenerate () ;
} ;
</pre>
This is the simplest of ssgaShapes - it defines nothing new over
and above the standard ssgaShape.
<A NAME="ssgaPatch"></A>
<H1>ssgaPatch</H1>
<pre>
class ssgaPatch : public ssgaShape
{
ssgaPatch (void) ;
ssgaPatch ( int numtris ) ;
void setControlPoint ( int s, int t, sgVec3 xyz, sgVec2 uv, sgVec4 rgba ) ;
void setControlPoint ( int s, int t,
float x, float y, float z,
float u, float v,
float r, float g, float b, float a ) ;
void getControlPoint ( int s, int t, sgVec3 xyz, sgVec2 uv, sgVec4 rgba ) ;
virtual void regenerate () ;
} ;
</pre>
This implements a basic spline patch - with a 4x4 grid of 'control points'
that define its shape. 'setContolPoint' allows you to set the spatial
position, the texture coordinate and the colour at any given (s,t) position.
(s and t each must be in the range 0..3).
<p>
It's necessary to call the 'regenerate' function whenever you have added
or changed one or more control points.
<A NAME="ssgaTeapot"></A>
<H1>ssgaTeapot </H1>
<pre>
class ssgaTeapot : public ssgaShape
{
ssgaTeapot (void) ;
ssgaTeapot ( int numtris ) ;
virtual void regenerate () ;
} ;
</pre>
This creates the 'classic' Martin Newell teapot model.
<A NAME="ssgaSphere"></A>
<H1>ssgaSphere</H1>
<pre>
class ssgaSphere : public ssgaShape
{
ssgaSphere (void) ;
ssgaSphere ( int numtris ) ;
void setLatLongStyle ( int ll ) ;
int isLatLongStyle () ;
virtual void regenerate () ;
} ;
</pre>
There are two ways to generate a sphere model - one is to produce a
fairly uniform grid of triangles that are as nearly equilateral
as possible. The alternative is to generate more nearly right-triangles
in cylindrical strips that are stacked on top of each other with a
circular disk at top and bottom.
<p>
The function 'setLatLongStyle(ll)' allows you to choose which you want,
call regenerate after you change types!
<A NAME="ssgaCylinder"></A>
<H1>ssgaCylinder</H1>
<pre>
class ssgaCylinder : public ssgaShape
{
ssgaCylinder (void) ;
ssgaCylinder ( int numtris ) ;
void makeCapped ( int c ) ;
int isCapped () ;
virtual void regenerate () ;
} ;
</pre>
Cylinders also come in two forms - capped and uncapped. Once again,
if you change the capped versus uncapped status, call regenerate to
make the new version.
<A NAME="ssgaWaveSystem"></A>
<H1>ssgaWaveSystem</H1>
This class is for handling water waves.
It generates a large polygonal mesh which it distorts in
realtime to simulate water waves.
<p>
The simulation uses between one and sixteen "Wave Trains" - each
using a class:
<pre>
class ssgaWaveTrain
{
ssgaWaveTrain () ;
float getSpeed () ;
float getLength () ;
float getLambda () ;
float getHeading () ;
float getWaveHeight () ;
void setSpeed ( float s ) ;
void setLength ( float l ) ;
void setLambda ( float l ) ;
void setHeading ( float h ) ;
void setWaveHeight ( float h ) ;
} ;
</pre>
So, you create a bunch of these trains (typically, two or three
is plenty to generate 'interesting' motion).
Each wave train has a direction in which the waves are travelling,
a speed, a wave length (which also affects the shape of the wave),
the height of the wave and a 'lambda' term (which controls how much
the tops of the waves bend over).
<p>
Next, generate the ssgaWaveSystem:
<pre>
class ssgaWaveSystem : public ssgaShape
{
ssgaWaveSystem ( int ntri ) ;
virtual void regenerate () ;
ssgaWSDepthCallback getDepthCallback () ;
void setDepthCallback ( ssgaWSDepthCallback cb ) ;
ssgaWaveTrain *getWaveTrain ( int i ) ;
void setWaveTrain ( int i, ssgaWaveTrain *t ) ;
float getWindSpeed () ;
float getWindDirn () ;
float getEdgeFlatten () ;
float getTexScaleU () ;
float getTexScaleV () ;
void setWindSpeed ( float speed ) ;
void setWindDirn ( float dirn ) ;
void setEdgeFlatten ( float dist ) ;
void setTexScale ( float u, float v ) ;
void updateAnimation ( float t ) ;
} ;
</pre>
The appearance of waves varies greatly with the depth of the
water - and this simulation produces the correct effects. There
is an optional user-callback that can be used to feed water depth
values into the simulation. The wave system will likely call this
function many thousands of times per frame - so make sure your
depth function is very efficient. If you don't provide a depth
function then the water will be assumed to be infinitely deep.
<p>
You can determine the number of polygons used to render
the patch of waves, the size of the wave patch and the amount
of texture repetition. The 'EdgeFlatten' setting determines
to what distance from the edge of the patch the waves are
gradually flattened out. This is useful because it allows
you to keep all those expensive wave polygons close to the
camera - and feather them out over range so that they blend
gently into a larger flat ocean.
<p>
Designing waves by calling the ssgaWaveSystem API is quite
difficult. You are advised to use the wave designer program
in the PLIB examples package. This program lets you adjust
wave parameters until it looks how you'd like - then hit the
'Write C++ code' to write out a source code snippet that you
can cut and paste into your program.
<p>
There is a 'README' in the 'water' source directory that
explains how to use the program in a little more detail.
That's all the wave system documentation I have time to write
just now - sorry.
<A NAME="ssgaParticleSystem"></A>
<H1>ssgaParticleSystem</H1>
This is a very flexible implementation of particle systems - it's not
as efficient as you might want for thousands of particles - this is intended
for high flexibility and relatively fewer numbers of particles.
<p>
All of that flexibility is evident in the complex constructor function:
<pre>
class ssgaParticleSystem : public ssgVtxArray
{
ssgaParticleSystem ( int max , /* Max Number of particles */
int init, /* Number to launch initially */
float add , /* Max number to create per sec */
int turn_to_face, /* Turn to face camera? */
float size, /* Size of particles */
float bsphere_rad, /* Size of bounding sphere */
ssgaParticleCreateFunc create, /* Initial create fn. */
ssgaParticleUpdateFunc update = NULL, /* Update function */
ssgaParticleDeleteFunc del = NULL /* Remove function */
) ;
void setSize ( float sz ) ;
float getSize () ;
update ( float dt ) ;
int getNumActiveParticles () ;
} ;
</pre>
There are three callback functions - with the following types:
<pre>
typedef void (* ssgaParticleCreateFunc) ( ssgaParticleSystem *ps,
int index,
ssgaParticle *p ) ;
typedef void (* ssgaParticleUpdateFunc) ( float deltaTime,
ssgaParticleSystem *ps,
int index,
ssgaParticle *p ) ;
typedef void (* ssgaParticleDeleteFunc) ( ssgaParticleSystem *ps,
int index,
ssgaParticle *p ) ;
</pre>
There is also a public class for a single particle:
<pre>
class ssgaParticle
{
public:
sgVec4 col ;
sgVec3 pos ;
sgVec3 vel ;
sgVec3 acc ;
float size ;
float time_to_live ;
void *userData ;
ssgaParticle () ;
} ;
</pre>
This is best explained with an example.
Here is an example of a fountain model:
<pre>
fountain = new ssgaParticleSystem ( 2000, /* Max Number of particles */
2, /* Number to launch initially */
200, /* Max number to create per sec */
TRUE, /* Turn to face? */
0.2, /* Size of particles */
20.0, /* Size of bounding sphere */
fountain_create, /* Initial create fn. */
fountain_update /* Update function */ ) ;
</pre>
This creates a system that has the capability to draw 2000 particles
(each is a quadrilateral). Two particles are launched initially and 200
more are added gradually every second. You can choose to have each particle
turn to face the camera - or to be oriented in the X/Z plane, mine are set to
turn-to-face. The particles are 0.2 OpenGL units across.
<p>
This fountain is a continuous effect - so the inital number of particles
to launch is small - and the 'per second' creation rate determines the
flow. If you wanted something more like an explosion, have a larger number
of initial particles and none launched per-second after that.
<p>
One messiness is that we don't know how big the fountain may become over
time - and it's VERY inefficient to recompute the bsphere every frame. Hence
you have to tell the class what the maximum bounding sphere of the fountain
is at the outset so we can field-of-view cull it - this <b>could</b> be a near
infinite radius (MAX_FLOAT say) if you truly don't know how big it could
get - but that's inefficient because all 2,000 particles must be sent to
OpenGL even if the fountain is 20 miles away behind the camera - so do your
best to come up with some kind of a reasonable guess.
<p>
fountain_create and fountain_update are user-defined callback functions,
we could also have defined a 'fountain_delete' function - but many applications
won't need this.
<ul>
<li>The 'create' callback is called every time the system needs to
create a new particle.
<li>The 'update' callback is called on every update cycle for every
particle that's in flight.
<li>The 'delete' callback is called when the system has decided
that a particle has 'died'.
</ul>
You have to have a 'create' function - but the other two are optional.
<p>
These callbacks are passed the address of the particle system, the index
number and address of the particle that's being created/updated/deleted -
and (for the 'update' function only) - the amount of elapsed time since
this particle was last updated.
<p>
The callbacks can set, read or change any or all aspects of the particle...
it's colour, position, velocity, accelleration, size and 'time to live'
(in seconds).
There is also a user data pointer - so you can hang your own data onto
each individual particle.
<p>
The particle system automatically moves each particle according to the usual
laws of motion and decrements it's time-to-live - so in many cases,
you can just set the initial velocity, the force due to
gravity and a reasonable time to live - and let the particle system code
do the rest.
<p>
My 'fountain_create' function looks like this:
<pre>
void fountain_create ( ssgaParticleSystem *, int, ssgaParticle *p )
{
sgSetVec4 ( p -&gt; col, 1, 1, 1, 1 ) ; /* initially white */
sgSetVec3 ( p -&gt; pos, 0, 0, 0 ) ; /* start off on the ground */
sgSetVec3 ( p -&gt; vel, (rand()%1000-500)/300.0f,
(rand()%1000-500)/300.0f, 50.0f ) ;
/* Shoot up and out */
sgSetVec3 ( p -&gt; acc, 0, 0, -9.8f ) ; /* Gravity */
p -&gt; time_to_live = 5 ; /* Droplets evaporate after 5 seconds */
}
</pre>
It populates the particle with an initial colour, position, velocity and
accelleration and gives it a 'time to live' of five seconds. The velocity
is randomised a bit to make a nicer looking fountain.
<p>
You can do all sorts of fancy things to the colour, position, velocity and
accelleration in your 'update' function.
<pre>
void fountain_update ( ssgaParticle *p )
{
if ( p -&gt; pos [ 2 ] &lt; 0 )
p -&gt; time_to_live = -1 ;
p -&gt; col [ 2 ] = (p -&gt; time_to_live &gt; 2) ? 1 : (p -&gt; time_to_live/2.0f) ;
}
</pre>
...this one just erases particles that go below zero altitude (by
setting their time-to-live variable to -1) and makes them go a pretty
shade of yellow for the last two seconds before they die.
<p>
The 'delete' function is principally useful for freeing up any user-data
you allocated in the 'create' function or during 'update's. Don't
delete the particle though - the particle system recycles it to avoid
doing too much dynamic memory allocation.
<p>
All that remains is to call the ssgaParticleSystem::update function
every frame with a parameter that tells the system how much time has
elapsed since the last call. This allows you to easily speed up, slow
down or pause the particles (or even run them backwards if you want).
<p>
I call this every frame:
<pre>
void updateFountain ()
{
static ulClock ck ;
ck . update () ;
if ( fountain != NULL )
fountain -&gt; update ( ck.getDeltaTime () ) ;
}
</pre>
This function could also check the number of particles currently in flight
and delete the fountain when there are none left - that might be useful
for an explosion or something where you'd want to save CPU time by not
running the explosion particle system when all the pieces have landed
and 'gone away'.
<p>
The size of each particle is the size field of the individual particle
MULTIPLIED by the number you pass into the size parameter of the
ssgaParticleSystem constructor (or set with setSize()). This allows you
to cheaply set the particle size for all the particles at once - or to
tweak the size of each one in turn. The number in the particle structure
defaults to 1.0 so you can ignore it and just set the size in the
particle system overall.
<p>
ssgaParticleSystem is derived from ssgVtxArray - so you can apply textures and
other state things using the usual ssgVtxArray::setState(ssgSimpleState*)
call. I applied a texture with a fuzzy alpha-blended circle.
<p>
While debugging this, I got a bug which caused a picture of Tux to be
applied instead of the droplet texture - it was absolutely hilarious
to see 2000 tiny penguins shooting up in a fountain and falling gently
to earth!
<A NAME="ssgaFire"></A>
<H1>ssgaFire</H1>
This class is actually a highly specialised particle system.
You have to construct it quite carefully in order to get a nice
looking fire:
<pre>
class ssgaFire : public ssgaParticleSystem
{
ssgaFire ( int num_tris,
float radius = 1.0f,
float height = 5.0f,
float speed = 2.0f ) ;
virtual ~ssgaFire () ;
virtual void update ( float t ) ;
void setUpwardSpeed ( float spd )
void setHeight ( float hgt )
void setRadius ( float rad )
void setHotColour ( sgVec4 col )
} ;
</pre>
In the constructor, you set the number of triangles you wish to
generate, the radius and height of the approximately cylindrical
fire and the speed at which the flames head up towards the sky.
<p>
The number of polygons you use tends to be rather critical - too
many and your fire will look too 'smooth' and will be mostly
white-hot. Too few and it'll look like a number of detached
reddish blobs floating upwards. For the default radius, between
100 and 200 triangles seems to look good - for a 10 meter patch
of fire, you may need as many as 2000 triangles to make it look
effective. All three parameters (speed, height and radius) can
be manipulated in realtime - but since the number of polygons
is fixed, there is a limit to the amount of realtime tweaking
you can do without making it look silly.
<p>
The 'setHotColour' function allows you to set the colour
of the hottest flames (at the base of the fire). Since many
layers of polygons add up to form the colour, you'll tend to
want to use a primary colour with about 10% of one or two of
the other primaries. The default colour is (1.0, 0.2, 0.1, 1.0)
which produces red flames with yellow and white in the hotter
regions.
<p>
<A NAME="ssgaLensFlare"></A>
<H1>ssgaLensFlare</H1>
When you view the sun (or some other very bright light source) through
the imperfect lens of a camera, you get a row of bright circles and
rings in a line from the light source, through the center of the lens.
This is called a 'lens flare' and it can be very effective in computer
graphics in depicting a light source that's brighter than the computer
screen can display. It almost makes you want to squint because of
the brightness.
<p>
The ssgaLensFlare object is a special kind of ssgaShape that can be
positioned beneath the same transform
as the source of the light - and it 'just works'. You don't need
to set any parameters - just add it into the SSG scene graph in the
right place.
<p>
eg:
<pre>
ssgTransform *myTransform ;
ssgBranch *myLightSource ;
/* Set up myTransform and myLightsource */
...
myTransform -&gt; addKid ( myLightSource ) ;
myTransform -&gt; addKid ( new ssgaLensFlare ) ;
</pre>
It contains a (hard-coded) 256x128 texture map which is compiled
into the code and shared between however many lens flares there
are in the scene.
<p>
<A NAME="ssgaSky"></A>
<H1>ssgaSky</H1>
<TABLE>
<TR>
<TD width="40%" valign="top">
The ssgaSky class models a blended sky dome, with methods to add celestial
bodies, for example a haloed sun or a textured moon, and methods to add
clouds, stars and planets.
<p>
<b>WARNING</b> - Solaris C/C++ compilers (from Sun Microsystems Inc) have
some nasty '#define's for the word 'SUN' and 'sun'. If you are writing
portable software, you might want to pick an alternative word! PLIB uses 'Sol',
the formal astronomical name for the star that happens to be our sun.
<p>
The sky implements various time of day lighting effects, it plays well
with fog and visibility effects, and implements scudded cloud fly-through
effects. Additionally, you can wire in the output of the SimGear
<a href="http://www.simgear.org/doxygen/classSGEphemeris.html">SGEphemeris</a>
class to accurately position all the objects in the sky.
<p>
This sky dome code was based on the <a href="http://www.simgear.org/">SimGear</a>
sky code, written by Curtis Olson, which is used in
<a href="http://www.flightgear.org/">FlightGear</a>.
The code was moved into PLIB for easier access, STL was removed and 'flat
earth' methods added. The main reason the code was moved here was to allow
the PLIB community to add their own extensions (not relevant to FlightGear),
to build for example, 'un-realistic' sky domes, with green skies, purple
clouds or multiple suns. This has not yet fully been achieved, but hopefully
when someone finds the time or has the need, these features will be added.
</TD>
<TD>
<center>
<IMG SRC="ssgaSky.png" ALT="ssgaSky screenshots" WIDTH=400 HEIGHT=300>
<br>
ssgaSky screenshots
</center>
</TD>
</TR>
</TABLE>
<pre>
class ssgaSky
{
public:
ssgaSky( void );
~ssgaSky( void );
void build( double h_radius, double v_radius,
int nplanets, sgdVec3 *planet_data,
int nstars, sgdVec3 *star_data);
ssgaCelestialBody* addBody( const char *body_tex_path, const char *halo_tex_path, double size, double dist, bool sol = false );
ssgaCelestialBody* addBody( ssgSimpleState *orb_state, ssgSimpleState *halo_state, double size, double dist, bool sol = false );
ssgaCelestialBody* getBody(int i) { return bodies.get(i); }
int getBodyCount() { return bodies.getNum(); }
ssgaCloudLayer* addCloud( const char *cloud_tex_path, float span, float elevation, float thickness, float transition );
ssgaCloudLayer* addCloud( ssgSimpleState *cloud_state, float span, float elevation, float thickness, float transition );
ssgaCloudLayer* getCloud(int i) { return clouds.get(i); }
int getCloudCount() { return clouds.getNum(); }
bool repositionFlat( sgVec3 view_pos, double spin, double dt );
bool reposition( sgVec3 view_pos, sgVec3 zero_elev, sgVec3 view_up,
double lon, double lat, double alt, double spin, double gst, double dt );
bool repaint( sgVec4 sky_color, sgVec4 fog_color, sgVec4 cloud_color, double sol_angle,
int nplanets, sgdVec3 *planet_data,
int nstars, sgdVec3 *star_data );
void modifyVisibility( float alt, float time_factor );
void preDraw();
void postDraw( float alt );
void enable();
void disable();
float getVisibility();
void setVisibility( float v );
} ;
</pre>
<H2>Building the sky</H2>
Once you have created an instance of ssgaSky you must call the
build() method. The arguments you pass to the build() method
allow you to specify the size of your sky dome, a number of planets,
and a multitude of stars. For the planets and stars you pass in
an array of right ascensions, declinations, magnitudes, and the
distance from the view point.
<H2>Celestial Bodies</H2>
Celestial bodies (eg. sun, moon or even mars if you like) can be
added or modified individually. To add a body use the addBody()
method. The arguments allow you to specify the body texture, the
halo texture, the size of the body, the body distance (usually the
sky dome size) and a boolean flag to indicate if the body should
be used as a reference to 'spin' the dome based on the bodies rotation
for correct sunrise and sunset effects (nb. the sun reference is only used
by repositionFlat() so the user does not need to calculate the spin
parameter). There is an additional form of this method that allows
you to specify your own ssgSimpleState for drawing the body and halo
texture.
<p>
Body accessor methods are available to:
<ul>
<li> set body right ascension and declination
<li> get body position and color
</ul>
note: body angle and rotation are calculated internally (by
ssgaSky::repositionFlat() only) for sunrise and sunset effects.
<pre>
class ssgaCelestialBody
{
...
void getPosition ( sgCoord* p );
void setAngle ( double angle );
double getAngle ();
void setRotation ( double rotation );
double getRotation ();
void setRightAscension ( double ra );
double getRightAscension ();
void setDeclination ( double decl );
double getDeclination ();
void setDist ( double dist );
double getDist ();
float *getColor();
} ;
</pre>
<H2>Cloud Layers</H2>
Cloud layers can be added or modified individually. To add a cloud
layer use the addCloud() method. The arguments allow you to specify
cloud texture, the size of the cloud object, base height above sea
level, layer thickness and a transition zone for entering/leaving
the cloud layer. There is an additional form of this method that
allows you to specify your own ssgSimpleState for drawing the cloud
layer texture.
<p>
Cloud accessor methods are available to:
<ul>
<li> enable/disable clouds
<li> set elevation above sea level
<li> set thickness and transition - used to simulate cloud 'puffs'
<li> set speed and direction - used to simulate cloud movement
</ul>
<pre>
class ssgaCloudLayer
{
...
void enable();
void disable();
bool isEnabled();
float getElevation ();
void setElevation ( float elevation );
float getThickness ();
void setThickness ( float thickness );
float getTransition ();
void setTransition ( float transition );
float getSpeed ();
void setSpeed ( float val );
float getDirection ();
void setDirection ( float val );
} ;
</pre>
<H2>Repainting the Sky</H2>
As the sun circles the globe, you can call the repaint() method to
re-color the sky objects to simulate sunrise and sunset effects,
visibility, and other lighting changes. The arguments allow you
to specify a base sky color (for the top of the dome), a fog color
(for the horizon), a cloud color (for blending clouds with the fog
color), the sun angle with the horizon (for sunrise/sunset effects),
and new star and planet data so that we can optionally change the
magnitude of these (for day/night transitions).
<H2>Positioning Sky Objects</H2>
As time progresses and as you move across the surface of the earth,
the apparent position of the objects and the various lighting effects
can change. At this point you may wish to call celestial body
setRightAscension() and setDeclination() methods to update the
position of your bodies (SimGear
<a href="http://www.simgear.org/doxygen/classSGEphemeris.html">SGEphemeris</a>
can be used if you wish to place bodies correctly).
<p>
Once you have specified the positions of all the sky objects, you must
call the repositionFlat() or reposition() method to allow you to specify
your view position.
<p>
The repositionFlat() arguments allow you to specify view position for
a 'flat earth' model. A 'spin' angle can be specified for orienting
the sky with the sun position so sunset and sunrise effects look correct.
If you specified a body to be the sun reference on addBody() you do not
need to specify the 'spin' angle. You may specify the amount of elapsed
time since the sky was last updated (used to animate cloud movement).
<p>
The reposition() arguments allow you to specify your view position in
world Cartesian coordinates, the zero elevation position in world
Cartesian coordinates (your longitude, your latitude, sea level),
the 'up' vector in world Cartesian coordinates, current longitude,
latitude, and altitude. A 'spin' angle can be specified for
orienting the sky with the sun position so sunset and sunrise
effects look correct. You must specify GMT side real time. You may
specify the amount of elapsed time since the sky was last updated
(used to animate cloud movement).
<H2>Rendering the Sky</H2>
The sky is designed to be rendered in two stages. The first stage
renders the parts that form your back drop - the sky dome, the
stars, the planets and the celestial bodies. These should be
rendered before the rest of your scene by calling the preDraw()
method. The second stage renders the clouds which are likely to be
translucent and should be drawn after your scene has been rendered.
Use the postDraw() method to draw the second stage of the sky.
<p>
A typical application might do the following:
<pre>
thesky->preDraw();
ssgCullAndDraw ( myscene ) ;
thesky->postDraw( my_altitude );
</pre>
The current altitude in meters is passed to the postDraw()
method so the clouds layers can be rendered correctly from
most distant to closest.
<H2>Visibility Effects</H2>
Visibility and fog is important for correctly rendering the sky.
You can inform ssgaSky of the current visibility by calling
the setVisibility() method.
<p>
When transitioning through clouds, it is nice to pull in the
fog as you get close to the cloud layer to hide the fact that
the clouds are drawn as a flat polygon. As you get nearer to
the cloud layer it is also nice to temporarily pull in the
visibility to simulate the effects of flying in and out of
the puffy edge of the cloud. These effects can all be
accomplished by calling the modifyVisibility() method. The
arguments allow you to specify your current altitude
(which is then compared to the altitudes of the various
cloud layers). You can also specify a time factor which
should be the length in seconds since the last time you
called modifyVisibility(). The time_factor value allows the
puffy cloud effect to be calculated correctly.
<p>
The modifyVisibility() method alters the ssgaSky's internal
idea of visibility, so you should subsequently call
getVisibility() to get the actual modified visibility.
You should then make the appropriate glFog() calls to
setup fog properly for your scene.
<H2>Accessor Methods</H2>
Once an instance of ssgaSky has been successfully
initialized, there are a couple accessor methods you
can use such as getBodyCount() to return the number
of celestial bodies, getBody(i) to return body number
i, getCloudCount() to return the number
of cloud layers, getCloud(i) to return cloud
layer number i, getVisibility() to return the actual
visibility as modified by the sky/cloud model.
<p>
<hr>
<table>
<tr>
<td>
<a href="http://validator.w3.org/check/referer"><img border="0" src="../valid-html40.png" alt="Valid HTML 4.0!" height="31" width="88"></a>
<td>
<ADDRESS>
<A HREF="http://www.sjbaker.org">
Steve J. Baker.</A>
&lt;<A HREF="mailto:sjbaker1@airmail.net">sjbaker1@airmail.net</A>&gt;
</ADDRESS>
</table>
</BODY>
</HTML>

BIN
doc/ssgAux/snapshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

BIN
doc/ssgAux/ssgaSky.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

BIN
doc/torcs_logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

BIN
doc/tux_aqfh.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

BIN
doc/tuxfleet_logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

BIN
doc/tuxkart_logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

626
doc/util/index.html Normal file
View File

@@ -0,0 +1,626 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<META http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<META name="keywords" content="UL, PLIB, OpenGL, utility, library, portable, Baker, Steve, ulDir, ulClock, ulDynamicLibrary, ulList, ulLinkedList, ulHashTable, ulPropertySet, ulSleep, ulMilliSecondSleep, ulFindFile, ulFileExists, ulIsAbsolutePathName, ulGetCWD, ulMakePath, ulSetErrorCallback, ulGetErrorCallback, ulGetError, ulClearError, ulStrEqual, ulStrNEqual">
<META name="description" content="The PLIB Utility Library is targeted towards hiding common operating system functions behind a thin layer that makes them portable and provides some useful helper classes and routines.">
<TITLE>The Utility Library.</TITLE>
</HEAD>
<BODY text="#B5A642" link="#8FFF8F" vlink="#18A515" alink="#20336B"
bgcolor="#005000" background="../marble.png">
<H1>The PLIB general Utility Library.</H1>
By Sebastian Ude
<H2>Introduction</H2>
The 'UL' utility library is primarily targeted towards hiding common
operating system functions behind a thin layer that makes them portable.
Additionally, it provides some helper classes or routines that were
usually written to support certain parts of the
<a href="../index.html">PLIB</a> library, but at some point we felt that
they could be useful for user applications as well.
<p>
UL is a part of <a href="../index.html">PLIB</a>.
<h2>Contents:</h2>
<ul>
<li><a href="#miscFunc">Misc. routines</a>
<li><a href="#fileHandling">File handling</a>
<li><a href="#dirHandling">Directory handling</a>
<li><a href="#dataStorage">Data storage</a>
<li><a href="#errorHandling">Error handling</a>
<li><a href="#miscClasses">Misc. classes</a>
<li><a href="#endianHandling">Endian handling</a>
</ul>
<h2>Quick reference:</h2>
<table>
<tr>
<td><h3>Classes:</h3>
<td colspan=2><h3>Non-class functions:</h3>
<tr>
<td>
<ul>
<li><a href="#ulDir">ulDir</a>
<li><a href="#ulClock">ulClock</a>
<li><a href="#ulDynamicLibrary">ulDynamicLibrary</a>
<li><a href="#ulList">ulList</a>
<li><a href="#ulLinkedList">ulLinkedList</a>
<li><a href="#ulHashTable">ulHashTable</a>
<li><a href="#ulPropertySet">ulPropertySet</a>
</ul>
<td>
<ul>
<li><a href="#ulSleep">ulSleep</a>, <a href="#ulMilliSecondSleep">ulMilliSecondSleep</a>
<li><a href="#ulFindFile">ulFindFile</a>
<li><a href="#ulFileExists">ulFileExists</a>
<li><a href="#ulIsAbsolutePathName">ulIsAbsolutePathName</a>
<li><a href="#ulGetCWD">ulGetCWD</a>
<li><a href="#ulMakePath">ulMakePath</a>
<li><a href="#ulSetErrorCallback">ulSetErrorCallback</a>, <a href="#ulGetErrorCallback">ulGetErrorCallback</a>
</ul>
<td valign="top">
<ul>
<li><a href="#ulGetError">ulGetError</a>, <a href="#ulClearError">ulClearError</a>
<li><a href="#ulStrEqual">ulStrEqual</a>, <a href="#ulStrNEqual">ulStrNEqual</a>
</ul>
</table>
<h2><a name="miscFunc">Misc. routines</a></h2>
<h3><a name="ulSleep">ulSleep</a></h3>
<pre><i>
void ulSleep ( int seconds ) ;
</i></pre>
Now comes a typical example of what the UL library does. If you need to
'sleep' for, say, 3 seconds, then under Linux/UNIX, you'd need to call:
<pre><i>
sleep ( 3 ) ;
</i></pre>
But under MS-Windows, you have to say:
<pre><i>
Sleep ( 3000 ) ;
</i></pre>
In order to avoid writing non-portable code, you can instead call:
<pre><i>
ulSleep ( 3 ) ;
</i></pre>
...under either operating system.
<p>
<h3><a name="ulMilliSecondSleep">ulMilliSecondSleep</a></h3>
<pre><i>
void ulMilliSecondSleep ( int milliseconds ) ;
</i></pre>
Same as <a href="#ulSleep">ulSleep</a>, except that it sleeps (as you
may have guessed) a certain number of milliseconds instead of seconds.
<h2><a name="fileHandling">File handling</a></h2>
<h3><a name="ulFindFile">ulFindFile</a></h3>
<pre><i>
void ulFindFile ( char *filenameOutput, const char *path, const char * tfnameInput, const char *sAPOM ) ;
</i></pre>
Basically, this utility function adds tfnameInput to the path and puts this
into the buffer filenameOutput.
<p>
It handles special chars in path:
<ul>
<li>";;" is replaced by ";"
<li>"$$" is replaced by "$"
<li>"$(APOM)" is replaced by sAPOM
</ul>
If there are ";" in path, the path-variable is interpreted as several paths
"segments", delimited by ";". The first file found by this function is
returned. It looks from left to right. A segment may end in $(...). ulFindFile
will then look in in this path and recursively in all the sub-paths.
<p>
Some examples:
<p>
To load *.MDl-models, it is very nice to set the texture path to
"$(APOM);$(APOM)/texture;$(APOM)/../texture". This consists of three segments
and tells ulFindFile to look in the path of the model, in a subpath texture
and in a path texture "besides" the path of the model. Some *.mdl-models are
shipped in a directory which contains a "texture"-directory, a
"Model"-directory and others. In this case you find the texture in
"$(APOM)/../texture".
<p>
Another example: You have all your textures in a directory-structure under
/roomplan:
<pre>
textures --+-- Wallpapers
|
+-- Wood --+-- Oak
| |
| +-- pine
...
</pre>
Then you should simply use the following texture path:
"/roomplan/$(...)"
<p>
<h3><a name="ulFileExists">ulFileExists</a></h3>
<pre><i>
bool ulFileExists ( const char *fileName ) ;
</i></pre>
Returns "true" if a file with the name 'fileName' exists, or "false" if
it does not.
<p>
<h3><a name="ulIsAbsolutePathName">ulIsAbsolutePathName</a></h3>
<pre><i>
int ulIsAbsolutePathName ( const char *pathname ) ;
</i></pre>
Returns '1' if 'pathname' is an absolute pathname or '0' if it is an
relative one.
<p>
<h3><a name="ulGetCWD">ulGetCWD</a></h3>
<pre><i>
char * ulGetCWD ( char *result, int maxlength ) ;
</i></pre>
Stores the current working directory in 'result', which has enough space
for 'maxlength' characters, including the trailing '\0'. On success,
'result' is returned.
<p>
<h3><a name="ulMakePath">ulMakePath</a></h3>
<pre><i>
char * ulMakePath ( char *path, const char *dir, const char *fname ) ;
</i></pre>
Concatenates the strings 'dir' and 'fname', puts the system's slash character
inbetween and stores stores the result in 'path'. Be sure that the buffer
'path' is large enough to store 'strlen ( dir ) + strlen ( fname ) + 2'
(slash and trailing '\0') characters.
<h2><a name="dirHandling">Directory handling</a></h2>
<h3><a name="ulDir">struct ulDir</a></h3>
This structure provides a portable way to read directories. To allocate and
initialize a new ulDir structure, call:
<pre><i>
ulDir * ulOpenDir ( const char* dirname ) ;
</i></pre>
This function returns a pointer to a newly allocated ulDir structure on
success or a NULL pointer if the specified directory could not be read.
<p>
After you have constructed an ulDir structure, the directory content can
be read with subsequent calls to:
<pre><i>
struct ulDirEnt
{
char d_name [ UL_NAME_MAX+1 ] ;
bool d_isdir ;
} ;
ulDirEnt * ulReadDir ( ulDir *dir ) ;
</i></pre>
This function returns a pointer to a ulDirEnt structure which resides in
the corresponding ulDir structure and which has the above form. The "d_isdir"
flag indicates if a directory entry is another directory. If the end of the
directory has been reached, the function returns NULL.
<p>
To free an ulDir object and to close the associated directory stream,
please call:
<pre><i>
void ulCloseDir ( ulDir *dir ) ;
</i></pre>
<h2><a name="dataStorage">Data storage</a></h2>
<h3><a name="ulList">class ulList</a></h3>
<pre><i>
ulList::ulList ( int init_max = 1 ) ;
</i></pre>
This class stores a list of generic (void*) pointers using an
automatically-growing array. Since the process of resizing the internal
array is rather expensive, it is important that one picks a reasonable default
array size (<i>init_max</i>) when constructing an ulList object if performance
matters. Remember that a too large size means that some memory is wasted (but
memory is cheap nowadays), while a too small one means that expensive array
resize operations will be necessary later.
<p>
If you have absolutely no clue about how many entities will be stored,
you should probably look at the <a href="#ulLinkedList">linked list class</a>
below, which has it's own disadvantages, though.
<p>
Once you have constructed an ulList (hopefully with a good initial size),
you can insert an element using one of the following methods:
<pre><i>
void ulList::addEntity ( void *entity ) ;
void ulList::addBefore ( int n, void *entity ) ;
</i></pre>
While the first one simply adds the new entity to the tail of the list,
the second one lets you specify an exact position (0 is the first element).
Note that due to it's array implementation, inserting an entity at the head
or the middle of the ulList requires that the following entities are all
shifted one array slot to the right, which can be a rather expensive
operation.
<p>
These functions automatically check whether there is room for one more element
and double the internal array's size if necessary. However, as said
previously, resizing the array is a rather expensive process, so it is not
recommended that you rely too much on this behavior. Instead, pick a good
initial array size.
<p>
Note that ulList allows you to have multiple entities with the same data
value in the list. Please also note that ulList does not make it's own copy
of the data pointed to by 'entity'. It is up to you to take care of that the
memory region that 'entity' points to holds something useful as long as the
ulList exists. Be especially careful with addresses of variables that have a
limited lifetime.
<p>
To retrieve an entity, call:
<pre><i>
void * ulList::getEntity ( unsigned int n ) ;
</i></pre>
Where 'n' is the position of the entity in the list. If 'n' is not a valid
index, NULL is returned. Once you have called this function, you can use
subsequent calls to
<pre><i>
void * ulList::getNextEntity ( void ) ;
</i></pre>
in order to retrieve the following entities in the list. If there are no more
entities, this function will return NULL.
<p>
To remove an entity, call one of:
<pre><i>
void ulList::removeEntity ( unsigned int n ) ;
void ulList::removeEntity ( void *entity ) ;
</i></pre>
Where the second function removes the <b>first</b> entity with the specified
data value in case there are multiple ones.
<p>
To replace the value of an entity, call one of:
<pre><i>
void ulList::replaceEntity ( unsigned int n, void *new_entity ) ;
void ulList::replaceEntity ( void *old_entity, void *new_entity ) ;
</i></pre>
Where the second function will replace the value of the <b>first</b> entity
with the specified old data value in case there are multiple ones.
<p>
And finally, you can retrieve the number of entities stored in the list
(that's <b>not</b> necessarily the internal array's size), remove all
entities or retrieve the position of an entity by specifying it's data
value:
<pre><i>
void ulList::getNumEntities ( void ) const ;
void ulList::removeAllEntities () ;
int ulList::searchForEntity ( void *entity ) const ;
</i></pre>
Where the latter returns a negative value if no entity with the specified
value was found in the list, and otherwise the position of the <b>first</b>
entity with the specified data value.
<p>
<h3><a name="ulLinkedList">class ulLinkedList</a></h3>
<pre><i>
ulLinkedList::ulLinkedList () ;
</i></pre>
The ulLinkedList class stores generic (void*) pointers using a linked list
of nodes where each node maintains a pointer to the next node.
<p>
This technique has some advantages compared to an array implementation of a
list like <a href="#ulList">ulList</a>.
<ul>
<li>
No wasted memory. When storing data using arrays (as
<a href="#ulList">ulList</a> does), it is a common practice to choose an array
size that seems "large enough". Most of the time the number of entities stored
will be smaller than the available array slots, so some memory space is wasted.
With a linked list, we allocate single nodes. No memory is wasted (except a
few bytes for each node's pointer to the next node).
<li>
Resizing an array is an expensive operation, since usually the whole array
content has to be copied from the old to the new memory location. We do not
have this problem with linked lists.
<li>
In contrast to arrays, it is a cheap operation to insert or remove entities
to / from the head or middle of a linked list. While with an array, the
following entities must all be shifted one slot to the left or right, we
simply need to (re)connect a few pointers with a linked list.
</ul>
There are some disadvantages, though:
<ul>
<li>
In contrast to an array, there is no cheap way to locate the n-th entity in a
linked list. With an array, you simply have to add the desired position
multiplied with the size of an element to the array's base address and
look at the content of the memory at this location - a very simple operation.
With a linked list, however, we need to iterate over all nodes 'n' times,
so locating the 1000th node is a rather expensive operation.
<li>
One may argue that insertion operations are more expensive with linked lists
than with arrays, since we allocate single nodes from the heap in contrast
to an array, where the whole list is one huge allocated block of memory.
Although allocation from the heap is indeed rather expensive, this is not
true when it comes to insertions to the middle of a list, these are usually
<b>way</b> more expensive with arrays. Furthermore, a list implemented using
an array such as <a href="#ulList">ulList</a> may make resizes of the array
necessary on insertions, which are again rather expensive.
</ul>
Decide yourself if a list implemented as an array such as
<a href="#ulList">ulList</a> or a linked list implementation like this one fits
your needs better.
<p>
Once you have constructed a ulLinkedList object, you can insert a node using
one of:
<pre><i>
void ulLinkedList::appendNode ( void *data ) ;
void ulLinkedList::prependNode ( void *data ) ;
void ulLinkedList::insertNode ( void *data, int pos ) ;
</i></pre>
While "appendNode" adds the new node at the tail of the list, "prependNode"
will place the new node at the head of the list, and "insertNode" allows
you to specify the desired position ('0' is the first node) yourself; 'pos'
must be either '0' or a number between '0' and the number of nodes minus one.
"prependNode" is equal to calling "insertNode" with pos == 0.
<p>
Note that ulLinkedList allows you to have two nodes with the same data in
the list. Also note that just as <a href="#ulList">ulList</a>, ulLinkedList
does not make it's own copy of the memory pointed to by 'data', so make sure
that the corresponding memory location holds something useful as long as the
list exists.
<p>
To retrieve the number of nodes in the list, call:
<pre><i>
int ulLinkedList::getNumNodes ( void ) const ;
</i></pre>
<p>
To retrieve the data of the node at a certain position in the list, call:
<pre><i>
void * ulLinkedList::getNodeData ( int pos ) const ;
</i></pre>
Where 'pos' must be a number between '0' and the number of nodes minus one,
again.
<p>
If you need to retrieve the position of a node in the list by specifying it's
data value, call:
<pre><i>
int ulLinkedList::getNodePosition ( void *data ) const ;
</i></pre>
If there is more than one node whose data value is 'data' in the list, this
function will return the position of the <b>first</b> one. If there is no
node with the specified data value in the list, this function will return a
negative number to indicate failure.
<p>
Checking if the return value of "getNodePosition" is non-negative is also
the recommended way to determine whether there exists at least one node with
a certain data value in a list.
<p>
To remove a node from the list, call one of:
<pre><i>
bool ulLinkedList::removeNode ( void *data ) ;
void * ulLinkedList::removeNode ( int pos ) ;
</i></pre>
Where the first function returns 'true' if the node was sucessfully removed or
'false' if it could not find a node whose value is 'data'. In case there is
more than one node whose data value is 'data', it will remove the <b>first</b>
one. With the second function, 'pos' has to be a number between '0' and the
number of nodes minus one. It's return value is the removed node's data
value.
<p>
To iterate over the list (starting from the head) and to have a custom
function being called for each node's data pointer, call:
<pre><i>
typedef bool (*ulIterateFunc)( void *data, void *user_data ) ;
void * ulLinkedList::forEach ( ulIterateFunc fn, void *user_data = NULL ) const ;
</i></pre>
The iteration process will stop if your ulIterateFunc returns 'false', in
which case "forEach" returns the data value of the node at which the iteration
stopped, or if the tail of the list has been reached, in which case "forEach"
returns NULL. The user_data pointer will be passed to your ulIterateFunc as
the second argument.
<p>
ulLinkedList allows you to maintain a sorted list as an option. To set up
a sorted list, simply be sure to insert all nodes using the sorted insertion
function as soon as there is at least one node in the list. It's prototype is:
<pre><i>
typedef int (*ulCompareFunc)( const void *data1, const void *data2 ) ;
int ulList::insertSorted ( void *data, ulCompareFunc comparefn ) ;
</i></pre>
Where 'comparefn' is your custom comparison function that takes two
data pointers, compares them and returns a memcmp / strcmp-like result:
<ul>
<li>
A number <b>less than zero</b> if "data1" is "smaller" than "data2", that
means if "data1" had to be inserted <b>before</b> "data2" in the list.
<li>
A number <b>equal to zero</b> if "data1" is equal to "data2", that means if
"data" had to be inserted immediately before or after "data2" in the list.
<li>
A number <b>greater than zero</b> if "data1" is "greater" than "data2",
that means if "data" had to be inserted <b>after</b> "data2" in the list.
</ul>
The return value of "insertSorted" is the position of the new node in the list
on success, or a negative value if you tried to do a sorted insertion on a
non-sorted list, that is a list which contains more than one node of which
at least one was not inserted using the sorted insertion function. In the
latter case, the new node would not have been inserted to the list.
<p>
To determine whether a list is sorted or not, call the following function:
<pre><i>
bool ulLinkedList::isSorted ( void ) const ;
</i></pre>
Note that with a linked list, you <b>must not</b> modify the criteria of a
node's data that is used for sorting without removing the node from the list
and re-inserting it.
<p>
Finally, you can empty a list (remove all nodes) by calling:
<pre><i>
typedef bool (*ulIterateFunc)( const void *data ) ;
void ulList::empty ( ulIterateFunc destroyfn = NULL, void *user_data = NULL ) ;
</i></pre>
Where "destroyfn" is an optionally specified function that will be called
with each destroyed node's data pointer as the first and with user_data as
the second argument. This is for example useful if the list entries are
pointers to dynamically allocated objects that have to be freed on destruction
of the list. The return value of the specified function is ignored.
<p>
<h3><a name="ulHashTable">ulHashTable</a></h3>
Not yet.
<h2><a name="errorHandling">Error handling</a></h2>
<h3><a name="ulSetErrorCallback">ulSetErrorCallback</a></h3>
<pre><i>
typedef void (*ulErrorCallback) ( enum ulSeverity severity, char* msg ) ;
void ulSetErrorCallback ( ulErrorCallback cb ) ;
</i></pre>
<a href="../index.html">PLIB</a> has an internal error handling system
that the subsystems use to report debug, warning or error messages.
An application can set up an error callback that PLIB will call whenever such
a message occurs in addition to printing the message on the user's terminal.
<p>
ulSeverety indicates the importance of an message and is currently defined
the following way:
<pre><i>
enum ulSeverity
{
UL_DEBUG,
UL_WARNING,
UL_FATAL
} ;
</i></pre>
Where
<ul>
<li>UL_DEBUG are unimportant debug messages that can usually safely be ignored
<li>UL_WARNING are important warning messages that should not be ignored
<li>UL_FATAL are fatal errors that PLIB can not recover from
</ul>
<p>
<h3><a name="ulGetErrorCallback">ulGetErrorCallback</a></h3>
<pre><i>
typedef void (*ulErrorCallback) ( enum ulSeverity severity, char* msg ) ;
ulErrorCallback ulGetErrorCallback ( void ) ;
</i></pre>
Returns the current <a href="#ulSetErrorCallback">error callback</a> (if
any, else NULL is returned).
<p>
<h3><a name="ulGetError">ulGetError</a></h3>
<pre><i>
char * ulGetError ( void ) ;
</i></pre>
Returns a pointer to the error buffer, that is, the last error message or an
empty string if there were not any error messages or if the error buffer has
just been <a href="#ulClearError">cleared</a>.
<p>
<h3><a name="ulClearError">ulClearError</a></h3>
<pre><i>
void ulClearError ( void ) ;
</i></pre>
Clears the <a href="#ulGetError">error buffer</a>.
<h2><a name="miscClasses">Misc. classes</a></h2>
<h3><a name="ulDynamicLibrary">class ulDynamicLibrary</a></h3>
<pre><i>
ulDynamicLibrary::ulDynamicLibrary ( const char *libname ) ;
</i></pre>
This class provides a portable way to load a dynamic library and to retrieve
the memory address of a specific function afterwards. When constructing an
ulDynamicLibrary object, you have to specify the name of the dynamic library
you want to operate on <b>without</b> the platform-specific file extension
for dynamic libraries.
<p>
Afterwards, you can retrieve the memory address where a function / symbol of
the library has been loaded by calling:
<pre><i>
void * ulDynamicLibrary::getFuncAddress ( const char *funcname ) :
</i></pre>
This function returns NULL if the specified symbol was not found.
<p>
<h3><a name="ulClock">ulClock</a></h3>
<pre><i>
ulClock::ulClock () ;
</i></pre>
No further documentation yet.
<h3><a name="ulPropertySet">ulPropertySet</a></h3>
Not yet.
<h2><a name="stringHandling">String handling</a></h2>
<h3><a name="ulStrEqual">ulStrEqual</a></h3>
<pre><i>
int ulStrEqual ( const char *s1, const char *s2 ) ;
</i></pre>
This function provides a portable way to compare two strings while ignoring
the case of the characters. We need it since half of the machines on the
planet provide strcasecmp and the other half stricmp for this purpose.
<p>
In contrast to the libc string comparison routines, this routine returns '1'
if the strings are <b>equal</b> and '0' if they are <b>not</b>.
<p>
<h3><a name="ulStrNEqual">ulStrNEqual</a></h3>
<pre><i>
int ulStrNEqual ( const char *s1, const char *s2, int len ) ;
</i></pre>
Same as ulStrEqual, except that it only compares the first 'len' characters
of the strings.
<p>
<h2><a name="endianHandling">Endian handling</a></h2>
<pre><i>
bool ulIsLittleEndian ( void ) ;
bool ulIsBigEndian ( void ) ;
unsigned short ulEndianLittle16 ( unsigned short x ) ;
unsigned int ulEndianLittle32 ( unsigned int x ) ;
float ulEndianLittleFloat ( float x ) ;
unsigned short ulEndianBig16 ( unsigned short x ) ;
unsigned int ulEndianBig32 ( unsigned int x ) ;
float ulEndianBigFloat ( float x ) ;
void ulEndianLittleArray16 ( unsigned short *x, int length ) ;
void ulEndianLittleArray32 ( unsigned int *x, int length ) ;
void ulEndianLittleArrayFloat ( float *x, int length ) ;
void ulEndianBigArray16 ( unsigned short *x, int length ) ;
void ulEndianBigArray32 ( unsigned int *x, int length ) ;
void ulEndianBigArrayFloat ( float *x, int length ) ;
unsigned short ulEndianReadLittle16 ( FILE *f ) ;
unsigned int ulEndianReadLittle32 ( FILE *f ) ;
float ulEndianReadLittleFloat ( FILE *f ) ;
unsigned short ulEndianReadBig16 ( FILE *f ) ;
unsigned int ulEndianReadBig32 ( FILE *f ) ;
float ulEndianReadBigFloat ( FILE *f ) ;
size_t ulEndianWriteLittle16 ( FILE *f, unsigned short x ) ;
size_t ulEndianWriteLittle32 ( FILE *f, unsigned int x ) ;
size_t ulEndianWriteLittleFloat ( FILE *f, float x ) ;
size_t ulEndianWriteBig16 ( FILE *f, unsigned short x ) ;
size_t ulEndianWriteBig32 ( FILE *f, unsigned int x ) ;
size_t ulEndianWriteBigFloat ( FILE *f, float x ) ;
</i></pre>
No further documentation yet.
<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>
Sebastian Ude &lt;<A HREF="mailto:ude@handshake.de">ude@handshake.de</A>&gt;
</ADDRESS>
</table>
</BODY>
</HTML>

BIN
doc/valid-html40.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 799 B

196
doc/whats_inside.html Normal file
View File

@@ -0,0 +1,196 @@
<!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>PLIB: What's In PLIB</TITLE>
</HEAD>
<BODY text="#B5A642" link="#8FFF8F" vlink="#18A515" alink="#20336B"
bgcolor="#005000" background="marble.png">
<TABLE>
<TR>
<TD>
<IMG SRC="plib_logo.png" ALT="PLIB Logo" width=256 height=245>
<br>
</TD>
<TD>
<center>
<H1>
<FONT SIZE=9>S</FONT><FONT SIZE=5>TEVE'S</FONT>
<FONT SIZE=9>P</FONT><FONT SIZE=5>ORTABLE</FONT>
<FONT SIZE=9>G</FONT><FONT SIZE=5>AME</FONT>
<FONT SIZE=9>L</FONT><FONT SIZE=5>IBRARY.</FONT>
</H1>
</center>
</TD>
<TD>
<ul>
And Lo, the Lion and the Sheep shall lie down together - but the Sheep won't
get much Sleep.
<br>
-- Woody Allen
</ul>
<center>
<A href="http://sf.net">
<IMG src="http://sf.net/sflogo.php?group_id=382&type=1" width="88" height="31" border="0" ALT="Sourceforge Logo"></A>
</center>
</TD>
</TR>
</TABLE>
<TABLE>
<TR>
<TD valign=top align=left>
<A HREF="index.html"><IMG SRC="home.png" ALT="HOME" BORDER="0" width=150 height=50></A><br>
<A HREF="whats_inside.html"><IMG SRC="whats_inside.png" ALT="WHAT'S INSIDE" BORDER="0" width=150 height=50></A><br>
<A HREF="license.html"><IMG SRC="license.png" ALT="LICENSE" BORDER="0" width=150 height=50></A><br>
<A HREF="contacts.html"><IMG SRC="contacts.png" ALT="CONTACTS" BORDER="0" width=150 height=50></A><br>
<A HREF="requirements.html"><IMG SRC="requirements.png" ALT="REQUIREMENTS" BORDER="0" width=150 height=50></A><br>
<A HREF="gallery.html"><IMG SRC="gallery.png" ALT="GALLERY" BORDER="0" width=150 height=50></A><br>
<A HREF="download.html"><IMG SRC="download.png" ALT="DOWNLOAD & INSTALL" BORDER="0" width=150 height=50></A><br>
<A HREF="examples.html"><IMG SRC="examples.png" ALT="EXAMPLES" BORDER="0" width=150 height=50></A><br>
<A HREF="sg/index.html"><IMG SRC="SG.png" ALT="SG" BORDER="0" width=75 height=25></A>
<A HREF="ssg/index.html"><IMG SRC="SSG.png" ALT="SSG" BORDER="0" width=75 height=25></A><br>
<A HREF="ssgAux/index.html"><IMG SRC="ssgAux.png" ALT="SSGAUX" BORDER="0" width=75 height=25></A>
<A HREF="fnt/index.html"><IMG SRC="FNT.png" ALT="FNT" BORDER="0" width=75 height=25></A><br>
<A HREF="pui/index.html"><IMG SRC="PUI.png" ALT="PUI" BORDER="0" width=75 height=25></A>
<A HREF="psl/index.html"><IMG SRC="PSL.png" ALT="PSL" BORDER="0" width=75 height=25></A>
<A HREF="util/index.html"><IMG SRC="UL.png" ALT="UL" BORDER="0" width=75 height=25></A>
<A HREF="js/index.html"><IMG SRC="JS.png" ALT="JS" BORDER="0" width=75 height=25></A><br>
<A HREF="net/index.html"><IMG SRC="NET.png" ALT="NET" BORDER="0" width=75 height=25></A>
<A HREF="sl/index.html"><IMG SRC="SL.png" ALT="SL" BORDER="0" width=75 height=25></A><br>
<A HREF="pw/index.html"><IMG SRC="PW.png" ALT="PW" BORDER="0" width=75 height=25></A>
<A HREF="puAux/index.html"><IMG SRC="puAux.png" ALT="PUAUX" BORDER="0" width=75 height=25></A><br>
</TD>
<TD>
<H2>What's Inside PLIB?</H2>
PLIB is comprised of a number of semi-autonomous libraries
that you can pretty much mix and match - using as much or
as little PLIB as you need. The components libraries are:
<p>
<TABLE>
<TR>
<TD><A HREF="pui/index.html">Picoscopic User Interface Library (PUI)</A></TD>
<TD>A fully portable set of GUI widgets that need OpenGL and C++
to operate. Useful for games because rendering these widgets is
performed very quickly by your 3D hardware.</TD>
</TR>
<TR>
<TD><A HREF="sl/index.html">Sound Library (SL)</A></TD>
<TD>A fully portable Audio driver suited to C++, GLUT
and realtime applications that need low latency. Includes
a simple 'MOD' music loader/player.</TD>
</TR>
<TR>
<TD><A HREF="sg/index.html">Standard Geometry Library(SG)</A></TD>
<TD>A set of matrix and vector math functions that was
specifically written to simplify the writing of efficient OpenGL
programs. You need to include this code into any SSG applications.
Widely used within PLIB itself.
</TD>
</TR>
<TR>
<TD><A HREF="ssg/index.html">Simple Scene Graph Library (SSG)</A></TD>
<TD>A scene graph library layered on top of OpenGL. Also contains code to load and save lots of 3D file formats.</TD>
</TR>
<TR>
<TD><A HREF="puAux/index.html">PUI Auxiliary Library (PUAUX)</A></TD>
<TD>Additional functionality layered onto PUI - not every PUI program
will need these but they can perhaps save you some effort.</TD>
</TR>
<TR>
<TD><A HREF="ssgAux/index.html">SSG Auxiliary Library (SSGA)</A></TD>
<TD>Additional functionality layered onto SSG - not every SSG program
will need these but they can perhaps save you some effort.</TD>
</TR>
<TR>
<TD><A HREF="js/index.html">Joystick wrappers (JS)</A></TD>
<TD>Supports more Joysticks with more axes and buttons than GLUT.</TD>
</TR>
<TR>
<TD><A HREF="fnt/index.html">Fonts'n'Text Library (FNT)</A></TD>
<TD>Supports text output in OpenGL using texture mapped fonts.
These are much faster to render than GLUT's fonts.</TD>
</TR>
<TR>
<TD><A HREF="util/index.html">Utility Library (UL)</A></TD>
<TD>A simple portability library to hide basic operating system
incompatibilities. Widely used within PLIB itself.</TD>
</TR>
<TR>
<TD><A HREF="net/index.html">Pegasus Network Library (NET)</A></TD>
<TD>Pegasus is a C++ library for assist you in adding
networking to your games.</TD>
</TR>
<TR>
<TD><A HREF="psl/index.html">PLIB Scripting Language (PSL)</A></TD>
<TD>A very lightweight, stackless C-like scripting language.</TD>
</TR>
<TR>
<TD><A HREF="pw/index.html">PLIB Windowing Library (PW)</A></TD>
<TD>A lightweight windowing library. This is a very basic
library - it only supports a single, double-buffered RGB
OpenGL window - with support for keyboard and mouse.
Simple though it is, it's usually plenty for OpenGL games
and other simple OpenGL applications.</TD>
</TR>
</TABLE>
<p>
<H2> Goodies: Samples and Demo's </H2>
There are quite a few example programs that each show off
one aspect of PLIB's use. We also distribute a set of demonstration
programs. These tend to be more complete and usable applications - some
games, some tools. These also show off PLIB's features - but in a
more holistic way than the example programs.
<H2>Documentation.</H2>
All documentation is available online (click on the package name
in the section above) and distributed with PLIB in HTML.
<p>
There are some interdependencies between the PLIB components - all
need the common utility library - many need the standard geometry
library for matix operations:
<TABLE>
<TR>
<TD>
<ul>
<li>PW is independent
<li>UL is independent
<li>JS depends only on UL
<li>SL depends only on UL
<li>SG depends only on UL
<li>NET depends only on UL
</ul>
</TD>
<TD>
<ul>
<li>FNT depends on UL and SG
<li>SSG depends on UL and SG
<li>SSGAUX depends on UL, SG and SSG
<li>PUI depends on UL, SG and FNT
<li>PUAUX depends on UL, SG, FNT and PUI
<li>PSL depends on UL, SG and SSG
</ul>
</TD>
</TR>
</TABLE>
</TD>
</TR>
</TABLE>
<hr>
<ADDRESS>
<A HREF="http://www.sjbaker.org">
Steve J. Baker.</A>
&lt;<A HREF="mailto:sjbaker1@airmail.net">sjbaker1@airmail.net</A>&gt;
</ADDRESS>
</BODY>
</HTML>

BIN
doc/whats_inside.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB