
    3D Studio Animation Player  Version 1.62
    ----------------------------------------

  by  Mats Byggmastar  a.k.a.  MRI of Doomsday

               mri@penti.sit.fi
      Fyrstikkallen 11 B, 0661 Oslo, Norway

           (c) Copyright 1996-2048
  First release (0.7) 15.12.1996 Jakobstad Finland



============================ Version history ===============================

Version 1.62 (25.7.1998)
------------------------
    - Made EXTR3DS.EXE utility to extract keyframer data from .3ds
      files that the engine can merge with other .3ds files.
      Read: "Merging 3ds data"
    - Added 'FarClipPlane=' parameter to engine .INI file.

Version 1.61 (17.6.1998)
------------------------
    - New materials:
        * transp_dot
        * zbuf_transp_dot
    - Optional masking added to the following materials:    
        + persp_texture
        + persp_large_texture
        + persp_last_frame
        + persp_internal_texture
        + persp_large_transp_texture
        + persp_transp_last_frame
        + persp_transp_internal_texture
        + zbuf_texture
        + zbuf_environment
        + zbuf_phong
        + zbuf_persp_texture
    - Made aliases for material functions. Read: "Function aliases"
    - Tried to fix Doom's script calls not to cause a crash if
      misused from the script.

Version 1.6 (28.5.1998)
-----------------------
    - New materials:
        * tiled_zbuf_large_texture    (works ok now)
        * tiled_zbuf_persp_large_texture
      tiled_*** materials can handle textures from 8x8 to 512x512 in
      any width,height combination (pow2: 8,16,32,64,128,256,512).
      They are also Pentium cache optimized. This should increase
      the speed on _fast_ Pentiums.

Version 1.54 (22.5.1998)
------------------------
    - Fixed Vesa code to handle BytesPerScanLine != xres. Works only with
      LFB. This should fix problems with Matrox Millenium and other cards.
    - Made smooth animated filter bitmaps for DSYS. Read: filter.txt
    - Fixed general sync inconsistency in DSYS. All functions that has the 
      number of frames as speed parameter will now run at the same speed
      on all video cards.

Version 1.53 (15.5.1998)
------------------------
    - New materials:
        * zbuf_persp_transp_texture
    - Added 3 z-layers and the optional parameters 'z_pos' to _all_ materials
      to make the z-buffer work better with transparent materials. Read:
      "Sorting, z-buffer and stuff".
    - Oooops!!! My method of speeding up the z-buffer by dividing it up into
      segments has actually been patented by some company. But who cares. :-)

Version 1.52 (11.5.1998)
------------------------
    - New materials:
       (* tiled_zbuf_large_texture)  Bugs! Under construction.
        * zbuf_solid
        * zbuf_flat
        * zbuf_transp
        * zbuf_transp_flat
        The transparent z-buffer will need a new sorting method... tricky.
    - Made post processing RGB filters for DSYS. Read: filter.txt

Version 1.51 (27.3.1998)
------------------------
    - New materials:
        * transp_phong
        * zbuf_phong_texture
        * dot
        * zbuf_dot
    - Modified script DisplayText to support horizontal scrolling.

Version 1.5  (18.3.1998)
-------------------------
    - New materials:  (Read: "Z-buffer")
        * zbuf_texture
        * zbuf_environment
        * zbuf_phong
        * zbuf_persp_texture
    - 'SortOrder=' parameter added to the .INI file.

Version 1.41  (25.12.1997)
--------------------------
    - Better equation for magnet force. Force decreases to 0 when
      distance is ~4 * magnet radius

Version 1.4  (23.12.1997)
-------------------------
    - Magnets. Read: magnet.txt

Version 1.3  (14.12.1997)
-------------------------                  
    - New material:
        * line  (lineroutine in C by lz/SoCS)

Version 1.2  (25.11.1997)
-------------------------
    - New materials:
        * persp_large_transp_texture
        * persp_transp_last_frame
        * persp_transp_internal_texture
    - Made scrolling text for DSYS. Read: alpha.txt
    - Made animated texture for DSYS. Read: txtanim.txt
    - Made -SHOT (screenshot) parameter for DSYS.
    - Made PlaySample for DSYS. Read: sample.txt
    - Magnets....  uhm... not yet implemented.

Version 1.12  (14.9.1997)
-------------------------
    - New materials:
        * large_transp_texture
        * transp_last_frame            (persp version under constr.)
        * transp_internal_texture      (persp version under constr.)
        * environment_transp_last_frame
        * environment_transp_internal_texture
    - Made generic 15/16 -> 15/16 converter/blitter for any hi-color
      masksettings.
    - Made PCY file format. Engine can load both PCX/PCY files.
    - PCX2PCY.EXE image converter.
    - V.EXE PCX/PCY image viewer.
    - Fixed bugs in PCX load/save functions. It is now compatible
      with Adobe Photo Shop!

Version 1.11 (27.7.1997)  Back in Oslo
--------------------------------------
    - 'transparency' parameter added to 15/16 bit persp_transp_texture.
      0.125, 0.25, 0.5, 0.75 transparency are available. 0.5 is fastest!
      E.g. 0.25 (25% transparency) means 75% material and 25% background
    - 15/16 bit image cross fading for DSYS. Can also be used for fading
      in and out an image in 15/16 bit. 16 levels of mixing. This is an
      importnant "design" effect! Read "Pcx commands" in script.txt

Version 1.1  (14.7.1997)
------------------------
    - New materials:
        * persp_texture                  8/15/16 bit  z=0  persp  tilable
        * persp_transp_texture             15/16 bit  z=0  persp  tilable
      Note! persp_texture in v1.0 has changed name to persp_large_texture

Version 1.0  (10.7.1997)  Finally! 
----------------------------------
    - I found a very strange bug (?) in 3D Studio (or is it the engine
      that has broken?). 3D Studio seems to add texture wrapping flags on
      objects even when using planar mapping! So texturing a simple qube is
      not possible. Add a '-' to the object name in 3D Studio and the engine
      will ignore the wrapping flags for that object. This will fix the
      problem for now.
    - Script AnimBackground can be used to swap background image on the fly
    - Script AnimBlurr can be used to turn ON/OFF the motion blurr on the fly
    - Fake 15/16 bit mode using ordinary 8 bit with a special RGB palette.
      XRRRRRGGGGGBBBBB, RRRRRGGGGGGBBBBB is scaled to RRGGGBBB. If the 
      videocard doesn't support 15/16 bit, the engine will try to use this
      fakemode. Asm'97 organisers states that the demo must run in standard 
      VGA and now it will! It will also run on my portable. :-)
    - Found a wierd memory bug in DSYS & MIDAS. MIDAS seems to need at least
      16k low memory to work properly with SB16. So now 64k is allocated at
      the start of DSYS and freed just before starting MIDAS so that MIDAS
      can allocate the needed low memory.
    - New materials:
        * solid                          8/15/16 bit  z=0  persp. correct
        * transp    (was transp_solid)   8/15/16 bit  z=0  persp. correct
        * flat                           8/15/16 bit  z=0  persp. correct
        * transp_flat                    8/15/16 bit  z=0  persp. correct
        * environment_bump               8/15/16 bit
        * phong_texture_bump             8/15/16 bit
        * persp_texture                  8/15/16 bit  z=0  persp. correct
        * persp_last_frame               8/15/16 bit  z=0  persp. correct
        * persp_internal_texture         8/15/16 bit  z=0  persp. correct
        * environment_last_frame         8/15/16 bit
        * environment_internal_texture   8/15/16 bit
      Note! previous_*** has changed name to last_***
      Wode, 'environment_last_frame' and 'environment_internal_texture' is
      the floating mappings you asked for.
    - Pseudo mirros works. Use script InitAnimMirror to setup the internal
      texture. Read "Pseudo mirrors".
    - Script AnimMirror can be used to turn ON/OFF a mirror on the fly

Version 0.79  (27.6.1997)  Oslo coding
--------------------------------------
    - New parameters for materials in 15/16 bit modes. Read:
      "Shading parameters in hi-color modes" and "Phong parameters"
    - 15/16 bit support for the following materials:
        * solid
        * flat
        * phong
        * phong_texture
    - Morphing objects works. The main object in a morph track will define
      material, mapping coordinates, smoothing groups, vectors, etc. for
      all the other objects. 
    - Object hide attribute in Keyframer works (Display/Hide.../...).
      This is needed for hiding objects in a morph track.
    - MKVECTOR.EXE (v 1.1) updated to account for the morphing objects.
      Note! Only the main object in a morph track need vectors.
    - Scale tracks works for "homemade" scenes but probably not in weird
      .3ds files found on the inet
    - Script LoadImage, DisplayImage, FreeImage works in 15/16 bit modes.
    - Script LoadPcx, DisplayPcx, FreePcx works in 15/16 bit modes.

Version 0.78  (1.6.1997)
------------------------
    - 15/16 bit support. Materials works as before but the lookup tables in 
      8 bit modes are not needed. The following materials are currently
      implemented:
        * texture
        * environment
        * large_texture
        * transp_texture
        * transp_environment
        * previous_frame
        * internal_texture
        * flare      (mix or add)  set mask_index > 0 for masking
    - Engine can load 8 or 24 bit PCX images. 8 bit images are expanded
      to 15/16 bit in hi-color modes.
    - Motion blurr in 15/16 bit modes. Use: MotionBlurr=on in .INI file.
    - Parameter 'face_side' added to most materials. This parameter can be
      "front", "back" or "both". This way you can specify if faces should
      be rendered if they are frontface, backface or always. 
    - New parameters in ANIM.EXE. width,height,bitpp specify the screenmode
      to use.
    - Using Watcom C/C++ 11.0 
    - LFB bugs under Windows. DPMI remap problems?

Version 0.77  (17.5.1997)
-------------------------
    - There is a lot of alpha code in this version!!! 
    - VESA 1.2 & VESA 2.0 support.
    - Engine works in any 8 bit mode (15/16 bit under construction).
    - Nasty bug in the recursive hierarchic model scanning code fixed. This
      bug limited the total number of objects to ~70, after that -> stack
      overflow. There is no upper limit now, only that the hierachic model
      must be less than ~70 levels deep. It now uses a combination of  
      iteration and recursion to save stackspace.
    - Tree new material types:
       * Large texture mapping (large_texture)
           Can handle bitmaps of any size. Mapping function can not
           handle tiled textures of any kind, so use only Planar mapping
           with no tiling and place the mapping rectangle with great care!
           The object _must_ be completely inside the mapping rectangle.
       * Previous frame mapping (previous_frame)
           Maps the previous frame onto an object. This can give nice
           infinite mirror effects. The mapping function has the same
           limitations as large_texture above.
       * General 2D effect mapping (internal_texture)
           Function for mapping 2D effects on objects. The mapping function
           has the same limitations as large_texture above. This mapping
           type only works with DSYS. As an example I have made a simple
           moving XOR pattern that can be used as texture map.
    - Pre & post processing function installation method has changed!
    - Texture mapping coordinate setup has been simplified. Please
      report back if you notice unusual mapping errors especially
      when using spherical or tiled mapping.
    - Additive colors option added to MKTRANS.EXE. Use this for more
      realistic transparent flares.

Version 0.76  (9.3.1997)
------------------------
    - Single, Loop and Repeat works for all spline tracks.
    - Bug in hide track fixed.
    - Made MKVECTOR.EXE utility for creating precalculated Gouraud/Phong
      vectors using the smoothing groups in 3D Studio. This takes too long
      to do at runtime setup. (See 'Smoothing groups and MKVECTOR.EXE')
    - Added 'ambient=' to all material types using Flat, Gouraud or Phong
      shading. This will eliminate the almost black faces at bad angles
      especially when Flat shading is used. ambient is in the range
      [0.0 ... 1.0]. Set to 0.0 if you don't need this.
    - Flares are now sorted correctly.
    - Added camera name to debug print.

Version 0.75  (2.3.1997)
-------------------------
    - Tree new materials:
       * Transparent flat shading (transp_flat)
       * Transparent texture mapping (transp_texture)
       * Transparent environemnt mapping (transp_environment)
    - All mapping (except gouraud,gouraud-texture) have been
      totally rewritten. They now have better clipping and are
      subpixel & subtexel accurate. Big improvement! 
    - Spline track repeat works
    - Hide track & repeat works
    - Scale tracks buggs!!!

Version 0.74  (16.2.1997)  Quick prerelease so Damaq can stop swetting
----------------------------------------------------------------------
    - Uh! I need to fix the jumppy mappings! And clipping too!
    - Scale-tracks not supported!
    - Lambert & Gouraud shading bug fixed.
    - Flares works (not really lens flares, rater light maps)
    - Face sorting problem under development. This makes the "flares"
      to be sorted wrongly at the moment!

Version 0.73 (15.1.1997)  Work on demosystem mainly
---------------------------------------------------
    - SelectFileSystem no longer supported. The new demosystem handles this 
      internally.
    - Spline looping bugs badly. Under construction.
    - Debug text can be turned on and off from the .INI file.
    - Animation player support palette and volume fade from the script.
    - Made new scripting & demosystem (DSYS 2.0) that uses the new packed
      filesystem.

New stuff in version 0.72 (5.1.1997)  Bugfixes mainly
-----------------------------------------------------
    - The vsync handler seems to be stable now. It hasn't crashed since I did 
      the last changes. Placing heavy work inside a irq0 handler is tricky
      business! Tested under DOS, Win3.1, Win95, DOS4GW, PMODE/W, Pentium 120,
      Cyrix P150, 486dx2-66 and 486dx-50. :-)
    - Fixed a nasty bug in the multiple camera setup that made the engine
      crash.
    - malloc(), free() maps 1:1.
    - Some minor cleanup in the triangle array functions.
    - ANIM.EXE now gives parameter info on startup.
    - Added FPS (Frames Per Second) readout.
    - Made PFS (Packed Filesystem) as sideproject. Supports LZSS packed and
      unpacked files. Use MKPFS.EXE to create the filesystem.
    - Using PMODE/W 1.33

New stuff in version 0.71 (29.12.1996)
--------------------------------------
    - Object rotation tracks
    - Hierarchic objects
    - Camera can be attached on another object
    - Motion blurr (see .INI parameters)
    - Transparent solid shading function (see .MAT parameters)
    - Transparent DisplayImage (new parameter!)
    - MKTRANS.EXE utility
    - ANIM.EXE is now syncronized to screen
    - Texture and environment maps are now loaded correctly.
 BUGS:
    - ANIM.EXE might hang occationally. Big problems with the vsync handler.
      Try with SMARTDRV /C before calling ANIM.EXE in DOANIM.BAT.
    - Some objects that has been created by flipping another object
      horizontally or vertically might not be displayed correctly. It seems
      that I need to dig into some matrix algebra again. :-(

Version 0.70  (15.12.1996)
--------------------------
    - First release outside MRL to Doomsday members. 
 BUGS:
    - Texture and environment maps loaded upside down.

========================= Version history end ==============================


Story
-----

    3 weeks after Assembly'96, more exactly 6.9.1996, I somehow got inspired
    to start writing this 3D engine. The aim was to make something far
    superior to the old fixed point engine that was used in our demo Vivid
    Experiment that came 3:rd at Assembly'96. Because I also worked as a
    teacher, progress was slow. The first release (0.7) came after 3 month
    and it featured the same basic materials from the old engine and some 3D
    Studio support. The internal of the engine was completely new with
    transformations done with matrices and floating point used all the way to
    the shading functions. Now things started to happen. Rotation tracks,
    hierarchic objects, camera linking, PFS, DSYS, subpixel & subtextel
    accuracy, previous frame & internal texture mapping, hi-color, morphing
    objects, perspective correct mapping, fakemode, pseudo mirrors and many
    relases later it feels like we have something useful here. After our demo
    "I wish I was a skijumper" that came 2:nd at Abduction'97 demo compo,
    people has also told me that this engine is fast. ANIM 0.75 & DSYS 2.1
    was used in "I wish...". As I'm writing this, Assembly'97 is closing and
    I'm about to release ANIM version 1.0 and DSYS version 2.6. The source
    code for the 3D engine is now about 1.7 MB (57000 lines of code).

        MRI  8.7.1997


    Assembly'97 is over. The result was OK, we won the PC-demo compo with
    our demo BOOST. 3 times more wotes than the 2:rd place demo by Orange.

        MRI  12.9.1997


    Some time has passed now since The Party'97 where we released ELEKTRONIKS.
    A nice demo although it came only 8:th PC-demo compo. The Gathering'98
    is closing and I have just finnished the basic materials with z-buffer
    support. The 3D engine is now about 63000 lines of code.

        MRI  26.3.1998


    Abduction'98 is over. We won the PC-demo compo with STIGMA, a wierd demo
    by Damaq doing the main gfx-work and Muffler on music.

        MRI  14.6.1998

    
    Damaq puts together our last demo OFF which winns Dreamhack'98 PC-demo
    compo and Doomsday quits the scene. After a lot of thinking and a little
    discussion we decide to release the whole DSYS utility pack along with
    documentation and BOOST & OFF as example usage. 


        MRI 4.1.1999



Script functions
----------------

  Running an animation
  --------------------

    An animation is setup with InitAnim, run by DoAnim and deinitialized
    with ExitAnim.

    InitAnim
        This function should be called in advance as the setup can take a
        while on slow computers. Syntax:

        xxx xxx  InitAnim    inifile  3dsfile

        Parameters:
          inifile    - Path to .INI file.
          3dsfile    - Path to .3DS file. This will override the .3DS file
                       specified in the .INI file. Put a '-' character if you
                       want to use the file specified in the .INI file.
                       
    DoAnim
        This function can be called multiple times with different parameters.
        Syntax:

        epos erow  DoAnim   skey ekey tpk cam pal

        Parameters:
          epos - Music track position where to stop the animation.
          erow - Music track row where to stop the animation.
          skey - Animation starts at this key.
          ekey - Animation loops at this ending key.
          tpk  - Time Per Key in seconds.
          cam  - Camera name.
          pal  - Palette file.

        pos & row must be specified for each call. The other parameters can
        be a '-'character telling the engine to continue on using the old or
        default values. skey, ekey and tpk are floating point values.

    ExitAnim
        Call this function to free system resources used by the engine.
        Sysntax:

        xxx xxx  ExitAnim    


    When you make the animation in 3D Studio, you can create many cameras
    with different tracks. This can be used as a type of action movie where
    we have many cameras filming from different angles. Switch between the
    cameras (and/or palettes) for each call to DoAnim.
    
    Example:

        xxx xxx  InitAnim          movie/movie.ini  -
        001 001  WaitSYNC          
        002 001  DoAnim            0.0 50.0  1.4  Camera01  movie/cam01.pal
        003 010  DoAnim            -   -     0.6  Camera02  movie/cam02.pal
        004 001  DoAnim            -   -     -    Camera01  movie/cam01.pal
        005 001  DoAnim            -   -     0.4  -         -
        xxx xxx  ExitAnim     



  Static image handling
  ---------------------

    It is possible to draw images before or after the objects has been
    plotted to the virtual buffer. Images can be masked and/or transparent.
    First of all you need to load an image with LoadImage. Then call
    DisplayImage to specify drawing parameters. When the animation player is 
    running, it will look at what images has been selected with
    DisplayImage and then plot those for each frame checking the POS & ROW
    parameters of the Music Player. Images are freed with FreeImage.
    
    LoadImage
        Call this function to load an image and assign a handle to it. The
        image can be any size. Syntax:

        xxx xxx  LoadImage   handle  file  trafile

        Parameters:
          handle  - image handle. 0...31  Max 32 images can be loaded at a
                    time.
          file    - path to 256 color .PCX file.
          trafile - path to 64k translucent lookup table calculated for the
                    current palette with MKTRANS.EXE. Set this to '-' if you
                    only draw solid images. This table isn't needed for hi-
                    color.
                                        

    DisplayImage
        Call this function to specify when, where and how a image should be
        displayed during an animation. Syntax:

        ep er  DisplayImage  sp sr  handle  x1 y1 x2 y2  sx sy  mask proc sol

        Parameters:
          ep er  - Stop displaying the image at this POS & ROW. Can be
                   xxx xxx to leave the image on the screen.
          sp sr  - Start displaying the image at this POS & ROW. Can be
                   xxx xxx to display the image right away.
          handle - Image handle as in LoadImage
          x1 y1  - Upper left corner of destination window
          x2 y2  - Lower right corner of destination window
          sx sy  - Upper left corner in source image
          mask   - Mask index. All colors below this value will be masked out.
                   Set to 0 if no masking.
          proc   - PRE or POST. Tells the animation player to plot the image
                   before or after the objects has been plotted to the virual
                   buffer.
          sol    - SOLID or TRANSP. Tells the animation player to plot the
                   image as solid or using the translucent table.
                   
        Note! You can call DisplayImage max 64 times before freeing up space
        with FreeImage. I.e. You can have max 64 image segments on the screen
        at the same time.
        
        Note! You must call DisplayImage AFTER InitAnim has been called. This
        is because InitAnim resets the pointers to the internal pre- and
        postdrawing functions.
        
    FreeImage
        Call this to free an image loaded with LoadImage. All image segments
        setup with DispalyImage and associated with this image handle will be
        removed from sceen. Syntax:
        
        xxx xxx  FreeImage  handle

        where handle is the same as in DispalyImage.


    Example:

     xxx xxx  InitAnim          anim/test.ini anim/test.3ds
     xxx xxx  LoadImage         0  anim/logo.pcx - 
     xxx xxx  LoadImage         1  anim/texts.pcx anim/texts.tra
     xxx xxx  DisplayImage      xxx xxx  0  0 180 60 200  0   0  0 POST SOLID
     002 000  DisplayImage      001 000  1  0   0 100 20  0   0  1 POST TRANSP
     002 032  DisplayImage      001 032  1  100 0 200 20  100 0  1 POST TRANSP
     003 000  DoAnim            0.0 50.0  1.0 Camera01 anim/txt.pal
     004 000  DoAnim            -   -     0.5 -        -
     xxx xxx  ExitAnim
     xxx xxx  FreeImage         1
     xxx xxx  FreeImage         0



  Pseudo mirrors
  --------------
    
    Pseudo mirrors gives the engine the ability to map any camera view onto
    any object using any of the ***_internal_texture functions. You can link
    the camera target and position to an object and map the camera view
    to the same object making it look like a mirror. Cameras in 3D Studio
    are allowed to rotate to keep it's up-vector vertical, therefore the
    "mirror" can behave a bit strange. Note that the scene will be rendered
    for each "mirror-camera". Therefore you should specify a resonable sized
    internal map, say 64x64 or 128x128 pixel, to keep the speed up.
    The mirrors are automatically freed when ExitAnim is called.
    
    You setup the mirror with script InitAnimMirror after InitAnim has been
    called. Syntax:

     xxx xxx  InitAnimMirror  mirrhandle mapnumber camera width height aspect

     Parameters:
          mirrhandle  - mirror handle. 0...15   (max 16 mirrors active)
          mapnumber   - internal map number. 0...255
          camera      - camera name, as in 3D Studio 
          width       - width of the internal map in pixels
          height      - height of the internal map in pixels
          aspect      - aspect ratio of the camera view, float value

    You can turn ON/OFF a "mirror" (freeze it) with script AnimMirror
    between each call to DoAnim. Syntax:

     xxx xxx  AnimMirror  mirrhandle mode

      where mirrhandle is the same as in InitAnimMirror and mode is ON or OFF



Sorting, z-buffer and stuff
---------------------------

  A scene is divided into 3 layers: 'near', 'normal' and 'far'. 'normal' is
  default and is the layer where the main part of the scene should be. The
  'far' layer is always plotted first, i.e. it is pushed behind the faces
  that belong to the 'near' or 'normal' layers. The 'near' layer is plotted
  last and thus pulled in front of faces that belong to the 'normal' or
  'far' layers. You specify layer in the material definition with the
  optional 'z_pos' parameter:

       z_pos = "near"      # Faces with this material is in the 'near' layer
       z_pos = "normal"    # This is default, no need to specify.
       z_pos = "far"       # Faces with this material is in the 'far' layer

  Each layer are internally depth sorted using the center point of each
  face. The direction in wich they are sorted can be specified with the
  optional 'SortOrder' parameter in the .INI file:

       SortOrder=back_to_front      # This is default, no need to specify.
       SortOrder=front_to_back      # Use this for z-buffer materials

  The last step is z-buffer sorting of individual pixels if the material
  has z-buffer support. Read more about the z-buffer below.

  It is possible to mix z-buffer materials with ordinary materials. Good
  results can be acheived if you use the layers to force some materials to
  be plotted first or last or possibly by reversing the sort direction with
  'SortOrder'.
        
  Transparent z-buffer materials should be in 'near' layer.



Z-buffer
--------

  A z-buffer system stores the z-component (or rather 1/w in the homogenous
  coordinate system) for each plotted pixel in a separate buffer, the
  z-buffer. Thus we can check if the pixel we are about to plot is above or
  below (in front or behind) the previous pixel plotted at the same place.
  If the pixel is above (in front), we plot the pixel and update the z-buffer.
  If the pixel is below (behind), we don't plot or update the z-buffer. This
  will give perfect depth sorting for each pixel. On the other hand, checking
  the z-buffer for each pixel is relatively slow and furthermore, the
  z-buffer needs to be cleared between each frame. The z-buffer is typically
  very big (screen width * height * 4) which makes this a slow process.

  The engine does the following to speed these things up:  

    The z-buffer has 64 different levels. A frame can be rendered above
    the previous level without the need to clear it. Hovever, when we
    reach level 64, the z-buffer _must_ be cleared and we can continue
    at level 0. Furthermore, the z-buffer is split up into 64 line segments,
    i.e. one segment on a 320x200 screen is only 3 lines. Each segment
    will initially be on different levels. This means that for each frame
    only 3 lines in the z-buffer needs to be cleared!!!

    The sorting order can be reversed using the 'SortOrder' parameter in
    the .INI file. I.e. we can draw the faces that are closest first,
    which will eliminare all overwriting (invers painters algorithm).

  A z-buffer is automatically allocated when a zbuf_* material is used.
  zbuf_* materials can be mixed with other materials.



Flares
------

  Flares are made up of transparent scaled bitmaps, so they are not really
  3D objects. They do have a centre point and a radius (as well as a bounding
  box) in 3D space. 

  You make a flare in 3D Studio by creating an ordinary mesh object, e.g. a
  sphere. The object name is important, it should start with the @ character,
  e.g. @flare01. The engine will then convert this mesh to a flare. You should
  use a simple mesh with few vertices so that it won't occupy unnessecary
  space in the 3DS file. The vertices are not used, only the centre point and
  radius.

  You must assign a special material to the mesh. The material is defined in 
  the .MAT file like this:


    material = "FLARE BLUE"
    {
        function = "flare"
        large_texture_map_path = "mat/flare.pcx"        
        transparent_64k_path = "mat/env.tra"    
        mask_index = 1                           
    }

  large_texture_map_path - Path to PCX image. The image can be any size and it
                           will be stretched to the object radius. 64x64 pixel
                           images makes acceptable flares.
  transparent_64k_path   - Path to 64 kbyte transparent lookup table
                           calculated with MKTRANS.EXE. Same table is used for
                           the motion blurr.
  mask_index             - Mask out all colors below this palette index.

  In hi-color modes you don't need a transparent lookup table. Instead you
  specify what transparent mode should be used:

  transparent_mode       - "mix" or "add" 
  
  also, you must set mask_index greater than 0 for masking.  

  Because you create the flares as ordinary mesh objects in 3D Studio you can
  attach the flares to other objects or attach flares to other flares forming
  long arrays. The size of the flares are not affected by the scale track.



Error reporting
---------------

  The engine should print out an error message if something is missing or
  wrong. If you forget to put @end at the end of the initialization files,
  the egine will hang if something is missing in the files. Beware of this!



3D Studio support
-----------------

  The 3D engine reads the .3DS file directly. No need to scale any objects to
  a specific range. What you see in 3D Studio is what you get. You specify
  what file to use in the .INI file or as parameter to InitAnim.

  Note! If you import scenes from Lightwave, the scene will typically be
        very small. In this case you must scale up the scene because the
        3D enngine has the near clipping plane at the distance 1.0 from the
        camera.


    3D editor
    ---------

     Materials
        You can assign different materials to each triangle in the same
        object. Only the material name is used by the 3D engine so you must
        define the corresponding material name and definiton (textures,
        shades etc.) in the .MAT file that is specified in the .INI file.

        A good idea is to create a custom material library in 3D Studio (.MLI)
        with a few material names. Then make the corresponding .MAT file for
        those materials.
        
     Mapping
        Planar, Cylindrical and Spherical mapping should work without wrapping
        errors. Tiling might break this though. I'm using the same code as 3DS
        so it should work.
        
     Smoothing
        Use the MKVECTOR.EXE utility to precalculate the smoothed vectors and
        store in a file for speedy runtime setup.
        
     Camera
        FOV and Roll works ok. You can create many cameras in the same scene.
        You select which camera to use when starting an animation.


    Keyframer
    ---------

     Hierarchy
        Object linking works ok.
        Object pivot works ok.
        Camera target can be linked to another object.
        Camera position can be linked to another object.

     Spline tracks
        Ease To, Ease From, Tension, Continuity and Bias parametars supported. 
        Single, Loop and Repeat works.

     Camera tracks
        Target, position, FOV and Roll tracks works ok.   
    
     Object tracks
        Position and rotation tracks works ok.
        Scale tracks works for most "homemade" scenes. Use: Object/Modify/
        ResetXForm if problems.

     Hide tracks
        Object hide tracks works ok.
        Track single and repeat works.

     Morph tracks
        Vertex & vector morphing works ok.
        Note! Morphing uses the same spline system as 3DS so you can use
              Tension, Continuity, Bias, Loop etc...

     Hide attribute for mesh objects works ok.
        Use: Display/Hide.../...


Merging 3ds data
----------------

With the EXTR3DS.EXE utility it is possible to extract track data from
a .3ds file and save it to a file. The engine can load a .3ds file
and then merge it with the extracted data from the file (or several files).
You specify what data to extract with command line options to EXTR3DS.EXE,
e.g. between which frames track data should be extracted. By default,
EXTR3DS.EXE will extract all keyframer tracks and flags supported by the
3d engine.

In the animation .INI file you specify which data file to merge:

    3dsMergeFile=file.ext

If you want to merge many files you specify a list file:

    3dsMergeFile=@files.lst

the list file in turn should have the filenames of each file to merge
on separate lines. E.g:

    scene0.ext
    scene1.ext



Shading parameters in hi-color modes
------------------------------------

  Hi-color modes offers more flexibility than 256 color modes when it comes
  to selecting what colors should be used during shading of an object. The
  scheme used for defining the colorpath from darkest to brightest colors
  works like this:

  We define 3 colors where each color consists of an R,G,B triplet with each
  component in the range [0...1].

    dark_rgb   =  "  0.0  0.0  0.0  "
    color_rgb  =  "  1.0  0.0  0.0  "
    bright_rgb =  "  1.0  1.0  1.0  "

  Now we place these colors on the colorpath with the following parameters
  (the colorpath is in the range [0...1]):

    dark_pos   =  0.0
    color_pos  =  0.8
    bright_pos =  1.0

  The color is smoothly interpolated from dark_rgb -> color_rgb -> bright_rgb.
  color_pos defines where the specular highlight starts. If we are shading
  a texture map (e.g. phong_texture) the color_rgb components is taken from
  the palette for each color. Thus, bright_rgb should not be specified when
  shading a texture map.

  Note! You can tweak the values for some nice and weird color effects.
        Try the following for phong_texture:

            dark_rgb    = " 0.7  1.0  0.0 "
            bright_rgb  = " 1.0  0.0  1.0 "
            dark_pos    = 0.0
            color_pos   = 0.4
            bright_pos  = 1.8



Phong parameters
----------------

  With phong shading the intensity follows a curve (colorpath) defined by the
  following equation:

  intensity = ambient + diffuse * cos(x) + specular * cos(x)^exponent

    where x is the angle between the pixel normal and a vector in the
    direction of the lightsource.

  ambient, diffuse and specular are in the range [0...1] and the resulting
  intensity in the range [0...1] which means that

    (ambinet + diffuse + specular) always must equal 1.0

  ambient specifies the amount of ambient light (background light).
  diffuse and specular specifies the softness of the specular highlight.
  exponent specifies the size of the specular highlight.

    E.g.   ambient  = 0.0
           diffuse  = 0.4
           specular = 0.6
           exponent = 12.0
    
  It is also possible to load a precalculated phong map using the
  phong_map_path = "256x256_8bit.pcx" parameter.



Smoothing groups and MKVECTOR.EXE
---------------------------------

  In 3D Studio 3D editor, you can assign the faces of a mesh object to
  smoothing groups (Surface/Smoothing/...). If two or more faces connect and
  they are in the same smoothing group, the faces will be smoothly shaded
  removing the visible edge between them. Naturally, this is only valid if 
  Environment, Gouraud or Phong shading is used.

  Calculating the smoothed vectors for a .3DS file is very time consuming.
  Therefore they should be precalculated and stored in a file (.VEC) using
  the MKVECTOR.EXE utility. One .3DS file will give one .VEC file where all
  vector data is stored for each mesh object.

  Note! Vector files usually becomes very big, therefore you should not
  precalculate vectors for those objects that have only flat or no shading,
  i.e. plain texture mapping. Also, only the first object in a morph track
  needs vectors.

  You specify what .VEC file to use in an animation with the 'Vectors='
  parameter in the .INI file.

  MKVECTOR.EXE parameters:

     -i     Ignore smoothing groups. This is the same as not specifying a
            .VEC file in .INI file. Only here the vectors will be
            precalculated giving a faster runtime setup.
     -b     Treat the smoothing groups as a 32 bit bitfield.
     -u     Treat the smoothing groups as unique patterns.
     -y     Don't ask for file overwrite if destionation file exist.

  If you don't specify either -i, -b or -u, you will be asked for each
  object in the .3DS file. You can then also ansver 'N' if you don't need
  vectors for a specific object.

  To create smoothed objects, you should specify either b or u.

  Note! While you work on a scene, you don't need to create the .VEC file.
        Just remove 'Vectors=' from the .INI file. Then when the scene is
        ready you create the final .VEC file.



Files
-----
    
   .INI

        This is the main initialization file for the engine. This is an
        ordinary textfile. # means comment and @end must be at the end of
        file. The following parameters should be specified in this file:

         MemoryPoolSize=blocks

        where blocks is an integer. The memory pools is a memory handler for
        aligned memory blocks needed by some of the shading functions. Each
        block is 64 kbyte. Set this value as low as possible so that the pool
        won't occupy unused memory. 
        
         3dsFile=file

        where file is the filename of the .3DS file to use. Note! You can
        override this file by specifying a .3DS file as paremater to InitAnim.

         Vectors=file

        where file is the filename of a precalculated vector file (.VEC)
        created with MKVECTOR.EXE utility. If this parameters is missing,
        the engine will calculate the vectors at runtime setup but ignore
        the smoothing groups in the .3DS file. 

         MaterialFile=file

        where file is the filename of the material definition file (.MAT).
        Note! Only the materials needed for the given .3DS file will be
        loaded. So you could make a common .MAT file with all materials
        and use that for all animations.

         BackgroundImage=file
         BackgroundColor=color

        where file is the filename of a background image (.PCX) and color is
        an integer (0...255) used when clearing the background. If both are
        specified, the background will be filled by the background image. If
        none are given, the background will not be cleared. This is useful
        for external pre processing functions.

         MotionBlurrFile=file

        where file is the filename of a 64k byte translucent lookup table
        calculated for the current palette using MKTRANS.EXE. Motion blurr
        will automatically be activated when you give this parameter. Specify
        a lower translucent value to MKTRANS.EXE for more blurr.

         MotionBlurr=on

        Use the above line to activate motion blurr in hi-color modes.
        The MotionBlurrFile parameter is not needed in these modes.
        
         DebugPrint=yes

        Specify this to get some debug info while running an animation.
        
         SortOrder=order

        The above parameter can be used to specify in what order the
        faces should be sorted in. 'order' can be either back_to_front
        or front_to_back. back_to_front is default. In a scene with only
        z-buffered materials, specify front_to_back for maximum performance.


   .MAT
    
        Material definition file. When the .3DS file is read, only the
        material names will be extracted. This .MAT file should contain the
        actual definition for the material name. This is an ordinary textfile
        with @end at the end. # means comment. Material definitions looks
        like:
        
         material = "material name"
         {
            value_parameter = float_value
            string_parameter = "text_string"
         }

        where 'material name' is the material name as specified in 3D Studio.
        'value_parameter' is a parameter that expects a float value to follow.
        'string_parameter' is a parameter that expects a textstring to follow.
        Note! Textstrings should always be quoted (").

        Note that the parameters needed depends on the shading function
        specified. The most important parametar is:
        
         function = "shading function"



Materials and .MAT files
------------------------

  Function aliases
  ----------------
    Function name in material definition presented in the next section
    have a full name and an alias. This was made because function names
    was becomming very long, e.g. "environment_transp_internal_texture"
    has now the following alias: "env_tra_int_tex". The alias is simply
    made from the first 3 letters of each component.

        none         -->  non
        line         -->  lin
        solid        -->  sol
        transp       -->  tra
        flat         -->  fla
        gouraud      -->  gou
        phong        -->  pho
        environment  -->  env
        texture      -->  tex
        large        -->  lar
        bump         -->  bum
        last         -->  las
        frame        -->  fra
        internal     -->  int
        persp        -->  per
        zbuf         -->  zbu
        dot          -->  dot
        tiled        -->  til
        flare        -->  flare     (the only exception)


  Material list
  -------------

   function                              modes    special features
    
    none                                8/15/16  
    dot                                   15/16   Z
    zbuf_dot                              15/16   Z     ZB
    transp_dot                            15/16   Z     ZB
    zbuf_transp_dot                       15/16   Z     ZB
    line                                  15/16   Z
    solid                               8/15/16   Z
    zbuf_solid                            15/16   Z     ZB
    transp                              8/15/16   Z
    zbuf_transp                           15/16   Z     ZB
    flat                                8/15/16   Z
    zbuf_flat                             15/16   Z     ZB
    transp_flat                         8/15/16   Z
    zbuf_transp_flat                      15/16   Z     ZB
    gouraud                             8
    phong                               8/15/16
    transp_phong                          15/16
    zbuf_phong                            15/16         ZB   OM
    environment                         8/15/16
    zbuf_environment                      15/16         ZB   OM
    transp_environment                  8/15/16
    texture                             8/15/16       T
    zbuf_texture                          15/16       T ZB   OM
    large_texture                       8/15/16
    persp_texture                       8/15/16   Z P T      OM
    tiled_zbuf_large_texture              15/16       T ZB C
    zbuf_persp_texture                    15/16   Z P T ZB   OM
    tiled_zbuf_persp_large_texture        15/16   Z P T ZB C
    zbuf_persp_transp_texture             15/16   Z P T ZB
    persp_large_texture                 8/15/16   Z P        OM
    large_transp_texture                  15/16   Z P
    persp_large_transp_texture            15/16              OM
    transp_texture                      8/15/16       T
    persp_transp_texture                  15/16   Z P T
    flat_texture                        8             T
    gouraud_texture                     8             T
    phong_texture                       8/15/16       T
    zbuf_phong_texture                    15/16       T ZB
    environment_bump                    8/15/16       T
    phong_texture_bump                  8/15/16       T
    last_frame                          8/15/16  
    persp_last_frame                    8/15/16   Z P        OM
    transp_last_frame                     15/16
    persp_transp_last_frame               15/16   Z P        OM
    internal_texture                    8/15/16
    persp_internal_texture              8/15/16   Z P        OM
    transp_internal_texture               15/16
    persp_transp_internal_texture         15/16   Z P        OM
    environment_last_frame              8/15/16
    environment_transp_last_frame         15/16
    environment_internal_texture        8/15/16
    environment_transp_internal_texture   15/16
    flare                               8/15/16  scal.bitmap, @flares in 3ds

       Z  -  Z=0 clipping
       ZB -  Z-buffer
       P  -  perspective correct
       T  -  texture is tilable
       C  -  cache optimized (tiled texture scheme)
       OM -  optional masking

   Below is a complete list of the material definition rules. Note that
   the parameters depends on what mode (8/15/16 bit) is used. 8 bit mode
   usually requires a precalculated lookuptable wheres 15/16 bit modes
   need a colorpath definition (dark_rgb, dark_pos, etc.). Note that
   256 color (8 bit) images can always be used in all modes.

   Note! With phong shading you can either use 'phong_map_path' or
         'ambient', 'diffuse', 'specular' and 'exponent' parameters
         to specify phong lookup table.

   Note! All material that are tilable can have the optional parameters
         u_delta and v_delta.  

   Note! The optional parameter z_pos can be applied on all materials.
         Read more about z_pos in "Sorting, z-buffer and stuff".



        material = "NO MATERIAL" {
            function = "none"
        }

        material = "DOT" {
            function = "dot"
            face_side = "front" / "back" / "both"
            color_rgb = " R G B "  [0.0 ... 1.0 ]
        }

        material = "TRANSPARENT DOT" {
            function = "transp_dot"
            face_side = "front" / "back" / "both"
            color_rgb = " R G B "  [0.0 ... 1.0 ]
        }

        material = "Z-BUFFER DOT" {
            function = "zbuf_dot"
            face_side = "front" / "back" / "both"
            color_rgb = " R G B "  [0.0 ... 1.0 ]
        }

        material = "Z-BUFFER TRANSPARENT DOT" {
            function = "zbuf_transp_dot"
            face_side = "front" / "back" / "both"
            color_rgb = " R G B "  [0.0 ... 1.0 ]
        }

        material = "LINE" {
            function = "line"
            face_side = "front" / "back" / "both"
            color_rgb = " R G B "  [0.0 ... 1.0 ]
        }

        material = "SOLID COLOR" {
            function = "solid"
            face_side = "front" / "back" / "both"
            color_index = [0...255]                         # 8
            color_rgb = " R G B "  [0.0 ... 1.0 ]           # 15/16
        }

        material = "Z-BUFFER SOLID COLOR" {
            function = "zbuf_solid"
            face_side = "front" / "back" / "both"
            color_rgb = " R G B "  [0.0 ... 1.0 ]
        }

        material = "TRANSPARENT" {
            function = "transp"
            face_side = "front" / "back" / "both"
            transparent_256_path = "256byte.tra"            # 8
            color_rgb = " R G B "  [0.0 ... 1.0 ]           # 15/16
        }

        material = "Z-BUFFER TRANSPARENT" {
            function = "zbuf_transp"
            face_side = "front" / "back" / "both"
            color_rgb = " R G B "  [0.0 ... 1.0 ]
        }

        material = "FLAT SHADING" {
            function = "flat"       
            face_side = "front" / "back" / "both"
            color_index = [0 ... 255]                       # 8
            shades = [0 ... 256]                            # 8
            ambient = [0.0 ... 1.0]
            shades = [0 ... ]  no upper limit               # 15/16
            dark_rgb = " R G B "  [0.0 ... 1.0] tweak!      # 15/16
            color_rgb = " R G B "  [0.0 ... 1.0] tweak!     # 15/16
            bright_rgb = " R G B "  [0.0 ... 1.0] tweak!    # 15/16
            dark_pos = [0.0 ... 1.0] tweak!                 # 15/16
            color_pos = [0.0 ... 1.0] tweak!                # 15/16
            bright_pos = [0.0 ... 1.0] tweak!               # 15/16
        }

        material = "Z-BUFFER FLAT SHADING" {
            function = "zbuf_flat"       
            face_side = "front" / "back" / "both"
            ambient = [0.0 ... 1.0]
            shades = [0 ... ]  no upper limit               # 15/16
            dark_rgb = " R G B "  [0.0 ... 1.0] tweak!      # 15/16
            color_rgb = " R G B "  [0.0 ... 1.0] tweak!     # 15/16
            bright_rgb = " R G B "  [0.0 ... 1.0] tweak!    # 15/16
            dark_pos = [0.0 ... 1.0] tweak!                 # 15/16
            color_pos = [0.0 ... 1.0] tweak!                # 15/16
            bright_pos = [0.0 ... 1.0] tweak!               # 15/16
        }

        material = "TRANSPARENT FLAT SHADING" {
            function = "transp_flat"
            face_side = "front" / "back" / "both"
            transparent_64k_path = "64kbyte.tra"
            color_index = [0 ... 255]                       # 8
            shades = [0 ... 256]   15/16 no upper limit
            ambient = [0.0 ... 1.0]
            dark_rgb = " R G B "  [0.0 ... 1.0] tweak!      # 15/16
            color_rgb = " R G B "  [0.0 ... 1.0] tweak!     # 15/16
            bright_rgb = " R G B "  [0.0 ... 1.0] tweak!    # 15/16
            dark_pos = [0.0 ... 1.0] tweak!                 # 15/16
            color_pos = [0.0 ... 1.0] tweak!                # 15/16
            bright_pos = [0.0 ... 1.0] tweak!               # 15/16
        }

        material = "Z-BUFFER TRANSPARENT FLAT SHADING" {
            function = "zbuf_transp_flat"
            face_side = "front" / "back" / "both"
            shades = [0 ... ]   no upper limit
            ambient = [0.0 ... 1.0]
            dark_rgb = " R G B "  [0.0 ... 1.0] tweak!      # 15/16
            color_rgb = " R G B "  [0.0 ... 1.0] tweak!     # 15/16
            bright_rgb = " R G B "  [0.0 ... 1.0] tweak!    # 15/16
            dark_pos = [0.0 ... 1.0] tweak!                 # 15/16
            color_pos = [0.0 ... 1.0] tweak!                # 15/16
            bright_pos = [0.0 ... 1.0] tweak!               # 15/16
        }

        material = "GOURAUD SHADING" {
            function = "gouraud"
            color_index = [0 ... 255]
            shades = [0 ... 256]
            ambient = [0.0 ... 1.0]
        }        
        
        material = "PHONG SHADING" {
            function = "phong"
            face_side = "front" / "back" / "both"
            color_index = [0 ... 255]                       # 8
            shades = [0 ... 256]                            # 8
            phong_map_path = "256x256_8bit.pcx"
            ambient = [0.0 ... 1.0]
            diffuse = [0.0 ... 1.0]
            specular = [0.0 ... 1.0]
            exponent = [0.0 ... 30.0]
            dark_rgb = " R G B "  [0.0 ... 1.0] tweak!      # 15/16
            color_rgb = " R G B "  [0.0 ... 1.0] tweak!     # 15/16
            bright_rgb = " R G B "  [0.0 ... 1.0] tweak!    # 15/16
            dark_pos = [0.0 ... 1.0] tweak!                 # 15/16
            color_pos = [0.0 ... 1.0] tweak!                # 15/16
            bright_pos = [0.0 ... 1.0] tweak!               # 15/16
        }

        material = "TRANSPARENT PHONG SHADING" {
            function = "transp_phong"
            face_side = "front" / "back" / "both"
            phong_map_path = "256x256_8bit.pcx"
            ambient = [0.0 ... 1.0]
            diffuse = [0.0 ... 1.0]
            specular = [0.0 ... 1.0]
            exponent = [0.0 ... 30.0]
            dark_rgb = " R G B "  [0.0 ... 1.0] tweak!      # 15/16
            color_rgb = " R G B "  [0.0 ... 1.0] tweak!     # 15/16
            bright_rgb = " R G B "  [0.0 ... 1.0] tweak!    # 15/16
            dark_pos = [0.0 ... 1.0] tweak!                 # 15/16
            color_pos = [0.0 ... 1.0] tweak!                # 15/16
            bright_pos = [0.0 ... 1.0] tweak!               # 15/16
        }

        material = "Z-BUFFER PHONG SHADING" {
            function = "zbuf_phong"
            face_side = "front" / "back" / "both"
            masking = "on" / "off"                          # optional
            phong_map_path = "256x256_8bit.pcx"
            ambient = [0.0 ... 1.0]
            diffuse = [0.0 ... 1.0]
            specular = [0.0 ... 1.0]
            exponent = [0.0 ... 30.0]
            dark_rgb = " R G B "  [0.0 ... 1.0] tweak!      # 15/16
            color_rgb = " R G B "  [0.0 ... 1.0] tweak!     # 15/16
            bright_rgb = " R G B "  [0.0 ... 1.0] tweak!    # 15/16
            dark_pos = [0.0 ... 1.0] tweak!                 # 15/16
            color_pos = [0.0 ... 1.0] tweak!                # 15/16
            bright_pos = [0.0 ... 1.0] tweak!               # 15/16
        }

        material = "ENVIRONMENT MAPPING" {
            function = "environment"
            face_side = "front" / "back" / "both"
            environment_map_path = "256x256_8/24bit.pcx"    # 8/15/16
        }

        material = "Z-BUFFER ENVIRONMENT MAPPING" {
            function = "zbuf_environment"
            face_side = "front" / "back" / "both"
            masking = "on" / "off"                          # optional
            environment_map_path = "256x256_8/24bit.pcx"
        }

        material = "TRANSPARENT ENVIRONMENT MAPPING" {
            function = "transp_environment"
            face_side = "front" / "back" / "both"
            environment_map_path = "256x256_8/24bit.pcx"    # 8/15/16
            transparent_64k_path = "64kbyte.tra"            # 8
        }
        
        material = "TEXTURE MAPPING" {
            function = "texture"
            face_side = "front" / "back" / "both"
            texture_map_path = "256x256_8/24bit.pcx"        # 8/15/16
        }

        material = "Z-BUFFER TEXTURE MAPPING" {
            function = "zbuf_texture"
            face_side = "front" / "back" / "both"
            masking = "on" / "off"                          # optional
            texture_map_path = "256x256_8/24bit.pcx"
        }

        material = "LARGE TEXTURE MAPPING" {
            function = "large_texture"
            face_side = "front" / "back" / "both"
            large_texture_map_path = "anysize_8/24bit.pcx"  # 8/15/16
        }

        material = "TILED Z-BUFFER LARGE TEXTURE MAPPING" {
            function = "tiled_zbuf_large_texture"
            face_side = "front" / "back" / "both"
            large_texture_map_path = "anypow2size_8/24bit.pcx"
        }

        material = "PERSPECTIVE TEXTURE MAPPING" {
            function = "persp_texture"
            face_side = "front" / "back" / "both"
            masking = "on" / "off"                          # optional
            texture_map_path = "256x256_8/24bit.pcx"        # 8/15/16
        }

        material = "Z-BUFFER PERSPECTIVE TEXTURE MAPPING" {
            function = "zbuf_persp_texture"
            face_side = "front" / "back" / "both"
            masking = "on" / "off"                          # optional
            texture_map_path = "256x256_8/24bit.pcx"        
        }

        material = "TILED Z-BUFFER PERSPECTIVE LARGE TEXTURE MAPPING" {
            function = "tiled_zbuf_persp_large_texture"
            face_side = "front" / "back" / "both"
            large_texture_map_path = "anypow2size_8/24bit.pcx"
        }

        material = "Z-BUFFER PERSPECTIVE TRANSPARENT TEXTURE MAPPING" {
            function = "zbuf_persp_transp_texture"
            face_side = "front" / "back" / "both"
            texture_map_path = "256x256_8/24bit.pcx"        
        }

        material = "PERSPECTIVE LARGE TEXTURE MAPPING" {
            function = "persp_large_texture"
            face_side = "front" / "back" / "both"
            masking = "on" / "off"                          # optional
            large_texture_map_path = "anysize_8/24bit.pcx"  # 8/15/16    
        }

        material = "LARGE TRANSPARENT TEXTURE MAPPING" {
            function = "large_transp_texture"
            face_side = "front" / "back" / "both"
            large_texture_map_path = "anysize_8/24bit.pcx"       
        }

        material = "PERSPECTIVE LARGE TRANSPARENT TEXTURE MAPPING" {
            function = "persp_large_transp_texture"
            face_side = "front" / "back" / "both"
            masking = "on" / "off"                          # optional
            large_texture_map_path = "anysize_8/24bit.pcx"
        }

        material = "TRANSPARENT TEXTURE MAPPING" {
            function = "transp_texture"
            face_side = "front" / "back" / "both"
            texture_map_path = "256x256_8/24bit.pcx"        # 8/15/16          
            transparent_64k_path = "64kbyte.tra"            # 8
        }

        material = "PERSPECTIVE TRANSPARENT TEXTURE MAPPING" {
            function = "persp_transp_texture"
            face_side = "front" / "back" / "both"
            texture_map_path = "256x256_8/24bit.pcx"        # 8/15/16
            transparent_64k_path = "64kbyte.tra"            # 8
            transparency = [0.0 ... 1.0]                    # 15/16 
        }

        material = "FLAT SHADED TEXTURE MAPPING" {
            function = "flat_texture"
            face_side = "front" / "back" / "both"
            shades = [0 ... 256]
            ambient = [0.0 ... 1.0]
            texture_map_path = "256x256_8bit.pcx"
            lite_table_path  = "texture.lit"
        }
                
        material = "GOURAUD SHADED TEXTURE MAPPING" {
            function = "gouraud_texture"
            shades = [0 ... 256]
            ambient = [0.0 ... 1.0]
            texture_map_path = "256x256_8bit.pcx"
            lite_table_path  = "texture.lit"
        }
                
        material = "PHONG SHADED TEXTURE MAPPING" {
            function = "phong_texture"
            face_side = "front" / "back" / "both"
            shades = [0 ... 256]
            texture_map_path = "256x256_8bit.pcx"
            lite_table_path  = "texture.lit"                # 8
            phong_map_path   = "256x256_8bit.pcx"
            ambient = [0.0 ... 1.0]
            diffuse = [0.0 ... 1.0]
            specular = [0.0 ... 1.0]
            exponent = [0.0 ... 30.0]
            dark_rgb = " R G B "  [0.0 ... 1.0] tweak!      # 15/16
            bright_rgb = " R G B "  [0.0 ... 1.0] tweak!    # 15/16
            dark_pos = [0.0 ... 1.0] tweak!                 # 15/16
            color_pos = [0.0 ... 1.0] tweak!                # 15/16
            bright_pos = [0.0 ... 1.0] tweak!               # 15/16
        }

        material = "Z-BUFFER PHONG SHADED TEXTURE MAPPING" {
            function = "zbuf_phong_texture"
            face_side = "front" / "back" / "both"
            shades = [0 ... 256]
            texture_map_path = "256x256_8bit.pcx"
            phong_map_path   = "256x256_8bit.pcx"
            ambient = [0.0 ... 1.0]
            diffuse = [0.0 ... 1.0]
            specular = [0.0 ... 1.0]
            exponent = [0.0 ... 30.0]
            dark_rgb = " R G B "  [0.0 ... 1.0] tweak!      # 15/16
            bright_rgb = " R G B "  [0.0 ... 1.0] tweak!    # 15/16
            dark_pos = [0.0 ... 1.0] tweak!                 # 15/16
            color_pos = [0.0 ... 1.0] tweak!                # 15/16
            bright_pos = [0.0 ... 1.0] tweak!               # 15/16
        }

        material = "ENVIRONMENT BUMP MAPPING" {
            function = "environment_bump"
            face_side = "front" / "back" / "both"
            environment_map_path = "256x256_8/24bit.pcx"    # 8/15/16
            bump_map_path = "256x256_8bit.pcx"
        }
                
        material = "PHONG TEXTURE BUMP MAPPING" {
            function = "phong_texture_bump"
            face_side = "front" / "back" / "both"
            shades = [0 ... 256]
            texture_map_path = "256x256_8bit.pcx"           
            bump_map_path = "256x256_8bit.pcx"
            lite_table_path  = "texture.lit"                # 8
            phong_map_path   = "256x256_8bit.pcx"
            ambient = [0.0 ... 1.0]
            diffuse = [0.0 ... 1.0]
            specular = [0.0 ... 1.0]
            exponent = [0.0 ... 30.0]
            dark_rgb = " R G B "  [0.0 ... 1.0] tweak!      # 15/16
            bright_rgb = " R G B "  [0.0 ... 1.0] tweak!    # 15/16
            dark_pos = [0.0 ... 1.0] tweak!                 # 15/16
            color_pos = [0.0 ... 1.0] tweak!                # 15/16
            bright_pos = [0.0 ... 1.0] tweak!               # 15/16
        }
        
        material = "LAST FRAME TEXTURE MAPPING" {
            function = "last_frame" 
            face_side = "front" / "back" / "both"
        }
        
        material = "PERSPECTIVE LAST FRAME TEXTURE MAPPING" {
            function = "persp_last_frame" 
            masking = "on" / "off"                          # optional
            face_side = "front" / "back" / "both"
        }

        material = "TRANSPARENT LAST FRAME TEXTURE MAPPING" {
            function = "transp_last_frame" 
            face_side = "front" / "back" / "both"
        }

        material = "PERSPECTIVE TRANSPARENT LAST FRAME TEXTURE MAPPING" {
            function = "persp_transp_last_frame" 
            face_side = "front" / "back" / "both"
            masking = "on" / "off"                          # optional
        }

        material = "ENVIRONMENT LAST FRAME MAPPING" {
            function = "environment_last_frame" 
            face_side = "front" / "back" / "both"
        }

        material = "ENVIRONMENT TRANSPARENT LAST FRAME MAPPING" {
            function = "environment_transp_last_frame" 
            face_side = "front" / "back" / "both"
        }

        material = "INTERNAL TEXTURE MAPPING" {
            function = "internal_texture"
            face_side = "front" / "back" / "both"
            texture_map_number = [0 ... 255]
        }
        
        material = "PERSPECTIVE INTERNAL TEXTURE MAPPING" {
            function = "persp_internal_texture"
            face_side = "front" / "back" / "both"
            masking = "on" / "off"                          # optional
            texture_map_number = [0 ... 255]
        }

        material = "TRANSPARENT INTERNAL TEXTURE MAPPING" {
            function = "transp_internal_texture"
            face_side = "front" / "back" / "both"
            texture_map_number = [0 ... 255]
        }

        material = "PERSPECTIVE TRANSPARENT INTERNAL TEXTURE MAPPING" {
            function = "persp_transp_internal_texture"
            face_side = "front" / "back" / "both"
            masking = "on" / "off"                          # optional
            texture_map_number = [0 ... 255]
        }

        material = "ENVIRONMENT INTERNAL TEXTURE MAPPING" {
            function = "environment_internal_texture"
            face_side = "front" / "back" / "both"
            texture_map_number = [0 ... 255]
        }

        material = "ENVIRONMENT TRANSPARENT INTERNAL TEXTURE MAPPING" {
            function = "environment_transp_internal_texture"
            face_side = "front" / "back" / "both"
            texture_map_number = [0 ... 255]
        }

        material = "FLARE" {
            function = "flare"
            large_texture_map_path = "anysize_8/24bit.pcx"  # 8/15/16
            mask_index = [0 ... 255]
            transparent_64k_path = "64kbyte.tra"            # 8
            transparent_mode = "mix" / "add"                # 15/16
        }



Pre processing (technical stuff)
--------------------------------

  The player can call a set of external functions before drawing the objects
  to the virtual buffer. A pointer to the current virtual buffer and the width
  and height is passed to the external function. The external function
  prototype should look like this example:
  
      void FillBlurred(void * buffer, int width, int height);

  To make this an preprocessing function, do the following after InitAnim has
  beed called from the script:
  
      #include "anim.h"
  
      InsertPreDrawFunc(number, &FillBlurred);

  where number is the function number. There can be a maximum of 16 functions
  installed and they will be called by DoAnim starting from 0,1,2,3, ...

  When DoAnim is called, the FillBlurred() function will be called before
  drawing the objects to the virtual buffer for each frame. Note that you can
  turn off the background image or backround color by removing
  'BackgroundImage=' and 'BackgroundColor=' in the .INI file.
  
  Note! You must setup the preprocessing function after InitAnim has been
  called as the pointer is reset by InitAnim.
  
  You can deactivate a given preprocessing function by calling
  RemovePreDrawFunc(number); or from the script:  
  
      xxx xxx  RemovePreDraw  number


  
Post processing
---------------

  To setup an external postprocessing function that is called after the
  objects has been plotted to the virual buffer do the following:
  
      #include "anim.h"
  
      InsertPreDrawFunc(number, &FillBlurred);
  
  Note! You must setup the postprocessing function after InitAnim has been
  called as the pointer is reset by InitAnim.
  
  Deactivate the function with RemovePostDrawFunc(number); or from the
  script:
 
      xxx xxx  RemovePostDraw  number
  


General 2D effect mapping (internal_texture)
--------------------------------------------

  One use of the pre processing function is the internal_texture mapping
  function that can map any texture map onto an object, e.g. a 2D effect.

  First define a material in the .MAT file and give it an identifying
  number that will be used for the 2D effect also.

    material = "XOR EFFECT"
    {
        function = "internal_texture"
        texture_map_number = 0
    }

  The 2D effect should install it's texture map with the function

    void InsertInternalMap(int number, void * map, int width, int height);

  where:  number  - Same identifying number as in the material definition.
                    This parameter should be passed from the script.
          map     - Is the pointer to the 2D effect map. The map need not
                    be aligned.
          width   - Width of the map.
          height  - Height of the map.

  The 2D effect can then install a Pre processing function that will
  be called for each new frame by DoAnim and update the 2D effect map.

  Note that both the map and the pre processing function must be installed
  after InitAnim has been called.



Animation preview utility  ANIM.EXE
-----------------------------------

  When creating an animation in 3D Studio, ANIM.EXE is useful for checking
  the animation without the need to involve the Demo System. ANIM.EXE will
  syncronize the animation to screen the same way as the Demo System will.
  
  You can make ANIM.EXE an external process in 3D Studio or even better, make
  a .BAT file as an extenal process that in turn call ANIM.EXE with the
  correct parameters.
  
  Syntax for ANIM.EXE is:
  
   ANIM.EXE width height bitpp inifile 3dsfile startkey endkey tpk camera pal

     width    - width of screen
     height   - height of screen
     bitpp    - bits per pixel  (8, 15 or 16)
     inifile  - path to .INI file
     3dsfile  - path to .3DS file. This will override the path in the .INI
                file. Put a '-' character to use the path in the .INI file.
     startkey - start animation at this key (float value)
     endkey   - loop animation at this key  (float value)
     tpk      - seconds per key (float value)
     camera   - camera name
     pal      - path to .PAL file
  
  
  The .BAT file (DOANIM.BAT) could look like this:
  
      @echo off
      c:
      cd \anim
      ANIM.EXE 320 200 8 test.ini 3ds/test.3ds 0.0 50.0 0.4 Camera01 txt.pal
      pause
  
  
  To setup 3D Studio, add the following lines in the 3DS.SET file:
  
  USER-PROG5 =  "C:\ANIM\DOANIM.BAT","DoAnim"
  USER-PROG6 =  "C:\DOS\EDIT.EXE C:\ANIM\DOANIM.BAT","Edit" 
  
  You need to copy COMMAND.COM to the 3DS directory for .BAT files to work.



Translucent lookup table utility MKTRANS.EXE
--------------------------------------------

    This utility calculates two types of lookup tables for use with
    semitransparent shadings and motion blurr. You can specify the amount of
    translucency (0...1) on the command line. A small value will make the
    shading more transparent. A small value will also give longer motion
    blurr, if the table is used for motion blurr.

    256 byte lookup table
    
        This type is for single color transparent shadings as used for the
        typical spotlight effect (light pillars).

    64k byte lookup table

        This type is for transparent texture mapping and such. The same table
        is also used for motion blurr.

    Note that both of these tables should be calculated for a specific
    palette, the active palette.

    Uage:

        MKTRANS.EXE [params...] infile.{pcx|pal} outfile.tra

    Parameters:

        -t val    Tranclucency amount 0...1  (default 0.50)
        -c col    Make tranclucency table for color 'col' only. Default is to
                  create a 64k byte table for all colors
        -a        Additive colors (flare objects)
        -e ext    Force file extension of input file. PCX or PAL
        -y        Don't ask for file overwrite
        -v        Verbose mode on

    So for example to create a 256 byte table for color number 7 in the
    palette "texture.pal", do the following:

        MKTRANS.EXE -v -c 7 texture.pal texture.tra 

<EOF>
