text: //-----------------------------------------------------------------------------
  // Torque Game Engine
  // Copyright (C) GarageGames.com, Inc.
  //-----------------------------------------------------------------------------
  
  #ifndef _BLENDER_H_
  #define _BLENDER_H_
  
  #ifndef _PLATFORM_H_
  #include "platform/platform.h"
  #endif
  #ifndef _TERRDATA_H_
  #include "terrain/terrData.h"
  #endif
  #ifndef _TERRRENDER_H_
  #include "terrain/terrRender.h"
  #endif
  
  #define GRIDFLAGS(X,Y)   (TerrainRender::mCurrentBlock->findSquare( 0, Point2I( X, Y ) )->flags)
  #define MATERIALSTART       (GridSquare::MaterialStart)
  /**
     This MODULE contains class Blender. Blender has a set of textures and an ALPHA-VALUE MAP, and
     exposes   via the method Blender::blend(X, Y, LEVEL, LIGHT-MAP, DESTINATION-MIP-MAP) the facility
     to "blend" its textures into DESTINATION-MIP-MAP using X & Y as an offset into the ALPHA-VALUE
     MAP and the LIGHT-MAP.
  
     The LANDSCAPE of the MISSION is a single (mile square?) TILE repeated infinitely.
     The TILE is a SQUARES_PER_TILE_EDGE (currently 256) by SQUARES_PER_TILE_EDGE Row-Major
     array of SQUARES.
  
     A TEXEL in this context is a single element of a TEXTURE, an RGB triple or RGBA quad--what
     would be thought of as a PIXEL were it mapped one-to-one to the display device.
  
     A LUMEL is similarly the smallest unit of a LIGHT-MAP.  It consists of an RGB triple (there doesn't
     seem to be any special specular code, etc.) which is applied to the blended texel.
  
     And an ALPHEL is similarly the smallest unit of a TEXTURE-ALPHA-MAP. Each TEXEL of the blended
     (destination) texture is formed from the corresponding TEXELs of N source TEXTUREs.  The ALPHELs
     specify what part of the destination TEXEL coems from each source TEXEL.
  
     The Blender is created with a fixed NUMBER OF MIPMAP LEVELS, a fixed NUMBER OF SOURCE TEXTURES,
     and an ALPHA-VALUE MAP.  The ALPHA-VALUE MAP is passed by reference (I don't know if it
     can change interactively).  The maximum usable value for NUMBER OF MIPMAP LEVELS is
     MAX_MIPMAP_LEVELS (currently 4). I don't think anything bad happens if this is exceeded.
  
     Each SOURCE TEXTURE is then added to the Blender with addSourceTexture, by index number,
     specifying the MIP-MAP for the texture by value.
  
     A MIP-MAP is an array of NUMBER OF MIPMAP LEVELS square BIT-MAPs in progressively
     lower resolutions. The highest resolution BIT-MAP must be TEXELS_PER_SOURCE_EDGE (currently 256)
     TEXELS on each side. Each successive BIT-MAP in the MIP-MAP must be 1/2 the resolution of the
     preceding, or 1/4 the size.  Each BIT-MAP is in Row-Major 3*8-bit RGB format.
  
     Blender stores the value of the MIP-MAPs in an internal format, based on SQUARES. Each MIP-MAP
     is stored as NUMBER OF MIPMAP LEVELS consecutive levels of descending resolution. Each level
     of the MIP-MAP is stored as SQUARES_PER_MIPMAP (currently 64) consecutive SQUAREs in Row-Major
     form. Each Square is stored as consecutive 32-bit 0GBR TEXELs in Row-Major form (the 0 in the
     format means that those bits are waste). Please note that on LITTLE_ENDIAN platforms the
     32-bit 0BGR is identical in representation to 4*8-bit RGB0, however on BIG_ENDIAN platforms
     it is 4*8-bit 0BGR.
  
     The ALPHA-VALUE MAP consists of NUMBER OF SOURCE TEXTURES individual TEXTURE-ALPHA-MAPs.
     Individual TEXTURE-ALPHA-MAPs consist of a SQUARES_PER_TILE_EDGE by SQUARES_PER_TILE_EDGE
     Row-Major array of 8-bit alpha blending values.  The original code only used the high six bits
     of each 8-bit value, but I am using the whole thing.  I don't know if the lower two bits even
     have meaningful values, but since they are the low-order two bits I don't much care; the worst
     it can do is introduce a charming randomness. The ALPHELs are 8-bit fixed point, implicitly
     divided by 256. It is implied by the code that for each offset into the TEXTURE-ALPHA-MAPs,
     the sum of the ALPHELs at that offset across all of the TEXTURE-ALPHA-MAPs is less than 1.
     I don't know where this is enforced.
  
     Since the resolution of the ALPHA-MAP is one ALPHEL per SQUARE, the ALPHELs are interpolated
     across the SQUARE when the terrains are being blended.  Each ALPHEL is the ALPHA-VALUE of the
     lower-left corner of the corresponding square.  In order to compute the unlit blended texture
     of a SQUARE (each SQUARE is processed separately), for each SOURCE TEXTURE the ALPHELs at the
     four corners of   the SQUARE are taken and interpolated smoothly across the square.
  
    <b>How Blender::blend() does its thing:</b>
  
     Blend() blends an array of SQUAREs of the TILE and a LIGHT-MAP into an 8-level MIP-MAP of
     from 128x128 to 1x1 6-bit RGBA-5551 TEXELs per BIT-MAP.  The location in the TILE to blend
     from is specified by the X,Y co-ordinate of the lower-left corner and the length in SQUAREs
     of a side of the square to be blended.  The length of a side of the square to be blended in
     SQUAREs combined with the fixed 128x128 size of the highest resolution destination BIT-MAP
     implies a umber of TEXELs per SQUARE.
  
     Blend() blends the desired SQUAREs into the highest resolution texture of the MIP-MAP and
     generates the rest of the MIP-MAP from the first one (this seems like it should be an
     independent utility).
  
     Blend processes each SQUARE in turn, using the Terrain Grid to choose which SOURCE TEXTUREs
     apply to that square, and the ALPHA-MAPs for that SQUARE to determine the contribution
     of individual SOURCE TEXTURE's TEXELs.  This is a simple multiplication of TEXEL values
     by the interpolated ALPHELs.
  
     It then applies the light map by sub-dividing the SQUARE into LUMELS_PER_SQUARE sub-squares and
     interpolating LUMEL values across the sub-square in a manner exactly similar to the ALPHA-MAP. Each
     LUMEL is an RGB triple, and each component of the LUMEL is multipled by the corresponding component
     of the unlit texture to create the lit texture.
  
     @note Warning, this code is ugly, even though it is pretty well documented. Flee!
   */
  class Blender
  {
      /// Pointer to big buffer of source textures and mipmaps.
      U32 *bmp_alloc_ptr;
  
      /// One square buffer used for blending...
      U32 *blendbuffer;
  
      /// List of pointers into bmp buffer.  Grouped by mip level,
      ///  so first X pointers are textures 0-X, mip 0.
      U32 **bmpdata;
  
      /// List of pointers to alpha data for the bmp types.
      U8 **alpha_data;
  
      /// Number of bmp types
      int num_src_bmps;
  
      /// Mip levels (including top detail) for each bmp type
      int num_mip_levels;
      
      /// C version of the blender
      inline void blend_c( int x, int y, int level, const U16 *lightmap, U16 **destmips );
      
     #if defined(__VEC__)
     /// Altivec version of the blender
     inline void blend_vec( int x, int y, int level, const U16 *lightmap, U16 **destmips );
     #endif
  
  public:
      /// Constructor
      ///
      /// @param  num_bmp_types   Number of textures we are blending.
      /// @param  mips_per_bmp    This should include top level (always >= 1).
      /// @param  alphadata       This is an 8 bit 256x256 bitmap.
      Blender( int num_bmp_types, int mips_per_bmp, U8 **alphadata );
      ~Blender();
  
      /// Blends into 5551 format.
      ///
      /// X and Y are in blocks (same resolution as alpha table, i.e. at
      /// high detail, there are 4x4 blocks covered by the 128x128 destination bmp.)
      ///
      /// @param  x           Position in blocks.
      /// @param  y           Position in blocks.
      /// @param  lightmap    A 16 bit 512x512 bitmap.
      /// @param  level       What mipmapping level to blend to?
      /// @param  destmips    This is an array of pointers to the bitmap and it's
      ///                     mips to be filled in by this function
      void blend( int x, int y, int level, const U16 *lightmap, U16 **destmips );
  
      /// Add a texture to use in blending.
      ///
      /// Call this once per bmp type.  It copies the bmp into it's own format,
      ///  so you can then delete your versions of the bmp and mips.
      ///
      /// @param  bmp_type    Type of the bitmap.
      /// @param  bmps        This is an array of pointers to the bitmap and its mipmaps,
      ///                     highest detail first.  Should be in 24bit format.
      void addSourceTexture( int bmp_type, const U8 **bmps );
      
     #if defined(__VEC__)
     /// flag to determine which version of the blender is used.
     static bool smUseVecBlender;
     #endif
  };
  
  #endif
  