Bump mapping

Source code

//========================================================================
//
// Bump Mapping Enhanced using spot light or infinite light.
// This version is enhanced, some options added.
// QUAGLIOZZI ERIC - © 2007   All rights reserved
//
//========================================================================

/*
   Usable for low res (72 dpi) and double res (144 dpi) bitmap using 8 and 16 bits 
   Colors.
            ---------------------------------------------------------
            | Do not use with other resolutions, may system crash ! |
            ---------------------------------------------------------

  La technique de Bump Mapping utilisée nécessite:
  - Un tableau "Enviroment Map" de 32*32 octets qui permet de
    retrouver la norme du vecteur normal à la surface du bitmap
    de façon pré-calculée.
  - Un bitmap sur lequel appliquer le Bump Mapping
  - Un bitmap de texture, en niveaux de gris, représentant 
    l'altitude de chaque pixel.
    
  The technique used for my Bump Mapping function uses:
  - A table “Enviroment Map”  (32*32 bytes) which allows to retrieve
    the normal vector of each pixel on the surface of the bitmap
    (precalculated values). This is a kind of lookup table.
  - A bitmap on which is applied Bump Mapping
  - A texture bitmap , a grayscale image, representing the altitude
    of each pixels (heightmap).    
*/



//------------- Macros and constants ---------------------

#if defined(_MSC_VER)     // If compiling with VC++...

    #define private        static __inline
    #define longint        __int64
    
#elif defined(__GNUC__)  // If compiling with GCC...

    #define private        static inline
    #define longint        long long int
    
#else

    #error "Unknown Compiler!"
    
#endif


//--------------------- Types ----------------------------


typedef unsigned long Call68KFuncType(const void * emulStateP,
                                 unsigned long trapOrFunction,
                                 const void * argsOnStackP,
                                 unsigned long argsSizeAndwantA0);

typedef unsigned long NativeFuncType(const void * emulStateP,
                                     void * userData68KP,
                                     Call68KFuncType * call68KFuncP);

typedef struct {
    char hb_object_header[14];
    short swTransparent;
    unsigned char    * pData;
    short w;
    short wl;
    short h;
    short bitdepth;
    unsigned char swTranspColorH;
    unsigned char swTranspColorL;
    unsigned char swTranspIndex;
} ImageData;


typedef struct {
    unsigned char RGB4[1024];
} PalmOSPalette;    

typedef struct {
    unsigned char Index[216];
} PalmOSInverse;    

typedef struct {
    unsigned char NORM[1024];
} EnvMap;    

typedef struct {
    char hb_object_header[14];
    short         DebugShort;
    long          DebugLong;
    PalmOSPalette * pPalmOSPalette;   // palm os palette
    PalmOSInverse * pPalmOSInverse;
    EnvMap        * pEnvMap;          // environment map
    ImageData     * pSourceImage;     // source bitmap
    ImageData     * pDestImage;       // destination bitmap
    ImageData     * pTextureImage;    // heightmap bitmap
    short         X0, Y0;             // point of light in image source
    short         Edge;               // 0 <=> 2 pixels, 1 <=> 3 pixels
    short         LightKind;          // 0 <=> spot, 1 <=> infinite
    short         LAngleX, LAngleY;   // light angle if infinite
    short         DrawBorders;        // 1 <=> draw pixels on borders, 0 = no
    short         LightFactor;        // Extra light factor (16 bit fixed point value, 9:7)
    short         AmbiantLight;       // Extra Ambiant light (16 bit fixed point value, 9:7)
    short         UseLight;           // Use light flag 
    short         LimitLight;         // Limit light flag 
    unsigned char BkColorH;           //back color if no borders
    unsigned char BkColorL;
    unsigned char BkColorIndex;
} BumpMapEffect;    


typedef struct _ParamsType
  {
    BumpMapEffect       * pBump;
  } ParamsType;


//-------------- Advanced Bump Mapping Function ----------


unsigned long BumpMapSpotLight(const void * emulStateP, void * userData68KP,
                               Call68KFuncType * call68KFuncP)
{
  ParamsType    * p;                  //pointer to params structure
  BumpMapEffect * pBump;              //pointer for Bump effect structure
  PalmOSPalette * Pal;
  PalmOSInverse * InvPal;
  EnvMap        * pEnvMap;
  unsigned char * Pdest;
  unsigned char * Psource;
  unsigned char * Ptexture;
  unsigned int    w, h, wlimit;
  unsigned int    i, j, ir, id;
  unsigned int    bitdepth;
  unsigned int    Rs,Gs,Bs;
  unsigned long   Rd,Gd,Bd;
  unsigned int    RGB;
  int             Normalx, Normaly;
  int             x0, y0;             // light point center
  int             lx, ly, cl;
  int             clden, Oneden;
  unsigned int    Edge, EdgeW;
  unsigned int    LightKind;

  // >>>>  Do local copy of params

  p=(ParamsType *) userData68KP;
  pBump = p->pBump;
  Pal = pBump->pPalmOSPalette;
  InvPal = pBump->pPalmOSInverse;
  pEnvMap = pBump->pEnvMap;
  //we assume all bimap having same size, bitdepth and resolution !!!
  w = pBump->pSourceImage->w;
  h = pBump->pSourceImage->h;
  wlimit = pBump->pSourceImage->wl;
  bitdepth = pBump->pSourceImage->bitdepth;
  x0 = pBump->X0;
  y0 = pBump->Y0;
  Edge = (pBump->Edge)<< (bitdepth-1);
  if(Edge>0) EdgeW=wlimit; else EdgeW=0;
  LightKind = pBump->LightKind;

  //Bump Mapping
  Psource = pBump->pSourceImage->pData + wlimit;
  Pdest = pBump->pDestImage->pData + wlimit;
  Ptexture = pBump->pTextureImage->pData + wlimit;
  
  if(pBump->UseLight)
  { clden = 12; Oneden = 1<<clden; }
  else
  { clden = 5; }
   
  for (j=1;j<h-1;j++)  
  {
     if(bitdepth==1) ir = 1; else ir =2;
     for (i=1; i<w-1; i++)
     {
       // Get R, G and B of source pixel
       if (bitdepth==1)
       {
         // Get R & G & B of source in 8 bits colors
         id = Psource[ir]<<2;
         Rs = Pal->RGB4[id+1];
         Gs = Pal->RGB4[id+2];
         Bs = Pal->RGB4[id+3];
       }
       else
       {
         // Get R & G & B of source in 16 bits colors
         RGB = (Psource[ir]<<8)|Psource[ir+1];
         Rs=(RGB >> 11) & 0x001F;
         Gs=(RGB >> 5) & 0x003F;
         Bs= RGB & 0x001F;
       }
       // Compute normal vector of surface with texture data
       // Blue component = height factor
       if (bitdepth==1)
       {
         // Get B of source in 8 bits colors
         id = Ptexture[ir+Edge]<<2;
         Normalx=Pal->RGB4[id+3]>>3;
         id = Ptexture[ir-1]<<2;
         Normalx-=Pal->RGB4[id+3]>>3;
         id = Ptexture[ir+EdgeW]<<2;
         Normaly=Pal->RGB4[id+3]>>3;
         id = Ptexture[ir-wlimit]<<2;
         Normaly-=Pal->RGB4[id+3]>>3;
       }
       else
       {
         // Get B of source in 16 bits colors
         RGB = Ptexture[ir+Edge+1];
         Normalx= (RGB & 0x001F);
         RGB = Ptexture[ir-2+1];
         Normalx-= (RGB & 0x001F);
         RGB = Ptexture[ir+EdgeW+1];
         Normaly= (RGB & 0x001F);
         RGB = Ptexture[ir-wlimit+1];
         Normaly-= (RGB & 0x001F);
       }
       if(LightKind>0)
       {
        lx=i-x0;
        ly=j-y0;
       }
       else  
       { 
         lx = pBump->LAngleX;
         ly = pBump->LAngleY; 
       }
       if (lx<0) lx = -( (-lx)>>3); 
       else lx = lx>>3; 
       if (ly<0) ly = - ( (-ly)>>3); 
       else ly = ly>>3; 
       Normalx-=lx;
       Normaly-=ly;
       Normalx+=16;
       Normaly+=16;
       if (Normalx<0 || Normalx>31) Normalx=0;
       if (Normaly<0 || Normaly>31) Normaly=0;
       cl = pEnvMap->NORM[(Normaly<<5)+Normalx];
       if(pBump->UseLight) 
        {
         cl = cl*pBump->LightFactor + (pBump->AmbiantLight<<5); 
         if((pBump->LimitLight)&&(cl>Oneden)) cl=Oneden;
        }

       //pixel color source * light coefficient / 32
       Rd=(Rs*cl)>>clden;
       Gd=(Gs*cl)>>clden;
       Bd=(Bs*cl)>>clden;
       Rs=Rd;
       Gs=Gd;
       Bs=Bd;
       if (bitdepth==1)
       {
         //retrieve the nearest indexed color      
         if(Rs>255) Rs=255;
         if(Gs>255) Gs=255;
         if(Bs>255) Bs=255;
         Rs=((Rs+26)*5)>>8;  // (x*5)>>8 is about x/51
         Gs=((Gs+26)*5)>>8;
         Bs=((Bs+26)*5)>>8;
         Pdest[ir]= InvPal->Index[Rs*36+Gs*6+Bs];  // copy new color
       }
       else
       {
         //new color
         if (Rs > 0x001F) Rs=0x001F;
         if (Gs > 0x003F) Gs=0x003F;
         if (Bs > 0x001F) Bs=0x001F;
         Pdest[ir]  = (Rs<<3)|(Gs>>3);
         Pdest[ir+1]= (Gs<<5)|(Bs);
       }
       ir += bitdepth;
     }
     Psource+=wlimit;
     Pdest+=wlimit;
     Ptexture+=wlimit;
  }
  //draw pixels on borders, according to option
  //these pixels are same as source bitmap, without
  //bump mapping effect but they are enlightned
 
  if(pBump->UseLight) 
  {
   Oneden = 1<<7; clden= 7;
   cl = pBump->LightFactor + pBump->AmbiantLight; 
   if((pBump->LimitLight)&&(cl>Oneden)) cl=Oneden;
  }  

  //top and bottom borders
  Psource = pBump->pSourceImage->pData;
  Pdest = pBump->pDestImage->pData;
  
  for (j=0; j<2; j++)
  {
   for (i=0; i<w; i++) 
   { if(bitdepth==1)
     {
       if(pBump->DrawBorders !=0)
       {
        if(pBump->UseLight)
        {
          //get source color
          id = Psource[i]<<2;
          Rs = Pal->RGB4[id+1];
          Gs = Pal->RGB4[id+2];
          Bs = Pal->RGB4[id+3];
          //apply light 
          Rd=(Rs*cl)>>clden; Rs=Rd;
          Gd=(Gs*cl)>>clden; Gs=Gd;
          Bd=(Bs*cl)>>clden; Bs=Bd;
          //retrieve new color index from lookup table       
          if(Rs>255) Rs=255;
          if(Gs>255) Gs=255;
          if(Bs>255) Bs=255;
          Rs=((Rs+26)*5)>>8;  // (x*5)>>8 is about x/51
          Gs=((Gs+26)*5)>>8;
          Bs=((Bs+26)*5)>>8;
          Pdest[i]= InvPal->Index[Rs*36+Gs*6+Bs];  // copy new color
        }  
        else Pdest[i]=Psource[i];
       } 
       else 
         Pdest[i]=pBump->BkColorIndex;
     }    
     else
     {
       if(pBump->DrawBorders !=0)
       {
        if(pBump->UseLight)
        {
          // Get R & G & B of source in 16 bits colors
          RGB = (Psource[i<<1]<<8)|Psource[(i<<1)+1];
          Rs=(RGB >> 11) & 0x001F;
          Gs=(RGB >> 5) & 0x003F;
          Bs= RGB & 0x001F; 
          //apply light 
          Rd=(Rs*cl)>>clden; Rs=Rd;
          Gd=(Gs*cl)>>clden; Gs=Gd;
          Bd=(Bs*cl)>>clden; Bs=Bd;
          //new couleur
          if (Rs > 0x001F) Rs=0x001F;
          if (Gs > 0x003F) Gs=0x003F;
          if (Bs > 0x001F) Bs=0x001F;
          Pdest[i<<1]  = (Rs<<3)|(Gs>>3);
          Pdest[(i<<1)+1]= (Gs<<5)|(Bs);          
        }
        else
        {
          Pdest[i<<1]=Psource[i<<1];
          Pdest[(i<<1)+1]=Psource[(i<<1)+1]; 
        }
       } 
       else
       { Pdest[i<<1]=pBump->BkColorH;
         Pdest[(i<<1)+1]=pBump->BkColorH; }
     }
   }
   Psource += (long)wlimit*(h-1);
   Pdest += (long)wlimit*(h-1);
  }  

  //left and right borders
  for (i=0; i<2; i++)
  {
   if(i==0)
   { Psource = pBump->pSourceImage->pData;
     Pdest = pBump->pDestImage->pData; 
   }
   else
   { Psource = pBump->pSourceImage->pData+((w-1)<<(bitdepth-1));
     Pdest = pBump->pDestImage->pData+((w-1)<<(bitdepth-1)); 
   }
   for (j=0; j<h; j++) 
   { if(bitdepth==1)
    {
       if(pBump->DrawBorders !=0)
       {
        if(pBump->UseLight)
        {
          //get source color
          id = Psource[0]<<2;
          Rs = Pal->RGB4[id+1];
          Gs = Pal->RGB4[id+2];
          Bs = Pal->RGB4[id+3];
          //apply light 
          Rd=(Rs*cl)>>clden; Rs=Rd;
          Gd=(Gs*cl)>>clden; Gs=Gd;
          Bd=(Bs*cl)>>clden; Bs=Bd;
          //retrieve new color index from lookup table
          if(Rs>255) Rs=255;
          if(Gs>255) Gs=255;
          if(Bs>255) Bs=255;
          Rs=((Rs+26)*5)>>8;  // (x*5)>>8 is about x/51
          Gs=((Gs+26)*5)>>8;
          Bs=((Bs+26)*5)>>8;
          Pdest[0]= InvPal->Index[Rs*36+Gs*6+Bs];  // copy new color
        }
        else
        {
          Pdest[0]=Psource[0];
        }
       } 
       else  
       {
         Pdest[0]=pBump->BkColorIndex;
       } 
    }    
    else
    {
       if(pBump->DrawBorders !=0)
       {
        if(pBump->UseLight)
        {
          // Get R & G & B of source in 16 bits colors
          RGB = (Psource[0]<<8)|Psource[1];
          Rs=(RGB >> 11) & 0x001F;
          Gs=(RGB >> 5) & 0x003F;
          Bs= RGB & 0x001F; 
          //apply light 
          Rd=(Rs*cl)>>clden; Rs=Rd;
          Gd=(Gs*cl)>>clden; Gs=Gd;
          Bd=(Bs*cl)>>clden; Bs=Bd;
          //new couleur
          if (Rs > 0x001F) Rs=0x001F;
          if (Gs > 0x003F) Gs=0x003F;
          if (Bs > 0x001F) Bs=0x001F;
          Pdest[0]  = (Rs<<3)|(Gs>>3);
          Pdest[1]= (Gs<<5)|(Bs);         
        }
        else
        {
         Pdest[0]=Psource[0];
         Pdest[1]=Psource[1]; 
        } 
      }
      else
      {
        Pdest[0]=pBump->BkColorH;
        Pdest[1]=pBump->BkColorL;
      }
    }
    Psource += wlimit;
    Pdest += wlimit;
   }
  }
  return 0;
}

//========================================================================