/*************************************/
/* container_trans.cpp               */
/*                                   */
/* source for container transparency */
/*                                   */
/* loïc berthelot    janv 2004       */
/*************************************/

#include "container_trans.h"
#include "bitmap.h"
extern "C"
{
#include "osversion.h"
}
#include "container.h"
#include "colors.h"


//$LB (16/12/2003)
PtrObjBitmap LIB2DtransBkg=NULL; /* background bitmap for simulated window transparency */

PSLWA pSetLayeredWindowAttributes = NULL;
HMODULE user32DLL = NULL;
















//$LB (16/12/2003)
int InitWindowTransparency(PtrObjWindow W)
{
RECT screen;


	if (user32DLL == NULL)
	{
		if ((user32DLL = LoadLibrary ("user32")) == NULL)
		{
			MMechostr (MSKDEBUG, "\nWindows Transparency Initialization failed!... user32.dll not found...\n");
			return 0;
		}

		pSetLayeredWindowAttributes =   (PSLWA) GetProcAddress(user32DLL,"SetLayeredWindowAttributes");

		if (pSetLayeredWindowAttributes == NULL) 
		{
			MMechostr (MSKDEBUG, "\nWindows Transparency Initialization failed!... SetLayeredWindowAttributes function not found!\n");
			return 0;
		}
	}


	// LIB2D transparency bitmap background
	if (LIB2DtransBkg == NULL)
	{
	  GetWindowRect ( GetDesktopWindow () , &screen) ;

	  LIB2DtransBkg = (PtrObjBitmap) malloc (sizeof(struct ObjBitmap));
	  LIB2DtransBkg->TailleW = screen.right - screen.left;
	  LIB2DtransBkg->TailleH = screen.bottom - screen.top;
	  LIB2DtransBkg->BPP = 24;
	  LIB2DtransBkg->BytesPP = 3;

	  ObjBitmap_New (LIB2DtransBkg, NULL);
	}
	
	// update the screen capture
    CaptureScreen (LIB2DtransBkg, 0, 0, LIB2DtransBkg->TailleW, LIB2DtransBkg->TailleH);


	// window transparency buffer
	if (W != NULL)
	if (W->tBuf == NULL)
	{
		W->tBuf = (PtrObjBitmap) malloc (sizeof(struct ObjBitmap));
		W->tBuf->TailleW = W->TailleW;
		W->tBuf->TailleH = W->TailleH;
		W->tBuf->BPP = 24;
		W->tBuf->BytesPP = 3;
		W->tX = W->PosX;
		W->tY = W->PosY;

		ObjBitmap_NewDIBSection (W->tBuf, NULL);
	}

	return 1;
}





//$LB (16/12/2003)
/********************************************************/
/*                                                      */
/* int _SIMULATEcontainerTransparency                   */
/*                                                      */
/* allows to switch the transparency mode.              */
/*                                                      */
/* usefull to take a look at the graphic behaviour the  */
/* container should have if the transparency is simulated  */
/* (<=> when scol is running under Win95,98,ME)         */
/*                                                      */
/* parameters :                                         */
/*   - ObjWin container                                    */
/*   - I flag (1 : simulation ON; 0 : simulation OFF)   */
/*                                                      */
/********************************************************/
int _SIMULATEcontainerTransparency (mmachine m)
{
osinfo theOSinfo = GetOsInfo();
container* cont;
PtrObjWindow W;
HWND H;
int s, flag;


//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\n_SIMULATEcontainerTransparency");
#endif
//***********************************


    flag  = MTOI (MMpull(m));
	s      = MMpull(m) ;

    if ( s == NIL ) 
	{
		MMechostr(MSKDEBUG, "\n_SIMULATEcontainerTransparency : container is NIL!...\n");
		return MMpush ( m , NIL ) ;
	}


    if ((cont=RetrievePtrContainer(m,MTOP(s)))==NULL)
	{
		MMechostr(MSKTRACE,"_SIMULATEcontainerTransparency : container already destroyed\n");
		return MMpush ( m , NIL ) ;
	}
	else if (cont->GetPtrWindow()->parent != NULL)
	{
		W = cont->GetPtrWindow()->parent;
		H = W->WHandler;


		//
		// WinXP, Win2000
		//
		if ( ((theOSinfo &0XF0) | OS_WINDOWS) &&  (((theOSinfo &0x0F) | kOsInfoWinXp) || ((theOSinfo &0x0F) | kOsInfoWin2000)) )
		{

			if (flag == 0)
			{
				if (!InitWindowTransparency (NULL))
					return MMpush(m,NIL);

				pSetLayeredWindowAttributes (H,	_COLOR_BGR_TO_I (W->tColorB, W->tColorG, W->tColorR), W->tfactor, W->tflags);
				W->tSimulated = 0;
			}
			else
			{
				if (!InitWindowTransparency (W))
					return MMpush(m,NIL);

				pSetLayeredWindowAttributes (H,	0xCCCCCC, 255, LWA_ALPHA);
				W->tSimulated = 1;
			}


			//$LB (16/12/2003)
			//$LBDEBUG
			//$LB TODO TO DO : event if PAINTcontainer is called after that, there is no transparent blit 'til the window is moved... so what's wrong?

		}
		
		//
		// OTHER VERSIONS : nothing to do
		//

	}
	else
	{
		MMechostr (MSKDEBUG, "\n_SIMULATEcontainerTransparency : failed!... window container is NULL\n");
		return MMpush (m, NIL);
	}

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\n_SIMULATEcontainerTransparency ok");
#endif
//***********************************

	return MMpush (m, s);
    
}





//$LB (16/12/2003)
/********************************************************/
/* internal body                                        */
/*                                                      */
/* int SetWindowTransparency                            */
/*                                                      */
/* allows to set the window transparency, which can be  */
/* done with a transparency color, or with an alpha     */
/* blending factor.                                     */
/*                                                      */
/* it's fully functional with WinXP and Win2000.        */
/* With other Windows versions, we have to simulate the */
/* process with a screen capture, within the window     */
/* painting procedure.                                  */
/*                                                      */
/********************************************************/
int SetWindowTransparency (PtrObjWindow Wnd, int color, int factor, int flags)
{
HWND H = (HWND)Wnd->WHandler;


		// <=> do we have to simulate the process ?
		if (Wnd->tSimulated == 0)

		//
		// WIN XP and WIN 2K : no
		//
		{

			if (flags <=0) {flags = WN_TRANS_ALPHA; factor = 255;}

			SetWindowLong (H, GWL_EXSTYLE, GetWindowLong (H, GWL_EXSTYLE ) | WS_EX_LAYERED ) ;
			
			if (!InitWindowTransparency (Wnd))
				return 0;

			pSetLayeredWindowAttributes (H,	color, factor, flags);

		}
		
		//
		// OTHER VERSIONS : yes, transparency will be simulated in blit process
		//
		else
		{
			return 1;
		}

		return 1;
}






//$LB (16/12/2003)
/********************************************************/
/*                                                      */
/* int _SETcontainerTransparency                        */
/*                                                      */
/* allows to set the window container transparency.     */
/*                                                      */
/* use the internal SetWindowTransprency function.      */
/*                                                      */
/* parameters :                                         */
/*   - ObjWin window                                    */
/*   - I transparencyColor   [0x000000 --> 0xFFFFFF]    */
/*   - I alphaBlendingFactor [0x00 --> 0xFF]            */
/*   - I flags (WNT_COLORKEY|WNT_ALPHA)                 */
/*                                                      */
/********************************************************/
int _SETcontainerTransparency (mmachine m)
{
int s, color, factor, flags;
container* cont;
PtrObjWindow parent;


//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\n_SETcontainerTransparency");
#endif
//***********************************


    flags  = MTOI (MMpull(m));
	factor = MTOI (MMpull(m));
	color  = MTOI (MMpull(m));
	s      = MMpull(m) ;

    if ( s == NIL ) 
	{
		MMechostr(MSKDEBUG, "\n_SETcontainerTransparency : container is NIL!...\n");
		return MMpush ( m , NIL ) ;
	}

	if ((cont=RetrievePtrContainer(m,MTOP(s)))==NULL)
	{
		MMechostr(MSKTRACE,"_SETcontainerTransparency: container already destroyed\n");
		return MMpush ( m , NIL ) ;
	}
	else if (cont->GetPtrWindow()->parent != NULL)
	{
		parent = cont->GetPtrWindow()->parent;

		if (!SetWindowTransparency (parent, color, factor, flags))
			return MMpush (m, NIL);
		else 
		{
		_COLOR_I_TO_BGR (color, &(parent->tColorB), &(parent->tColorG), &(parent->tColorR));
		
		parent->tfactor = factor;
		parent->tflags = flags;


//***********************************
#if DEBUG_LIB2
MMechostr (0, "\n_SETcontainerTransparency ok");
#endif
//***********************************

		return MMpush (m, s);
		}
	}
	else
	{
		MMechostr(MSKDEBUG, "\n_SETcontainerTransparency : window container is NULL!...\n");
		return MMpush ( m , NIL ) ;
	}
    
}











//$LB (16/12/2003)
/*****************************************/
/* TransparentBlitBuffer                 */
/*                                       */
/* now, scol windows can be transparent. */
/* if Win95/98/ME, we have to simulate   */
/* the transparency.                     */
/*                                       */
/*****************************************/
//                                                window :
//                                                ---------------------------
//                                                |     zone1               |
//$LB (16/12/2003)                                |      ----------         |
//                                                | zone2| bmp    |  zone3  |  
// here we have to simulate the transparency      |      |        |         |
//                                                |      ----------         |
//                                                |     zone4               |
//                                                ---------------------------
//
//
int WindowScolWin::TransparentBlitBuffer (CObjBufferWindows* CoBuffer, int buff, int PosX,int PosY,int dw,int dh,int sx,int sy)
{
HDC Dcw,Dcbuf;
HBITMAP OldBuf;
WINDOWPLACEMENT pwi;
OBJBITMAP_BUFFER bmp;
OBJBITMAP_BUFFER bkg;
OBJBITMAP_BUFFER buf;
int j, i, restbmp, restbuf, restbkg; // windows bitmap are 32bits aligned
register unsigned char db, dg, dr, sb, sg, sr;
int BytesPP=3;
//
// for clipping
//
int bkgX, bkgY, bufX, bufY, bmpX, bmpY;
int bkgW, bkgH, bufW, bufH, bmpW, bmpH, MAXW, MAXH; 
int winW, winH;



			  // get actual window location
			  pwi.length = sizeof (WINDOWPLACEMENT);
			  GetWindowPlacement (this->parent->WHandler, &pwi);
			  this->parent->tX = pwi.rcNormalPosition.left;
			  this->parent->tY = pwi.rcNormalPosition.top;

			  MAXW = this->parent->tBkg->TailleW;  MAXH = this->parent->tBkg->TailleH;

			  winW = this->parent->TailleW;        winH = this->parent->TailleH;
 
			  bmpX = sx; bmpY = sy; bmpW = dw; bmpH = dh;
			  bufX = PosX; bufY = PosY; bufW = dw; bufH = dh;
			  bkgX = this->parent->tX; bkgY = this->parent->tY; bkgW = dw; bkgH = dh;



			//$LBDEBUG
			  /*
			  MMechostr(MSKDEBUG, "\nPAINT_CONTAINER_TRANSBLIT tx %d   ty %d\nPosX %d    PosY %d    dw %d     dh %d      sx %d     sy %d\n",
				this->parent->tX, this->parent->tY, PosX, PosY, dw, dh, sx, sy); 
				*/


			  //$LB (16/12/2003)
			  //$LBDEBUG
			  //$LB TO DO TODO : clip coordinates. there is a bug about dw (dh?) when window is outside the screen
			  // the bug seems to come from the redrawArea in HdlPaint Callback.
			  // now we just get out of blit process if window is outside the screen, 
			  // to do : process blit when window is outside the screen, in clipping coordinates, and in hacking the bug
			  if ((this->parent->tX < 0) || (this->parent->tY < 0) || (this->parent->tX+winW-1 >= MAXW) || (this->parent->tY+winH-1 >= MAXH)
				   || (PosX+dw >this->parent->TailleW) || (PosY+dh >this->parent->TailleH))
				  return 0;

			  // 
			  // clipping coordinates
			  //
			  /*			  
			  if ((this->parent->tX+PosX) <0) 
			  { 
				bkgX    = 0;  bkgW = dw + this->parent->tX + PosX;
				bufX    = -this->parent->tX +PosX; bufW = dw + this->parent->tX + PosX;
				bmpX    = -this->parent->tX; bmpW = dw + this->parent->tX +sx;
				
			  }
			  else if (this->parent->tX+winW > MAXW)
			  {
				bkgX = this->parent->tX; bkgW = winW - (bkgX + winW - MAXW);
				bufX = 0; bufW = winW - (bkgX + winW - MAXW);
			  }
			  */




			  // 
			  // BLIT BITMAP
			  //
			  buf = (OBJBITMAP_BUFFER) (this->parent->tBuf->bits + bufY*this->parent->tBuf->BPL       + bufX*BytesPP);
			  bmp = (OBJBITMAP_BUFFER) (CoBuffer->WinBmp         + bmpY*CoBuffer->WinBitsBitmapLength + bmpX*BytesPP);
			  bkg = (OBJBITMAP_BUFFER) (this->parent->tBkg->bits + bkgY*this->parent->tBkg->BPL       + bkgX*BytesPP);
			  restbuf = this->parent->tBuf->BPL       - (bufW*BytesPP);      
			  restbmp = CoBuffer->WinBitsBitmapLength - (bmpW*BytesPP);
			  restbkg = this->parent->tBkg->BPL       - (bkgW*BytesPP);

			  for (j=0; j < bmpH; j++, bmp+=restbmp, buf+=restbuf, bkg+=restbkg)
			  {
			      
				  for (i=0; i < bmpW; i++, bmp+=BytesPP, buf+=BytesPP, bkg+=BytesPP)				  
				  {

						// if the color is the transparency color 
						if (  (this->parent->tflags & WN_TRANS_COLOR)  &&  ((*bmp) == this->parent->tColorB)  &&  ((*(bmp+1)) == this->parent->tColorG)  &&  ((*(bmp+2)) == this->parent->tColorR)  )

						// blit WindowBuffer <--- BackgroundBitmap
						{				
						    (*buf) = (*bkg); *(buf+1) = *(bkg+1); *(buf+2) = *(bkg+2);
						}

						// else if there an alpha blending factor
						else if (this->parent->tflags & WN_TRANS_ALPHA)

						// alphablit WindowBuffer <-- (background, Image)
						{
							db = *(bkg); dg = *(bkg+1); dr = *(bkg+2);
							sb = *(bmp); sg = *(bmp+1); sr = *(bmp+2);

							if (this->parent->tfactor == 0)
							{
								(*buf) = db; *(buf+1) = dg; *(buf+2) = dr;
							}
							if (this->parent->tfactor == 255)
							{
								(*buf) = sb; *(buf+1) = sg; *(buf+2) = sr;
							}
							else
							{
							    (*buf)   = db + this->parent->tfactor * (sb - db) / 255;
								*(buf+1) = dg + this->parent->tfactor * (sg - dg) / 255;
								*(buf+2) = dr + this->parent->tfactor * (sr - dr) / 255;
							}
						}

						// else simply blit WindowBuffer <-- Image
						else
						{ (*buf) = (*bmp); *(buf+1) = *(bmp+1); *(buf+2) = *(bmp+2); }

					
				  } // end i
			  }     // end j


			  //
			  // FINAL STAGE : blit Window <-- WindowBuffer
			  //
				Dcw = GetDC (Whwnd) ;
				Dcbuf = CreateCompatibleDC (Dcw) ;
				OldBuf    = (HBITMAP)SelectObject ( Dcbuf, this->parent->tBuf->DIBhandler);
				
				BitBlt ( Dcw, PosX, PosY, dw,  dh, Dcbuf, sx, sy, SRCCOPY);

				SelectObject ( Dcbuf , OldBuf ) ;
				DeleteDC ( Dcbuf ) ; 
				ReleaseDC (Whwnd, Dcw);
		  

  return 0;
}



