//
// This File contains the definition of the MGImage-class
//
//   Author: Thomas Bretz
//   Version: V1.0 (1-8-2000)
//
// x11/src/GX11Gui.cxx
//
#include "MGImage.h"

#include <iostream>

#include <TGX11.h>
#include <TMutex.h>

ClassImp(MGImage);

using namespace std;
/*
class MyX11 : public TGX11
{
public:
    Display *GetDisplay() { return fDisplay; }
    Drawable GetRootWin() { return fRootWin; }
    Drawable GetVisRootWin() { return fVisRootWin; }
    Int_t    GetDepth() { return fDepth; }
};
*/

MGImage::MGImage(const TGWindow* p, UInt_t w, UInt_t h, UInt_t options, ULong_t back)
    : TGFrame(p, w, h, options, back), fWidth(w), fHeight(h)
{
    // p = pointer to MainFrame (not owner)
    // w = width of frame
    // h = width of frame

    //
    // Creat drawing semaphore
    //
    fMuxPixmap = new TMutex;

    Resize(w, h);

    //
    // create empty pixmap
    //
    fPixmap = gVirtualX->CreatePixmap(fId, fWidth, fHeight);
    fDefGC  = gVirtualX->CreateGC(fId, 0);
    fImage  = (XImage*)gVirtualX->CreateImage(fWidth, fHeight);

    cout << "Detected Color Depth: " << gVirtualX->GetDepth() << endl;
}

MGImage::~MGImage()
{
    fMuxPixmap->Lock();

    cout << "Deleting MGImage..." << endl;

    gVirtualX->DeletePixmap(fPixmap);
    gVirtualX->DeleteGC(fDefGC);
    gVirtualX->DeleteImage((Drawable_t)fImage);

    delete fMuxPixmap;

    cout << "MGImage destroyed." << endl;
}

void MGImage::DoRedraw()
{
    fMuxPixmap->Lock();

    if (TestBit(kNeedRedraw))
    {
        gVirtualX->PutImage(fId, fDefGC, (Drawable_t)fImage, 0, 0, 0, 0, fWidth, fHeight);
        ResetBit(kNeedRedraw);
    }

    fMuxPixmap->UnLock();
}

void MGImage::DrawImg16(unsigned short *d, char *s, char *e)
{
    // d=destination, s=source, e=end
    // rrrrrggg gggbbbbb
    //
    while (s<e)
    {
        //      11111100    11111000      11111100
        *d++ = (*s&0xfc) | (*s&0xf8)<<5 | (*s&0xfc)<<11;
        s++;
    }
}

void MGImage::DrawImg24(char *d, char *s, char *e)
{
    // d=destination, s=source, e=end
    // rrrrrrrr gggggggg bbbbbbbb aaaaaaaa
    //
    while (s<e)
    {
        *d++ = *s;
        *d++ = *s;
        *d++ = *s++;
        d++;
    }
}

void MGImage::DrawImg(const byte *buffer)
{
    if (fMuxPixmap->TryLock()==13)
        return;

    switch (gVirtualX->GetDepth())
    {
    case 8:
        memcpy(fImage->data, buffer, fWidth*fHeight);
        break;
    case 16:
        DrawImg16((unsigned short*)fImage->data, (char*)buffer, (char*)(buffer+fWidth*fHeight));
        break;
    case 24:
        DrawImg24(fImage->data, (char*)buffer, (char*)(buffer+fWidth*fHeight));
        break;
    default:
        cout << "Sorry, " << gVirtualX->GetDepth() << "bit color depth not yet implemented." << endl;
    }

    SetBit(kNeedRedraw);

    fMuxPixmap->UnLock();
}

void MGImage::DrawColImg16(unsigned short *d, char *s1, char *s2, char *e)
{
    // d=destination, s1=source1, s2=source2, e=end
    // d:  rrrrrggg gggbbbbb
    // s2:          00rrggbb
    //
    while (s1<e)
    {
        if (*s2)
        {    
            //      00000011   00001100        00110000
            *d++ = (*s2&0x3) | (*s2&0xb)<<3 | (*s2&0x30)<<7;
            s1++;
        }
        else
        {
            //      11111100     11111000        11111100
            *d++ = (*s1&0xfc) | (*s1&0xf8)<<5 | (*s1&0xfc)<<11;
            s2++;
        }
    }
}

void MGImage::DrawColImg24(char *d, char *s1, char *s2, char *e)
{
    // d=destination, s1=source1, s2=source2, e=end
    while (s1<e)
    {
        if (*s2)
        {
            *d++ = ((*s2>>4)&0x3)*85;
            *d++ = ((*s2>>2)&0x3)*85;
            *d++ = ((*s2++ )&0x3)*85;
            d++;
            s1++;
        }
        else
        {
            *d++ = *s1;
            *d++ = *s1;
            *d++ = *s1++;
            d++;
            s2++;
        }
    }
}

void MGImage::DrawColImg(const byte *gbuf, const byte *cbuf)
{
    if (fMuxPixmap->TryLock()==13)
        return;

    // FROM libAfterImage:
    // -------------------
    //#define ALPHA_TRANSPARENT      	0x00
    //#define ALPHA_SEMI_TRANSPARENT 	0x7F
    //#define ALPHA_SOLID            	0xFF
    // * Lowermost 8 bits - Blue channel
    // * bits 8 to 15     - Green channel
    // * bits 16 to 23    - Red channel
    // * bits 24 to 31    - Alpha channel
    //#define ARGB32_White    		0xFFFFFFFF
    //#define ARGB32_Black    		0xFF000000

    // FIXME: This loop depends on the screen color depth
    switch (gVirtualX->GetDepth())
    {
    case 16:
        DrawColImg16((unsigned short*)fImage->data, (char*)gbuf, (char*)cbuf, (char*)(gbuf+fWidth*fHeight));
        break;
    case 24:
        DrawColImg24(fImage->data, (char*)gbuf, (char*)cbuf, (char*)(gbuf+fWidth*fHeight));
        break;
    default:
        cout << "Sorry, " << gVirtualX->GetDepth() << "bit color depth not yet implemented." << endl;
    }

    SetBit(kNeedRedraw);

    fMuxPixmap->UnLock();
}
