

			RTL - realtime lighting demo

		      By Shawn Hargreaves, 30 May 1998



   Last updated on July 1, 1999, to work under Linux. Previously updated on 
   June 21, 1999, to work with the 3.9.x Allegro WIP versions, and to 
   compile under Windows using MSVC.

   This program is really more of a "technology demo" than a complete game. 
   It started out as a simple experiment, because I was curious to see 
   whether true pixel-level lighting could be done at a reasonable 
   framerate. The results were impressive enough that I went on to draw some 
   proper graphics and added a few flying saucers for you to shoot at, but 
   it would take a lot more work to turn this into a lastingly fun game 
   rather than just a cool visual effect.

   The game is basically a Space Invaders ripoff, with a sideways scrolling 
   engine, three layers of background parallax, smooth dynamic lighting, and 
   some (heavily overused! :-) lensflare effects. It runs smoothly enough 
   (20 fps) on my p133, but probably won't be very playable on slower 
   machines.

   It uses the 320x200 VGA mode, and the screen is composed from five 
   individual layers: three levels of parallax, a greyscale light map, and 
   the flare overlays (drawn using additive transparency).

   The three bottom layers are predrawn 512x200 bitmaps, which wrap from 
   left to right to allow infinite scrolling in either direction. Each layer 
   scrolls slightly faster than the one below it, and the second and third 
   layers are drawn in a masked mode so parts of the lower levels will show 
   through the gaps. Object sprites (the player ship, flying saucers, 
   missiles, etc), are treated as part of the third layer, by blitting the 
   relevant part of it onto a temporary bitmap and then drawing sprites over 
   the top (this could be optimised dramatically by using dirty rectangles, 
   but this blit is actually quite a small overhead compared to everything 
   that happens later on :-)

   The light map is a 256 color greyscale image, with zero representing a 
   dark pixel and 255 a location that is fully lit. Because many objects may 
   be casting light over the same area of the screen, this map is drawn in 
   translucent mode using a custom color mapping table, which simply adds 
   the new pixel value to the value already at that location (clamping if 
   the result overflows the maximum light level). The resulting light map is 
   used to tint the top two parallax layers (it doesn't affect the very 
   bottom layer), using a second color mapping table. This lighting is done 
   in a single pass which simultaneously combines the three parallax layers: 
   the same thing could have been done using multiple Allegro calls to draw 
   the layers from back to front, but it is more efficient to integrate 
   everything into a single loop that draws from front to back (the masking 
   tests for the top layer avoid any redundant lighting of zero pixels or 
   drawing of hidden pixels from lower layers).

   The final stage is to overlay the lensflares and explosion graphics, 
   which is done using a third color mapping table, this time for additive 
   translucency. Finally, the resulting image is blasted across to the 
   screen for your viewing pleasure.


   Keys:

      left and right arrows move the ship
      spacebar fires a missile
      'l' toggles the dynamic lighting on/off
      'f' toggles the flare overlays on/off
      'g' displays the light map as a greyscale image


   Note:

      In the process of writing this program I discovered a few bugs in the 
      Allegro 'fix' class. These have of course now been corrected, but this 
      means that the program is unlikely to compile with versions of Allegro 
      prior to this patch. If your version of Allegro is earlier than the 
      May 30, 1998 work-in-progress release, you will probably need to 
      upgrade.


   Wishes:

      (note: I'm not going to spend any longer working on this program, but 
      if I did, this is what I would do...)

      Add all the usual paraphernalia of an arcade game: multiple lives, 
      shield/weapon pickups, etc.

      Add more varied types of enemy, flying at different heights and with a 
      range of attack patterns. Make them come in waves of progressive 
      difficulty, rather than just an endless progression of more/faster 
      like it is at the moment.

      Add multiple levels, with different background graphics for each.

      Add sound.

      The explosions could look a lot better. The problem with the current 
      ones is that the palette doesn't contain enough suitable colors for 
      them to use, so it would be worth spending some time to come up with a 
      more balanced palette. I made the current one by drawing the 
      background image in Photoshop, exporting a combined copy of all three 
      layers into a truecolor .tga file, using Image Alchemy to reduce this 
      to 256 colors, and then using the grabber to map the original 
      truecolor layer bitmaps into this palette. That works fine for the 
      background graphics (Alchemy is very good at palette generation), but 
      the resulting palette didn't contain any good explosion colors. I 
      bodged it by hand editing the results to add a few yellow/red shades, 
      but that is far from ideal. A better solution would have been to do a 
      mockup of how I wanted the explosion to look in Photoshop, overlay 
      that on my background graphics, and then use that combined image when 
      generating the palette, so that Alchemy would have included the right 
      colors from the start.

      The explosions cast circles of light, which expand outwards while 
      decreasing in intensity. These are currently drawn using a 
      circlefill() call, but would look much better if they had soft edges 
      rather than just snapping off at the rim of the circle (or even 
      better, soft edges and a slightly darker centre, so the most intense 
      light would be in an expanding circle around the rim of the 
      explosion). I could just store a sprite animation for this, but that 
      would waste a lot of memory (64 frames ranging up to 192x192 pixels in 
      size). I could store a single sprite image and scale it as required, 
      but that is a performance hit that I would prefer to avoid. Or I could 
      write a special soft_edged_circlefill() routine, which wouldn't be too 
      hard because the results don't need to be exact (the eye is very 
      forgiving of a few slight irregularities in light level). Or of course 
      I can take the easy option, and say "sod it, they look good enough the 
      way they are at the moment" :-)


   This program is free. You may do anything you like with it.


   Shawn Hargreaves
   http://www.talula.demon.co.uk/
