Here is a run-thru of the main rendering loop. This document is not an
explanation of portal technology. It just explains how the main
rendering loop in Crystal Space works so that you can have a quick idea
of where you have to go to see a particular part of the algorithm work
(or to make nice enhancements :-) This is a rather technical document
and not intended for people who are only interested in using CS in their
own projects. It is intended for people who want to know how CS works
internally.

This document should be read AFTER you have read document.txt so that
you understand how portals are used in Crystal Space.

You should also read tutorial.html as this explains the basics
for using Crystal Space. I will base this document on the 'simple'
application (apps/simple/) because this looks a lot like the tutorial.

First we start in apps/simple/simple.cpp. In the 'main' function we
initialize our world. This is an instance of csWorld which actually
represents the engine. I will not explain how all the init works. This
is explained in the tutorial.html file. But I will go straight to
csWorld::Draw() which is called indirectly from within Simple::NextFrame().
It is called indirectly because first we call csView::Draw() which will
then call csWorld::Draw().

=============================================================================
csWorld::Draw() (libs/csengine/world.cpp)
=============================================================================

csWorld::Draw() will first setup the initial csRenderView structure. This
structure is defined in libs/csengine/rview.h and is the main structure
which is used throughout the whole rendering process. It collects all data
that is required for rendering the recursive portal structure. Basicly
it contains the following:
	- view: this is the current clipper. A clipper is a 2D polygon
	  which defines what is visible. Every object is clipped to the
	  view first. Every time we go through a portal the view is
	  modified.
	- g3d and g2d are just pointers to our 3D and 2D graphics
	  subsystems.
	- clip_plane is a special plane. If do_clip_plane is used then
	  we clip all geometry in 3D to clip_plane. This is normally
	  not used except in special cases where we have portals that
	  arrive in the middle of a sector. In that case the portal
	  will be used as an extra clipping plane because we don't
	  want to render everything that is behind the arrival plane
	  of the portal.
	- callback and callback_data are used for special purposes
	  and are not important here.

Another important thing is that csRenderView is actually a subclass
of csCamera (libs/csengine/camera.h) so all camera functionality is
present as well.

To set up the initial csRenderView structure csWorld::Draw() will
create a new instance based on the given camera.

After this csWorld::Draw() will get the current sector from the camera
and call csSector::Draw() (in libs/csengine/sector.cpp). This will
essentially draw the whole screen (see below for more information on that).

After doing this (so now the screen is fully updated) we optionally draw
halos. Halos are drawn on top of everything else since they are an effect
in the eyes.

=============================================================================
csSector::Draw() (libs/csengine/sector.cpp)
=============================================================================

csSector::Draw() is responsible for rendering everything in the
current sector. It will do this by first rendering the walls of the
sector (using Z fill only). It is possible that there is a BSP tree
attached to the sector. In that case csSector::Draw() will use that BSP
tree to sort the wall polygons back to front.

Before actually starting to render it will first transform the sector
to the camera position (so that (0,0,0) is the camera point, (1,0,0)
is one unit right of the camera, (0,1,0) is one unit above the camera, and
(0,0,1) is one unit above the camera). This is done in
csPolygonSet::NewTransformation() and csPolygonSet::TransformWorld2Cam()
(see libs/csengine/basic/polyset.cpp). The call to NewTransformation() is
needed because it is possible that we render the same sector multiple
times in the same recursion tree. Because of this we don't actually want
to loose the transformation that occured the previous time so
NewTransformation() takes care of potentially storing the old transformation
and setting a new one (mirrors and other space warping portals make this
feature essential).

After that the drawing of the transformed polygons actually happens in
csSector::DrawPolygons() which will in turn call
csPolygonSet::DrawPolygonArray() (see libs/csengine/basic/polyset.cpp).
DrawPolygonArray() is further discussed in the next section.

While drawing the polygons of the sector (sector walls) some of them
may be portals. In that case csPolygonSet::DrawPolygonArray() will
immediatelly perform recursion to the destination sector of the portal.
This means creating a new csRenderView with the new view and then
recursing into csSector::Draw() of the new sector. It is important to note
that DrawPolygonArray() may already enter recursion for a new sector even
though the first sector has not finished drawing yet.

So it is important to note that after drawing all sector walls we have
in fact drawn the whole world visible from this sector (including things
and sprites in other sectors). But we have not drawn things and sprites
in this sector yet.

csSector::Draw() will then continue to draw all things in the current
sector. There are some special cases here. It is possible that all
non-moving things have been collected into one thing which has an attached
BSP tree. This is the 'static_thing'. If that exists we first render
that static_thing by using back to front ordering and using Z fill instead
of Z buffer. Note that all non-moving things which were collected into the
static thing are still in the list of things for the sector. But you can
recognize them because they IsMerged() returns true.

Now there are two important cases depending on wether or not there
was a static thing in the previous case. If there was a static thing or
if the sector itself had a BSP tree, then all remaining things have to
be drawn using the Z buffer (ignoring foggy things for the moment). In
this case we can't use Z fill anymore because there was a BSP tree used
to render the previous sector or static thing.

If there was no static thing and there was no BSP tree for the
sector then we can still use Z fill to render all convex things provided
we render them back to front. This part of the algorithm does not work
correctly yet and that's the reason that it has been disabled.

In any case all foggy things are collected and then Z sorted. This is
also not correct but currently the only way. Here we need a better way
to do Z sorting.

Now we can proceed to drawing all sprites. @@@ UPDATE @@@ NO LONGER
TRUE! --> Currently this algorithm is
somewhat simple. It assumes that a sprite always lives in one sector.
This is of course not always right and the sprite structure (csSprite3D
in libs/csengine/objects/cssprite.h) already has provisions for the
fact that a single sprite can live in several sectors at the same time.
What we want to do here is to only draw a sprite if one of the below
conditions is true:
	1. the current sector is being rendered through an alpha mapping
	   portal.
	2. the sector we came from before entering the portal (in the
	   render process) is also a sector where the sprite lives.

In the first case we have to clip the sprite to the portal and render
only the side on this portal. When returning from the recursion we will
have to render the other side of the sprite.

In the second case we don't render the sprite but it will be rendered
when we return from our recursion because the sprite is also part of
the previous sector.

The next step in csSector::Draw() is to queue all halos that were
encountered in this sector so that they can be drawn later. A z buffer
visibility test will be used later to make sure that the halo only
appears when the center is visible.

Finally we conclude by optionally fogging the current sector if this
is needed. There are currently two ways of fogging:
	- Using the Z Buffer (G3DFOGMETHOD_ZBUFFER)
	- Using planed fog (G3DFOGMETHOD_PLANES)
The last method does not work correctly yet. The first method is only
implemented by the software renderer.

We end csSector::Draw() by restoring the transformation
(csPolygonSet::RestoreTransformation()).

=============================================================================
csPolygonSet::DrawPolygonArray() (libs/csengine/basic/polyset.cpp)
=============================================================================

Both csSector and csThing inherit from csPolygonSet so they both
basicly use the same way of rendering polygons. DrawPolygonArray() is
responsible for that. DrawPolygonArray() is typically called on either
the complete list of polygons for the csThing or csSector or else a
subset which was computed from a BSP tree.

DrawPolygonArray() will process every polygon in the array in turn.
It will basicly do the following three things for every polygon:
	1. csPolygon3D::ClipToPlane() (libs/csengine/polygon/polygon.cpp)
	2. csPolygon3D::DoPerspective()
	3. csPolygon2D::ClipAgainst() (libs/csengine/polygon/polygon.cpp)

ClipToPlane() will do a quick test to see if all vertices of the polygon
are in front of the Z plane. That will at least exclude polygons quickly
which are behind the viewer. Then it will perform backface culling.
Finally it will process the special clip_plane field in csRenderView
which was mentioned in the beginning of this document. In other words,
it will clip the polygon in 3D to that plane. This is rarely needed.

If ClipToPlane() fails then the polygon is not visible and we don't need
to continue with the other steps.

DoPerspective() does perspective correction on the polygon and thus
transforms the polygon from 3D to 2D. The 2D polygon will be placed
in a special static variable of type csPolygon2D (called 'clipped').
Finally it will also transform the plane of the polygon to camera space.

DoPerspective() can also fail in which case the polygon is not visible and
processing can stop here.

Finally we do ClipAgainst(). This will clip the polygon to the current
view. The clipping happens in place: the result will be in 'clipper'.

If ClipAgainst() fails the polygon was completely clipped away and we
don't need to show anything.

When all three steps above succeed we have a visible (part) of a polygon
which has been perspective corrected. We can now render that polygon.

If the polygon is a portal then we initiate a recursive process by
calling csPortal::Draw() (libs/csengine/polygon/portal.cpp) which will
in turn call csSector::Draw() for the destination sector. csPortal::Draw()
also takes care of possible space warping and also creation of the
clip_plane in csRenderView if this should be needed.

If a portal has an alpha transparent texture superimposed then we will
draw that texture on top of the portal when csPortal::Draw() returned.
However since 'clipped' is a static variable we need to copy it locally
to be able to draw it again later. This happens in 'keep_clipped' and
'keep_plane'.

If the polygon was not a portal then we just render it. This happens
in csPolygon2D::DrawFilled() (libs/csengine/polygon/polygon.cpp) which
is further explained in the next section.

That's basicly it for this function.

=============================================================================
csPolygon2D::DrawFilled() (libs/csengine/polygon/polygon.cpp)
=============================================================================

@@@@@@@@@@@@@@@@

=============================================================================

This explains the main rendering loop. I hope this document can help
people navigating in the source.

