@c -*-texinfo-*-
@node Dynamic Worlds, Level of Detail, Visibility Culling, Engine
@subsection Dynamic Worlds
@cindex Dynamic Worlds

@noindent
@emph{Written by Jorrit Tyberghein,
@email{jorrit.tyberghein@@gmail.com}. Last updated 28 September 1998.}

This section contains a number of ideas and stuff but it is mostly
outdated.

Normally the portal approach lends itself very well for dynamic worlds.
However, the big problem is lighting.  Static lightmaps are very static (as
you can imagine) and are difficult to scale and recompute.  This severely
restricts what you can do dynamically in general.  You can also use stencil
shadows in which case there is no recalculation needed but the problem with
stencil shadows is that they tend to get slower with big levels and lots
of lights. Finally you can also use just regular vertex lighting with no
shadows. The discussion below focusses on the situation where you want to use
static lightmaps.

First a small definition.  The @dfn{sector-lights} is the list of lights that
affect some sector.  Every sector will have a sector-lights list containing
not only the lights in that sector but every light that shines through the
sector.  It will contain dynamic, pseudo-dynamic and static lights.

Another small note about lighting.  Crystal Space currently has static lights,
pseudo-dynamic lights and dynamic lights.  The pseudo-dynamic lights are an
extension on the static lights which allow the static light to change color or
intensity but not move.  The advantage of pseudo-dynamic lights compared to
real dynamic lights is that shadows are computed more correctly.
Pseudo-radiosity will also work correctly and there is no run-time
view-frustum calculation as with dynamic lights.  Their only disadvantage is
that they cannot move.

Now on to the cases for dealing with lights:

@itemize @bullet
@item
Creating a New Thing

When you create a new @dfn{thing} it is easy to update the static lightmaps
for that thing.  This involves taking all lights in the sector-lights list and
doing a view frustum calculation for all the static lights and only for the
new thing.  This only means that lighting on the Thing itself will be correct
but it will not mean that the Thing will cast shadows for static lights.
Calculating correct shadows is more complicated and time consuming.  We cannot
just update the lightmaps of the polygons that will become shadowed since
there is no way to know how much light we should remove.  The problem is that
there is an upper light-level.  If many lights affect the same lumel then it
will be capped.  When that happens you cannot just subtract a light because it
will then not correspond with the real amount of light still reaching the
lumel.  The only way to correct this would be to redo all static lighting
precalculation for those polygons.  This is time-consuming.

@item
Destroying a Thing

In this case it would be easier to remove the shadows.  You can redo the
needed static lighting precalculations.  However you have to be careful here.
If you remove a Thing which was added without doing shadows (previous
paragraph) then you should not remove shadows! So we have to remember if a
Thing has casted shadows or not so that we can remove them.

@item
Moving a Thing

This basically boils down to first destroying it and then recreating it at
another position.  There is an optimization possible.  If we know that a Thing
is meant to move from one position to another without interruption then we can
calculate the lightmaps as they will become finally (at the last position) and
just linearly interpolate the lightmaps in between.

@item
Opening a Predefined Portal

In future it will be possible to flag portals that are
closed.  When you open this portal you'll have to recalculate all lighting
that goes through the new portal.  If you know in advance that some polygon is
going to be opened in the future you can already store a lot of helpful
information together with this portal to make calculation easier.  One
possibility would be to store the light-patches combined with view-frustum for
every light that hits the polygon.  We can then just continue the static
lighting precalculation when the portal opens.  This would be useful for doors
that open and when opened let through the light: the door would be a Thing.
When closed the portal is also closed and blocks the light.  As soon as the
door opens the portal opens and let's the light come through.  A disadvantage
is that this will be sudden and not gradual (as the door opens).  But I think
this is better than not relighting at all.  But see the discussion in the next
paragraph.

@item
Closing a Predefined Portal

The problem with the previous approach is that you cannot in general use it
for closing a portal again.  The problem is that while it is easy to add light
to a static lightmap you cannot easily remove light (since lightvalues are
capped to a maximum).  So the above solution would really only be useful for
doors that once opened, remain open for the rest of the game.  But maybe we
have another solution.  When the engine knows that a portal can open/close we
can do the static lighting calculations as usual but store all lighting
information that came through that portal in separate static lightmaps.  That
would be surprisingly easy to do.  What this means is that polygons may have
several series of static lightmaps which are conditionally used depending on
the state of nearby portals.  Another big advantage of this approach is that
you can then use linear interpolation to interpolate between the two static
lightmaps when a door is opening.  For example, when a door is 50% open you
show 50% of the first static lightmap and 50% of the second.

@item
Opening an Arbitrary Portal

In principle it is possible to open portals everywhere you want, to anywhere
you want.  In this case however it is more difficult to adjust the lighting.
You can still do it but more slowly.  Opening arbitrary portals is going to be
useful when you create new sectors to simulate destroying a wall.  For
example, when you shoot a missile at a wall you could create a new portal on
that wall which simulates a hole.  You could also create a whole new sector
behind the wall.  Note that this is getting a little complicated.  Calculating
the lighting is relatively easy as the sector is brand new and you can just
calculate the lighting.  Also see @emph{Breaking Through} below.

@item
Closing an Arbitrary Portal

No problem but you'll not be able to remove the lighting easily without
recomputing a @emph{lot}.  Note that in the current version of Crystal Space
portals also have correctly lighted lightmaps so closing a portal will yield a
polygon which is correctly lighted.

@item
Breaking Through

When you fire a missile at a wall you may expect to be able to break through
to the sector that is behind that wall.  Aside from the portal and lighting
problems there is an additional problem here.  The portal world does not in
itself have spatial information like this.  It does @emph{not} know that there
is a sector behind that polygon.  In fact there really is no concept of
``behind a polygon''.  This would of course be a solution.
If you make breakable walls state-portals (portals
which can be closed and opened on demand like explained earlier) then there is
no problem.  But if you want to support this in general then we'll need to
find a way to calculate spatial information like this.  Calculating this at
run-time is probably too expensive (you have to traverse every sector in the
world and see which one you're arriving in).  One way to solve this would be
with a sparse 3D matrix which contains all sectors that intersect with a given
3D cube.  This could be precalculated and would greatly improve the speed of
testing in which sector a given 3D location falls.  This of course only works
with worlds which are @dfn{standard} and contain no special space-warping
features (like overlapping sectors).  Mirrors and reflecting surfaces would be
ok as they can be flagged as not defining extra geometry but only reflecting
existing geometry.

@item
Adding a Static Light

In some cases it may be a good option to have the ability to add a static
light.  Static lights have the advantage that there is no run-time overhead as
soon as they are merged with the other static lights.  So if you want to be
able to put a light at an arbitrary position which is never going to be
removed again then you should be able to create new static lights.  Note that
you can (and should) use pseudo-dynamic lights when you know in advance where
the light is going to be.  A good option would probably be the ability to
merge a pseudo-dynamic light with the static lights.  When you know that a
pseudo-dynamic light is never going to change then this would be a very good
idea.  So converting a pseudo-dynamic light to a static light should be
possible.

@item
Removing a Static Light

This is more complicated.  In general you should use pseudo-dynamic lights for
this.  The pseudo-dynamic light can be on by default.  When you want the light
to be removed (for example because it is destroyed by a missile or something).
You can set the intensity of the pseudo-dynamic light to black and then remove
it from the world.
@end itemize

