/******************
    GRAND BLEU
******************/

Underwater demo with Dolphins, sharks, turtles, fish.
This demos demonstrates the use of textures multiplications 
(in one pass on 2TMUS boards, and 2 passes on 1TMU boards) to
render water-reflections effects on the entire scene (terrain
and objects).


SYSTEM REQUIREMENTS
-------------------
A Pentium 90MHz & up with either a 1 TMU board (like the Rightous 3D
from Orchyd or the Monster 3D from Diamond) or a 2 TMU board (Amethyst
board).
By default, Grand Bleu builds the 1TMU version, but you can edit the
makefile and uncomment the line
#TWO_TMUS=1
and rebuild for 2TMUS.

Memory: if you have less than 32Mb than flipper might not have some
difficulty loading the soundtrack. In that case, start flipper with
the -nosound option.


Running the demo
----------------
run flipper.exe.
There are some options available, see more details below.


Controls
--------
You can press F1 at any time during the demo to get a help screen.

Press 8 to toggle between user controlled camera and automatic camera
mode. The automatic camera mode follows the animals in the scene.
Each time the SPACE BAR is pressed, the camera will switch to a new animal.
For each animal, there is a set of predefined automatic camera positions:
you can skip through these by pressing CTRL and SPACE at the same time.

When you are on User controlled mode, you should, by default, get attracted
to the ground. Press G to stop the Gravity.
To more around, you can either use the joystick or the keyboard.
Use the Up and down keys to move forward/backward.
Use the Right and Left (arrow) keys to rotate right and left.
Use the SHIFT key with Up and Down to look up and down.
Use the CTRL key with Up and Down to translate up and down.
Use the CTRL key with Right and Left to translate right and left.

F8 will freeze all the animals. Press F8 again to unfreeze the animals.

CTRL+S will remove the lower right 3Dfx demo.

F switches through 3 different screen formats.

Press the ESCP key to quit the demo.


Bugs
----
Sometimes the camera goes a bit wild, and gets lost in space. Try to switch
back and forth between the automatic camera mode and the user controlled mode
(by pressing key 8) and by switching from one animal to the other (space bar).
If nothing happens, then exit and restart.

The capability to turn off mipmapping and bilinear filtering have been disabled
in that version of Grand Bleu.




Some usefull environment variables for recompiling
---------------------------------------------------------

- TWO_TMUS=1:   if that variable is set to 1, the demo is compiled with the code
                that uses the 2 TMUS of an Amethyst board (recommended). If the 
                variable is not set, the demo is compiled for a one TMU system 
                (slower because the projected texture is done in 2 passes instead of one).

                
- ATBSOUND=1 :  use of ATA (The Arcade ToolBox Audio Library) for playing sound.
                ATA is based on DirectSound, so you need to have DirectX installed
                on your machine.

- FX_NO_DEMO_HELP=1: prevents the recompilation of the help and start screen files.
            The first time you compile flipper, make sure this variable is not set to 1.
            The obj files for the help and start screen have to be generated at least once.
            The help and start screen files take about 5 minutes to compile on a 166.
            Since the help is not meant to be changed too often, the FX_NO_DEMO_HELP offers
            the possibility to avoid recompiling the help and start screen files
            (the compilation reuses the current .obj file) each time a little modification
            is made to the makefile or each time you want to make a full 
            (except for the help) recompilation of flipper.

- MSVC41=1: set this variable to 1 to make sure that the msvc compiler does not choke during
            the comilation of the help files. These are pretty big and requires the stack to
            be increased quite a bit.


- XHEAD:    set this variable to 1 to build for multi head. look at the makefile to make sure
            that the variable is not overwritten by some default value. See XHEAD section 
            below for details on how to operate.

- NONBLOCKING: set this variable to 1 to build the multi-head version with nonblocking socket
                calls. This was the original code, which was working fine with win95 machines
                but seemed to fail on one of the NT machines we had. (it appeared that each
                call to select() (for checking if there was something to read on the socket,
                using a small timeout) was very expensive on the NT machine. So, the code
                was modified to use blocking recvfrom() calls. This makes the whole lockstep
                mechanism a lot less flexible and almost unrecoverable in case of packet miss
                (either a loss or an out of order event), because the protocol is completly
                frozen in linear calls to send() and recvfrom. But again, the XHEAD demo
                is supposed to be running on a dedicated LAN, where misses should be
                almost inexistant especially given the size of our messages and
                the frequency at which there are sent (about 6 total messages on the
                network per frame. At 60Hz that's about 360 messages/sec.
                At that rate their should -almost- never be any misses happening.
                

           
Notes: 

1. The default makefile compiles for 1TMU with Sound.

2. Flipper uses a modified version of one of the Arcade ToolBox libraries, namely atr.lib.
   It is included in the project, and is linked with in place of the regular atr.lib.



Files
-----
t1.dat is the files that contains info about the terrain to generate.
see the Terrain Generation paragraph below.


MISC
----
Note that the kind of projected texture used in that demo is of the planar kind. This means that
we do not need to specify a projection origin. There is a bit of code commented out that can be
used for doing a positional projected texture, in which case you need to specify a Projector location.


There are a few places where coded is enclosed in a pair of:
#if 0
#endif
which means that the code is never compiled and does not contribute to the demo.
Usually, these piece of code were left overs from previous version, and they
show how to do things differently. There were left FYI.
                

No more go.bat file
-------------------
Please, note that there is no need for a batch file anymore to start Grand Bleu.


Output
------
Since Flipper has become a Windows application, the problem of being able to do *SIMPLE*
output araised. I mean, just being able to do a simple printf(), which is pretty usefull
when debugging. Some might like the Windows' message box, but I just hate it.
So, when Flipper is compiled as a WIN32 application, a Dos Console is allocated which
allows us to do good old formatted output.
Here is how to do output to this console:

whenever you feel like doing:

printf( "Debug level %d, height = %f \n", gDebugLevel, height );

do the following:

#include "grutil.h"
char    *message[MAX_MESSAGE];

sprintf( message, "Debug level %d, height = %f \n", gDebugLevel, height );
printC( message );


It is a bit more combersome but it is better than nothing. 
If the application is compiled as a DOS app (with which it is possible to do regular
printf() ), the printC() stays compatible (it will just translate to a regular
printf() ).



High and low resolution dolphins
--------------------------------
There are 2 models for the dolphin. A low count poly one (~500 triangles) and a high res one
(~1500 triangles). Whenever a dolphin becomes the target of the automatic camera, the model
is switched from low res to high res. When the camera jumps to another target, the previous
target (if it was a dolphin) is switched back to a low res model, and the next target, (if
it is a dolphin) is switched from low res to high res.


UpdateRate optimization
-----------------------
This demo experiments with the concept of entity update rate optimization.
The idea of "Do a full update of the entity only every over updateRate frames".
The idea is to do a less computation by not doing a complete update
at each frame. That's kind of related to the concept of level
of detail of behaviour, except that in this case, it is FULL-UPDATE
or NO-UPDATE at all, and that it is controlled by a updateRate rather
than things like "distance from the viewer" or "is in the view frustrum".
Well, it turns out that it makes almost no difference in the frame rate. :-(
I was hoping that turning the gOptimizeUpdate on would show a big improvment
in the frame rate but it does not. The good thing about that is it means that
the bottleneck is not in the player&animals code but probably in the
transformation/projection/lighting/scene management libraries.
Please see the "Optimizations" section below.


Terrain Generation
------------------
Flipper's terrain is generated at runtime.
It uses a ppm file is interprated as a height field.
For each pixel in the ppm file:
    the red component defines the height of the terrain
    the green component defines which texture map is associated to it.
    (the bleu component is ignore).
The terrain is divided into sub-meshes of size STEP*STEP. (look for the variable
"step" in terrain.c:buildTerrainFromPPM() ).
Be carefull: if you want to use a new PPM file, the size of the image must be
a multiple of STEP, plus 1. It is alos expected that the ppm image is square.
In other words:
if ppm.width = ppm.height = L
then we have the relation :
L = N * STEP + 1
where N is an integer > 0
More on STEP:
STEP is indeed directly related to the textures used for the terrain.
Also, the terrain creation process uses a configuration file, in this example, called t1.dat.
The configuration file can have any name, just make sure you fill in the correct field
of the terrain structure with the right filename before calling the function that constructs
the terrain (buildTerrainFromPPM()).
That configuration file must contain the following info:
the ppm fileanme that will be use to generate the height map
the number of textures used for the terrain
the name (path included) of the textures (these are *.3df files) followed by 
a green color code.
The green color code will be used to uniquely identify which texture each point
in the height field gets its color from.
WARNING: there is a little art challenge here. The different textures has to be 
assigned in square patterns into the green channel of the pppm image, the size
of the square being also STEP*STEP. In other words, a texture is applied in
adjacent patterns of STEP*STEP. Note: since the ppm's size is L = STEP*N + 1, this means
that there will be a line and row of pixel left with no texture info. Just duplicate
the last value.

ALSO: boundaries issues. Because the terrain is tiled, one has to make sure that
the edges of the ppm file are continuous (in a 2 pixel wide area), otherwise tearing
might appear where edge meshes are displayed.

Generation of the ppm file:
The original height map was a tga file worked through Adobe Photoshop, which
is pretty at letting one work on the different channels of an RGB image.
Then, the tga file was imported in PaintShopPro where it was saved directly
into a ppm (binary) format. 


Optimizations
-------------
A lot could be done to optimize Flipper. 
First, there is a lot of floor() in the code that is used to convert correctly
a float into an integer. With a few shifts, it should be possible to achieve the
desired results for a fraction of the cost of floor.
I also use some cos() and sin(). These are expensive. I started to write the code
for using cos and sin look up tables but I didn't have the time to finish it.

Since its first implementation, Grand Bleu went through a few modifications
in order to improve performances. Originaly designed for a Pentium P6 (200 MHz)
and a 2TMU system, performance became an issue when we decided to port it
for a 166MHz and 1TMU board.
Here are the optimizations that made that port possible:

- sorting the Terrain submeshes by material.
The terrain is subdivided into submeshes, which are then tiled
to fill in the field of view. Each submesh has its own material.
It used to be that each time the terrain was drawn, for each
submesh, a material was pushed, the submesh was drawn and the
material was poped before going to the next submesh. So, if there
was 50 submeshes in the filled of view, than there would be 50 material
pushes. Kind of wastefull considering that the number of different
materials used for the terrain is usually pretty small (in this version,
there are only 4 different textures). It obviously seemed like more
advantageous to sort all submeshes by material, and push one material
and draw all the submeshes using that material before going to the 
next material.
That optimization is controled by the flag SORT_MESHES.

- sorting the fishes by material.
Same principle as terrain submeshes sorting by material.
It turned out that most fishes were using only one material. Since
there can be anywhere between 5 to 20 fishes of the same kind, it was
a real waste to push and pop exactly the same material 20 times.
So now, after a little bit of hacking, each material is pushed only
once and all the fishes using that material are drawn before going to
the next fish. Warning: this is a real hack. It only works because
each fish only uses one material (it is one triset and one material). 
Also, it only works because at the time of the creation of the school,
all the fishes of the same kind are create one after the other and
added to the school. If there were randomly created, then the optimization
code will fail.
Warning: there is one fish that I had to remove from the school because
it was using more than 1 material. If you ever get a black fish, it is 
probably because it uses 2 materials, which makes the fish optimization fail.


- decreasing the Terrain depth.
this helps a lot. By decreasing the depth of the view, we have less computation
to do and less to draw for the terrain.

- reducing the camera's field of view. Same principle. By reducing the field of view,
we reduce the surface of the terrain that is visible and therefore reduce the number
of submeshes to process (and to draw).


- reducing the number of animals.




XHEAD:
-----
Grand Bleu can run in multi-head (multi-screen) mode.
For this, you need to:
- make sure that it was build with the XHEAD flag (look at the makefile).
- have 2 or 3 machines with a 3Dfx board (Rightous3D or Monster3D)
- have networking cards on all machines
- connect all machines on a network (on you regular LAN, or isolated with
  their own mini hub).

Notes:
1.  The XHEAD mode uses the bcstudp.lib library (for broadcast upd). It should
    be part of your regular Arcade Tool Box distribution. Just make sure it was compiled
    before you build Grand Bleu. Just in case, the bcstudp.lib was included with Grand Bleu.
    If you want to use this local copy of the bcstudp.lib library, make sure to 
    modify the makefile and change the path for the library.

2.  The XHEAD mode is based on a Master/Slaves configuration. The master screen (the center
    screen) is the master of the simulation and the right and left screens are the slaves.
    Each computer actually runs a full Grand Bleu simulation. But all computers are synchronized
    via the network: the Master awaits for all slaves to tell him that there are down to render
    the current frame before it allows them to go to the next frame. This ensures that all
    simulations are frame lockstepped. But there was still the issue of animal behaviours.
    There would have been too much data involved to consider having the Master send network
    packets to all the slave for all the animals in the simulations at each frame.
    By seeding the random generator with the same seed on all machines, and thanks to the
    lockstep mechanism, we were able to get all the computers to run exactly the same simulation
    with no risk of diverging.

    
    
Starting an XHEAD session
Let MAXPLAYERS be the number of machine running the simulation. 
Usually this should be 3: the master (center screen) and the slaves
(right and left screens).



On the master machine, set the MAXPLAYERS environment variable to 3.
set the MASTER environment variable to 1.
and start flipper with the -xhead option:
set MAXPLAYER=3
set MASTER=1
flipper -xhead
OR you can run the batch file master.bat that does all of this for you.

On the right slave machine, do the following:
set MAXPLAYER=3
set RIGHT=1
flipper -xhead
OR you can run the batch file right.bat that does all of this for you.

On the left slave machine, do the following:
set MAXPLAYER=3
set LEFT=1
flipper -xhead
OR you can run the batch file left.bat that does all of this for you.








--------------------------------------------------------------

So, if you have any question, send your comments or request to
devsupport@3dfx.com
Good luck.
