Resonance effect

Source code

/* =======================================================
 Resonance Effect - QUAGLIOZZI ERIC - 2006

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


#include "MathLibFixed.c"


//------------------------ 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);

//Structure of Image class (HB++ class)
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;

//Structure of Palm OS palette 
typedef struct {
    unsigned char RGB4[1024];
} PalmOSPalette;    

//Structure for Palm Os inverse operation
typedef struct {
    unsigned char Index[216];
} PalmOSInverse;    

//Structure of Resonance class (HB++ class)
typedef struct {
    char hb_object_header[14];
    short        DebugShort;
    long        DebugLong;
    PalmOSPalette * pPalmOSPalette;
    PalmOSInverse * pPalmOSInverse;
    ImageData     * swSourceImage;
    ImageData     * swDestImage;
    long          Intensity;
    long          Cx;
    long          Cy;
    short          Alpha;
    short          UseAlpha;
} ResonanceEffect;    

//main structure
typedef struct _ParamsType
  {
    ResonanceEffect          * pRes;
  } ParamsType;


//----------------- Resonance Function -------------------


unsigned long BumpMapSpotLight(const void * emulStateP, 
                               void * userData68KP,
                               Call68KFuncType * call68KFuncP)

{
  ParamsType     * p;                       //pointer: params structure
  ResonanceEffect  * pRes;                  //pointer: HB++ objet clsResonance
  ImageData      * lpImage;                 //pointer: Image structure
  unsigned char  * src;                     //pointer: source image pixels;
  unsigned char  * dest;                    //pointer: dest image pixels;
  PalmOSPalette  * Pal;                     //pointer: palette Palm OS
  PalmOSInverse  * InvPal;                  //pointer: inverse Palette
  unsigned char  * Pd;                      //generic pixel's pointer;
  unsigned char  * Ps;                      //generic pixel's pointer;
  long            ratio;
  long            ratioInv, jp, ip;
  long            cx,cy;
  short           w,wl,h;
  short           sw0,sh0,sw,sh,dx,dy;
  short           i, j, ddx, ddy;
  unsigned short  id, alpha, usealpha;
  short           R, G, B, RGB;
  unsigned long   Rd,Gd,Bd;
  long            hfp, dhfp, wfp, dwfp;

  // Do local copy of params

  p=(ParamsType *) userData68KP;
  pRes = p->pRes;
  lpImage = pRes->swSourceImage;
  src  = pRes->swSourceImage->pData;
  dest = pRes->swDestImage->pData;
  Pal   = pRes->pPalmOSPalette;
  InvPal = pRes->pPalmOSInverse;
  w = pRes->swSourceImage->w;
  wl = pRes->swSourceImage->wl;
  h = pRes->swSourceImage->h;
  ratio = pRes->Intensity;
  alpha = pRes->Alpha;
  usealpha = pRes->UseAlpha;
  cx = pRes->Cx;                        //cx et cy [0;1] en virgule fixe
  cy = pRes->Cy;
  
  sw0=w; sh0=h;
  sw = FixedPointToInt(FPS_MUL(ratio,IntToFixedPoint(sw0)));
  sh = FixedPointToInt(FPS_MUL(ratio,IntToFixedPoint(sh0)));  
  dx=FixedPointToInt(FPS_MUL(cx,IntToFixedPoint((sw0-sw))));
  dy=FixedPointToInt(FPS_MUL(cy,IntToFixedPoint((sh0-sh))));
  ddx=dx; ddy=dy;

  //fill background color
  Pd=dest; Ps=src;
  for (j=0;j<h;j++)  
  {
    for (i=0; i<w; i++)
    {
      if (pRes->swSourceImage->bitdepth==1)
      { // 8 bit case    
          if (!( (lpImage->swTransparent !=0) && (lpImage->swTranspIndex==Ps[i]) ) )
          Pd[i] = Ps[i];
        else
          Pd[i] = pRes->BkIndex;
      }
      else
      { // 16 bit case    
        if (!((lpImage->swTransparent !=0)&&(lpImage->swTranspColorH==Ps[i<<1])
              && (lpImage->swTranspColorL==Ps[(i<<1)+1])))
        { Pd[i<<1] = Ps[i<<1]; 
          Pd[(i<<1)+1] = Ps[(i<<1)+1];
        }
        else
        { Pd[i<<1] = pRes->BkColorH;
          Pd[(i<<1)+1] = pRes->BkColorL;
        }
      }
    }
    Pd += wl;
    Ps += wl;
  }
  
  //apply effect
  dwfp = FPUS_DIV(w,sw);
  dhfp = FPUS_DIV(h,sh);
  ratioInv=FPUS_DIV(ONEFixedPoint,ratio);  
  while ((sw>=4)&&(sh>=4))
  {
    Pd=dest+(long)ddy*wl;
    hfp=0;
    for (j=0;j<sh;j++)  
    {
      jp = FixedPointToInt(hfp);
      if (jp>=h) jp=h-1;
      Ps = src+(long)wl*jp;
      wfp=0;
      for (i=0;i<sw;i++)  
      {
        ip = FixedPointToInt(wfp);
        if (ip>=w) ip=w-1;
        if (pRes->swSourceImage->bitdepth==1)
        { // 8 bit case
          if (!((lpImage->swTransparent !=0)&&(lpImage->swTranspIndex==Ps[ip])))
          {
            if(usealpha != 0)
            {
              //couleur pixel dest * ALPHA
              id = Pd[ddx+i]<<2;
              R=Pal->RGB4[id+1];
                 G=Pal->RGB4[id+2];
              B=Pal->RGB4[id+3];
              Rd=R*alpha;
              Gd=G*alpha;
              Bd=B*alpha;
              //couleur pixel source * (255-ALPHA)
              id = Ps[ip]<<2;
              R=Pal->RGB4[id+1];
              G=Pal->RGB4[id+2];
              B=Pal->RGB4[id+3];
              Rd+=R*(256-alpha);
              Gd+=G*(256-alpha);
              Bd+=B*(256-alpha);
              //couleur finale  ( coef<=255)
              R=Rd>>8;
              G=Gd>>8;
              B=Bd>>8;
              //Retrouve la couleur indexée la plus proche       
              // (x*5)>>8 est ~ x/51 pour retrouver index
              R=(((R+26)<<2)+R+26)>>8;                
              G=(((G+26)<<2)+G+26)>>8;                
              B=(((B+26)<<2)+B+26)>>8;                
              RGB = (R<<5)+(R<<2)+(G<<2)+(G<<1)+B;
              Pd[ddx+i] = InvPal->Index[RGB];  // copy new color
            }
            else
            {    Pd[ddx+i]=Ps[ip]; }
          }
        }
        else
        { // 16 bit case
          if (!((lpImage->swTransparent !=0)&&(lpImage->swTranspColorH==Ps[ip<<1])
                && (lpImage->swTranspColorL==Ps[(ip<<1)+1])))
          {
            if(usealpha != 0)
            {
              //couleur pixel source * ALPHA
              RGB = (Pd[(ddx+i)<<1]<<8)|Pd[((ddx+i)<<1)+1];
              R=(RGB >> 11) & 0x001F;
              G=(RGB >> 5) & 0x003F;
              B= RGB & 0x001F;
              Rd=R*alpha;
              Gd=G*alpha;
              Bd=B*alpha;
              //couleur pixel dest * (255-ALPHA)
              RGB = (Ps[ip<<1]<<8)|Ps[(ip<<1)+1];
              R=(RGB >> 11) & 0x001F;
              G=(RGB >> 5) & 0x003F;
              B= RGB & 0x001F;
              Rd+=R*(256-alpha);
              Gd+=G*(256-alpha);
              Bd+=B*(256-alpha);
              //couleur finale 
              R=Rd>>8;
              G=Gd>>8;
              B=Bd>>8;
              if (R > 0x001F) R=0x001F;
              if (G > 0x003F) G=0x003F;
              if (B > 0x001F) B=0x001F;
              //Affecte nouvelle couleur
              Pd[(ddx+i)<<1]=(R<<3)|(G>>3);
              Pd[((ddx+i)<<1)+1]=(G<<5)|(B);    
            }
            else
            {    Pd[(ddx+i)<<1]=Ps[ip<<1];
                 Pd[((ddx+i)<<1)+1]=Ps[(ip<<1)+1];    }
          }
        }
        wfp+=dwfp;
      }
      Pd += wl;
      hfp += dhfp;
    }
    sw0=sw; sh0=sh;
    sw = FixedPointToInt(FPS_MUL(ratio,IntToFixedPoint(sw0)));
    sh = FixedPointToInt(FPS_MUL(ratio,IntToFixedPoint(sh0)));  
    dx=FixedPointToInt(FPS_MUL(cx,IntToFixedPoint((sw0-sw))));
    dy=FixedPointToInt(FPS_MUL(cy,IntToFixedPoint((sh0-sh))));
    ddx+=dx; ddy+=dy;
    dwfp = FPS_MUL(dwfp,ratioInv);
    dhfp = FPS_MUL(dhfp,ratioInv);
    } 
  return 0;
}


//********************************************************
//             "MathLibFixed.c"  file  content
//********************************************************


//---------- Global 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

// For endianness conversions
#define Read68KUnaligned32(addr)            \
  (((((unsigned char *)(addr))[0]) << 24) | \
  ((((unsigned char *)(addr))[1]) << 16) |  \
  ((((unsigned char *)(addr))[2]) << 8) |   \
  ((((unsigned char *)(addr))[3])))        


#define Read68KUnaligned16(addr)            \
  (((((unsigned char *)(addr))[0]) << 8) | \
  ((((unsigned char *)(addr))[1]))) 




#define Write68KUnaligned32(addr, value) \
    (((unsigned char *)(addr))[0] = (unsigned char)((unsigned long)(value) >> 24), \
     ((unsigned char *)(addr))[1] = (unsigned char)((unsigned long)(value) >> 16), \
     ((unsigned char *)(addr))[2] = (unsigned char)((unsigned long)(value) >> 8), \
     ((unsigned char *)(addr))[3] = (unsigned char)((unsigned long)(value)))


#define Write68KUnaligned16(addr, value) \
    (((unsigned char *)(addr))[0] = (unsigned char)((unsigned int)(value) >> 8), \
     ((unsigned char *)(addr))[1] = (unsigned char)((unsigned int)(value)))


#define EndianSwap16(n) (((((unsigned int) n) << 8) & 0xFF00) | \
                         ((((unsigned int) n) >> 8) & 0x00FF))

#define EndianSwap32(n) (((((unsigned long) n) << 24) & 0xFF000000) | \
                         ((((unsigned long) n) <<  8) & 0x00FF0000) | \
                         ((((unsigned long) n) >>  8) & 0x0000FF00) | \
                         ((((unsigned long) n) >> 24) & 0x000000FF))





//---------- Math Fixed Point Functions and macros -------


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

//>>>> Fixed point unsigned A/B <<<<
private long FPUS_DIV(long a, long b)
{
  longint A, B, R;
  int     i,n;
  R=0; A=a; B=b; n=0;
  //ensure A<B for this algorythm
  while(A>B) { B=B<<1; n+=1;  }
  n=n+1+FixedPoint;
  //div computation
  for (i=0; i<n; i++)
  {
   R=R<<1;
   if (A>B) { A=A-B; R+=1; }
   A=A<<1;    
  }
  return (long)(R);
}

//>>>> Fixed point signed A/B <<<<
private long FPS_DIV(long a, long b)
{
  longint A, B, R;
  int     i,n;
  char    sA, sB;
  // Absolute A and B values
 
  if (a<0) 
   { A = -a;  sA=0xFF; }
  else
   { A = a;  sA=0x00; }
  if (b<0) 
   { B = -b;  sB=0xFF; }
  else
   { B = b;  sB=0x00; }
  sA = sA ^ sB;
  R=0; n=0;
  //ensure A<B for this algorythm
  while(A>B) { B=B<<1; n+=1; }
  n=n+1+FixedPoint;
  //div computation
  for (i=0; i<n; i++)
  {
    R=R<<1;
    if (A>B) { A=A-B; R+=1; }
    A=A<<1;    
  }
  //take care of sign
  if (sA != 0) R=-R;
  return (long)(R);
}

//>>>> Fixed point signed A*B <<<<
private long FPS_MUL(long a, long b)
{
  return (long)(((longint) (a) * (longint) (b))>>FixedPoint );
}


//>>>> FixedPointToInt <<<<
// extract the I part of fixed point and format it to int (16 bits)
#define FixedPointToInt(fixedPointnum) \
    ( (short) ( (long)(fixedPointnum)>>FixedPoint)  )

#define FixedPointToLong(fixedPointnum) \
    ( (long) ( (long)(fixedPointnum)>>FixedPoint)  )

    
//>>>> IntToFixedPoint <<<<
// convert an int (16 bits) to fixed point 20:12 format
#define IntToFixedPoint(intnum) \
    ( (long)(intnum)<<FixedPoint )

const long ONEFixedPoint = 1<< FixedPoint;       // "1.0" au format fixed point
const long HalfFixedPoint = 1<< (FixedPoint-1);  // "0.5" au format fixed point