Fire effect

Source code

/*==================================================================

  Perform Fire effect - (c) QUAGLIOZZI ERIC - 2005

  Version 2.1  - Last modification January 2007
  ------------------------------------------------------------------

  In this version, Rendering surface can be a shared surface with
  dimensions different from those of the FireSurface.

  The render can be clipped or stretched using alphablending or not.

  It is possible to define a range of color index as transparency colors
  in locale palette for creating overlayed drawing with gradient.

  For alpha blending: Alpha=0 <=> no alpha blending (fast code), alpha 
  transparency otherwise (max=256).

  CopyMode:
  ---------

  0 = Simple color mapping of Firebitmap
  1 = Fire effect + color mapping of Firebitmap

  Fire surface
  ------------

  This surface use byte value, so, a 256 colors bitmap (bitdpeth=8). 
  Value=0 <=> to dead fire, Value=255 <=> to active fire.

  Rendering surface
  -----------------

  Can be any bitmap with Low/double density and 256/true colors.

  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 ! |
      ---------------------------------------------------------
            
  ==============================================================*/


//--------------------------- 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 w;
    short wl;
    short h;
    unsigned char    * pData;
    short Wind;
    unsigned short Stretched;
    unsigned short Alpha;
    unsigned short Transparent;
    unsigned short TranspIndex;
    unsigned short TranspBand;
    unsigned short CopyMode;
} FireSurfaceHB;    


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


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

typedef struct {
    char RGB3[768];
} LocalPalette;    


typedef struct {
    char hb_object_header[14];
    short         Padding;           // 32 bit alignement
    PalmOSPalette * pPalmOSPalette;
    PalmOSInverse * pPalmOSInverse;
    LocalPalette  * pLocalPalette;
    FireSurfaceHB * pFireSurface;
    unsigned char    * pDest;     // bitmap rendering destination pointer
    long          Rnd;            // Randomized number
    long          RatioInvX;      // 1/RatioX , format Fixed point 20:12
    long          RatioInvY;      // 1/RatioY , format Fixed point 20:12
    short         FClipL;         // Zone, Clipping Fire Surface
    short         FClipT;         // Zone, Clipping Fire Surface
    short         FClipR;         // Zone, Clipping Fire Surface
    short         FClipB;         // Zone, Clipping Fire Surface
    long          FVoffset;       // Vertical Offset, Fire surface               
    short         BClipL;         // Zone, Clipping Rendering Surface
    short         BClipT;         // Zone, Clipping Rendering Surface
    short         BClipR;         // Zone, Clipping Rendering Surface
    short         BClipB;         // Zone, Clipping Rendering Surface
    short         wl;             // limit off bitmap width
    short         w;              // bitmap width
    short         h;              // bitmap height
    short         bd;             // Bitdpeth (1=8bits, 2=16bits)
    long          BVoffset;       // Vertical Offset, Rendering Surface                
} FxFireHB;    




typedef struct _ParamsType
  {
    FxFireHB        * pFxFireObject;  // HB++ object pointer
    }
    ParamsType;


#define FixedPoint    12      // We use 20:12 fixed point operations


//--------------------------- Fire Effect Function ---------------------


unsigned long FireEffect(const void * emulStateP,
                         void * userData68KP,
                         Call68KFuncType * call68KFuncP)
{
  ParamsType    * p;             //pointer to params structure
  FxFireHB      * Fx;          
  FireSurfaceHB * Fs;          
  PalmOSPalette * PPal;
  PalmOSInverse * InvPal;
  LocalPalette  * LPal;

  long            seed;          //Randomized number  
  unsigned char * P1;            //Source Pixel line pointers
  unsigned char * P2;
  unsigned char * P3;
  unsigned char * Pdest;         //Destination Pixel line pointer
           long   i, j;          //Loops and index
           long   is, js;        //Loops and index
  unsigned short  id;
  unsigned long   R,G,B;         //Color management
  short           PalID;
  short           Dx, Fact;      //Only for Wave/Scramble effect
  short           WaveL;
  short           DresIndex;
  unsigned long   Rd,Gd,Bd;
  unsigned long   RGB, IDcol;



  // Do local copy of params

  p=(ParamsType *) userData68KP;
  Fx = p->pFxFireObject;
  Fs = Fx->pFireSurface;
  PPal  = Fx->pPalmOSPalette;
  LPal  = Fx->pLocalPalette;
  InvPal = Fx->pPalmOSInverse;
 
  // Perform initialization
  seed  = Fx->Rnd;
  Fact  = 0;
  WaveL = Fs->Wind;

  if (Fs->CopyMode)
  {
   //Fire effect on fire surface
  for (i=0; i<Fs->w; i++)
      {
         P1 = Fs->pData;
         P2 = P1+Fs->wl;
         P3 = P2+Fs->wl;
         for (j=1; j<Fs->h-2; j++)
         {
             if (i<5)
             {
                 P1[i]=0;
                 P2[i]=0;
                 P3[i]=0;
             }
             else
             {
             //random number
             seed = (0x015A4E35L * seed)+1;
             if (((seed >> 24) & 0xFF)>128) Dx=1; else Dx=-1;
             Fact = Fact + Dx;
             if ((Fact>WaveL)|(Fact<-WaveL)) Fact=0;
             Dx=Fact;
             PalID = (P3[Dx+i-1]+P3[Dx+i+1]+P3[Dx+i]+P1[Dx+i]) >> 2;
             //decrease intensity
             if (PalID>255) 
                { PalID=255; }
             else 
                { 
                   if (PalID<1) 
                    { PalID=0; }
                   else
                    { PalID-=1;}
                }
             //store new data in fire surface
             P2[i]=PalID;
             }

             //next lines
             P1 += Fs->wl;
             P2 += Fs->wl;
             P3 += Fs->wl;
         }
    }
    
  Fx->Rnd = seed;
  //Erase first line
  for (i=0; i<=Fs->w-1; i++) 
    { Fs->pData[i]=0;  }

  }

  //Copy fire surface to rendering surface

  if (!Fs->Stretched) {    P1 = Fs->pData+Fx->FVoffset;}

  Pdest = Fx->pDest + Fx->BVoffset;

  for (j=Fx->BClipT; j<=Fx->BClipB; j++)
   {

    if (Fs->Stretched)
        {  js=(long)(((longint)(j-Fx->BClipT) * (longint) Fx->RatioInvY)>>FixedPoint );
           js = Fx->FClipT + js;
           P1=Fs->pData+js*(long)(Fs->wl);    }
    else
        {  is = Fx->FClipL; }

    for (i=Fx->BClipL; i<=Fx->BClipR; i++)
      {

          if (Fs->Stretched)
            {
              is=(long)(((longint) (i-Fx->BClipL) * (longint) Fx->RatioInvX)>>FixedPoint );
              is = Fx->FClipL + is; 
            }
           
           //color index of current pixel  
           PalID=P1[is] & 0xFF;

           //if no transparency, new destination color. 
           if ( (!Fs->Transparent)||(PalID<Fs->TranspIndex)||(PalID>(Fs->TranspIndex+Fs->TranspBand))  )
           {
            //retreive RGB color according to local color palette

            id = (PalID<<1)+PalID;  //3*PalID otherwise
            R=(Fx->pLocalPalette->RGB3[id]) & 0xFF;
            G=(Fx->pLocalPalette->RGB3[id+1]) & 0xFF;
            B=(Fx->pLocalPalette->RGB3[id+2]) & 0xFF;


            //Render color taking into account the bitdepth and alpha
            if (Fx->bd==1)
            {
               //256 colors mode
               if (Fs->Alpha)
               {
                   Rd=R*(256-Fs->Alpha);
                   Gd=G*(256-Fs->Alpha);
                   Bd=B*(256-Fs->Alpha);
                    
                   id = (Pdest[i] & 0xFF)<<2;
                   R=PPal->RGB4[id+1] & 0xFF;
                   G=PPal->RGB4[id+2] & 0xFF;
                   B=PPal->RGB4[id+3] & 0xFF;
                   Rd+=R*Fs->Alpha;
                   Gd+=G*Fs->Alpha;
                   Bd+=B*Fs->Alpha;
                   
                   //final color 
                   
                   R=Rd>>8; if(R>255) R=255;
                   G=Gd>>8; if(G>255) G=255;
                   B=Bd>>8; if(B>255) B=255;
               }

               //retreive nearest indexed color     
               //(x*5)>>8 is about x/51
               R=(((R+26)<<2)+R+26)>>8;           
               G=(((G+26)<<2)+G+26)>>8;           
               B=(((B+26)<<2)+B+26)>>8;           
               //IDcol = R*36 + G*6 + B
               IDcol = (R<<5)+(R<<2)+(G<<2)+(G<<1)+B;
               Pdest[i]= (char)(Fx->pPalmOSInverse->Index[IDcol]);  // copy new color;
            }
            else
            {
                //true colors mode
                DresIndex = i<<1;
                if (Fs->Alpha)
                {
                    Rd=R*(256-Fs->Alpha);
                    Gd=G*(256-Fs->Alpha);
                    Bd=B*(256-Fs->Alpha);

                    RGB = ( ((long)(Pdest[DresIndex]) & 0xFF)<< 8) | (Pdest[DresIndex+1] & 0xFF);
                    R=(RGB >> 8) & 0x00F8;
                    G=(RGB >> 3) & 0x00FC;
                    B= (RGB << 3) & 0x00F8;

                    //destination color * (255-ALPHA)

                    Rd+=R*Fs->Alpha;
                    Gd+=G*Fs->Alpha;
                    Bd+=B*Fs->Alpha;
        
                    //final color(coef<=255, byte data)
       
                    R=Rd>>8; if(R>255) R=255;
                    G=Gd>>8; if(G>255) G=255;
                    B=Bd>>8; if(B>255) B=255;
         
        
                }

               Pdest[DresIndex]  = (char)((R & 0xF8)|((G>>5) & 0x07));
               Pdest[DresIndex+1]= (char)(((G<<3)&0xE0)|((B>>3)&0x1F));
            }

           }

           //next pixel
           is++;

      }

    //next line
    P1 += Fs->wl;
    Pdest += Fx->wl;
   }


  return 0;
}

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