Forums
This is the online documentation for Colossus Entertainments Pixie Game Engine

RLEBitmap.cpp

Go to the documentation of this file.
00001 #include "RLEBitmap.h"
00002 #include "Image.h"
00003 #include "Asset.h"
00004 #include "Bitmap.h"
00005 #include "AlphaBitmap.h"
00006 
00007 #define max(a,b)    (((a) > (b)) ? (a) : (b))
00008 #define min(a,b)    (((a) < (b)) ? (a) : (b))
00009 
00010 const char* Pixie_Rle_Header="PIXIE_RLE";
00011 
00012 //*** Constructor ***
00013 
00014 RLEBitmap::RLEBitmap():
00015    usesMask_(0),
00016    xOffset_(0),
00017    yOffset_(0),
00018    activeWidth_(0),
00019    activeHeight_(0),
00020    width_(0),
00021    height_(0),
00022    opaqueSize_(0),
00023    opaqueData_(0),
00024    alphaSize_(0),
00025    alphaData_(0),
00026    colorCount_(0),
00027    palette_(0),
00028    modulatedPalette_(0),
00029    currentPalette_(0)
00030    {
00031    }  
00032       
00033 
00034 //*** Constructor ***
00035 
00036 RLEBitmap::RLEBitmap(const Image& image):
00037    usesMask_(0),
00038    xOffset_(0),
00039    yOffset_(0),
00040    activeWidth_(0),
00041    activeHeight_(0),
00042    width_(0),
00043    height_(0),
00044    opaqueSize_(0),
00045    opaqueData_(0),
00046    alphaSize_(0),
00047    alphaData_(0),
00048    colorCount_(0),
00049    palette_(0),
00050    modulatedPalette_(0),
00051    currentPalette_(0)
00052    {
00053    CreateFromImage(&image);
00054    }
00055 
00056 
00057 //*** Constructor ***
00058 
00059 RLEBitmap::RLEBitmap(const Asset& asset):
00060    usesMask_(0),
00061    xOffset_(0),
00062    yOffset_(0),
00063    activeWidth_(0),
00064    activeHeight_(0),
00065    width_(0),
00066    height_(0),
00067    opaqueSize_(0),
00068    opaqueData_(0),
00069    alphaSize_(0),
00070    alphaData_(0),
00071    colorCount_(0),
00072    palette_(0),
00073    modulatedPalette_(0),
00074    currentPalette_(0)
00075    {
00076    Load(asset);
00077    }
00078 
00079 
00080 //*** Destructor ***
00081 
00082 RLEBitmap::~RLEBitmap()
00083    {
00084    if (opaqueData_)
00085       {
00086       Free(opaqueData_);
00087       }
00088 
00089    if (alphaData_)
00090       {
00091       Free(alphaData_);
00092       }
00093 
00094    if (palette_)
00095       {
00096       Free(palette_);
00097       }
00098 
00099    if (modulatedPalette_)
00100       {
00101       Free(modulatedPalette_);
00102       }
00103    }
00104 
00105 
00106 //*** ReadFromAsset ***
00107 
00108 void RLEBitmap::ReadFromAsset(const Asset* asset)
00109    {
00110    asset->Read(&width_);
00111    asset->Read(&height_);
00112    asset->Read(&activeWidth_);
00113    asset->Read(&activeHeight_);
00114    asset->Read(&colorCount_);
00115    palette_=(unsigned short*)Malloc(sizeof(unsigned short)*colorCount_);
00116    asset->Read(palette_,colorCount_);
00117    asset->Read(&usesMask_);
00118    asset->Read(&opaqueSize_);
00119    if (opaqueSize_>0)
00120       {
00121       opaqueData_=(unsigned char*)Malloc(opaqueSize_);
00122       asset->Read(opaqueData_,opaqueSize_);
00123       }
00124    asset->Read(&alphaSize_);
00125    if (alphaSize_>0)
00126       {
00127       alphaData_=(unsigned char*)Malloc(alphaSize_);
00128       asset->Read(alphaData_,alphaSize_);
00129       }
00130    asset->Read(&xOffset_,1);
00131    asset->Read(&yOffset_,1);
00132    }
00133 
00134 
00135 //*** WriteToAsset ***
00136 
00137 void RLEBitmap::WriteToAsset(Asset* asset)
00138    {
00139    asset->Write(&width_);
00140    asset->Write(&height_);
00141    asset->Write(&activeWidth_);
00142    asset->Write(&activeHeight_);
00143    asset->Write(&colorCount_);
00144    asset->Write(palette_,colorCount_);
00145    asset->Write(&usesMask_);
00146    asset->Write(&opaqueSize_);
00147    if (opaqueSize_>0 && opaqueData_)
00148       {
00149       asset->Write(opaqueData_,opaqueSize_);
00150       }
00151    asset->Write(&alphaSize_);
00152    if (alphaSize_>0 && alphaData_)
00153       {
00154       asset->Write(alphaData_,alphaSize_);
00155       }
00156    asset->Write(&xOffset_);
00157    asset->Write(&yOffset_);
00158    }
00159 
00160 
00161 //*** calculateDiff ***
00162 
00163 int calculateDiff(unsigned short a, unsigned short b)
00164    {
00165    unsigned char ar=(unsigned char)((a & 0xf800)>>11);
00166    unsigned char ag=(unsigned char)((a & 0x7e0)>>5);
00167    unsigned char ab=(unsigned char)((a & 0x1f));
00168    unsigned char br=(unsigned char)((b & 0xf800)>>11);
00169    unsigned char bg=(unsigned char)((b & 0x7e0)>>5);
00170    unsigned char bb=(unsigned char)((b & 0x1f));
00171 
00172    // Diff  
00173    int dr=Abs(ar-br);
00174    int dg=Abs(ab-bb);
00175    int db=Abs(ag-bg);
00176    
00177    return dr+dg+db;
00178    }
00179 
00180 
00181 //*** FindGetRidOfDiff ***
00182 
00183 void RLEBitmap::FindGetRidOfDiff(unsigned short* palette, int usedPaletteEntries,int& diff, int& a, int& b)
00184    {
00185    // Find best match
00186    int bestPairA=0;
00187    int bestPairB=1;
00188    int bestDiff=calculateDiff(palette[bestPairA],palette[bestPairB]);
00189    for (int i=0; i<usedPaletteEntries-1; i++)
00190       {
00191       for (int j=i+1; j<usedPaletteEntries; j++)
00192          {
00193          int diff=calculateDiff(palette[i],palette[j]);
00194          if (diff<bestDiff)
00195             {
00196             bestDiff=diff;
00197             bestPairA=i;
00198             bestPairB=j;
00199             }
00200          }
00201       }     
00202    a=bestPairA;
00203    b=bestPairB;
00204    diff=bestDiff;
00205    }
00206    
00207 
00208 //*** GetRidOfColor ***
00209 
00210 void RLEBitmap::GetRidOfColor(unsigned char* data, int size, unsigned short* palette, int& usedPaletteEntries,unsigned int* timesUsed, int bestDiff, int bestPairA, int bestPairB)
00211    {
00212    // Remove color
00213    if (timesUsed[bestPairB]>timesUsed[bestPairA])
00214       {
00215       int temp=bestPairB;
00216       bestPairB=bestPairA;
00217       bestPairA=temp;
00218       }
00219    timesUsed[bestPairA]+=timesUsed[bestPairB];
00220    for (int i=0; i<size; i++)
00221       {
00222       if (data[i]==bestPairB)
00223          {
00224          data[i]=(unsigned char)bestPairA;
00225          }
00226       }
00227    
00228    // Move last color to free slot     
00229    palette[bestPairB]=palette[usedPaletteEntries-1];
00230    for (int i=0; i<size; i++)
00231       {
00232       if (data[i]==(usedPaletteEntries-1))
00233          data[i]=(unsigned char)bestPairB;
00234       }
00235    
00236    // Reduce number of used colors
00237    usedPaletteEntries--;
00238    }
00239    
00240 
00241 //*** FindBestColor ***
00242 
00243 unsigned char RLEBitmap::FindBestColor(unsigned char* data, int size, unsigned short* palette, int& usedPaletteEntries,unsigned int* timesUsed, unsigned char r, unsigned char g, unsigned char b)
00244    {
00245    unsigned short color=(r<<11)|(g<<5)|(b);
00246    for (int i=0; i<usedPaletteEntries; i++)
00247       {
00248       if (palette[i]==color)
00249          {
00250          timesUsed[i]++;
00251          return (unsigned char)i;
00252          }
00253       }
00254    if (usedPaletteEntries==254)
00255       {
00256       // Find best match
00257       int bestMatch=0;
00258       int bestDiff=calculateDiff(color,palette[bestMatch]);
00259       for (int i=1; i<usedPaletteEntries; i++)
00260          {
00261          int diff=calculateDiff(color,palette[i]);
00262          if (diff<bestDiff)
00263             {
00264             bestDiff=diff;
00265             bestMatch=i;
00266             }
00267          }     
00268    
00269       int ridPairA=0;
00270       int ridPairB=0;
00271       int ridDiff=0;
00272       FindGetRidOfDiff(palette,usedPaletteEntries,ridDiff,ridPairA,ridPairB);
00273       if (bestDiff<=ridDiff)
00274          {
00275          timesUsed[bestMatch]++;
00276          return (unsigned char)bestMatch;
00277          }
00278       GetRidOfColor(data,size,palette,usedPaletteEntries,timesUsed,ridDiff,ridPairA,ridPairB);
00279       }
00280 
00281    Assert(usedPaletteEntries<254,"Palette full!");
00282 
00283    palette[usedPaletteEntries]=color;
00284    timesUsed[usedPaletteEntries]=0;
00285    usedPaletteEntries++;
00286    return (unsigned char)(usedPaletteEntries-1);
00287    }
00288 
00289 
00290 //*** CreateFromImage ***
00291 
00292 void RLEBitmap::CreateFromImage(const Image* image)
00293    {
00294    width_=(unsigned short)image->GetWidth();
00295    height_=(unsigned short)image->GetHeight();
00296    int minX=0;
00297    int minY=0;
00298    int maxX=0;
00299    int maxY=0;
00300    
00301    // Crop image
00302    Crop(image,&minX,&minY,&maxX,&maxY);
00303    if (maxX<minX || maxY<minY)
00304       {
00305       return;
00306       }
00307 
00308    activeWidth_=(unsigned short)(maxX-minX+1);
00309    activeHeight_=(unsigned short)(maxY-minY+1);
00310    
00311    xOffset_=(unsigned short)minX;
00312    yOffset_=(unsigned short)minY;
00313 
00314    // First, create palettized version
00315    unsigned char* data=0;
00316    unsigned char* mask=0;
00317    Palettize(image,&data,&mask,&palette_,&colorCount_);
00318    
00319    if (mask)
00320       usesMask_=1;
00321    else
00322       usesMask_=0;
00323 
00324    // Create RLE data
00325    opaqueSize_=GetRLESize(data,mask);
00326    if (opaqueSize_>0)
00327       {
00328       opaqueData_=(unsigned char*)Malloc(opaqueSize_);
00329       CreateRLE(data,mask,opaqueData_);
00330       }
00331 
00332    // Create RLE mask
00333    if (mask)
00334       {
00335       alphaSize_=GetRLESize_Alpha(data,mask);
00336       if (alphaSize_>0)
00337          {
00338          alphaData_=(unsigned char*)Malloc(alphaSize_);
00339          CreateRLE_Alpha(data,mask,alphaData_);
00340          }
00341       }
00342       
00343 
00344    // Release temp stuff
00345    if (data)
00346       {
00347       Free(data);
00348       }
00349    if (mask)
00350       {
00351       Free(mask);
00352       }
00353    }
00354 
00355 
00356 //*** GetRunLength ***
00357 
00358 int   RLEBitmap::GetRunLength(unsigned char* data, unsigned char* mask,int size)
00359    {
00360    int length=0;
00361    int currCol=*data;
00362    if (mask && *mask<255)
00363       {
00364       currCol=255;
00365       }
00366    int c=currCol;
00367    while ((currCol==c) && size>0)
00368       {
00369       length++;
00370       data++;
00371       if (mask)
00372          {
00373          mask++;
00374          }
00375       size--;
00376       currCol=*data;
00377       if (mask && *mask<255)
00378          {
00379          currCol=255;
00380          }
00381       }
00382    return length;
00383    }
00384 
00385 
00386 //*** GetUniquesLength ***
00387 
00388 int   RLEBitmap::GetUniquesLength(unsigned char* data, unsigned char* mask,int size)
00389    {
00390    int length=0;
00391    while (GetRunLength(data,mask,size)<=2 && size>0)
00392       {
00393       length++;
00394       data++;
00395       if (mask)
00396          {
00397          mask++;
00398          }
00399       size--;
00400       }
00401    return length;
00402    }
00403 
00404 
00405 //*** GetRLESize ***
00406 
00407 int RLEBitmap::GetRLESize(unsigned char* data,unsigned char* mask)
00408    {
00409    return CreateRLE(data,mask,0);
00410    }
00411 
00412 
00413 //*** CreateRLE ***
00414 
00415 int RLEBitmap::CreateRLE(unsigned char* source, unsigned char* mask, unsigned char* destination)
00416    {
00417    int size=activeWidth_*activeHeight_;
00418    int result=0;  
00419    int xleft=activeWidth_;
00420    while (size>0)
00421       {
00422       unsigned char len=(unsigned char)GetRunLength(source,mask,min(127,min(size,xleft)));
00423       if (len<=2)
00424          {
00425          unsigned char len=(unsigned char)GetUniquesLength(source,mask,min(127,min(size,xleft)));
00426 
00427          result++; // Count value
00428          if (destination)
00429             {
00430             *destination=(len | 0x80); // Top bit set to indicate run of unique colors
00431             destination++;
00432             }
00433          
00434          result+=len; // Unique colors
00435          if (destination)
00436             {
00437             unsigned char* colorsource=source;
00438             unsigned char* maskvalue=mask;
00439             for (int i=0; i<len; i++)
00440                {
00441                if (mask && *maskvalue<255)
00442                   *destination=255; // Transparent or semitransparent pixel
00443                else
00444                   *destination=*colorsource;
00445                destination++;
00446                colorsource++;
00447                if (mask)
00448                   maskvalue++;
00449                }
00450             }
00451       
00452          if (mask)
00453             mask+=len;
00454          source+=len;
00455          xleft-=len;
00456          Assert(xleft>=0,"Inavlid run length");
00457          if (xleft==0)
00458             xleft=activeWidth_;
00459          size-=len;
00460          }
00461       else
00462          {
00463          result++; // Count value
00464          if (destination)
00465             {
00466             *destination=len; // Top bit not set to indicate run of same color
00467             destination++;
00468             }
00469       
00470          result++; // Repeated color
00471          if (destination)
00472             {
00473             if (mask && *mask<255)
00474                *destination=255; // Transparent or semitransparent pixel
00475             else
00476                *destination=*source;
00477             destination++;
00478             }
00479             
00480          source+=len;
00481          xleft-=len;
00482          Assert(xleft>=0,"Inavlid run length");
00483          if (xleft==0)
00484             xleft=activeWidth_;
00485          if (mask)
00486             mask+=len;
00487          size-=len;
00488          }
00489       }
00490       
00491    return result;
00492    }  
00493    
00494 
00495 
00496 //*** GetRunLength_Alpha ***
00497 
00498 int   RLEBitmap::GetRunLength_Alpha(unsigned char* data, unsigned char* mask,int size)
00499    {
00500    int length=0;
00501    int currCol=*data;
00502    int currMask=*mask;
00503    if (currMask==0 || currMask==255)
00504       {
00505       currMask=0;
00506       currCol=255;
00507       }
00508    int c=currCol;
00509    int m=currMask;
00510    while ((currCol==c) && (currMask==m) && size>0)
00511       {
00512       length++;
00513       data++;
00514       mask++;
00515       size--;
00516       currCol=*data;
00517       currMask=*mask;
00518       if (currMask==0 || currMask==255)
00519          {
00520          currMask=0;
00521          currCol=255;
00522          }
00523       }
00524    return length;
00525    }
00526 
00527 
00528 //*** GetUniquesLength_Alpha ***
00529 
00530 int   RLEBitmap::GetUniquesLength_Alpha(unsigned char* data, unsigned char* mask,int size)
00531    {
00532    int length=0;
00533    while (GetRunLength_Alpha(data,mask,size)<=2 && size>0)
00534       {
00535       length++;
00536       data++;
00537       mask++;
00538       size--;
00539       }
00540    return length;
00541    }
00542 
00543 
00544 //*** GetRLESize_Alpha ***
00545 
00546 int RLEBitmap::GetRLESize_Alpha(unsigned char* data,unsigned char* mask)
00547    {
00548    return CreateRLE_Alpha(data,mask,0);
00549    }
00550 
00551 
00552 //*** CreateRLE_Alpha ***
00553 
00554 int RLEBitmap::CreateRLE_Alpha(unsigned char* source, unsigned char* mask, unsigned char* destination)
00555    {
00556    int size=activeWidth_*activeHeight_;
00557    int result=0;  
00558    int xleft=activeWidth_;
00559    while (size>0)
00560       {
00561       unsigned char len=(unsigned char)GetRunLength_Alpha(source,mask,min(127,min(size,xleft)));
00562       if (len<=2)
00563          {
00564          unsigned char len=(unsigned char)GetUniquesLength_Alpha(source,mask,min(127,min(size,xleft)));
00565 
00566          result++; // Count value
00567          if (destination)
00568             {
00569             *destination=(len | 0x80); // Top bit set to indicate run of unique colors
00570             destination++;
00571             }
00572          
00573          // Unique colors
00574          unsigned char* colorsource=source;
00575          unsigned char* maskvalue=mask;
00576          for (int i=0; i<len; i++)
00577             {
00578             if (*maskvalue==0 || *maskvalue==255)
00579                {
00580                if (destination)
00581                   {
00582                   *destination=0;   // Fully transparent pixel
00583                   destination++;
00584                   *destination=0;   
00585                   destination++;
00586                   }
00587                result+=2;
00588                }
00589             else
00590                {
00591                if (destination)
00592                   {
00593                   *destination=*maskvalue;   // Semi-transparent pixel
00594                   destination++;
00595                   *destination=*colorsource;
00596                   destination++;
00597                   }
00598                result+=2;
00599                }
00600             colorsource++;
00601             maskvalue++;
00602             }
00603             
00604          mask+=len;
00605          source+=len;
00606          xleft-=len;
00607          Assert(xleft>=0,"Invalid run length");
00608          if (xleft==0)
00609             xleft=activeWidth_;
00610          size-=len;
00611          }
00612       else
00613          {
00614          result++; // Count value
00615          if (destination)
00616             {
00617             *destination=len; // Top bit not set to indicate run of same color
00618             destination++;
00619             }
00620       
00621          // Repeated color
00622 
00623          if (*mask==0 || *mask==255)
00624             {
00625             if (destination)
00626                {
00627                *destination=0;   // Fully transparent pixel
00628                destination++;
00629                *destination=0;
00630                destination++;
00631                }
00632             result+=2;
00633             }
00634          else
00635             {
00636             if (destination)
00637                {
00638                *destination=*mask;
00639                destination++;
00640                *destination=*source;
00641                destination++;
00642                }
00643             result+=2;
00644             }
00645                      
00646          source+=len;
00647          xleft-=len;
00648          Assert(xleft>=0,"Invalid run length");
00649          if (xleft==0)
00650             xleft=activeWidth_;
00651          mask+=len;
00652          size-=len;
00653          }
00654       }
00655       
00656    return result;
00657    }  
00658    
00659 
00660 //*** Palettize ***
00661 
00662 void RLEBitmap::Palettize(const Image* image,unsigned char** data, unsigned char** mask, unsigned short** palette, unsigned char* colorCount)   
00663    {
00664    static unsigned short pal[256];
00665    static unsigned int timesUsed[256];
00666    int usedPaletteEntries=0;
00667    *data=(unsigned char*)Malloc(sizeof(unsigned char)*activeWidth_*activeHeight_);
00668    *mask=(unsigned char*)Malloc(sizeof(unsigned char)*activeWidth_*activeHeight_);
00669    unsigned char* img=*data;
00670    unsigned char* maskimg=*mask;
00671    bool maskUsed=false;
00672    bool maskUsedTrans=false;
00673 
00674    for (int y=0; y<activeHeight_; y++)
00675       {
00676       for (int x=0; x<activeWidth_; x++)
00677          {
00678          unsigned int color=image->GetPixel(xOffset_+x,yOffset_+y);
00679          unsigned short color16=RGB32TO16(color);
00680          unsigned char a=((unsigned char)((color&0xff000000)>>24));
00681          unsigned char r=((unsigned char)((color16 & 0xf800)>>11));
00682          unsigned char g=((unsigned char)((color16 & 0x07e0)>>5));
00683          unsigned char b=((unsigned char)((color16 & 0x1f)));
00684          
00685          *img=FindBestColor(*data,(int)(img-*data),pal,usedPaletteEntries,timesUsed,r,g,b);
00686          img++;
00687          *maskimg=a;
00688          maskimg++;
00689          if (a<255)
00690             {
00691             maskUsed=true;
00692             if (a>0)
00693                {
00694                maskUsedTrans=true;
00695                }
00696             }
00697          }
00698       }
00699 
00700    if (!maskUsed)
00701       {
00702       Free(*mask);
00703       *mask=0;
00704       }
00705    
00706    *palette=(unsigned short*)Malloc(sizeof(unsigned short)*usedPaletteEntries);
00707    MemCpy(*palette,pal,sizeof(unsigned short)*usedPaletteEntries);
00708    *colorCount=(unsigned char)usedPaletteEntries;
00709    }  
00710    
00711    
00712 //*** Crop ***
00713 
00714 void RLEBitmap::Crop(const Image* image, int* minX, int* minY, int* maxX, int* maxY)
00715    {
00716    *minX=image->GetWidth();
00717    *minY=image->GetHeight();
00718    *maxX=0;
00719    *maxY=0;
00720    for (int y=0; y<image->GetHeight(); y++)
00721       {
00722       for (int x=0; x<image->GetWidth(); x++)
00723          {
00724          unsigned int color=image->GetPixel(x,y);
00725          if (color>>24)
00726             {
00727             if (y<*minY)
00728                *minY=y;
00729             if (x<*minX)
00730                *minX=x;
00731             if (y>*maxY)
00732                *maxY=y;
00733             if (x>*maxX)
00734                *maxX=x;
00735             }
00736          }
00737       }
00738    }
00739 
00740 
00741 //*** Blit ***
00742 
00743 void RLEBitmap::Blit(Bitmap* target,int x, int y,unsigned short modulate, unsigned char alpha) const
00744    {
00745    Blit(0,0,activeWidth_-1,activeHeight_-1,target,x,y,modulate,alpha);
00746    }
00747    
00748 
00749 //*** Blit ***
00750 
00751 void RLEBitmap::Blit(int x1, int y1, int x2, int y2, Bitmap* target,int x, int y, unsigned short modulate, unsigned char alpha) const
00752    {
00753    // Check for empty bitmap
00754    if (!opaqueData_ && !alphaData_)
00755       {
00756       return;
00757       }
00758 
00759    if (alpha==0)
00760       {
00761       return;
00762       }
00763 
00764 
00765    int clipX1=x+xOffset_;
00766    int clipY1=y+yOffset_;
00767    int clipX2=x+xOffset_+(x2-x1);
00768    int clipY2=y+yOffset_+(y2-y1);
00769 
00770    x-=x1;
00771    y-=y1;
00772 
00773    if (clipX1<0)
00774       clipX1=0;
00775    if (clipY1<0)
00776       clipY1=0;
00777    if (clipX2>=target->GetWidth())
00778       clipX2=target->GetWidth()-1;
00779    if (clipY2>=target->GetHeight())
00780       clipY2=target->GetHeight()-1;
00781    
00782    // Set up palette
00783    currentPalette_=palette_;
00784    if (modulate!=0xffff)
00785       {
00786       if (!modulatedPalette_)
00787          {
00788          modulatedPalette_=(unsigned short*)Malloc(sizeof(unsigned short)*colorCount_);
00789          }
00790       for (int i=0; i<colorCount_; i++)
00791          {
00792          int c=palette_[i];
00793          unsigned int r=(c & 0xf800)>>11;
00794          unsigned int g=(c & 0x7e0)>>5;
00795          unsigned int b=(c & 0x1f);
00796          unsigned int mr=(modulate & 0xf800)>>11;
00797          unsigned int mg=(modulate & 0x7e0)>>5;
00798          unsigned int mb=(modulate & 0x1f);
00799          r*=mr;
00800          g*=mg;
00801          b*=mb;
00802          r>>=5;
00803          g>>=6;
00804          b>>=5;
00805          modulatedPalette_[i]=(unsigned short)((r<<11)|(g<<5)|(b));
00806          }
00807       currentPalette_=modulatedPalette_;
00808       }
00809    int targetDelta=target->GetWidth()-activeWidth_;
00810    int tx1=x+xOffset_;
00811    int ty1=y+yOffset_;
00812    int tx2=tx1+activeWidth_-1;
00813    int ty2=ty1+activeHeight_-1;
00814    unsigned short* data=&(target->GetData())[tx1+ty1*target->GetWidth()];
00815    
00816    // Do we need to clip?
00817    if (tx1>=clipX1 && ty1>=clipY1 && tx2<=clipX2 && ty2<=clipY2)
00818       {
00819       // Render opaque part
00820       if (opaqueData_)
00821          {
00822          if (usesMask_)
00823             {
00824             if (alpha==255)
00825                {
00826                Blit_Opaque_Unclipped_Masked(data,targetDelta,tx1,ty1);
00827                }
00828             else 
00829                {
00830                Blit_Opaque_Unclipped_Masked_Transparent(data,targetDelta,tx1,ty1,alpha);
00831                }
00832             }
00833          else
00834             {
00835             if (alpha==255)
00836                {
00837                Blit_Opaque_Unclipped_Unmasked(data,targetDelta,tx1,ty1);
00838                }
00839             else
00840                {
00841                Blit_Opaque_Unclipped_Unmasked_Transparent(data,targetDelta,tx1,ty1,alpha);
00842                }
00843             }
00844          }
00845          
00846       // Render alpha part
00847       if (alphaData_)         
00848          {
00849          if (alpha==255)
00850             {
00851             Blit_Alpha_Unclipped(data,targetDelta,tx1,ty1);
00852             }
00853          else
00854             {
00855             Blit_Alpha_Unclipped_Transparent(data,targetDelta,tx1,ty1,alpha);
00856             }
00857          }
00858       }
00859    else  // Yes, clipping required
00860       {
00861       // Trivial rejection test
00862       if (tx2<clipX1 || ty2<clipY1 || tx1>clipX2 || ty1>clipY2)
00863          return;
00864       
00865       // Calculate visible part
00866       int xStart=0;
00867       int yStart=0;
00868       int xEnd=0;
00869       int yEnd=0;
00870 
00871       if (tx1<clipX1)
00872          {
00873          xStart=clipX1-tx1;
00874          }
00875       if (ty1<clipY1)
00876          {
00877          yStart=clipY1-ty1;
00878          }
00879       if (tx2>clipX2)
00880          {
00881          xEnd=tx2-clipX2+1;
00882          }
00883       if (ty2>clipY2)
00884          {
00885          yEnd=ty2-clipY2+1;
00886          }
00887       
00888       // Render opaque part
00889       if (opaqueData_)
00890          {
00891          if (usesMask_)
00892             {
00893             if (alpha==255)
00894                {
00895                Blit_Opaque_Clipped_Masked(data,targetDelta,tx1,ty1,xStart,yStart,xEnd,yEnd);
00896                }
00897             else
00898                {
00899                Blit_Opaque_Clipped_Masked_Transparent(data,targetDelta,tx1,ty1,xStart,yStart,xEnd,yEnd,alpha);
00900                }
00901             }
00902          else
00903             {
00904             if (alpha==255)
00905                {
00906                Blit_Opaque_Clipped_Unmasked(data,targetDelta,tx1,ty1,xStart,yStart,xEnd,yEnd);
00907                }
00908             else
00909                {
00910                Blit_Opaque_Clipped_Unmasked_Transparent(data,targetDelta,tx1,ty1,xStart,yStart,xEnd,yEnd,alpha);
00911                }
00912             }
00913          }
00914          
00915       // Render alpha part
00916       if (alphaData_)         
00917          {
00918          Blit_Alpha_Clipped(data,targetDelta,tx1,ty1,xStart,yStart,xEnd,yEnd);
00919          }
00920       }
00921    }
00922 
00923 
00924 //*** Blit ***
00925 
00926 void RLEBitmap::Blit(AlphaBitmap* target,int x, int y) const
00927    {
00928    Blit(0,0,activeWidth_-1,activeHeight_-1,target,x,y);
00929    }
00930    
00931 
00932 //*** Blit ***
00933 
00934 void RLEBitmap::Blit(int x1, int y1, int x2, int y2, AlphaBitmap* target, int x, int y) const
00935    {
00936    // Check for empty bitmap
00937    if (!opaqueData_ && !alphaData_)
00938       {
00939       return;
00940       }
00941 
00942    x-=x1;
00943    y-=y1;
00944 
00945 
00946    int clipX1=x+xOffset_;
00947    int clipY1=y+yOffset_;
00948    int clipX2=x+xOffset_+(x2-x1);
00949    int clipY2=y+yOffset_+(y2-y1);
00950 
00951 
00952    if (clipX1<0)
00953       clipX1=0;
00954    if (clipY1<0)
00955       clipY1=0;
00956    if (clipX2>=target->GetWidth())
00957       clipX2=target->GetWidth()-1;
00958    if (clipY2>=target->GetHeight())
00959       clipY2=target->GetHeight()-1;
00960    
00961    currentPalette_=palette_;
00962 
00963    int targetDelta=target->GetWidth()-activeWidth_;
00964    int tx1=x+xOffset_;
00965    int ty1=y+yOffset_;
00966    int tx2=tx1+activeWidth_-1;
00967    int ty2=ty1+activeHeight_-1;
00968    unsigned short* colorData=&(target->GetColorData())[tx1+ty1*target->GetWidth()];
00969    unsigned char* alphaData=&(target->GetAlphaData())[tx1+ty1*target->GetWidth()];
00970    
00971    // Do we need to clip?
00972    if (tx1>=clipX1 && ty1>=clipY1 && tx2<=clipX2 && ty2<=clipY2)
00973       {
00974       // Render opaque part
00975       if (opaqueData_)
00976          {
00977          if (usesMask_)
00978             {
00979             PreserveAlpha_Blit_Opaque_Unclipped_Masked(colorData, alphaData, targetDelta, tx1, ty1);
00980             }
00981          else
00982             {
00983             PreserveAlpha_Blit_Opaque_Unclipped_Unmasked(colorData, alphaData, targetDelta, tx1, ty1);
00984             }
00985          }
00986          
00987       // Render alpha part
00988       if (alphaData_)         
00989          {
00990          PreserveAlpha_Blit_Alpha_Unclipped(colorData, alphaData, targetDelta, tx1, ty1);
00991          }
00992       }
00993    else  // Yes, clipping required
00994       {
00995       // Trivial rejection test
00996       if (tx2<clipX1 || ty2<clipY1 || tx1>clipX2 || ty1>clipY2)
00997          return;
00998       
00999       // Calculate visible part
01000       int xStart=0;
01001       int yStart=0;
01002       int xEnd=0;
01003       int yEnd=0;
01004 
01005       if (tx1<clipX1)
01006          {
01007          xStart=clipX1-tx1;
01008          }
01009       if (ty1<clipY1)
01010          {
01011          yStart=clipY1-ty1;
01012          }
01013       if (tx2>clipX2)
01014          {
01015          xEnd=tx2-clipX2+1;
01016          }
01017       if (ty2>clipY2)
01018          {
01019          yEnd=ty2-clipY2+1;
01020          }
01021       
01022       // Render opaque part
01023       if (opaqueData_)
01024          {
01025          if (usesMask_)
01026             {
01027             PreserveAlpha_Blit_Opaque_Clipped_Masked(colorData, alphaData, targetDelta, tx1, ty1, xStart, yStart, xEnd, yEnd);
01028             }
01029          else
01030             {
01031             PreserveAlpha_Blit_Opaque_Clipped_Unmasked(colorData, alphaData, targetDelta, tx1, ty1, xStart, yStart, xEnd, yEnd);
01032             }
01033          }
01034          
01035       // Render alpha part
01036       if (alphaData_)         
01037          {
01038          PreserveAlpha_Blit_Alpha_Clipped(colorData, alphaData, targetDelta, tx1, ty1, xStart, yStart, xEnd, yEnd);
01039          }
01040       }
01041    }
01042 
01043    
01044 //*** Fill ***
01045 
01046 __forceinline void Fill(unsigned short* data, unsigned short color, int len)
01047    {
01048    for (int i=0; i<len; ++i)
01049       {
01050       *data=color;
01051       data++;
01052       }
01053    }
01054 
01055 
01056 //*** Blend ***
01057 
01058 __forceinline void Blend(unsigned short* destination, unsigned int color, unsigned int alpha)   
01059    {
01060    if (alpha==255)
01061       {
01062       *destination=(unsigned short)color;
01063       }
01064    else
01065       {
01066       unsigned int inva=255-alpha;
01067       unsigned int s=*destination;
01068       unsigned int sr=(s & 0xf800)>>11;
01069       unsigned int sg=(s & 0x7e0)>>5;
01070       unsigned int sb=(s & 0x1f);
01071       unsigned int dr=(color & 0xf800)>>11;
01072       unsigned int dg=(color & 0x7e0)>>5;
01073       unsigned int db=(color & 0x1f);
01074       unsigned int r=((sr*inva)+dr*alpha)>>8;
01075       unsigned int g=((sg*inva)+dg*alpha)>>8;
01076       unsigned int b=((sb*inva)+db*alpha)>>8;
01077       unsigned int c=(r<<11)|(g<<5)|b;
01078       *destination=(unsigned short)c;
01079       }
01080    }
01081 
01082 
01083 //*** FillTransparent ***
01084 
01085 __forceinline void FillTransparent(unsigned short* data, unsigned short color, int len, unsigned char alpha)
01086    {
01087    for (int i=0; i<len; ++i)
01088       {
01089       Blend(data,color,alpha);
01090       data++;
01091       }
01092    }
01093 
01094 
01095 //*** BurstFill ***
01096 
01097 // This is to make sure we fill on 4 byte alignment as much as possible
01098 __forceinline void BurstFill(unsigned short* data, unsigned short color, int len)
01099    {
01100    int len2=len;
01101 
01102 
01103 #pragma warning (push)
01104 #pragma warning( disable: 4311)
01105 #ifdef _WIN32
01106    if (((int)data)!=(((int)data)&(0xfffffffc)))
01107 #else
01108    if (((long long)data)!=(((long long)data)&(0xfffffffffffffffc)))
01109 #endif 
01110 #pragma warning (pop)
01111       {
01112       *data=color;
01113       ++data;
01114       --len2;
01115       if (len2==1)
01116          {
01117          *data=color;
01118          ++data;
01119          --len2;
01120          }
01121       }        
01122    if (len2)
01123       {
01124       unsigned int color32=color | (color<<16);
01125       int halflen=len2/2;
01126       unsigned int* data32=(unsigned int*)data;
01127       for (int i=0; i<halflen; ++i)
01128          {
01129          *data32=color32;
01130          ++data32;
01131          }
01132       data=(unsigned short*)data32;
01133       if (len2-halflen*2)
01134          {
01135          *data=color;
01136          ++data;
01137          }
01138       }
01139    }  
01140    
01141 
01142 //*** DoOpaqueUnclippedUnmasked ***
01143 
01144 __forceinline void  DoOpaqueUnclippedUnmasked(int len,unsigned short* data, unsigned char** source, unsigned short* palette)
01145    {
01146    unsigned char* dataRLE=*source;
01147    if (len&0x80)  
01148       {
01149       len&=0x7f;
01150       // Unique values
01151       for (int i=0; i<len; ++i)
01152          {
01153          *data=palette[*dataRLE];
01154          ++data;
01155          ++(dataRLE);
01156          }
01157       }
01158    else
01159       {
01160       // Run of values
01161       #ifdef _DEBUG
01162          Fill(data,palette[*dataRLE],len);
01163       #else
01164          BurstFill(data,palette[*dataRLE],len);
01165       #endif
01166       ++(dataRLE);
01167       }
01168    *source=dataRLE;
01169    }  
01170    
01171    
01172 //*** DoOpaqueUnclippedUnmaskedTransparent ***
01173 
01174 __forceinline void  DoOpaqueUnclippedUnmaskedTransparent(int len,unsigned short* data, unsigned char** source, unsigned short* palette, unsigned char alpha)
01175    {
01176    unsigned char* dataRLE=*source;
01177    if (len&0x80)  
01178       {
01179       len&=0x7f;
01180       // Unique values
01181       for (int i=0; i<len; ++i)
01182          {
01183          Blend(data,palette[*dataRLE],alpha);
01184          ++data;
01185          ++(dataRLE);
01186          }
01187       }
01188    else
01189       {
01190       // Run of values
01191       FillTransparent(data,palette[*dataRLE],len,alpha);
01192       ++(dataRLE);
01193       }
01194    *source=dataRLE;
01195    }  
01196    
01197 
01198 //*** DoOpaqueClippedMasked ***
01199 
01200 __forceinline void  DoOpaqueClippedMasked(int len,unsigned short* data, unsigned char** source, unsigned short* palette, int clipStart, int clipEnd)
01201    {
01202    unsigned char* dataRLE=*source;
01203    int x=0;
01204    if (len&0x80)  
01205       {
01206       len&=0x7f;
01207       // Unique values
01208       for (int i=0; i<len; ++i)
01209          {
01210          if ((*dataRLE)<255 && x>=clipStart && x<=clipEnd)
01211             *data=palette[*dataRLE];
01212          ++x;
01213          ++data;
01214          ++(dataRLE);
01215          }
01216       }
01217    else
01218       {  
01219       // Run of values
01220       int colorIndex=*dataRLE;
01221       if(colorIndex<255)
01222          {
01223          unsigned short color=palette[colorIndex];
01224          for (int i=0; i<len; ++i)
01225             {
01226             if (colorIndex<255 && x>=clipStart && x<=clipEnd)
01227                {
01228                *data=color;
01229                }
01230             ++x;
01231             ++data;
01232             }
01233          }
01234       else
01235          {
01236          x+=len;
01237          data+=len;
01238          }
01239          
01240       ++(dataRLE);
01241       }
01242    *source=dataRLE;
01243    }  
01244 
01245 
01246 //*** DoOpaqueClippedMaskedTransparent ***
01247 
01248 __forceinline void  DoOpaqueClippedMaskedTransparent(int len,unsigned short* data, unsigned char** source, unsigned short* palette, int clipStart, int clipEnd, unsigned char alpha)
01249    {
01250    unsigned char* dataRLE=*source;
01251    int x=0;
01252    if (len&0x80)  
01253       {
01254       len&=0x7f;
01255       // Unique values
01256       for (int i=0; i<len; ++i)
01257          {
01258          if ((*dataRLE)<255 && x>=clipStart && x<=clipEnd)
01259             {
01260             Blend(data,palette[*dataRLE],alpha);
01261             }
01262          ++x;
01263          ++data;
01264          ++(dataRLE);
01265          }
01266       }
01267    else
01268       {  
01269       // Run of values
01270       int colorIndex=*dataRLE;
01271       if(colorIndex<255)
01272          {
01273          unsigned short color=palette[colorIndex];
01274          for (int i=0; i<len; ++i)
01275             {
01276             if (colorIndex<255 && x>=clipStart && x<=clipEnd)
01277                {
01278                Blend(data,color,alpha);
01279                }
01280             ++x;
01281             ++data;
01282             }
01283          }
01284       else
01285          {
01286          x+=len;
01287          data+=len;
01288          }
01289          
01290       ++(dataRLE);
01291       }
01292    *source=dataRLE;
01293    }  
01294 
01295 //*** DoOpaqueUnclippedMasked ***
01296 
01297 __forceinline void  DoOpaqueUnclippedMasked(int len,unsigned short* data, unsigned char** source, unsigned short* palette)
01298    {
01299    unsigned char* dataRLE=*source;
01300    if (len&0x80)  
01301       {
01302       len&=0x7f;
01303       // Unique values
01304       for (int i=0; i<len; ++i)
01305          {
01306          if ((*dataRLE)<255)
01307             {
01308             *data=palette[*dataRLE];
01309             }
01310          ++data;
01311          ++(dataRLE);
01312          }
01313       }
01314    else
01315       {
01316       // Run of values
01317       if ((*dataRLE)<255)
01318          {
01319          #ifdef _DEBUG
01320             Fill(data,palette[*dataRLE],len);
01321          #else
01322             BurstFill(data,palette[*dataRLE],len);
01323          #endif
01324          }
01325       ++(dataRLE);
01326       }
01327    *source=dataRLE;
01328    }  
01329    
01330 
01331 //*** DoOpaqueUnclippedMaskedTransparent ***
01332 
01333 __forceinline void  DoOpaqueUnclippedMaskedTransparent(int len,unsigned short* data, unsigned char** source, unsigned short* palette, unsigned char alpha)
01334    {
01335    unsigned char* dataRLE=*source;
01336    if (len&0x80)  
01337       {
01338       len&=0x7f;
01339       // Unique values
01340       for (int i=0; i<len; ++i)
01341          {
01342          if ((*dataRLE)<255)
01343             {
01344             Blend(data,palette[*dataRLE],alpha);
01345             }
01346          ++data;
01347          ++(dataRLE);
01348          }
01349       }
01350    else
01351       {
01352       // Run of values
01353       if ((*dataRLE)<255)
01354          {
01355          FillTransparent(data,palette[*dataRLE],len,alpha);
01356          }
01357       ++(dataRLE);
01358       }
01359    *source=dataRLE;
01360    }  
01361    
01362 
01363 //*** IgnoreOpaque ***
01364 
01365 __forceinline void  IgnoreOpaque(int len, unsigned char** source)
01366    {
01367    unsigned char* dataRLE=*source;
01368    if (len&0x80)  
01369       {
01370       len&=0x7f;
01371       dataRLE+=len;
01372       }
01373    else
01374       {
01375       ++dataRLE;
01376       }
01377    *source=dataRLE;
01378    }  
01379    
01380 
01381 //*** IgnoreAlpha ***
01382 
01383 __forceinline void  IgnoreAlpha(int len, unsigned char** source)
01384    {
01385    unsigned char* dataRLE=*source;
01386    if (len&0x80)  
01387       {
01388       len&=0x7f;
01389       dataRLE+=len*2;
01390       }
01391    else
01392       {
01393       dataRLE+=2;
01394       }
01395    *source=dataRLE;
01396    }  
01397    
01398 
01399 //*** Blit_Opaque_Unclipped_Unmasked ***
01400 
01401 void RLEBitmap::Blit_Opaque_Unclipped_Unmasked(unsigned short* data, int backBufferDelta,int x, int y) const
01402    {
01403    unsigned char* dataRLE=opaqueData_;
01404    for (int yi=0; yi<activeHeight_; ++yi)
01405       {
01406       int xi=0;
01407       while (xi<activeWidth_)
01408          {
01409          // Get run length
01410          int len=*dataRLE;
01411          ++dataRLE;
01412 
01413          DoOpaqueUnclippedUnmasked(len,data,&dataRLE,currentPalette_);
01414          len&=0x7f;
01415          data+=len;
01416 
01417          xi+=len;
01418          }
01419 
01420       data+=backBufferDelta;
01421       }
01422    }
01423 
01424 
01425 //*** Blit_Opaque_Unclipped_Unmasked_Transparent ***
01426 
01427 void RLEBitmap::Blit_Opaque_Unclipped_Unmasked_Transparent(unsigned short* data, int backBufferDelta,int x, int y, unsigned char alpha) const
01428    {
01429    unsigned char* dataRLE=opaqueData_;
01430    for (int yi=0; yi<activeHeight_; ++yi)
01431       {
01432       int xi=0;
01433       while (xi<activeWidth_)
01434          {
01435          // Get run length
01436          int len=*dataRLE;
01437          ++dataRLE;
01438 
01439          DoOpaqueUnclippedUnmaskedTransparent(len,data,&dataRLE,currentPalette_,alpha);
01440          len&=0x7f;
01441          data+=len;
01442 
01443          xi+=len;
01444          }
01445 
01446       data+=backBufferDelta;
01447       }
01448    }
01449 
01450 
01451 //*** Blit_Opaque_Unclipped_Masked ***
01452 
01453 void RLEBitmap::Blit_Opaque_Unclipped_Masked(unsigned short* data, int backBufferDelta,int x, int y) const
01454    {
01455    unsigned char* dataRLE=opaqueData_;
01456    for (int yi=0; yi<activeHeight_; ++yi)
01457       {
01458       int xi=0;
01459       while (xi<activeWidth_)
01460          {
01461          // Get run length
01462          int len=*dataRLE;
01463          ++dataRLE;
01464 
01465          DoOpaqueUnclippedMasked(len,data,&dataRLE,currentPalette_);
01466          len&=0x7f;
01467          data+=len;
01468 
01469          xi+=len;
01470          }
01471       data+=backBufferDelta;
01472       }
01473    }  
01474    
01475 
01476 //*** Blit_Opaque_Unclipped_Masked_Transparent ***
01477 
01478 void RLEBitmap::Blit_Opaque_Unclipped_Masked_Transparent(unsigned short* data, int backBufferDelta,int x, int y, unsigned char alpha) const
01479    {
01480    unsigned char* dataRLE=opaqueData_;
01481    for (int yi=0; yi<activeHeight_; ++yi)
01482       {
01483       int xi=0;
01484       while (xi<activeWidth_)
01485          {
01486          // Get run length
01487          int len=*dataRLE;
01488          ++dataRLE;
01489 
01490          DoOpaqueUnclippedMaskedTransparent(len,data,&dataRLE,currentPalette_,alpha);
01491          len&=0x7f;
01492          data+=len;
01493 
01494          xi+=len;
01495          }
01496       data+=backBufferDelta;
01497       }
01498    }  
01499 
01500 
01501 //*** Blit_Opaque_Clipped_Masked ***
01502 
01503 void RLEBitmap::Blit_Opaque_Clipped_Masked(unsigned short* data, int backBufferDelta,int x, int y, int xStart, int yStart, int xEnd, int yEnd) const
01504    {  
01505    if (yStart>activeHeight_-yEnd)
01506       return;
01507    if (xStart>activeWidth_-xEnd)
01508       return;
01509    unsigned char* dataRLE=opaqueData_;
01510    
01511    // Skip clipped rows
01512    for (int i=0; i<yStart; i++)
01513       {
01514       int xi=0;
01515       while (xi<activeWidth_)
01516          {
01517          // Get run length
01518          int len=*dataRLE;
01519          ++dataRLE;
01520 
01521          IgnoreOpaque(len,&dataRLE);
01522          len&=0x7f;
01523 
01524          xi+=len;
01525          }
01526       }
01527       
01528    data+=yStart*(backBufferDelta+activeWidth_);
01529    
01530    for (int yi=yStart; yi<(activeHeight_-yEnd); ++yi)
01531       {
01532       int xi=0;
01533       while (xi<activeWidth_)
01534          {
01535          // Get run length
01536          int len=*dataRLE;
01537          ++dataRLE;
01538          
01539          // Are we on the edge?
01540          int runLength=(len&0x7f);
01541          if (xi<xStart || (xi+runLength)>(activeWidth_-xEnd))
01542             {
01543             // yes, on the edge, but is the whole segment off screen?
01544             if ((xi+runLength)<xStart || xi>(activeWidth_-xEnd))
01545                {
01546                // Yes, whole segment is out of view, so ignore
01547                IgnoreOpaque(len,&dataRLE);
01548                }  
01549             else
01550                {
01551                // No, only part of the segment is out of view, so need to draw with clipping
01552                int clipStart=xStart-xi;
01553                int clipEnd=(activeWidth_-xEnd)-xi;
01554          
01555                DoOpaqueClippedMasked(len,data,&dataRLE,currentPalette_,clipStart,clipEnd);
01556                }
01557             }
01558          else // nope, not near edge, so just barge ahead
01559             {
01560             DoOpaqueUnclippedMasked(len,data,&dataRLE,currentPalette_);
01561             }
01562 
01563          len&=0x7f;
01564          data+=len;
01565 
01566          xi+=len;
01567          }
01568       data+=backBufferDelta;
01569       }
01570    }  
01571    
01572 
01573 //*** Blit_Opaque_Clipped_Masked_Transparent ***
01574 
01575 void RLEBitmap::Blit_Opaque_Clipped_Masked_Transparent(unsigned short* data, int backBufferDelta,int x, int y, int xStart, int yStart, int xEnd, int yEnd, unsigned char alpha) const
01576    {  
01577    if (yStart>activeHeight_-yEnd)
01578       return;
01579    if (xStart>activeWidth_-xEnd)
01580       return;
01581    unsigned char* dataRLE