/////////////////////////////////////
// ptc conversion routine profiler //
/////////////////////////////////////
#include "ptc.h"







float Profile32(int width,int height,int format)
{
    // initialize ptc
    PTC ptc(width,height,format);
    if (!ptc.ok()) return 0.0f;

    // create fullscreen surface
    Surface surface(ptc,width,height,ARGB8888);
    if (!surface.ok()) return 0.0f;

    // load image
    Surface image(ptc,"image.tga");
    image.Convert(ARGB8888);
    if (!image.ok()) return 0.0f;

    // tile image to surface
    for (int y=0; y<height; y+=image.GetHeight())
    {
        for (int x=0; x<width; x+=image.GetWidth())
        {
            // bitblt image to surface
            if (!image.BitBlt(surface,x,y)) return 0;
        }
    }
    
    // profile 1000 updates
    int reps=1000;
    clock_t time_start=clock();
    for (int i=0; i<reps; i++) 
    {
        if (!surface.Update()) return 0.0f;
    }
    clock_t time_end=clock();

    // calculate time taken
    float dt=(time_end-time_start);
    float t=dt/(float)CLOCKS_PER_SEC/(float)reps;
    return t;
}


float Profile16(int width,int height,int format)
{
    // initialize ptc
    PTC ptc(width,height,format);
    if (!ptc.ok()) return 0.0f;

    // create fullscreen surface
    Surface surface(ptc,width,height,RGB565);
    if (!surface.ok()) return 0.0f;

    // load image
    Surface image(ptc,"image.tga");
    image.Convert(RGB565);
    if (!image.ok()) return 0.0f;

    // tile image to surface
    for (int y=0; y<height; y+=image.GetHeight())
    {
        for (int x=0; x<width; x+=image.GetWidth())
        {
            // bitblt image to surface
            if (!image.BitBlt(surface,x,y)) return 0;
        }
    }
    
    // profile 1000 updates
    int reps=1000;
    clock_t time_start=clock();
    for (int i=0; i<reps; i++) 
    {
        if (!surface.Update()) return 0.0f;
    }
    clock_t time_end=clock();

    // calculate time taken
    float dt=(time_end-time_start);
    float t=dt/(float)CLOCKS_PER_SEC/(float)reps;
    return t;
}


float Profile8(int width,int height,int format)
{
    // initialize ptc
    PTC ptc(width,height,format);
    if (!ptc.ok()) return 0.0f;

    // create fullscreen surface
    Surface surface(ptc,width,height,GREY8);
    if (!surface.ok()) return 0.0f;

    // load image
    Surface image(ptc,"image.tga");
    image.Convert(ARGB8888);
    image.Convert(GREY8);
    if (!image.ok()) return 0.0f;

    // get image palette
    Palette *palette=image.GetPalette();
    if (!palette) return 0.0f;

    // attach image palette to surface
    surface.AttachPalette(palette);

    // set display palette
    ptc.SetPalette(*palette);

    // tile image to surface
    for (int y=0; y<height; y+=image.GetHeight())
    {
        for (int x=0; x<width; x+=image.GetWidth())
        {
            // bitblt image to surface
            if (!image.BitBlt(surface,x,y)) return 0;
        }
    }
    
    // profile 1000 updates
    int reps=1000;
    clock_t time_start=clock();
    for (int i=0; i<reps; i++) 
    {
        if (!surface.Update()) return 0.0f;
    }
    clock_t time_end=clock();

    // calculate time taken
    float dt=(time_end-time_start);
    float t=dt/(float)CLOCKS_PER_SEC/(float)reps;
    return t;
}


void PrintResult(char format[],float dt)
{
    cout << format << "= ";
    if (dt>0.000001) cout << 1/dt << " fps\n";
    else cout << "n/a\n";
}








int main(int argc,char *argv[])
{
    // parse command line for profile resolution
    int xres=320;
    int yres=200;
    if (argc>=3)
    {
        xres=atoi(argv[1]);
        yres=atoi(argv[2]);
    }

    // profile all 32bit -> X converters
    float Time32_ARGB8888   = Profile32(xres,yres,ARGB8888);
    float Time32_ABGR8888   = Profile32(xres,yres,ABGR8888);
    float Time32_RGBA8888   = Profile32(xres,yres,RGBA8888);
    float Time32_BGRA8888   = Profile32(xres,yres,BGRA8888);
    float Time32_RGB888     = Profile32(xres,yres,RGB888);
    float Time32_BGR888     = Profile32(xres,yres,BGR888);
    float Time32_RGB565     = Profile32(xres,yres,RGB565);
    float Time32_BGR565     = Profile32(xres,yres,BGR565);
    float Time32_ARGB1555   = Profile32(xres,yres,ARGB1555);
    float Time32_ABGR1555   = Profile32(xres,yres,ABGR1555);
    float Time32_FAKEMODE1A = Profile32(xres,yres,FAKEMODE1A);
    float Time32_FAKEMODE1B = Profile32(xres,yres,FAKEMODE1B);
    float Time32_FAKEMODE1C = Profile32(xres,yres,FAKEMODE1C);
    float Time32_FAKEMODE2A = Profile32(xres,yres,FAKEMODE2A);
    float Time32_FAKEMODE2B = Profile32(xres,yres,FAKEMODE2B);
    float Time32_FAKEMODE2C = Profile32(xres,yres,FAKEMODE2C);
    float Time32_FAKEMODE3A = Profile32(xres,yres,FAKEMODE3A);
    float Time32_FAKEMODE3B = Profile32(xres,yres,FAKEMODE3B);
    float Time32_FAKEMODE3C = Profile32(xres,yres,FAKEMODE3C);
    float Time32_GREY8      = Profile32(xres,yres,GREY8);
    float Time32_RGB332     = Profile32(xres,yres,RGB332);

    // profile all 16bit -> X converters
    float Time16_ARGB8888   = Profile16(xres,yres,ARGB8888);
    float Time16_ABGR8888   = Profile16(xres,yres,ABGR8888);
    float Time16_RGBA8888   = Profile16(xres,yres,RGBA8888);
    float Time16_BGRA8888   = Profile16(xres,yres,BGRA8888);
    float Time16_RGB888     = Profile16(xres,yres,RGB888);
    float Time16_BGR888     = Profile16(xres,yres,BGR888);
    float Time16_RGB565     = Profile16(xres,yres,RGB565);
    float Time16_BGR565     = Profile16(xres,yres,BGR565);
    float Time16_ARGB1555   = Profile16(xres,yres,ARGB1555);
    float Time16_ABGR1555   = Profile16(xres,yres,ABGR1555);
    float Time16_FAKEMODE1A = Profile16(xres,yres,FAKEMODE1A);
    float Time16_FAKEMODE1B = Profile16(xres,yres,FAKEMODE1B);
    float Time16_FAKEMODE1C = Profile16(xres,yres,FAKEMODE1C);
    float Time16_FAKEMODE2A = Profile16(xres,yres,FAKEMODE2A);
    float Time16_FAKEMODE2B = Profile16(xres,yres,FAKEMODE2B);
    float Time16_FAKEMODE2C = Profile16(xres,yres,FAKEMODE2C);
    float Time16_FAKEMODE3A = Profile16(xres,yres,FAKEMODE3A);
    float Time16_FAKEMODE3B = Profile16(xres,yres,FAKEMODE3B);
    float Time16_FAKEMODE3C = Profile16(xres,yres,FAKEMODE3C);
    float Time16_GREY8      = Profile16(xres,yres,GREY8);
    float Time16_RGB332     = Profile16(xres,yres,RGB332);

    // profile all 8bit -> X converters
    float Time8_INDEX8     = Profile8(xres,yres,INDEX8);
    float Time8_4BYTE      = Profile8(xres,yres,32);
    float Time8_3BYTE      = Profile8(xres,yres,24);
    float Time8_2BYTE      = Profile8(xres,yres,16);
    float Time8_FAKEMODE1A = Profile8(xres,yres,FAKEMODE1A);
    float Time8_FAKEMODE1B = Profile8(xres,yres,FAKEMODE1B);
    float Time8_FAKEMODE1C = Profile8(xres,yres,FAKEMODE1C);
    float Time8_FAKEMODE2A = Profile8(xres,yres,FAKEMODE2A);
    float Time8_FAKEMODE2B = Profile8(xres,yres,FAKEMODE2B);
    float Time8_FAKEMODE2C = Profile8(xres,yres,FAKEMODE2C);
    float Time8_FAKEMODE3A = Profile8(xres,yres,FAKEMODE3A);
    float Time8_FAKEMODE3B = Profile8(xres,yres,FAKEMODE3B);
    float Time8_FAKEMODE3C = Profile8(xres,yres,FAKEMODE3C);
    float Time8_GREY8      = Profile8(xres,yres,GREY8);
    float Time8_RGB332     = Profile8(xres,yres,RGB332);

    // output results
    cout << "PTC PROFILE RESULTS (" << xres << "," << yres << ")\n\n\n";
    cout << "32bit -> X\n";
    cout << "----------\n";
    PrintResult("ARGB8888   ",Time32_ARGB8888);
    PrintResult("ABGR8888   ",Time32_ABGR8888);
    PrintResult("RGBA8888   ",Time32_RGBA8888);
    PrintResult("BGRA8888   ",Time32_BGRA8888);
    PrintResult("RGB888     ",Time32_RGB888);
    PrintResult("BGR888     ",Time32_BGR888);
    PrintResult("RGB565     ",Time32_RGB565);
    PrintResult("BGR565     ",Time32_BGR565);
    PrintResult("ARGB1555   ",Time32_ARGB1555);
    PrintResult("ABGR1555   ",Time32_ABGR1555);
    PrintResult("FAKEMODE1A ",Time32_FAKEMODE1A);
    PrintResult("FAKEMODE1B ",Time32_FAKEMODE1B);
    PrintResult("FAKEMODE1C ",Time32_FAKEMODE1C);
    PrintResult("FAKEMODE2A ",Time32_FAKEMODE2A);
    PrintResult("FAKEMODE2B ",Time32_FAKEMODE2B);
    PrintResult("FAKEMODE2C ",Time32_FAKEMODE2C);
    PrintResult("FAKEMODE3A ",Time32_FAKEMODE3A);
    PrintResult("FAKEMODE3B ",Time32_FAKEMODE3B);
    PrintResult("FAKEMODE3C ",Time32_FAKEMODE3C);
    PrintResult("GREY8      ",Time32_GREY8);
    PrintResult("RGB332     ",Time32_RGB332);

    cout << "\n16bit -> X\n";
    cout << "----------\n";
    PrintResult("ARGB8888   ",Time16_ARGB8888);
    PrintResult("ABGR8888   ",Time16_ABGR8888);
    PrintResult("RGBA8888   ",Time16_RGBA8888);
    PrintResult("BGRA8888   ",Time16_BGRA8888);
    PrintResult("RGB888     ",Time16_RGB888);
    PrintResult("BGR888     ",Time16_BGR888);
    PrintResult("RGB565     ",Time16_RGB565);
    PrintResult("BGR565     ",Time16_BGR565);
    PrintResult("ARGB1555   ",Time16_ARGB1555);
    PrintResult("ABGR1555   ",Time16_ABGR1555);
    PrintResult("FAKEMODE1A ",Time16_FAKEMODE1A);
    PrintResult("FAKEMODE1B ",Time16_FAKEMODE1B);
    PrintResult("FAKEMODE1C ",Time16_FAKEMODE1C);
    PrintResult("FAKEMODE2A ",Time16_FAKEMODE2A);
    PrintResult("FAKEMODE2B ",Time16_FAKEMODE2B);
    PrintResult("FAKEMODE2C ",Time16_FAKEMODE2C);
    PrintResult("FAKEMODE3A ",Time16_FAKEMODE3A);
    PrintResult("FAKEMODE3B ",Time16_FAKEMODE3B);
    PrintResult("FAKEMODE3C ",Time16_FAKEMODE3C);
    PrintResult("GREY8      ",Time16_GREY8);
    PrintResult("RGB332     ",Time16_RGB332);

    cout << "\n8bit -> X\n";
    cout << "---------\n";                           
    PrintResult("INDEX8     ",Time8_INDEX8);
    PrintResult("4BYTE      ",Time8_4BYTE);
    PrintResult("3BYTE      ",Time8_3BYTE);
    PrintResult("2BYTE      ",Time8_2BYTE);
    PrintResult("FAKEMODE1A ",Time8_FAKEMODE1A);
    PrintResult("FAKEMODE1B ",Time8_FAKEMODE1B);
    PrintResult("FAKEMODE1C ",Time8_FAKEMODE1C);
    PrintResult("FAKEMODE2A ",Time8_FAKEMODE2A);
    PrintResult("FAKEMODE2B ",Time8_FAKEMODE2B);
    PrintResult("FAKEMODE2C ",Time8_FAKEMODE2C);
    PrintResult("FAKEMODE3A ",Time8_FAKEMODE3A);
    PrintResult("FAKEMODE3B ",Time8_FAKEMODE3B);
    PrintResult("FAKEMODE3C ",Time8_FAKEMODE3C);
    PrintResult("GREY8      ",Time8_GREY8);
    PrintResult("RGB332     ",Time8_RGB332);
    return 1;
}
