/******************************************************************************************/
/*                                                                                        */
/*  bitmap.c                                                                              */
/*                                                                                        */
/*  Implementation des fonctions du packages Bitmap.pkg                                   */
/*                                                                                        */
/******************************************************************************************/


//
// Modifications History
//
//$ LB (13/06/2002) : -- added a objbitmap handler counter : "ObjBitmapHandler"
//
//					  -- added ObjBitmap_GetNewHandler function : return a valid handler for a new ObjBitmap
//
//                    -- NewObjBitmap function ==> ObjBitmap_New : don't create a DIBSection anymore, when creating 
//                       an ObjBitmap. Alloc memory for buffer and palette. The DIBSection will be create later if needed.
//
//                    -- added ObjBitmap_CreateDIBsection function : create DIBSection from the bitmap buffer
//
//                    -- added calls to ObjBitmap_CreateDIBSection, in order to ensure the compatibility with the older system.
//                       next stage : suppr those calls where the DIBSection management can be replaced by a manual management of the bitmap buffer
//
//
//$LB (15/12/2002) : 16bits to 24bits
//
//$LB (07/02/2003) : flags debug
//
//$ LB (21/07/2003) : ObjBitmap_New and ObjBitmap_CreateDIBSection functions had to be moved 
//                    from lib2d OS to kernel sources, in order to control memory usage without crash
//
//$LB (22/07/2003) : add _DIBbitmap to easy the process of Multimedia objects
//
//$LB (11/12/2003) : add _DRAWgradient to draw a gradient color into a bitmap
//
//$LB (12/12/2003) : add _BLURbitmap to process a gaussian blur into a bitmap
//
//$LB (14/12/2003) : add _CAPTUREscreen to capture a screen area into a bitmap
//
//$LB (15/12/2003) : add _CRmaskFromBitmap to create an grayscale alpha mask from a bitmap
//
//$LB (16/12/2003) : BlitBitmap : now process window transparency simulation (Win95,98,ME,NT)
//
//$LB (10/05/2004) : fixed float number reading in GRMulBitmap
//
//$LB (10/05/2004)2 : add _GETbitmapBGR, _SETbitmapBGR, _STEREObitmap
//

#include <windows.h>
#include <wingdi.h>

#include "x/Version.h"
#include "x/scolplugin.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "objstr.h"

#include "loadbmp.h"
#include "scolsys.h"
#include "colors.h"
#include "macros.h"
#include "objects/win.h"
#include <math.h>
#include "objects/win_trans.h"
 




/**************************************************************************************************/
/*                                                                                                */
/* D A T A                                                                                        */
/*                                                                                                */
/**************************************************************************************************/



typedef struct BitmapInfo2
{
    BITMAPINFO Bit ;
    RGBQUAD Quad [ 256 ] ;
} BitmapInfo2 ;

typedef struct LPalette2
{
    WORD    Version ;
    WORD    ColorNum ;
    PALETTEENTRY Colors [256 ] ;
} LPalette ;


int ObjBitmap_CreateDIBSection (PtrObjBitmap B);

int GenericCreateBitmap ( mmachine m , int BPP );

void SetBitmapPalette ( PtrObjBitmap B , PtrPalette P ) ;

/**************************************************************************************************/
/*                                                                                                */
/* B O D Y                                                                                        */
/*                                                                                                */
/**************************************************************************************************/


//int ObjBitmap_New ( PtrObjBitmap B , PtrPalette P );

//int GREmptyBuffer ( mmachine m );




//$LB (10/05/2004)2 : add _GETbitmapBGR
//**************************************
//
// _GETbitmapBGR
//
// fun [Chn ObjBitmap] [ObjBitmap8 ObjBitmap8 ObjBitmap8]
//
//**************************************
//
int _GETbitmapBGR (mmachine m)
{
int chn,s,i,j,rest,rest8;
PtrObjBitmap B;
PtrObjVoid   O;
OBJBITMAP_BUFFER pB;
OBJBITMAP_BUFFER pBB;
OBJBITMAP_BUFFER pBG;
OBJBITMAP_BUFFER pBR;
struct Palette Pal;


  // init bitmap8 palette
  for (i=0; i < 256; i++)
  {Pal.B[i] = i; Pal.G[i] = i; Pal.R[i] = i;}

  
  s   = MMpull(m);     // bitmap
  chn = MMpull(m);     // channel

  if (s == NIL)
  {
	MMechostr(0, "\n_GETbitmapBGR : bitmap is NIL!\n");
	return MMpush (m, NIL);
  }

  s>>=1;
  
  // get bitmap data
  O = ( PtrObjVoid ) MMstart(m,s) ;    
  B = ( PtrObjBitmap ) MMstart(m, (O->Buffer>>1) ) ;
  pB = B->bits;

  // windows bitmap are 32bits aligned
  rest = B->BPL - (B->TailleW * B->BytesPP);

  // create 3 objBitmap8
  if ( MMpush(m, chn)) return MERRMEM ;
  if ( MMpush(m, B->TailleW<<1)) return MERRMEM ;
  if ( MMpush(m, B->TailleH<<1)) return MERRMEM ; 
  // create red buffer
  GenericCreateBitmap (m, 8);

  if ( MMpush(m, chn)) return MERRMEM ;
  if ( MMpush(m, B->TailleW<<1)) return MERRMEM ;
  if ( MMpush(m, B->TailleH<<1)) return MERRMEM ; 
  // create green buffer
  GenericCreateBitmap (m, 8);
   
  if ( MMpush(m, chn)) return MERRMEM ;
  if ( MMpush(m, B->TailleW<<1)) return MERRMEM ;
  if ( MMpush(m, B->TailleH<<1)) return MERRMEM ; 
  // create blue buffer
  GenericCreateBitmap (m, 8);
 
 
   // get first bitmap8 data
   s = MMget(m, 0)>>1;
   O = ( PtrObjVoid ) MMstart(m, s) ;    
   B = ( PtrObjBitmap ) MMstart(m, (O->Buffer>>1) ) ;
   // init bitmap8 palette
   SetBitmapPalette (B, &Pal);
   pBR = B->bits;


   // get second bitmap8 data
   s = MMget(m, 1)>>1;
   O = ( PtrObjVoid ) MMstart(m, s) ;    
   B = ( PtrObjBitmap ) MMstart(m, (O->Buffer>>1) ) ;
   // init bitmap8 palette
   SetBitmapPalette (B, &Pal);
   pBG = B->bits;


   // get third bitmap8 data
   s = MMget(m, 2)>>1;
   O = ( PtrObjVoid ) MMstart(m, s) ;    
   B = ( PtrObjBitmap ) MMstart(m, (O->Buffer>>1) ) ;
   // init bitmap8 palette
   SetBitmapPalette (B, &Pal);
   pBB = B->bits;

   //bitmap windows are 32bits aligned
   rest8 = B->BPL - B->TailleW;

   //
   // process color separation
   //
   for (j=0; j < B->TailleH; j++, pB+=rest, pBB+=rest8, pBG+=rest8, pBR+=rest8)  
	   for (i=0; i < B->TailleW; i++)
	   {
		   *(pBB++) = *(pB++);
		   *(pBG++) = *(pB++);
		   *(pBR++) = *(pB++);
	   }


	// build 3-tuple
	if ( MMpush(m, 3<<1)) return MERRMEM ;
    return MBdeftab( m );

}







//$LB (10/05/2004)2 : add _SETbitmapBGR
//**************************************
//
// _SETbitmapBGR
//
// fun [ ObjBitmap [ObjBitmap8 ObjBitmap8 ObjBitmap8]] I
//
//**************************************
//
int _SETbitmapBGR (mmachine m)
{
int s, s1, s2, s3, i, j, rest, rest8;
int w, w1, w2, w3, h, h1, h2, h3;
PtrObjVoid O;
PtrObjBitmap B;
OBJBITMAP_BUFFER pB;
OBJBITMAP_BUFFER pBB;
OBJBITMAP_BUFFER pBG;
OBJBITMAP_BUFFER pBR;

  s = MMpull(m);

  if (s == NIL)
  {
	  MMechostr(0, "\n_SETbitmapBGR : ObjBitmap8 tuple is NIL!\n");
	  MMset (m, 0, NIL);
	  return 0;
  }

  // get objBitmap8 objects 
  s1 = MMfetch(m, s>>1, 0);
  s2 = MMfetch(m, s>>1, 1);
  s3 = MMfetch(m, s>>1, 2);

  if ( (s1 == NIL) || (s2 == NIL) || (s3 == NIL) )
  {
	  MMechostr(0, "\n_SETbitmapBGR : at least one of the ObjBitmap8 objects is NIL!\n");
	  MMset (m, 0, NIL);
	  return 0;
  }

  // get blue Bitmap8 data
  O = ( PtrObjVoid ) MMstart(m, s1>>1) ;    
  B = ( PtrObjBitmap ) MMstart(m, (O->Buffer>>1) ) ;
  w1 = B->TailleW; h1 = B->TailleH;
  pBB = B->bits;

  // get green Bitmap8 data
  O = ( PtrObjVoid ) MMstart(m, s2>>1) ;    
  B = ( PtrObjBitmap ) MMstart(m, (O->Buffer>>1) ) ;
  w2 = B->TailleW; h2 = B->TailleH;
  pBG = B->bits;

  // get red Bitmap8 data
  O = ( PtrObjVoid ) MMstart(m, s3>>1) ;    
  B = ( PtrObjBitmap ) MMstart(m, (O->Buffer>>1) ) ;
  w3 = B->TailleW; h3 = B->TailleH;
  pBR = B->bits;

  // windows bitmap are 32bits aligned
  rest8 = B->BPL - B->TailleW;


  // get ObjBitmap object
  s = MMpull(m);
  if (s == NIL)
  {
	  MMechostr(0, "\n_SETbitmapBGR : ObjBitmap object is NIL!\n");
	  return MMpush (m, NIL);
  }

  // get Bitmap data
  O = ( PtrObjVoid ) MMstart(m, s>>1) ;    
  B = ( PtrObjBitmap ) MMstart(m, (O->Buffer>>1) ) ;
  w = B->TailleW; h = B->TailleH;
  pB = B->bits;  



  // check bitmaps size : it must be the same size
  if ( ! ((w == w1) && (w1 == w2) && (w2 == w3) && (h == h1) && (h1 == h2) && (h2 == h3)) )
  {
	  MMechostr(0, "\n_SETbitmapBGR error : all bitmap objects must have the same size!! \n sizes : (%d x %d) [(%d x %d) (%d x %d) (%d x %d)]\n", 
		        w, h, w1, h1, w2, h2, w3, h3);
	  return MMpush (m, NIL);
  }
  
  // windows bitmap are 32bits aligned
  rest = B->BPL - (B->TailleW * B->BytesPP);

  //
  // process color mix
  //
  for (j=0; j < B->TailleH; j++, pB+=rest, pBB+=rest8, pBG+=rest8, pBR+=rest8)  
	   for (i=0; i < B->TailleW; i++)
	   {
		   *(pB++) = *(pBB++);
		   *(pB++) = *(pBG++);
		   *(pB++) = *(pBR++);
	   }
	   

  // return objbitmap object
  return MMpush(m,s);
}




//$LB (10/05/2004)2 : add _STEREObitmap
//**************************************
//
// _STEREObitmap
//
// <=> _GETbitmapBGR bmpLEFT; 
//     _GETbitmapBGR bmpRIGHT; 
//     _SETbitmapBGR bmp3 [bLEFT gLEFT rRIGHT]
//
// fun [ObjBitmap(1) ObjBitmap(2) ObjBitmap(3)] ObjBitmap(1)
//
//**************************************
//
int _STEREObitmap (mmachine m)
{
int i, j, s, rest;
int wd, wl, wr, hd, hl, hr;
PtrObjVoid O;
PtrObjBitmap B;
OBJBITMAP_BUFFER dst;
OBJBITMAP_BUFFER left;
OBJBITMAP_BUFFER right;

  
  ///////////////////////////////////////
  //
  // check right bitmap
  //
  s = MMpull (m);

  if (s == NIL)
  {
    MMechostr(0, "\n_STEREObitmap  : second source bitmap is NIL!\n");
	MMpull(m);
	MMset(m, 0, NIL);
	return 0;
  }

  // get right bitmap buffer
  O = ( PtrObjVoid ) MMstart(m, s>>1) ;    
  B = ( PtrObjBitmap ) MMstart(m, (O->Buffer>>1) ) ;
  wr = B->TailleW; hr = B->TailleH;
  right = B->bits; 

  
  ///////////////////////////////////////
  //
  // check left bitmap
  //
  s = MMpull (m);

  if (s == NIL)
  {
    MMechostr(0, "\n_STEREObitmap  : first source bitmap is NIL!\n");
	MMset(m, 0, NIL);
	return 0;
  }

  // get left bitmap buffer
  O = ( PtrObjVoid ) MMstart(m, s>>1) ;    
  B = ( PtrObjBitmap ) MMstart(m, (O->Buffer>>1) ) ;
  wl = B->TailleW; hl = B->TailleH;
  left = B->bits; 


  ///////////////////////////////////////
  //
  // check destination bitmap
  //
  s = MMpull (m);

  if (s == NIL)
  {
    MMechostr(0, "\n_STEREObitmap  : destination bitmap is NIL!\n");
	return MMpush(m, NIL);
  }

  // get destination bitmap buffer
  O = ( PtrObjVoid ) MMstart(m, s>>1) ;    
  B = ( PtrObjBitmap ) MMstart(m, (O->Buffer>>1) ) ;
  wd = B->TailleW; hd = B->TailleH;
  dst = B->bits; 



  // check bitmaps size : they must have the same size!
  if ( ! ((wd == wl) && (wl == wr) && (hd == hl) && (hl == hr)) )
  {
    MMechostr(0, "\n_STEREObitmap  error : all bitmap objects must have the same size!!\nsizes : (%d x %d) (%d x %d) (%d x %d)\n", 
		      wd, hd, wl, hl, wr, hr);
	return MMpush(m, NIL);

  } 


  // windows bitmaps are 32bits aligned
  rest = B->BPL - (B->TailleW * B->BytesPP);


  ///////////////////////////////////////
  //
  // process color mix
  //
  for (j=0; j < B->TailleH; j++, dst+=rest, left+=rest, right+=rest)
	  for (i=0; i < B->TailleW; i++, left++, right+=3)
	  {
		*(dst++) = *(left  ++);
		*(dst++) = *(left  ++);
		*(dst++) = *(right +2);
	  }
  

  // return destination bitmap
  return MMpush(m, s);
}



//$LB (15/12/2003)
/********************************************************/
/* fun [Chn ObjBitmap I I] ObjBitmap8                   */
/*                                                      */
/* int _CRmaskFromBitmap                                */
/*                                                      */
/* create a bitmap8 alpha mask, from the bitmap object, */
/* in converting bitmap colors into black or white      */
/* the palette of the bitmap8 object is init. as a      */
/* grayscale palette.                                   */
/*                                                      */
/* scol parameters are :                                */
/*  - Chn channel                                       */
/*  - ObjBitmap bmp                                     */
/*  - I I whiteColor, blackColor                        */
/*                                                      */
/********************************************************/

int _CRmaskFromBitmap (mmachine m)
{
    PtrObjVoid O,O8 ;
    PtrObjBitmap B,B8 ;
	OBJBITMAP_BUFFER buf;
	OBJBITMAP_BUFFER buf8;
    int s, s8, color, blackColor, whiteColor, rest, rest8, i, j, tmp_res;
	struct Palette pal;

	// stack state : channel bitmap whiteC blackC 
	blackColor = MTOI (MMpull(m));
	whiteColor = MTOI (MMpull(m));
	// stack state : channel bitmap
	INVERT(m,0,1);
	// stack state : bitmap channel 
	s = MMget (m, 1);

	if (s == NIL)
	{
        MMechostr ( 1 , "_CRmaskFromBitmap : Bitmap object is NIL\n" ) ;
	}
	else
	{

		O = ( PtrObjVoid ) MMstart(m,(s>>1) ) ;    
        B = ( PtrObjBitmap ) MMstart(m, (O->Buffer>>1) ) ;

		
		// store parameters for _CRbitmap8
		if ( MMpush(m,B->TailleW<<1)) return MERRMEM ;
		if ( MMpush(m,B->TailleH<<1)) return MERRMEM ; 

		// stack state : bitmap channel width height
		// create the 8bits bitmap
		GenericCreateBitmap (m, 8);

		// stack state : bitmap bitmap8
		s8 = MMpull(m);
		if (s8 == NIL) { MMechostr (1, "_CRmaskFromBitmap creation of Bitmap8 failed!\n"); return MERRMEM;}

		// get the 8bits bitmap buffer
		O8 = ( PtrObjVoid ) MMstart(m,(s8>>1) ) ;    
        B8 = ( PtrObjBitmap ) MMstart(m, (O8->Buffer>>1) ) ;

		// set the palette of the bitmap8 object : a grayscale palette
		for (i=0; i < 256; i++)
		{ pal.R[i] = i; pal.G[i] = i; pal.B[i] = i; }
		SetBitmapPalette (B8 , &pal) ;

		// get the 8bits bitmap buffer
		buf8 = (OBJBITMAP_BUFFER) B8->bits;
		rest8 = B8->BPL - (B8->TailleW * B8->BytesPP);

		// get the 24bits bitmap buffer
		s = MMpull(m);
        O = ( PtrObjVoid ) MMstart(m,(s>>1) ) ;    
        B = ( PtrObjBitmap ) MMstart(m, (O->Buffer>>1) ) ;
		buf = (OBJBITMAP_BUFFER) B->bits;
		rest = B->BPL - (B->TailleW * B->BytesPP);


		// if whiteColor and blackColor are both NIL, take the color of first pixel as blackColor, 
		// and all the rest as whiteColor 
		if ((whiteColor <0) && (blackColor <0))
		{
		  blackColor = ((B->bits[0]<<16) &0xFF0000) | ((B->bits[1]<<8) &0xFF00) | (B->bits[2] &0xFF);
		}


		//
		// for ALL pixels
		//
		for (j=0; j < B->TailleH; j++, buf += rest, buf8 += rest8)
		
			for (i=0; i < B->TailleW; i++, buf+=B->BytesPP, buf8++)
			{
				// get the pixel color
				color = (((*(buf+0)) <<16)&0xFF0000) | (((*(buf+1)) <<8)&0xFF00) | ((*(buf+2))&0xFF);

				if ((color == whiteColor) || ((color != blackColor) && (whiteColor <0)))
				 (*buf8) = 0xFF; 
                else
				 (*buf8) = 0x00; 
			}

	}

	// return bitmap object
    if ( MMpush(m,s8 )) return MERRMEM ;
	return 0;
} 





void CaptureScreen (PtrObjBitmap B, int x, int y, int w, int h)
{
HDC         hScrDC, hMemDC;         // screen DC and memory DC     
int         wScrn, hScrn;           // screen resolution      
HGDIOBJ     hOldBitmap;


	   // make sure the bitmap object is an Device Independant Bitmap
       ObjBitmap_CreateDIBSection (B);

	   // create a DC for the screen and create     
	   // a memory DC compatible to screen DC          
       hScrDC = CreateDC("DISPLAY", NULL, NULL, NULL);     
       hMemDC = CreateCompatibleDC(hScrDC);      // get points of rectangle to grab  

		//
        // clipping according to the Screen Resolution 
		//
        wScrn = GetDeviceCaps(hScrDC, HORZRES);     
        hScrn = GetDeviceCaps(hScrDC, VERTRES);      

        if (w > wScrn) w = wScrn;
		if (h > hScrn) h = hScrn;
		if (x+w > wScrn) w = wScrn-x;
		if (y+h > hScrn) h = hScrn-y;


   
       // select new bitmap into memory DC     
       hOldBitmap =   SelectObject (hMemDC, B->DIBhandler);      
   
       // bitblt screen DC to memory DC     
       BitBlt(hMemDC, 0, 0, w, h, hScrDC, x, y, SRCCOPY);     
   
       // select old bitmap back into memory DC and get handle to     
       // bitmap of the screen          
       B->DIBhandler = SelectObject(hMemDC, hOldBitmap);      
   
       // clean up      
       DeleteDC(hScrDC);     
       DeleteDC(hMemDC);      
}




// 
//$LB (11/12/2003)
/********************************************************/
/* fun [ObjBitmap I I I I] ObjBitmap                    */
/*                                                      */
/* int _CAPTUREscreen                                   */
/*                                                      */
/* capture the screen area into the bitmap              */
/*                                                      */
/* scol parameters are :                                */
/*  - ObjBitmap bmp                                     */
/*  - I I       x, y                                    */
/*  - I I       w, h                                    */
/*                                                      */
/********************************************************/
int _CAPTUREscreen (mmachine m)
{
    PtrObjVoid O ;
    PtrObjBitmap B ;
    int s, x, y, w, h, k;


    h      = MTOI (MMpull (m));
    w      = MTOI (MMpull (m));
    y      = MTOI (MMpull (m)); 
    x      = MTOI (MMpull (m));

    s = MMpull ( m ) ;  
	

    if ( s == NIL )
    {
        MMechostr ( 1 , "_CAPTUREscreen : Bitmap object is NIL\n" ) ;
    } 
    else
    {
        O = ( PtrObjVoid ) MMstart(m,(s>>1) ) ;    
        B = ( PtrObjBitmap ) MMstart(m, (O->Buffer>>1) ) ;
		
		//
		// clipping according to the bitmap object
		//
		if (x < 0) x=0; if (y< 0) y=0;
		if ((w <=0) || (h <=0))
		{
			k = (MMpush(m,NIL));
			return k;
		}
		if (w > B->TailleW) w = B->TailleW;
		if (h > B->TailleH) h = B->TailleH;
 

		CaptureScreen (B, x, y, w, h);
   
 	}

	// return bitmap object
    if ( MMpush(m,s )) return MERRMEM ;
	return 0;
}







//$LB (11/12/2003)
/********************************************************/
/* fun [ObjBitmap I I I I I I I] [ObjBitmap]            */
/*                                                      */
/* int _DRAWgradient                                    */
/*                                                      */
/* draw a color gradient into the bitmap                */
/*                                                      */
/* scol parameters are :                                */
/*  - ObjBitmap bmp                                     */
/*  - I I       x, y                                    */
/*  - I I       w, h                                    */
/*  - I I       color1, color2                          */
/*  - I         angle (in degrees <=> [0, 360])         */
/*                                                      */
/********************************************************/
int _DRAWgradient (mmachine m)
{
    PtrObjVoid O ;
    PtrObjBitmap B ;
    int s, angle, color2, color1, w, h, x, y;
	int x1, x2, y1, y2, incrX, incrY, multX, multY, plusX, plusY;
	int r1, r2, g1, g2, b1, b2, rDiff, gDiff, bDiff;
	int i,j, offset;
	OBJBITMAP_BUFFER bits;
	double rf, gf, bf, p1, p2;



    angle  = MTOI (MMpull (m));
	color2 = MTOI (MMpull (m));
    color1 = MTOI (MMpull (m));
    h      = MTOI (MMpull (m));
    w      = MTOI (MMpull (m));
    y      = MTOI (MMpull (m)); 
    x      = MTOI (MMpull (m));

    s = MMpull ( m ) ;  
	


    if ( s == NIL )
    {
        MMechostr ( 1 , "_DRAWgradient : Bitmap object is NIL\n" ) ;
    } 
    else
    {
        O = ( PtrObjVoid ) MMstart(m,(s>>1) ) ;    
        B = ( PtrObjBitmap ) MMstart(m, (O->Buffer>>1) ) ;

		bits = (OBJBITMAP_BUFFER)B->bits;

		//
		// clipping
		//

		if (x <0) x=0; if (x >= B->TailleW) x = B->TailleW-1;
		if (y <0) y=0; if (y >= B->TailleH) y = B->TailleH-1;
		if (w <0) w=0; if (w > B->TailleW) w = B->TailleW;
		if (h <0) h=0; if (h > B->TailleH) h = B->TailleH;
		if ((x+w) > B->TailleW) w = B->TailleW - x;
		if ((y+h) > B->TailleH) h = B->TailleH - y;
		 

		angle = angle % 360;
		if (angle < 0) angle = 360 - angle;

		if ((angle >= 0) && (angle <= 90))
		{
           x1 = x; x2 = x+w-1; incrX = 1; multX = 1; plusX = 0;
		   y1 = y; y2 = y+h-1; incrY = 1; multY = 1; plusY = 0;
		   angle = angle;
		}
		else if ((angle > 90) && (angle <180))
		{
           x1 = x+w-1; x2 = x;     incrX = (-1); multX = (-1); plusX = x+w-1;
		   y1 = y;     y2 = y+h-1; incrY = 1;    multY = 1;    plusY = 0;
		   angle = 180-angle;

		}
		else if ((angle >= 180) && (angle <= 270))
		{
			x1 = x+w-1; x2 = x; incrX = (-1); multX = (-1); plusX = x+w-1;
			y1 = y+h-1; y2 = y; incrY = (-1); multY = (-1); plusY = y+h-1;
			angle = angle-180;
		}
		else
		{
			x1 = x;     x2 = x+w-1; incrX = 1;    multX = 1;    plusX = 0;
			y1 = y+h-1; y2 = y;     incrY = (-1); multY = (-1); plusY = y+h-1;
			angle = 360-angle;
		}

		x2 += incrX;
		y2 += incrY;


  	    // get the colors components 
  	    b1 = (color1>>16)&0xFF; g1 = (color1>>8)&0xFF; r1 = color1&0xFF;
  	    b2 = (color2>>16)&0xFF; g2 = (color2>>8)&0xFF; r2 = color2&0xFF;
  	    rDiff = r2 - r1; gDiff = g2 - g1; bDiff = b2 - b1;
  	    
		// compute color percentages, from the angle value
  	    p2 = (double)((angle * 100.0f) / 90.0f);
     	p1 = (double)(100 - p2);

		// now, w and h are the number of pixels "divisions"
		w--; h--; 

		// draw the gradient
		i=x1;
		while (i != x2)
		{
			j=y1;
			while (j != y2)
			{
				offset = j*B->BPL + i*B->BytesPP;
		
				bf = (double) (((b1+(bDiff*(i*multX + plusX)) /w) *p1) /100.0f) + (((b1+(bDiff*(j*multY + plusY)) /h) *p2) /100.0f);
				gf = (double) (((g1+(gDiff*(i*multX + plusX)) /w) *p1) /100.0f) + (((g1+(gDiff*(j*multY + plusY)) /h) *p2) /100.0f);
				rf = (double) (((r1+(rDiff*(i*multX + plusX)) /w) *p1) /100.0f) + (((r1+(rDiff*(j*multY + plusY)) /h) *p2) /100.0f);

				bits[offset + 0] = ((int)bf) %256;
				bits[offset + 1] = ((int)gf) %256;
				bits[offset + 2] = ((int)rf) %256;
 
				j+=incrY;
			}

			i+=incrX;
		}
		
    } 


    if ( MMpush(m,s )) return MERRMEM ;
	return 0;
}








/*****************************************************************/
/* internal body                                                 */
/*                                                               */
/*                                                               */
/* utils for the gaussian blur function                          */
/*****************************************************************/



void  pixel_region_set_row (PtrObjBitmap srcR,  OBJBITMAP_BUFFER src, int row, int x, int width)
{
int i, offset;

  for (i = 0; i < width; i++)
  {
	offset = row*srcR->BPL + (x+i)*srcR->BytesPP;
	  
	srcR->bits [offset + 0] = *(src++);
	srcR->bits [offset + 1] = *(src++);
	srcR->bits [offset + 2] = *(src++);
  }
}

void  pixel_region_set_col (PtrObjBitmap srcR, OBJBITMAP_BUFFER src, int col, int y, int height)
{
int i, offset;
  for (i = 0; i < height; i++)
  {
    offset = col*srcR->BytesPP + (y+i)*srcR->BPL;
	srcR->bits [offset + 0] = *(src++);
	srcR->bits [offset + 1] = *(src++);
	srcR->bits [offset + 2] = *(src++) ;
  }
}


void  pixel_region_get_row (PtrObjBitmap srcR, OBJBITMAP_BUFFER src, int row, int x, int width)
{
int i, offset;

  for (i = 0; i < width; i++)
  {
	offset = row*srcR->BPL + (x+i)*srcR->BytesPP;
	  
	*(src++) = srcR->bits [offset + 0];
	*(src++) = srcR->bits [offset + 1];
	*(src++) = srcR->bits [offset + 2];
  }
}


void  pixel_region_get_col (PtrObjBitmap srcR, OBJBITMAP_BUFFER src, int col, int y, int height)
{
int i, offset;
  for (i = 0; i < height; i++)
  {
    offset = col*srcR->BytesPP + (y+i)*srcR->BPL;
	*(src++) = srcR->bits [offset + 0]; 
	*(src++) = srcR->bits [offset + 1];
	*(src++) = srcR->bits [offset + 2];
  }
}



static void transfer_pixels (double *src1, double *src2, OBJBITMAP_BUFFER dest, int bytes, int width)
{
  int b;
  int bend = bytes * width;
  double sum;

  for(b = 0; b < bend; b++)
    {
      sum = *src1++ + *src2++;
      if (sum > 255) sum = 255;
      else if(sum < 0) sum = 0;
	  
      *dest++ = (unsigned char) sum;
    }
}


#define PI 3.1415

static void
find_constants (double n_p[], double n_m[], double d_p[], double d_m[], double bd_p[], double bd_m[], double std_dev)
{
  int i;
  double constants [8];
  double div;

  /*  The constants used in the implemenation of a casual sequence
   *  using a 4th order approximation of the gaussian operator
   */

  div = sqrt(2 * PI) * std_dev;
  constants [0] = -1.783 / std_dev;
  constants [1] = -1.723 / std_dev;
  constants [2] = 0.6318 / std_dev;
  constants [3] = 1.997  / std_dev;
  constants [4] = 1.6803 / div;
  constants [5] = 3.735 / div;
  constants [6] = -0.6803 / div;
  constants [7] = -0.2598 / div;

  n_p [0] = constants[4] + constants[6];
  n_p [1] = exp (constants[1]) *
    (constants[7] * sin (constants[3]) -
     (constants[6] + 2 * constants[4]) * cos (constants[3])) +
       exp (constants[0]) *
	 (constants[5] * sin (constants[2]) -
	  (2 * constants[6] + constants[4]) * cos (constants[2]));
  n_p [2] = 2 * exp (constants[0] + constants[1]) *
    ((constants[4] + constants[6]) * cos (constants[3]) * cos (constants[2]) -
     constants[5] * cos (constants[3]) * sin (constants[2]) -
     constants[7] * cos (constants[2]) * sin (constants[3])) +
       constants[6] * exp (2 * constants[0]) +
	 constants[4] * exp (2 * constants[1]);
  n_p [3] = exp (constants[1] + 2 * constants[0]) *
    (constants[7] * sin (constants[3]) - constants[6] * cos (constants[3])) +
      exp (constants[0] + 2 * constants[1]) *
	(constants[5] * sin (constants[2]) - constants[4] * cos (constants[2]));
  n_p [4] = 0.0;

  d_p [0] = 0.0;
  d_p [1] = -2 * exp (constants[1]) * cos (constants[3]) -
    2 * exp (constants[0]) * cos (constants[2]);
  d_p [2] = 4 * cos (constants[3]) * cos (constants[2]) * exp (constants[0] + constants[1]) +
    exp (2 * constants[1]) + exp (2 * constants[0]);
  d_p [3] = -2 * cos (constants[2]) * exp (constants[0] + 2 * constants[1]) -
    2 * cos (constants[3]) * exp (constants[1] + 2 * constants[0]);
  d_p [4] = exp (2 * constants[0] + 2 * constants[1]);


  memcpy(d_m, d_p, 5 * sizeof(double));


  n_m[0] = 0.0;
  for (i = 1; i <= 4; i++)
    n_m [i] = n_p[i] - d_p[i] * n_p[0];

  {
    double sum_n_p, sum_n_m, sum_d;
    double a, b;

    sum_n_p = 0.0;
    sum_n_m = 0.0;
    sum_d = 0.0;
    for (i = 0; i <= 4; i++)
    {
	  sum_n_p += n_p[i];
	  sum_n_m += n_m[i];
	  sum_d += d_p[i];
    }

    sum_d++;
    a = sum_n_p / sum_d;
    b = sum_n_m / sum_d;

    for (i = 0; i <= 4; i++)
    {
	  bd_p[i] = d_p[i] * a;
 	  bd_m[i] = d_m[i] * b;
    }
  }
}
/*****************************************************************/
/* internal body     END                                         */
/*                                                               */
/*                                                               */
/*****************************************************************/




/*******************************************/
/* internal body                           */
/*                                         */
/* static void gauss_iir                   */
/*                                         */
/* process a gaussian blur                 */
/* source code updated from The Gimp       */
/*******************************************/
static void gauss_iir (PtrObjBitmap B, int x, int y, int width, int height, double horz, double vert)
{
  int bytes;
  OBJBITMAP_BUFFER dest;
  OBJBITMAP_BUFFER src;
  OBJBITMAP_BUFFER sp_p;
  OBJBITMAP_BUFFER sp_m;

  double n_p[5], n_m[5];
  double d_p[5], d_m[5];
  double bd_p[5], bd_m[5];
  double *val_p, *val_m, *vp, *vm;

  int i, j;
  int row, col, b;
  int terms;
  double progress, max_progress;
  int initial_p[4];
  int initial_m[4];
  OBJBITMAP_BUFFER guc_tmp1;
  OBJBITMAP_BUFFER guc_tmp2;
  int *gi_tmp1, *gi_tmp2;
  double std_dev;

  if (horz < 1.0 && vert < 1.0)    return;
 
  if (width < 1 || height < 1)    return;

  bytes = B->BytesPP;

  val_p = (double*)malloc ((max (width, height) * bytes) * sizeof(double));
  val_m = (double*)malloc ((max (width, height) * bytes) * sizeof(double));

  src =  (OBJBITMAP_BUFFER) malloc (max (width, height) * bytes);
  dest = (OBJBITMAP_BUFFER) malloc (max (width, height) * bytes);


  progress = 0.0;
  max_progress  = (horz < 1.0 ) ? 0 : width * height * horz;
  max_progress += (vert < 1.0 ) ? 0 : width * height * vert;


  /*  First the vertical pass  */
  if (vert >= 1.0)
    {
      vert = fabs (vert) + 1.0;
      std_dev = sqrt (-(vert * vert) / (2 * log (1.0 / 255.0)));

      /*  derive the constants for calculating the gaussian from the std dev  */
      find_constants (n_p, n_m, d_p, d_m, bd_p, bd_m, std_dev);

      for (col = 0; col < width; col++)
	{
	  memset(val_p, 0, height * bytes * sizeof (double)); 
	  memset(val_m, 0, height * bytes * sizeof (double));

	  pixel_region_get_col (B, src, col + x, y, height);

	  sp_p = src;
	  sp_m = src + (height - 1) * bytes;
	  vp = val_p;
	  vm = val_m + (height - 1) * bytes;

	  /*  Set up the first vals  */
	  for(guc_tmp1 = sp_p, guc_tmp2 = sp_m,
		gi_tmp1 = initial_p, gi_tmp2 = initial_m;
	      (guc_tmp1 - sp_p) < bytes;)
	    {
	      *gi_tmp1++ = *guc_tmp1++;
	      *gi_tmp2++ = *guc_tmp2++;
	    }


	  for (row = 0; row < height; row++)
	    {
	      double *vpptr, *vmptr;
	      terms = (row < 4) ? row : 4;

	      for (b = 0; b < bytes; b++)
		{
		  vpptr = vp + b; vmptr = vm + b;
		  for (i = 0; i <= terms; i++)
		    {
		      *vpptr += n_p[i] * sp_p[(-i * bytes) + b] -
			d_p[i] * vp[(-i * bytes) + b];
		      *vmptr += n_m[i] * sp_m[(i * bytes) + b] -
			d_m[i] * vm[(i * bytes) + b];
		    }
		  for (j = i; j <= 4; j++)
		    {
		      *vpptr += (n_p[j] - bd_p[j]) * initial_p[b];
		      *vmptr += (n_m[j] - bd_m[j]) * initial_m[b];
		    }
		}

	      sp_p += bytes;
	      sp_m -= bytes;
	      vp += bytes;
	      vm -= bytes;
	    }

	  transfer_pixels (val_p, val_m, dest, bytes, height);

	  pixel_region_set_col (B, dest, col + x, y, height);

	}

    }

  /*  Now the horizontal pass  */
  if (horz >= 1.0)
    {
      horz = fabs (horz) + 1.0;

      if (horz != vert)
	{
	  std_dev = sqrt (-(horz * horz) / (2 * log (1.0 / 255.0)));
	        
	  /*  derive the constants for calculating the gaussian from the std dev  */
	  find_constants (n_p, n_m, d_p, d_m, bd_p, bd_m, std_dev);
	}

      for (row = 0; row < height; row++)
	{
	  memset(val_p, 0, width * bytes * sizeof (double));
	  memset(val_m, 0, width * bytes * sizeof (double));

	  pixel_region_get_row (B, src, row + y, x, width);

	  sp_p = src;
	  sp_m = src + (width - 1) * bytes;
	  vp = val_p;
	  vm = val_m + (width - 1) * bytes;

	  /*  Set up the first vals  */
	  for(guc_tmp1 = sp_p, guc_tmp2 = sp_m,
		gi_tmp1 = initial_p, gi_tmp2 = initial_m;
	      (guc_tmp1 - sp_p) < bytes;)
	    {
	      *gi_tmp1++ = *guc_tmp1++;
	      *gi_tmp2++ = *guc_tmp2++;
	    }

	  for (col = 0; col < width; col++)
	    {
	      double *vpptr, *vmptr;
	      terms = (col < 4) ? col : 4;

	      for (b = 0; b < bytes; b++)
		{
		  vpptr = vp + b; vmptr = vm + b;
		  for (i = 0; i <= terms; i++)
		    {
		      *vpptr += n_p[i] * sp_p[(-i * bytes) + b] -
			d_p[i] * vp[(-i * bytes) + b];
		      *vmptr += n_m[i] * sp_m[(i * bytes) + b] -
			d_m[i] * vm[(i * bytes) + b];
		    }
		  for (j = i; j <= 4; j++)
		    {
		      *vpptr += (n_p[j] - bd_p[j]) * initial_p[b];
		      *vmptr += (n_m[j] - bd_m[j]) * initial_m[b];
		    }
		}

	      sp_p += bytes;
	      sp_m -= bytes;
	      vp += bytes;
	      vm -= bytes;
	    }

	  transfer_pixels (val_p, val_m, dest, bytes, width);

	  pixel_region_set_row (B, dest, row + y, x, width);

	}
    }


  /*  free up buffers  */
  free (val_p);
  free (val_m);
  free (src);
  free (dest);
}




 
/*$LB (12/12/2003)                                      */ 
/********************************************************/
/* fun [ObjBitmap I I I I I I] [ObjBitmap]              */
/*                                                      */
/* int _BLURbitmap                                      */
/*                                                      */
/* process a gaussian blur into a bitmap                */
/*                                                      */
/* parameters :                                         */
/*     - ObjBitmap bitmap                               */
/*     - I I x, y                                       */
/*     - I I w, h                                       */
/*     - I I horizontal gaussian radius, and vertical one */
/********************************************************/
int _BLURbitmap ( mmachine m )
{
    PtrObjVoid O ;
    PtrObjBitmap B ;
    int s, x, y, w, h, radius_x, radius_y;

	radius_y = MTOI (MMpull(m));
	radius_x = MTOI (MMpull(m));
	h        = MTOI (MMpull(m));
	w        = MTOI (MMpull(m));
	y        = MTOI (MMpull(m));
	x        = MTOI (MMpull(m));
    s = MMpull ( m ) ;     

    if ( s == NIL )
    {
        MMechostr ( 1 , "_BLURimage : Bitmap object is NIL\n" ) ;
    } 
    else
    {

        O = ( PtrObjVoid ) MMstart(m,(s>>1) ) ;    
        B = ( PtrObjBitmap ) MMstart(m, (O->Buffer>>1) ) ;
 

        if (w <0) w=0; if (h <0) h=0;
		if (x <0) x=0; if (y <0) y=0;
		if (x >=B->TailleW) x = B->TailleW-1;
		if (y >=B->TailleH) y  = B->TailleH-1;
		if (x+w > B->TailleW) w = B->TailleW-x;
		if (y+h > B->TailleH) h = B->TailleH-y;

		gauss_iir (B, x, y, w, h, (double)radius_x, (double)radius_y);
    }

    if ( MMpush(m,s )) return MERRMEM ;
	return 0;
}













//$ LB (13/06/2002) : don't create a DIBSection anymore, when creating an ObjBitmap.
//                    alloc memory for buffer and palette. The DIBSection will be create later if needed.

/********************************************************/
/*                                                      */
/* int ObjBitmap_New (old NewObjBitmap)                 */
/*                                                      */
/* create a new bitmap buffer and return a handler      */
/*                                                      */
/********************************************************/
int ObjBitmap_New ( PtrObjBitmap B , PtrPalette P )
{
int tf;
int sizeImage;
int newHandler;


//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nObjBitmap_New");
#endif
//***********************************


 	 //
	 // Init Data
	 //
 
	 B->BPL = B->TailleW * (B->BPP >>3);                    // nb bytes per line
	 if (B->BPL % 4 != 0 ) B->BPL += 4 - ( B->BPL % 4 ) ;   // align 32 bits (Windows constraint)

	 //$ LB (13/06/2002) : use BPL instead of (BPP * 8 * Width), because Windows Bitmaps are 32 bits aligned...
	 sizeImage = B->BPL * abs(B->TailleH);



	 //
     // alloc Palette
	 //
     if ( B->BPP == 8 )
	 {

			B->table = (PALETTEENTRY*) malloc (256 * sizeof (PALETTEENTRY));

			if (!B->table) return 0;

			if (P)
				for ( tf = 0 ; tf < 256 ; tf ++ )
				{
					B->table[tf].peRed = GET_RED(P,tf) ; 
					B->table[tf].peGreen = GET_GREEN(P,tf) ;
					B->table[tf].peBlue = GET_BLUE(P,tf) ;
					B->table[tf].peFlags = ( unsigned char ) NULL ;
				}
				
			else 
				for ( tf = 0 ; tf < 256 ; tf ++ )
				{
					B->table[tf].peRed = tf; 
					B->table[tf].peGreen = tf;
					B->table[tf].peBlue = tf;
					B->table[tf].peFlags = ( unsigned char ) NULL ;
				}

     } else B->table = NULL;


 	 //
     // alloc Bitmap Buffer
	 //
	 B->bits = (OBJBITMAP_BUFFER) malloc (sizeImage);  
	 if (!B->bits) return 0;


	 //
	 // Init Data
	 //
 	 //memset ((void*) B->bits, 0, sizeImage);  // bitmap buffer
	 B->bits[0] = 0;

     B->DIBhandler = NULL;                    // DIBSection handler
	 #ifdef USE_DRAWDIB
         B->Flags = BUFFER_FLAG_DOWN;         // Flags
     #else
		 B->Flags = 0 ;     
	 #endif


     newHandler = OBJgetNewHandler ();
 

	 //MMechostr(MSKDEBUG, "creating bitmap %d %d %d\n", newHandler, B->TailleW, B->TailleH);

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nObjBitmap_New end %d", newHandler);
#endif
//***********************************
      
     return newHandler; // return the new handler
}    





 


//$ LB (13/06/2002) : added ObjBitmap_CreateDIBsection
/********************************************************/
/*                                                      */
/* int ObjBitmap_CreateDIBSection                       */
/*                                                      */
/* create DIBSection from the bitmap buffer             */
/*                                                      */
/********************************************************/

int ObjBitmap_CreateDIBSection (PtrObjBitmap B)
{
DIBSECTION Info ;
BitmapInfo2 Bi ;
int tf,i ;
HDC dc ;
LPalette Pal ;
HPALETTE HPal , HPOld ;
OBJBITMAP_BUFFER bits;
UINT fuColorUse;

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nObjBitmap_CreateDIBSection");
#endif
//***********************************

	if (B->DIBhandler) return 0; // job has already been done....

     
	//
	// Palette : create the Windows Palette from the table buffer
	//
    if ( B->BPP == 8 )
    {
            Pal.Version = ( unsigned short ) GetVersion () ;
            Pal.ColorNum = 256 ;
            if ( B->table != NULL)
			for (i=0; i < 256; i++)
			{
	            Pal.Colors[i].peRed = B->table[i].peRed; 
				Pal.Colors[i].peGreen = B->table[i].peGreen; 
				Pal.Colors[i].peBlue = B->table[i].peBlue; 
				Pal.Colors[i].peFlags = B->table[i].peFlags; 
			}

			
            HPal = CreatePalette ( (LOGPALETTE*) (&Pal) ) ;            
            dc = CreateCompatibleDC ( NULL ) ;
            HPOld = SelectPalette ( dc , HPal , FALSE ) ;

    } else dc = NULL ;


	//
	// fill BITMAP INFOS
	//
    Bi.Bit.bmiHeader.biSize = sizeof ( BITMAPINFOHEADER );
    Bi.Bit.bmiHeader.biWidth = B->TailleW;

    #ifdef USE_DRAWDIB
         Bi.Bit.bmiHeader.biHeight = B->TailleH ;
    #else
         Bi.Bit.bmiHeader.biHeight = - B->TailleH ;
    #endif

	Bi.Bit.bmiHeader.biPlanes = 1;
    Bi.Bit.bmiHeader.biBitCount = B->BPP;

    if ( B->BPP == 8 || B->BPP == 24 ) 
         Bi.Bit.bmiHeader.biCompression = BI_RGB ;
    else  
	{
		MMechostr ( 1 , "BITMAP %d DIBSection : wrong BPP %d" , B->handler, B->BPP);
		return 0;
	}

    Bi.Bit.bmiHeader.biSizeImage = 0 ;
    Bi.Bit.bmiHeader.biXPelsPerMeter = 0 ;
    Bi.Bit.bmiHeader.biYPelsPerMeter = 0 ;

    if ( B->BPP == 8 )
    {
        Bi.Bit.bmiHeader.biClrUsed = 256;
        fuColorUse = DIB_PAL_COLORS; 
    }
    else 
    {
        Bi.Bit.bmiHeader.biClrUsed = 0 ;
        fuColorUse = DIB_RGB_COLORS ;
    }
	tf = fuColorUse;
    Bi.Bit.bmiHeader.biClrImportant = Bi.Bit.bmiHeader.biClrUsed ;




	//
	// DIB SECTION : create
	//
    if ((B->DIBhandler = CreateDIBSection ( dc, (BITMAPINFO * ) &Bi, tf, (void**)&bits, NULL, 0 )) == NULL) 
	{
		MMechostr ( 1 , "BITMAP %d DIBSection ERROR WIN32 Num %d" , B->handler, GetLastError ());
		return 0;
	}



	//
	// Palette
	//
    if ( dc ) 
    {
        SelectPalette ( dc , HPOld , FALSE ) ;
        DeleteObject ( HPal ) ;
        DeleteDC ( dc ) ;
		if (B->table) free (B->table);
    }


	//
	// DIB SECTION Buffer : set the DIBsection buffer with the bitmap buffer
	//
	memcpy (bits, B->bits, B->BPL * B->TailleH);
	free (B->bits);
	i = GetObject ( B->DIBhandler, sizeof( DIBSECTION ) , &Info ) ;
	if (!i) MMechostr ( 1 , "GETOBJECT ERROR Num %d" , GetLastError ());
	B->bits = (OBJBITMAP_BUFFER)Info.dsBm.bmBits;

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nObjBitmap_CreateDIBSection end");
#endif
//***********************************
     
    return 1;          
}





/*****************************************************************************/
/*                                                                           */
/* int DIBbitmap   ( mmachine m )                                            */
/*                                                                           */
/* fun [ObjBitmap] ObjBitmap                                                 */
/*                                                                           */
/* force the switch from a local memory bitmap to a DIB section              */
/* (usefull to video API)                                                    */
/*****************************************************************************/

int DIBbitmap ( mmachine m )
{

        int s;
        PtrObjVoid O ;
        PtrObjBitmap B ;

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nDIBbitmap");
#endif
//***********************************
        
        
        s = MMpull(m) ;
        if ( s == NIL )
        {
            MMechostr ( 1 , "_DIBbitmap : Buffer object is NIL\n" ) ;
            return MMpush(m,NIL) ;
        }
        O = ( PtrObjVoid ) MMstart(m, (s>>1) ) ;
        B = ( PtrObjBitmap ) MMstart(m, (O->Buffer>>1) ) ;

		if (B->bits == NULL)
		{
			MMechostr(MSKTRACE,"_DIBbitmap : Bitmap already destroyed %x\n",B->handler);
			return MMpush(m,NIL);
		}

		ObjBitmap_CreateDIBSection (B);

        return MMpush(m, s);
}




/******************************************************************************/
/*                                                                            */
/*  void SetBitmapPalette ( PtrObjBitmap B , PtrPalette P ) ;                 */
/*                                                                            */
/*  Fonction qui affecte une nouvelle palette a un bitmap                     */
/*                                                                            */
/******************************************************************************/

void SetBitmapPalette ( PtrObjBitmap B , PtrPalette P ) 
{
RGBQUAD Pal [ 257 ] ;
HDC dc ;
int i ;
HBITMAP OldBitmap ;   

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nSetBitmapPalette");
#endif
//***********************************

	//$ LB (13/06/2002) : create DIBSection from bitmap buffer
	if (!B->DIBhandler) ObjBitmap_CreateDIBSection (B);



    for ( i = 0 ; i < 256 ; i ++ ) 
    {
        Pal[i].rgbRed      = GET_RED   (P,i);
        Pal[i].rgbGreen    = GET_GREEN (P,i);
        Pal[i].rgbBlue     = GET_BLUE  (P,i);
        Pal[i].rgbReserved = 0 ;
    }


      
    dc = CreateCompatibleDC ( NULL ) ;   
    OldBitmap = SelectObject ( dc , B->DIBhandler) ;
    i=SetDIBColorTable ( dc , 0 , 256 , &(Pal[0]) ) ;
    SelectObject ( dc , OldBitmap ) ;
    DeleteDC ( dc ) ;

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nSetBitmapPalette end");
#endif
//***********************************

}





/*********************************************************************************/
/*                                                                               */
/*  void GetBitmapPalette ( PtrObjBitmap B , PtrPalette P ) ;                    */
/*                                                                               */
/*  Fonction qui renvoi la palette d'un bitmap                                   */
/*                                                                               */
/*********************************************************************************/

void GetBitmapPalette ( PtrObjBitmap B , PtrPalette P )
{
RGBQUAD Pal [ 256 ] ;
HDC dc ;
int i ;
HBITMAP OldBitmap ;


//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGetBitmapPalette");
#endif
//***********************************

	//$ LB (13/06/2002) : create DIBSection from bitmap buffer
	if (!B->DIBhandler) ObjBitmap_CreateDIBSection (B);

    dc = CreateCompatibleDC ( NULL ) ;
    OldBitmap = SelectObject ( dc , B->DIBhandler) ;
    i = GetDIBColorTable ( dc , 0 , 256 , Pal ) ;
    SelectObject ( dc , OldBitmap ) ;
    DeleteDC ( dc ) ;

    for ( i = 0 ; i < 256 ; i ++ )
    {
        GET_RED(P,i) = Pal[i].rgbRed ;
        GET_GREEN(P,i) = Pal[i].rgbGreen ;
        GET_BLUE(P,i) = Pal[i].rgbBlue ;
    
    }


//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGetBitmapPalette end");
#endif
//***********************************

}




int fillPalette(mmachine m,char *palette, int s2)
{
    RGBQUAD Pal [ 256 ] ;
    HDC dc ;
    int i ;
    HBITMAP OldBitmap ;
    PtrObjVoid OB ;
    PtrObjBitmap B ;


//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nfillPalette");
#endif
//***********************************


    if ( s2 == NIL ) return -1;
    OB = ( PtrObjVoid ) MMstart(m,s2>>1);
    if ( OB->Type != OBJ_TYPE_BITMAP << 1 ) return -1;
    B = ( PtrObjBitmap ) MMstart(m,OB->Buffer>>1);


	//$ LB (13/06/2002) : create DIBSection from bitmap buffer
	if (!B->DIBhandler) ObjBitmap_CreateDIBSection (B);


    dc = CreateCompatibleDC ( NULL ) ;
    OldBitmap = SelectObject ( dc , B->DIBhandler) ;
    i = GetDIBColorTable ( dc , 0 , 256 , Pal ) ;
    SelectObject ( dc , OldBitmap ) ;
    DeleteDC ( dc ) ;

    for ( i = 0 ; i < 256 ; i ++ )
    {
        palette[i*4+2] = Pal[i].rgbRed ;
        palette[i*4+1] = Pal[i].rgbGreen ;
        palette[i*4] = Pal[i].rgbBlue ;
    }

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nfillPalette end");
#endif
//***********************************

	return 0;
}


extern sysexe (*SCexeSearch)(char *categ, char *name);


int GRdrawIcon(mmachine m)
{
	PtrObjVoid OB ;
	PtrObjBitmap B ;
	HDC Dcb ;
	sysexe e;
	char *path,*categ;
	HICON hic;
	HBITMAP OldBitmap ;
	int c,s,s2,x,y,num;
	SHFILEINFO sfi;

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRdrawIcon");
#endif
//***********************************

	y=MMpull(m)>>1;
	x=MMpull(m)>>1;
	num=MMpull(m)>>1;
	s2 = MMpull(m) ;
	s = MMpull(m)>>1 ;
	c = MMpull(m)>>1 ;

	if ((s2==NIL)||(s==NIL)) return MMpush(m,NIL);
	categ=NULL;
	if (c!=NIL) categ=MMstartstr(m,c);
	e=SCexeSearch(categ,MMstartstr(m,s));
	if (e==NULL) return MMpush(m,NIL);
	path=e->path;
	if (path==NULL) return MMpush(m,NIL);

	hic=ExtractIcon((HINSTANCE)SCgetExtra("this_inst"),path,num);
	if ((num==0)&&( (((int)hic)==1) || (hic==NULL)))
	{
		MMechostr(MSKDEBUG,"try again\n");
		CoInitialize(NULL);
		if (SHGetFileInfo(path,0,&sfi,sizeof(SHFILEINFO),SHGFI_ICON)==0)
		{
			MMechostr(MSKDEBUG,"cannot retrieve icon %d from %s\n",num,path);
			return MMpush(m,NIL);
		}
		hic=sfi.hIcon;
		CoUninitialize();

//		strcpy(buf,path);
//		hic=ExtractAssociatedIcon(thisinst,buf,&num);
	}

	if ( (((int)hic)==1) || (hic==NULL))
	{
		MMechostr(MSKDEBUG,"cannot retrieve icon %d from %s (%d)\n",num,path,hic);
		return MMpush(m,NIL);
	}
	OB = ( PtrObjVoid ) MMstart(m, (s2>>1) ) ;        
	B = ( PtrObjBitmap ) MMstart(m, (OB->Buffer>>1) ) ;


	//$ LB (13/06/2002) : create DIBSection from bitmap buffer
	if (!B->DIBhandler) ObjBitmap_CreateDIBSection (B);


	Dcb = CreateCompatibleDC ( NULL ) ;
	OldBitmap = SelectObject ( Dcb , B->DIBhandler) ;
	DrawIcon(Dcb,x,y,hic);
	SelectObject ( Dcb , OldBitmap ) ;
	DeleteDC ( Dcb ) ;
	DestroyIcon(hic);

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRdrawIcon end");
#endif
//***********************************

	return MMpush(m,0);
}






int GRinfoIcon(mmachine m)
{
	sysexe e;
	char *path,*categ;
	HICON hic;
	int c,s,num;
	ICONINFO icinf;
	BITMAP bmpinf;
	SHFILEINFO sfi;

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRinfoIcon");
#endif
//***********************************
	
	num=MMpull(m)>>1;
	s = MMpull(m)>>1 ;
	c = MMpull(m)>>1 ;

	if (s==NIL) return MMpush(m,NIL);
	categ=NULL;
	if (c!=NIL) categ=MMstartstr(m,c);
	e=SCexeSearch(categ,MMstartstr(m,s));
	if (e==NULL) return MMpush(m,NIL);
	path=e->path;
	if (path==NULL) return MMpush(m,NIL);

	hic=ExtractIcon((HINSTANCE)SCgetExtra("this_inst"),path,num);
	if ((num==0)&&( (((int)hic)==1) || (hic==NULL)))
	{
		MMechostr(MSKDEBUG,"try again\n");
		CoInitialize(NULL);
		SHGetFileInfo(path,0,&sfi,sizeof(SHFILEINFO),SHGFI_ICON);
		hic=sfi.hIcon;
		CoUninitialize();
	}
	if ( (((int)hic)==1) || (hic==NULL) || (!GetIconInfo(hic,&icinf)) )
	{
		MMechostr(MSKDEBUG,"cannot retrieve icon %d from %s\n",num,path);
		return MMpush(m,NIL);
	}
	GetObject(icinf.hbmMask,sizeof(BITMAP),&bmpinf);
	if (MMpush(m,bmpinf.bmWidth*2)) return MERRMEM;
	if (MMpush(m,bmpinf.bmHeight*2)) return MERRMEM;
	if (MMpush(m,2*2)) return MERRMEM;
	DestroyIcon(hic);

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRinfoIcon end");
#endif
//***********************************

	return MBdeftab(m);
}







/*****************************************************************************/
/*                                                                           */
/* int GRLoadBitmap ( mmachine m )                                           */
/*                                                                           */
/* correspond a la fonction magma I _load_bitmap ( S )                       */
/* qui charge un bitmap BMP en memoire windows                               */
/*                                                                           */
/*****************************************************************************/

int GenericLoadBitmap ( mmachine m , char BPP )
{
    int R ;
    int res,l,s,s2;
    PtrObjVoid O ;
    PtrObjBitmap B ;
    char Name [ 8000 ] ;   


//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGenericLoadBitmap");
#endif
//***********************************


    /* test channel nil */
    if(MMget(m,1)==NIL)
    {
        MMechostr(MSKDEBUG,"_LDbitmap generic : Channel NIL\n");
        m->pp+=1;
        return 0;
    }
    /* test nom nil */

    s = MMget(m,0) ;
    if ( s == NIL ) 
    {
		MMpull(m);
        MMset(m,0,NIL);
        return 0 ;
    }
    strcpy ( Name , ( char * ) MMstart(m, (s>>1)+1) ) ; 
        
    
    l = ( sizeof ( struct ObjVoid ) + 3 ) >> 2 ;
    s = MMmallocCLR (m,l,TYPETAB) ;
    if ( s==NIL) return MERRMEM ;
    if ( MMpush(m,(s<<1)+1)) return MERRMEM ;
    l = ( sizeof ( struct ObjBitmap ) + 3 ) >> 2 ;
    s2 = MMmalloc ( m,l,TYPEBUF ) ;
    if ( s2 == NIL ) return MERRMEM ;
    s = MMpull(m) ;

    O = ( PtrObjVoid ) MMstart(m, (s>>1) ) ;
    B = ( PtrObjBitmap ) MMstart(m, s2 ) ;
    O->Type = OBJ_TYPE_BITMAP << 1 ;
    O->Buffer = ( s2 << 1 ) + 1 ;
    O->Tab = MMpull(m);   
    B->PosY = 0 ;
    B->PosX = 0 ;
    O->Father = NIL ;
   
    B->bits = NULL ;

    LoadBMP ( Name , B , BPP ) ;

    if ( B->bits == NULL )
    {
        MMechostr ( 1 , "_load_bitmap failed\n" ) ;
        MMpull(m);
        return MMpush(m,NIL);
    }
     
    R = B->handler;
//    MMechostr ( 1 , "££LDbitmap%d %x %d %d %s\n",B->BPP,B->HBitmap,B->TailleW,B->TailleH,Name) ;

    MMpush(m,s) ;
    res = OBJcreate(m,OBJTYPBITMAP,(int)R,0,(int)NULL) ;   

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGenericLoadBitmap end");
#endif
//***********************************

    return res ;
}





int GRLoadBitmap ( mmachine m ) 
{
    return GenericLoadBitmap ( m ,  24 ) ;
}





/*****************************************************************************/
/*                                                                           */
/* int GREmptyBuffer   ( mmachine m )                                        */
/*                                                                           */
/* correspond a la fonction magma Obj _empty_buffer ( Obj , I )              */
/* laquelle remplit un buffer graphique d'une couleur unie                   */
/*                                                                           */
/*****************************************************************************/

#define FILL_VERSION

int GREmptyBuffer ( mmachine m )
{

        int s , c ;
        PtrObjVoid O ;
        PtrObjBitmap B ;

#ifdef FILL_VERSION
         int i,j,dcx,dcy ;
         OBJBITMAP_BUFFER Image ;
         OBJBITMAP_BUFFER Image8 ;
#else        

        HPEN Pinceau , OldPen ;
        HWND OldItem ;
        LOGBRUSH Brush ;
        HBRUSH HBrush , OldBrush ;
        HDC Dc ;
#endif

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGREmptyBuffer");
#endif
//***********************************
        
        c = MMpull(m) >> 1 ;
     
        
        s = MMpull(m) ;
        if ( s == NIL )
        {
            MMechostr ( 1 , "_FILLbitmap : Buffer object is NIL\n" ) ;
            return MMpush(m,NIL) ;
        }
        O = ( PtrObjVoid ) MMstart(m, (s>>1) ) ;
        
        B = ( PtrObjBitmap ) MMstart(m, (O->Buffer>>1) ) ;

		if (B->bits == NULL)
		{
			MMechostr(MSKTRACE,"FILLbitmap : Bitmap already destroyed %x\n",B->handler);
			return MMpush(m,NIL);
		}

#ifdef FILL_VERSION
                
        if ( B->BPP == 24)
        {
			unsigned char r,g,b;

            Image = (OBJBITMAP_BUFFER) B->bits;            
			_COLOR_I_TO_BGR (c, &b, &g, &r);
           
            dcy = 0;

            for (j=0; j < B->TailleH; j++) 
			{
				for (i=0, dcx=dcy; i < B->TailleW; i++, dcx+=3)
				{
					Image [ dcx   ] = (unsigned char)b ;
					Image [ dcx+1 ] = (unsigned char)g ;
					Image [ dcx+2 ] = (unsigned char)r ;
				}

				dcy += B->BPL;
			}

        }
        else if ( B->BPP == 8 )
        {

            Image8 = (OBJBITMAP_BUFFER) B->bits;
            i = ( B->BPL * B->TailleH ) ;
            while ( i ) Image8 [-- i ] = ( unsigned char ) c ;
        }
#else


		//$ LB (13/06/2002) : create DIBSection from bitmap buffer
		if (!B->DIBhandler) ObjBitmap_CreateDIBSection (B);


        Dc = CreateCompatibleDC ( NULL ) ;
        OldItem = SelectObject ( Dc , B->DIBhandler) ;
        Pinceau = CreatePen ( PS_SOLID , 0 , c ) ;
        Brush.lbStyle = BS_SOLID ;
        Brush.lbColor = c ;

        HBrush = CreateBrushIndirect ( & Brush ) ;        
        OldPen = SelectObject ( Dc , Pinceau ) ;
        OldBrush = SelectObject ( Dc , HBrush ) ;
        Rectangle ( Dc , 0 , 0 , B->TailleW , B->TailleH ) ;        
        SelectObject ( Dc , OldPen ) ;
        SelectObject ( Dc , OldBrush ) ;
        DeleteObject ( HBrush ) ;
        DeleteObject ( Pinceau ) ;
        SelectObject ( Dc , OldItem ) ;
        DeleteDC ( Dc ) ;
#endif

        s = MMpush(m,s) ;
    
//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGREmptyBuffer end");
#endif
//***********************************
        return s ;
}


    



/*****************************************************************************/
/*                                                                           */
/* int GRGetBitmapSize  ( mmachine m )                                       */
/*                                                                           */
/*  correspond a la fonction magma I _get_bitmap_wsize  ( Obj )              */
/*  qui renvoi la taille d'un bitmap                                         */
/*                                                                           */
/*****************************************************************************/

int GRGetBitmapSize ( mmachine m )
{
    PtrObjVoid O ;
    PtrObjBitmap B ;
    int s , h , w ; 

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRGetBitmapSize");
#endif
//***********************************



    s = MMpull ( m ) ;     
    if ( s == NIL )
    {
        MMechostr ( 1 , "GetBitmapWSize : Bitmap object is NIL\n" ) ;
        w = -1 ; 
        h = -1 ;
    } 
    else
    {
        O = ( PtrObjVoid ) MMstart(m,(s>>1) ) ;    
        B = ( PtrObjBitmap ) MMstart(m, (O->Buffer>>1) ) ;
        w = B->TailleW << 1 ;
        h = B->TailleH << 1 ;
    }
    if ( MMpush(m,w )) return MERRMEM ;
    if ( MMpush(m,h )) return MERRMEM ;
    if ( MMpush(m,4 )) return MERRMEM ;
    s = MBdeftab ( m ) ;

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRGetBitmapSize end");
#endif
//***********************************


    return s ;

}

/*****************************************************************************/
/*                                                                           */
/* int GRCreateBitmap ( mmachine m ) ;                                       */
/*                                                                           */
/* correspond a la fonction magma Obj _create_buffer ( I TailleW , I TailleH,*/
/* I Handler ) laquelle cree une buffer graphique                            */
/*                                                                           */
/*****************************************************************************/

int GenericCreateBitmap ( mmachine m , int BPP )
{
        int s , s2 , l , res ;
        PtrObjVoid O ;
        PtrObjBitmap B ;        
        int R ;        

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGenericCreateBitmap");
#endif
//***********************************


		if ((MMget(m,0)<=0)||(MMget(m,1)<=0))
		{
            MMechostr ( 1 , "Creation of graphical Buffer impossible.\n" ) ;
            MMechostr ( 1 , "W=%d H=%d\n",MMget(m,1)>>1,MMget(m,0)>>1 ) ;
			MMpull(m);
			MMpull(m);
			MMpull(m);
			return MMpush(m,NIL);
		}
        
        l = ( sizeof ( struct ObjVoid ) + 3 ) >> 2 ;
        s = MMmallocCLR (m,l,TYPETAB) ;
        if ( s == NIL ) return MERRMEM ;
        if ( MMpush(m,(s<<1)+1)) return MERRMEM  ;
        l = ( sizeof ( struct ObjBitmap ) + 3 ) >> 2 ;
        s2 = MMmalloc ( m,l,TYPEBUF ) ;
        if ( s2 == NIL ) return MERRMEM ;
        s = MMpull(m) ;

        O = ( PtrObjVoid ) MMstart(m, (s>>1) ) ;
        B = ( PtrObjBitmap ) MMstart(m, s2 ) ;
     
        O->Buffer = (s2<<1)+1;
        O->Tab = NIL ;
        O->Father = NIL ;
        O->Type = OBJ_TYPE_BITMAP << 1 ;

        B->TailleH = MMpull(m)>> 1 ;
        B->TailleW = MMpull(m) >> 1 ;
        B->BPP = BPP ; 
		B->BytesPP = B->BPP >>3;
        B->handler = ObjBitmap_New ( B , NULL ) ;

        if ( B->bits == NULL )
        {
            MMechostr ( 1 , "Creation of graphical Buffer failed.\n" ) ;
            MMechostr ( 1 , "W=%d H=%d\n",B->TailleW,B->TailleH ) ;
            MMpull(m) ; /* depile le channel */ 
            return MMpush(m,NIL);
        }       

        R = B->handler;
        MMpush(m,s) ;
//        MMechostr ( 1 , "££CRbitmap%d %x %d %d\n",B->BPP,B->HBitmap,B->TailleW,B->TailleH) ;
        res = OBJcreate(m,OBJTYPBITMAP,(int)R,0,(int)NULL ) ;

/****************************/
 #ifdef DEBUG_LIB2DOS
   MMechostr (0 , "\nGenericCreateBitmap end : %d   BPP %d  BytesPP %d    BPL %d    w %d  h %d", B->handler, B->BPP, B->BytesPP, B->BPL, B->TailleW, B->TailleH); 
#endif
/****************************/
        return res ;
}



int GRCreateBitmap ( mmachine m )
{
    return GenericCreateBitmap( m , 24 ) ;
}



#define BLIT_CLIP(winX, winY, x, y, w, h, screenW, screenH) \
	                                                        \
if (winX+x < 0)              {x = -(winX)+x; w += winX; }   \
else if (winX+x+w < 0)       w = 0;                         \
else if (winX+x > screenW)   w = 0;                         \
else if (winX+x+w > screenW) w -= (winX+x+w - screenW);     \
                                                            \
if (winY+y < 0)              {y = -(winY)+y; h += winY; }   \
else if (winY+y+h < 0)       h = 0;                         \
else if (winY+y > screenH)   h = 0;                         \
else if (winY+y+h > screenH) h -= (winY+y+h - screenH);      



/*****************************************************************************/
/*                                                                           */
/*  int GRBlitBitmap ( mmachine m ) ;                                        */
/*                                                                           */
/* correspond a la fonction magma Obj _paint_buffer ( ObjWin , ObjBuf ,      */
/* I PosX , I PosY ) ;                                                       */
/*                                                                           */
/*****************************************************************************/

int GRBlitBitmap ( mmachine m )
{
int PosX , PosY , s , s2 , res ;
PtrObjVoid OW , OB ;
PtrObjWindow W ;
PtrObjBitmap B ;
HDC Dcw , Dcb , Dcbuf;       
HBITMAP OldBitmap, OldBuf;



//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRBlitBitmap");
#endif
//***********************************


        PosY = MMpull(m)>>1 ;
        PosX = MMpull(m)>>1 ;
        s2 = MMpull(m) ;
        s = MMpull(m) ;

        if ( s2 != NIL && s != NIL )
        {
            OB = ( PtrObjVoid ) MMstart(m, (s2>>1) ) ;        
            OW = ( PtrObjVoid ) MMstart(m, (s>>1) ) ;

         
            B = ( PtrObjBitmap ) MMstart(m, (OB->Buffer>>1) ) ;
            W = ( PtrObjWindow ) MMstart(m, (OW->Buffer>>1) ) ;

			
			//$ LB (13/06/2002) : create DIBSection from bitmap buffer
			if (!B->DIBhandler) ObjBitmap_CreateDIBSection (B);
 
 
			//
			//$LB (16/12/2003) : process window transparency simulation
			//
			if (!(W->tSimulated))
			{

				Dcw = GetDC (W->WHandler) ;       
				Dcb = CreateCompatibleDC (Dcw) ;
				OldBitmap = SelectObject ( Dcb , B->DIBhandler) ;


				// no simulation. let Windows do it itself (if the transparency is required by the program, of course...
				// otherwize it's only a simple blit)
				BitBlt ( Dcw, PosX, PosY, B->TailleW,  B->TailleH, Dcb, 0, 0, SRCCOPY);

				SelectObject ( Dcb , OldBitmap ) ;
				DeleteDC ( Dcb ) ; 
				ReleaseDC (W->WHandler, Dcw);
			}

			//                                                window :
			//                                                ---------------------------
			//                                                |     zone1               |
			//$LB (16/12/2003)                                |      ----------         |
			//                                                | zone2| bmp    |  zone3  |  
			// here we have to simulate the transparency      |      |        |         |
			//                                                |      ----------         |
			//                                                |     zone4               |
			//                                                ---------------------------
			else
			{
			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 x1, y1, w1, h1, x2, y2, w2, h2, x3, y3, w3, h3, x4, y4, w4, h4;         
			int xbkg, ybkg, xbkgdst, ybkgdst, wbkg, hbkg, 
				wwin, hwin, 
				xbmp, ybmp, wbmp, hbmp, offsetBmpX, offsetBmpY, 
				MAXW, MAXH; 


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

			  MAXW = LIB2DOStransBkg->TailleW;
			  MAXH = LIB2DOStransBkg->TailleH;

			  wwin = W->TailleW; hwin = W->TailleH;
			  wbmp = B->TailleW; hbmp = B->TailleH;

			  //
			  // clipping coordinates
			  //
			  if (W->tX <0) 
			  { 
				xbkg    = 0;  wbkg = wwin + W->tX;
				xbkgdst = -(W->tX); 
			  }
			  else if (W->tX+wwin > MAXW)
			  {
				xbkg = W->tX; wbkg = wwin - (xbkg + wwin - MAXW);
				xbkgdst = 0;
			  }
			  else
			  {
				xbkg = W->tX; wbkg = wwin;
				xbkgdst = 0;
			  }


			  //
			  // clipping coordinates
			  //
			  if (W->tY <0)
			  {
			    ybkg = 0;  hbkg = hwin + W->tY;
				ybkgdst = -(W->tY);
			  }
			  else if (W->tY + hwin > MAXH)
			  {
				ybkg = W->tY; hbkg = hwin - (ybkg + hwin - MAXH);
				ybkgdst = 0;
			  }
			  else
			  { 
			    ybkg = W->tY;  hbkg = hwin;
				ybkgdst = 0;
			  } 


			  //
			  // clipping coordinates
			  //
			  x1 = 0;         y1 = 0;     w1 = wwin;         h1 = PosX;       
			  x2 = 0;         y2 = PosY;  w2 = PosX;         h2 = hbmp;       
			  xbmp = PosX;    ybmp = PosY; 
			  x3 = w2 + wbmp; y3 = PosY;  w3 = wwin-w2-wbmp; h3 = h2;         
			  x4 = 0;         y4 = y2+h2; w4 = wwin;         h4 = hwin-h1-h2; 

			  BLIT_CLIP(W->tX, W->tY, x1, y1, w1, h1, MAXW, MAXH);
			  BLIT_CLIP(W->tX, W->tY, x2, y2, w2, h2, MAXW, MAXH);
			  BLIT_CLIP(W->tX, W->tY, x3, y3, w3, h3, MAXW, MAXH);
			  BLIT_CLIP(W->tX, W->tY, x4, y4, w4, h4, MAXW, MAXH);

			  //
			  // clipping bitmap coordinates
			  //
			  offsetBmpX = 0;
			  offsetBmpY = 0;

			  if (W->tX+xbmp <0)               {xbmp = -(W->tX)+xbmp; wbmp+=W->tX; offsetBmpX += (B->TailleW-wbmp)*BytesPP;}
			  else if (W->tX+xbmp+wbmp <0)     {wbmp = 0; offsetBmpX = 0;}
			  else if (W->tX+xbmp > MAXW)      {wbmp=0; offsetBmpX = 0;}
			  else if (W->tX+xbmp+wbmp > MAXW) {wbmp-= (W->tX+xbmp+wbmp - MAXW); offsetBmpX = 0;}
			  else                             {offsetBmpX = 0;}

			  if (W->tY+ybmp <0)               {ybmp = -(W->tY)+ybmp; hbmp+=W->tY; offsetBmpY += (B->TailleH - hbmp)*B->BPL;}
			  else if (W->tY+ybmp+hbmp <0)     {hbmp = 0; offsetBmpY = 0;}
			  else if (W->tY+ybmp > MAXH)      {hbmp=0; offsetBmpY = 0;}
			  else if (W->tY+ybmp+hbmp > MAXH) {hbmp-= (W->tY+ybmp+hbmp - MAXH); offsetBmpY = 0;}
			  else                             {offsetBmpY = 0;}
			  


			  //
			  // DRAW ZONE1
			  //
			  buf = (OBJBITMAP_BUFFER) (W->tBuf->bits + y1*W->tBuf->BPL + x1*BytesPP);
			  bkg = (OBJBITMAP_BUFFER) (LIB2DOStransBkg->bits + ybkg*LIB2DOStransBkg->BPL + xbkg*BytesPP);
			  restbuf = W->tBuf->BPL - (w1*BytesPP);      
			  restbkg = LIB2DOStransBkg->BPL - (w1*BytesPP);
			  for (j=0; j < h1; j++, buf+=restbuf, bkg+=restbkg)
			  {
				  for (i=0; i < w1; i++, buf+=BytesPP, bkg+=BytesPP)
				  { (*buf) = (*bkg); *(buf+1) = *(bkg+1); *(buf+2) = *(bkg+2);  }
			  }


			  //
			  // DRAW ZONE2
			  //
			  buf = (OBJBITMAP_BUFFER) (W->tBuf->bits + y2*W->tBuf->BPL + x2*BytesPP);
			  bkg = (OBJBITMAP_BUFFER) (LIB2DOStransBkg->bits + (ybkg+y2)*LIB2DOStransBkg->BPL + (xbkg+x2)*BytesPP);
			  restbuf = W->tBuf->BPL - (w2*BytesPP);      
			  restbkg = LIB2DOStransBkg->BPL - (w2*BytesPP);
			  for (j=0; j < h2; j++, buf+=restbuf, bkg+=restbkg)
			  {
				  for (i=0; i < w2; i++, buf+=BytesPP, bkg+=BytesPP)
				  { (*buf) = (*bkg); *(buf+1) = *(bkg+1); *(buf+2) = *(bkg+2);  }
			  }
				  
			  

			  // 
			  // BLIT BITMAP
			  //
			  buf = (OBJBITMAP_BUFFER) (W->tBuf->bits + ybmp*W->tBuf->BPL + xbmp*BytesPP);
			  bmp = (OBJBITMAP_BUFFER) (B->bits + offsetBmpX + offsetBmpY);
			  bkg = (OBJBITMAP_BUFFER) (LIB2DOStransBkg->bits + (ybkg+PosY)*LIB2DOStransBkg->BPL + (xbkg+PosX)*BytesPP);
			  restbuf = W->tBuf->BPL - (wbmp*BytesPP);      
			  restbmp = B->BPL - (wbmp*BytesPP);
			  restbkg = LIB2DOStransBkg->BPL - (wbmp*BytesPP);

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

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

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

						// else if there an alpha blending factor
						else if (W->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 (W->tfactor == 0)
							{
								(*buf) = db; *(buf+1) = dg; *(buf+2) = dr;
							}
							if (W->tfactor == 255)
							{
								(*buf) = sb; *(buf+1) = sg; *(buf+2) = sr;
							}
							else
							{
							    (*buf)   = db + W->tfactor * (sb - db) / 255;
								*(buf+1) = dg + W->tfactor * (sg - dg) / 255;
								*(buf+2) = dr + W->tfactor * (sr - dr) / 255;
							}
						}

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

					
				  } // end i
			  }     // end j



			  //
			  // DRAW ZONE3
			  //
			  buf = (OBJBITMAP_BUFFER) (W->tBuf->bits + y3*W->tBuf->BPL + x3*BytesPP);
			  bkg = (OBJBITMAP_BUFFER) (LIB2DOStransBkg->bits + (ybkg+y3)*LIB2DOStransBkg->BPL + (xbkg+x3)*BytesPP);
			  restbuf = W->tBuf->BPL - (w3*BytesPP);      
			  restbkg = LIB2DOStransBkg->BPL - (w3*BytesPP);
			  for (j=0; j < h3; j++, buf+=restbuf, bkg+=restbkg)
			  {
				  for (i=0; i < w3; i++, buf+=BytesPP, bkg+=BytesPP)
				  { (*buf) = (*bkg); *(buf+1) = *(bkg+1); *(buf+2) = *(bkg+2);  }
			  }


			  //
			  // DRAW ZONE4
			  //
			  buf = (OBJBITMAP_BUFFER) (W->tBuf->bits + y4*W->tBuf->BPL + x4*BytesPP);
			  bkg = (OBJBITMAP_BUFFER) (LIB2DOStransBkg->bits + (ybkg+y4)*LIB2DOStransBkg->BPL + (xbkg+x4)*BytesPP);
			  restbuf = W->tBuf->BPL - (w4*BytesPP);      
			  restbkg = LIB2DOStransBkg->BPL - (w4*BytesPP);
			  for (j=0; j < h4; j++, buf+=restbuf, bkg+=restbkg)
			  {
				  for (i=0; i < w4; i++, buf+=BytesPP, bkg+=BytesPP)
				  { (*buf) = (*bkg); *(buf+1) = *(bkg+1); *(buf+2) = *(bkg+2);  }
			  }
 

			  //
			  // FINAL STAGE : blit Window <-- WindowBuffer
			  //
				Dcw = GetDC (W->WHandler) ;
				Dcbuf = CreateCompatibleDC (Dcw) ;
				OldBuf    = SelectObject ( Dcbuf, W->tBuf->DIBhandler);
				
				BitBlt ( Dcw, 0, 0, B->TailleW,  B->TailleH, Dcbuf, 0, 0, SRCCOPY);

				SelectObject ( Dcbuf , OldBuf ) ;
				DeleteDC ( Dcbuf ) ; 
				ReleaseDC (W->WHandler, Dcw);
			}




        }
        res = MMpush(m,s) ;

 //***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRBlitBitmap end");
#endif
//***********************************

        return res ;
}





/*****************************************************************************/ 
/*                                                                           */ 
/*  int GRStretchBlit ( mmachine m ) ;                                       */ 
/*                                                                           */ 
/* Correspond a la fonction scol ObjWin _STBLITbitmap (                      */ 
/* ObjWin , I WX , I WY , I WW , I WY , ObjBitmap , I BX , I BY , I BW ,I BH)*/ 
/*                                                                           */ 
/*  Laquelle effectue une copie par stretching dans une fenetre d'un bitmap  */ 
/*                                                                           */ 
/*****************************************************************************/ 

int GRStretchBlit ( mmachine m )
{
        int WX , WY , BX , BY , s , s2 , res , BW , BH , WW , WH ;
        PtrObjVoid OW , OB ;
        PtrObjWindow W ;
        PtrObjBitmap B ;
        HDC Dcw , Dcb ;       
        HBITMAP OldBitmap ;

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRStretchBlit");
#endif
//***********************************

        BH = MMpull(m) >> 1 ;
        BW = MMpull(m) >> 1 ;
        BY = MMpull(m) >> 1 ;
        BX = MMpull(m) >> 1 ;
        s2 = MMpull(m) ;
        WH = MMpull(m) >> 1 ;
        WW = MMpull(m) >> 1 ;
        WY = MMpull(m) >> 1 ;
        WX = MMpull(m) >> 1 ;
        s = MMpull(m) ;

        if ( s != NIL && s2 != NIL )
        {
            OB = ( PtrObjVoid ) MMstart(m, (s2>>1) ) ;    
            OW = ( PtrObjVoid ) MMstart(m, (s>>1) ) ;
        
            B = ( PtrObjBitmap ) MMstart(m, (OB->Buffer>>1) ) ;
            W = ( PtrObjWindow ) MMstart(m, (OW->Buffer>>1) ) ;

			
			//$ LB (13/06/2002) : create DIBSection from bitmap buffer
			if (!B->DIBhandler) ObjBitmap_CreateDIBSection (B);

        
            Dcw = GetDC ( W->WHandler ) ;       
            Dcb = CreateCompatibleDC ( Dcw ) ;
            OldBitmap = SelectObject ( Dcb , B->DIBhandler) ;
            StretchBlt( Dcw , WX , WY , WW , WH , Dcb , BX , BY , BW , BH , SRCCOPY ) ;

            SelectObject ( Dcb , OldBitmap ) ;
            DeleteDC ( Dcb ) ;      
			ReleaseDC (W->WHandler, Dcw);
        }
        
        res = MMpush(m,s) ;

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRStretchBlit end");
#endif
//***********************************

        return res ;
}






/*****************************************************************************/
/*                                                                           */
/* int GRDrawRectangle ( mmachine m )                                        */
/*                                                                           */
/* correspond a la fonction magma Obj _draw_rectangle ( Obj Buffer , I PosX ,*/
/* I PosY , I TailleW , I TailleH , I Mode contour , I Taille contour ,      */
/* I Couleur contour , I mode remplissage , I couleur remplissage )          */
/* laquelle dessine u nrectangle dans une buffer graphique                   */
/*                                                                           */
/*****************************************************************************/

int GRDrawRectangle ( mmachine m )
{
        int Couleur_Remplissage ;
        int Mode_Remplissage ;
        int Couleur_Contour ;
        int Taille_Contour ;
        int Mode_Contour ;
        int TailleW , TailleH , PosX , PosY , s ;
        PtrObjVoid O ;        
		PtrObjBitmap B;
        HPEN Pinceau , OldPen ;
        HWND Item , OldItem ;
        LOGBRUSH Brush ;
        HBRUSH HBrush , OldBrush ;
        HDC Dc ;

 //***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRDrawRectangle");
#endif
//***********************************
        

        Couleur_Remplissage = MMpull(m)>> 1 ;
        Mode_Remplissage = MMpull(m)>>1 ;
        Couleur_Contour = MMpull(m)>>1 ;
        Taille_Contour = MMpull(m)>>1 ;
        Mode_Contour = MMpull(m)>>1 ;
        TailleH = MMpull(m)>>1 ;
        TailleW = MMpull(m)>>1 ;
        PosY = MMpull(m)>>1 ;
        PosX = MMpull(m)>>1 ;
        s = MMpull(m) ;
        if ( s == NIL )
        {
            MMechostr ( 1 , "DrawRectangle : Buffer is NIL\n" ) ;
            return MMpush(m,NIL) ;
        }
        O = ( PtrObjVoid ) MMstart(m, (s>>1 ) ) ;        
        switch ( O->Type >> 1 )
        {
            case OBJ_TYPE_BITMAP :

				B = ( PtrObjBitmap ) MMstart(m, (O->Buffer>>1));
				
				//$ LB (13/06/2002) : create DIBSection from bitmap buffer
				if (!B->DIBhandler) ObjBitmap_CreateDIBSection (B);

                Item = (HWND)B->DIBhandler;
                Dc = CreateCompatibleDC ( NULL ) ;
                OldItem = SelectObject ( Dc , Item ) ;
                break ;

            case OBJ_TYPE_WINDOW :
                Item = (( PtrObjWindow ) MMstart(m,(O->Buffer>>1) )) ->WHandler ;
                Dc = GetDC ( Item ) ;
                break ;
        }

        if ( Taille_Contour <= 0 ) {Taille_Contour = 0 ; Mode_Contour = DRAW_INVISIBLE;}

        if ( Mode_Contour == DRAW_INVISIBLE )
                Pinceau = CreatePen ( PS_NULL , Taille_Contour , Couleur_Contour ) ;
        else Pinceau = CreatePen ( PS_SOLID , Taille_Contour , Couleur_Contour ) ;
        if ( Mode_Remplissage == DRAW_INVISIBLE )
                Brush.lbStyle = BS_NULL ;
        else Brush.lbStyle = BS_SOLID ;
        Brush.lbColor = Couleur_Remplissage ;
              
        HBrush = CreateBrushIndirect ( & Brush ) ;        
        OldPen = SelectObject ( Dc , Pinceau ) ;
        OldBrush = SelectObject ( Dc , HBrush ) ;
        Rectangle ( Dc , PosX , PosY , PosX + TailleW , PosY + TailleH ) ;        
        SelectObject ( Dc , OldPen ) ;
        SelectObject ( Dc , OldBrush ) ;
        DeleteObject ( HBrush ) ;
        DeleteObject ( Pinceau ) ;
        if ( O->Type == OBJ_TYPE_BITMAP << 1 )
        {
            SelectObject ( Dc , OldItem ) ;
            DeleteDC ( Dc ) ;
        }
        s = MMpush(m,s) ;

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRDrawRectangle end");
#endif
//***********************************

        return s ;
}    







/*****************************************************************************/
/*                                                                           */
/* int GRDrawLine ( mmachine m )                                             */
/*                                                                           */
/* cette fonction correspond a la fonction magma Obj _draw_line (            */
/* ( Obj Buffer , I X1 , I Y1 , I X2 , I Y2 , I Mode_Contour,I Taille_Contour*/
/* I Couleur_Contour )                                                       */
/*                                                                           */
/*****************************************************************************/

int GRDrawLine ( mmachine m )
{
    int Taille_Contour , Mode_Contour , Couleur_Contour , X1 , Y1 , X2 , Y2 ;
    int s ;
    PtrObjVoid O ;    
	PtrObjBitmap B;
    HPEN Pinceau , OldPen ;
    HWND Item , OldItem ;
    POINT Ligne [ 2 ] ;
    HDC Dc ;

 //***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRDrawLine");
#endif
//***********************************
    Couleur_Contour = MMpull(m)>>1 ;
    Taille_Contour = MMpull ( m ) >> 1 ;
    Mode_Contour = MMpull(m)>>1 ;
    Y2 = MMpull(m) >> 1 ;
    X2 = MMpull(m) >> 1 ;
    Y1 = MMpull(m) >> 1 ;
    X1 = MMpull(m) >> 1 ;
    s = MMpull(m) ;
    if ( s== NIL )
    {
        MMechostr ( 1 , "DrawLine : Buffer is NIL\n" ) ;
        return MMpush(m,NIL) ;
    }
    O = ( PtrObjVoid ) MMstart(m, (s>>1) ) ;         
    switch ( O->Type >> 1 )
    {
        case OBJ_TYPE_BITMAP :          

			B = ( PtrObjBitmap ) MMstart(m, (O->Buffer>>1));
				
			//$ LB (13/06/2002) : create DIBSection from bitmap buffer
			if (!B->DIBhandler) ObjBitmap_CreateDIBSection (B);

            Dc = CreateCompatibleDC ( NULL ) ;
            Item = (HWND)B->DIBhandler;
            OldItem = SelectObject ( Dc , Item ) ;
            break ;

        case OBJ_TYPE_WINDOW :
            Item = (( PtrObjWindow ) MMstart(m,(O->Buffer>>1) ) ) ->WHandler ;
            Dc = GetDC ( Item ) ;
            break ;
    }

    if ( Mode_Contour == DRAW_INVISIBLE ||Taille_Contour <= 0 )
        Pinceau = CreatePen ( PS_NULL  , Taille_Contour , Couleur_Contour ) ;
    else Pinceau = CreatePen ( PS_SOLID , Taille_Contour , Couleur_Contour ) ;
    OldPen = SelectObject ( Dc , Pinceau ) ;
    

    Ligne [ 0 ] .x = X1 ;
    Ligne [ 0 ] .y = Y1 ;
    Ligne [ 1 ] .x = X2 ;
    Ligne [ 1 ] .y = Y2 ;

    if ( X1 == X2 && Y1 == Y2 ) SetPixel ( Dc , X1 , Y1 , Couleur_Contour ) ;
    else Polygon ( Dc , Ligne , 2 ) ;   
   
    OldPen = SelectObject ( Dc , OldPen ) ;
    s = MMpush(m,s) ;
    if ( O->Type == OBJ_TYPE_BITMAP << 1 )
    {
        SelectObject ( Dc , OldItem ) ;
        DeleteDC ( Dc ) ;
    }
    DeleteObject ( OldPen ) ;

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRDrawLine end");
#endif
//***********************************

    return s ;
            
}







/*****************************************************************************/
/*                                                                           */
/* int GRDrawCircle ( mmachine m )                                           */
/*                                                                           */
/* correspond a la fonction magma Obj _draw_circle ( Obj Buffer , I PosX ,   */
/* I PosY , I Rayon , I Mode_Contour , I Taille_Contour , I Couleur_Contour, */
/* I Mode_Remplissage , I Couleur_Remplissage ) ;                            */
/* laquelle dessine un cercle dans un buffer graphique                       */
/*                                                                           */
/*****************************************************************************/

int GRDrawCircle ( mmachine m )
{
    int s , PosX , PosY , Mode_Contour , Taille_Contour , Couleur_Contour , Rayon ;
    int Mode_Fill , Couleur_Fill ;
    PtrObjVoid O ;
    PtrObjBitmap B ;
    HPEN Pinceau , OldPen ;
    HWND OldItem , Item ;
    LOGBRUSH Brush ;
    HBRUSH HBrush , OldBrush ;
    HDC Dc ;

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRDrawCircle");
#endif
//***********************************


    Couleur_Fill = MMpull(m) >> 1 ;
    Mode_Fill = MMpull(m) >> 1 ;
    Couleur_Contour = MMpull(m) >> 1 ;
    Taille_Contour = MMpull(m) >> 1 ;
    Mode_Contour = MMpull(m) >> 1 ;
    Rayon = MMpull(m) >> 1 ;
    PosY = MMpull(m) >> 1 ;
    PosX = MMpull(m) >> 1 ;
    s = MMpull(m) ;
    if ( s == NIL )
    {
        MMechostr ( 1 , "DrawCircle : Buffer is NIL\n" ) ;
        return MMpush(m,NIL) ;
    }
    O = ( PtrObjVoid ) MMstart(m, ( s>>1 ) ) ;

    switch ( O->Type >> 1 )
    {
        case OBJ_TYPE_BITMAP :
            B = ( PtrObjBitmap ) MMstart(m, (O->Buffer>>1) ) ;
				
			//$ LB (13/06/2002) : create DIBSection from bitmap buffer
			if (!B->DIBhandler) ObjBitmap_CreateDIBSection (B);

            Dc = CreateCompatibleDC ( NULL ) ;
            Item = (HWND)B->DIBhandler; 
            OldItem = SelectObject ( Dc , Item ) ;
            break ;
        case OBJ_TYPE_WINDOW :
            Item = (( PtrObjWindow ) MMstart(m,( O->Buffer>>1) ) ) ->WHandler ;
            Dc = GetDC ( Item ) ;
            break ;
    }

    if ( Taille_Contour <= 0 ) { Taille_Contour = 0 ; Mode_Contour = DRAW_INVISIBLE;}

    if ( Mode_Contour == DRAW_INVISIBLE )
        Pinceau = CreatePen ( PS_NULL , Taille_Contour , Couleur_Contour ) ;
    else Pinceau = CreatePen ( PS_SOLID , Taille_Contour , Couleur_Contour ) ;
    if ( Mode_Fill == DRAW_INVISIBLE ) Brush.lbStyle = BS_NULL ;
    else Brush.lbStyle = BS_SOLID ;
    Brush.lbColor = Couleur_Fill ;
  
    HBrush = CreateBrushIndirect ( & Brush ) ;
    OldBrush = SelectObject ( Dc , HBrush ) ;
    OldPen = SelectObject ( Dc , Pinceau ) ;
    
    Ellipse ( Dc , PosX - Rayon , PosY - Rayon , PosX + Rayon , PosY + Rayon ) ;

    SelectObject ( Dc , OldBrush ) ;    
    SelectObject ( Dc , OldPen ) ;
    DeleteObject ( Pinceau ) ;
    DeleteObject ( HBrush ) ;
    if ( O->Type == OBJ_TYPE_BITMAP << 1 )
    {
        SelectObject ( Dc , OldItem ) ;
        DeleteDC ( Dc ) ;
    }

    s = MMpush(m,s) ;

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRDrawCircle end");
#endif
//***********************************

    return s ;
}






/********************************************************************************/
/*                                                                              */
/* int GRLoadBitmap8 ( mmachine m ) ;                                           */
/*                                                                              */
/* correspond a la fonction magma ObjBitmap8 _LDbitmap8 ( S )                   */
/* laquelle charge un bitmap 256 couleurs                                       */
/*                                                                              */
/********************************************************************************/

int GRLoadBitmap8 ( mmachine m )
{

    return GenericLoadBitmap ( m , 8 ) ;
}





/***********************************************************************************/
/*                                                                                 */
/*  int GRCreatebitmap8 ( mmachine m ) ;                                           */
/*                                                                                 */
/*  correspond ala fonction ObjBitmap8 _create_bitmap8 ( I tialleW , I tailleH )   */
/* laquelle cree un bitmap palette de la taille desiree                            */
/*                                                                                 */
/***********************************************************************************/

int GRCreateBitmap8 ( mmachine m ) 
{
   return GenericCreateBitmap ( m , 8 ) ;
}





/***********************************************************************************/
/*                                                                                 */
/*  int GRDestroyBitmap ( mmachine m ) ;                                           */
/*                                                                                 */
/*  correspond a la fonction magma I _destroy_bitmap ( ObjBitmap )                 */
/* et a la fonction I _destroy_bitmap8 ( ObjBitmap8 )                              */
/* lesquelles detruisent un objet bitmap et libere la memoire de celui-ci          */
/*                                                                                 */
/***********************************************************************************/

int GRDestroyBitmap ( mmachine m )
{
    int s ; 
    PtrObjVoid O ;
    PtrObjBitmap M ;

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRDestroyBitmap");
#endif
//***********************************

    s = MMget(m,0) ;
    if ( s == NIL ) 
    {
        MMset(m,0,0) ;
        return 0 ;
    }

    O = ( PtrObjVoid ) MMstart(m,(s>>1) ) ;
    M = ( PtrObjBitmap ) MMstart(m,(O->Buffer>>1) ) ;  

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRDestroyBitmap handler %d", (int)M->handler);
#endif
//***********************************


    OBJdelTH(m,OBJTYPBITMAP,(int)M->handler);
     
//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRDestroyBitmap end");
#endif
//***********************************

    MMset(m,0,0) ;
    return 0 ;
}




/**********************************************************************************/
/*                                                                                */
/*  int GRGetbitmapPalette ( mmachine m ) ;                                       */
/*                                                                                */
/*  correspond a la fonction tab [i ] = _get_bitmap_paletet ( ObjBItmap8 ) ;      */
/* laquelle renvoi la palette d'un bitmap palete                                  */
/*                                                                                */
/**********************************************************************************/

int GRGetBitmapPalette ( mmachine m ) 
{
    int s ;
    PtrObjVoid O ;
    PtrObjBitmap M ;
    struct Palette Pal ;

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRGetBitmapPalette");
#endif
//***********************************

    s = MMpull(m) ;
    if ( s == NIL ) 
    {
        MMpush(m,NIL) ;
        return 0 ;
    }

    O = ( PtrObjVoid ) MMstart(m,(s>>1) ) ;
    M = ( PtrObjBitmap ) MMstart(m,(O->Buffer>>1) ) ;  
    GetBitmapPalette ( M , &Pal ) ;

    for ( s = 0 ; s < 256 ; s ++ )
    {
        if ( MMpush ( m , ( GET_RED   (&Pal,s))<<1)) return MERRMEM ;
        if ( MMpush ( m , ( GET_GREEN (&Pal,s))<<1)) return MERRMEM ;
        if ( MMpush ( m , ( GET_BLUE  (&Pal,s))<<1)) return MERRMEM ;
    }

    if ( MMpush(m,768<<1)) return MERRMEM ;

 //***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRGetBitmapPalette end");
#endif
//***********************************
    
    return MBdeftab ( m ) ;
}





/**************************************************************************************/
/*                                                                                    */
/*  int GRSetBitmapPalette ( mmachine m ) ;                                           */
/*                                                                                    */
/* correspond a la focntion magma ObjBitmap8 _set_bitmap_palette ( ObjBitmap8 , tab[i]*/
/* laquelle affecte une nouvelle palette a un objet bitmap palettee                   */
/*                                                                                    */
/**************************************************************************************/

int GRSetBitmapPalette ( mmachine m )
{

    int s , j  , i ;
    PtrObjVoid O ;
    PtrObjBitmap M ;
    struct Palette Pal ;
    unsigned int * Tablo ;

 //***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRSetBitmapPalette");
#endif
//***********************************

    s = MMpull(m) ;
    if ( s == NIL ) return 0 ;
    if ( MMsize(m,s>>1) != 768 )
    {
        MMechostr ( 1 , "The Palette Array haven't the good size\n" ) ;
        return 0 ;
    }
    Tablo = ( unsigned int * ) MMstart(m,(s>>1) );

    s = MMget(m,0) ;
    if ( s == NIL ) 
    {
        MMset(m,0,0) ;
        return 0 ;
    }

    O = ( PtrObjVoid ) MMstart(m,(s>>1) ) ;
    M = ( PtrObjBitmap ) MMstart(m,(O->Buffer>>1) ) ;  

    i = 0 ;
    for ( j = 0 ; j < 256 ; j ++ )
    {
        GET_RED   (&Pal,j) = Tablo [ i ++ ] >> 1;
        GET_GREEN (&Pal,j) = Tablo [ i ++ ] >> 1;
        GET_BLUE  (&Pal,j) = Tablo [ i ++ ] >> 1;
    }

    SetBitmapPalette ( M , &Pal ) ;
   

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRSetBitmapPalette end");
#endif
//***********************************
    
    return 0 ;
}






/*****************************************************************************/
/*                                                                           */
/*  int GRCopyBitmap ( mmachine m ) ;                                        */
/*                                                                           */
/* correspond a la fonction magma Obj _copy_bitmap ( ObjBitmap8 Destination, */
/* I PosX , I PosY , ObjBitmap8 Source , I SPosX,  I SPosY , I TaillW ,      */
/* I TailleH , I Couleur) ;                                                  */
/*                                                                           */
/*****************************************************************************/

int GRCopyBitmap ( mmachine m )
{
        int s , s2 , res , couleur , taillew , tailleh, sposx , sposy , dposx , dposy;
		int dcx , dcy , scx , scy ;
        PtrObjVoid OS , OD ;       
        PtrObjBitmap BD,BS ;        
        int i;
        register OBJBITMAP_BUFFER BufS;
		register OBJBITMAP_BUFFER BufD;       
        register j ;
        struct Palette Pal ;       

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRCopyBitmap");
#endif
//***********************************


        couleur = MMpull(m) >> 1 ;        
        tailleh = MMpull(m) >> 1 ;
        taillew = MMpull(m)>> 1 ;
        sposy = MMpull(m) >> 1 ;
        sposx = MMpull(m) >> 1 ;
        s2 = MMpull(m) ;
        dposy = MMpull(m) >> 1;
        dposx = MMpull(m) >> 1 ;
        s = MMpull(m) ;
        if ( s2 == NIL )
        {
            MMechostr ( 1 , "PaintBuffer : Buffer object is NIL\n" ) ;
            return MMpush(m,s) ;
        }
        OS = ( PtrObjVoid ) MMstart(m, (s2>>1) ) ;        
        if ( s == NIL )
        {
            MMechostr ( 1 , "PaintBuffer : Window object is NIL\n" ) ;
            return MMpush(m,s) ;
        }
        OD = ( PtrObjVoid ) MMstart(m, (s>>1) ) ;
        
        BS = ( PtrObjBitmap ) MMstart(m, (OS->Buffer>>1) ) ;
        BD = ( PtrObjBitmap ) MMstart(m, (OD->Buffer>>1) ) ;

		if (BS->bits == NULL)
		{
		    if (OS->Tab==NIL) MMechostr(MSKDEBUG,"bitmap is _CRbitmap\n");
	    	  else  MMechostr(MSKDEBUG,"bitmap is _LDbitmap : %s\n",MMstartstr(m,OS->Tab>>1));

			MMechostr(MSKTRACE,"COPYbitmap : Source Bitmap already destroyed %x\n",BS->handler);
			return MMpush(m,NIL);
		}

		if (BD->bits==NULL)
		{
			MMechostr(MSKTRACE,"COPYbitmap : Dest Bitmap already destroyed %x\n",BD->handler);
			return MMpush(m,NIL);
		}

		
        /* calcule le rectangle final = proc de clipping */
      
        
        if ( ClipBlit ( BD->TailleW , BD->TailleH , BS->TailleW , BS->TailleH ,
                &dposx , &dposy , &sposx , &sposy , &taillew , &tailleh ) )
        {      
         
            if (( BD->BPP == 8 ) && ( BS->BPP == 8 ))
            {

				//***********************************
				#if DEBUG_LIB2DOS
				MMechostr (0, "\nGRCopyBitmap 8bits -> 8bits copy");
				#endif
				//***********************************

                BufS = (OBJBITMAP_BUFFER) BS->bits;
                BufD = (OBJBITMAP_BUFFER) BD->bits;

                dcy = dposy * BD->BPL + dposx ;
                scy = sposy * BS->BPL + sposx ;

                if ( couleur == NIL )  for ( j = 0 ; j < tailleh ; j ++ )
                {                     
                   
                    CopyMemory(BufD + dcy , BufS + scy , taillew ) ;
                    dcy += BD->BPL ; scy += BS->BPL ;
                } else
                for ( j = 0 ; j < tailleh ; j ++ )
                {                     
                    dcx = dcy  ;
                    scx = scy ;
                    for ( i = 0 ; i < taillew ; i ++ )
                    {             
                        if ( BufS [scx ] != couleur ) BufD [ dcx ] = BufS [ scx ] ;
                        dcx ++ ;
                        scx ++ ;
                    }
                    dcy += BD->BPL ;
                    scy += BS->BPL ;
                }
            } else if (( BD->BPP == 24 ) && ( BS->BPP == 8 ))
            {

				//***********************************
				#if DEBUG_LIB2DOS
				MMechostr (0, "\nGRCopyBitmap 8bits -> 24bits copy");
				#endif
				//***********************************
				
				GetBitmapPalette ( BS , & Pal ) ;
                BufS = (OBJBITMAP_BUFFER) BS->bits;
                dcy = dposy * BD->BPL  + (dposx * BD->BytesPP) ;
                scy = sposy * BS->BPL + sposx ;
                                
                for ( j = 0 ; j < tailleh ; j ++ )
                {
                    dcx = dcy ;
                    scx = scy ;
                    for ( i = 0 ; i < taillew ; i ++)
                    {
                        if ( BufS [ scx ] != couleur )
                        BD->bits [ dcx ] =  GET_BLUE(&Pal, BufS [ scx ]);
						BD->bits [dcx+1] =  GET_GREEN ( &Pal,BufS[ scx ]);
						BD->bits [dcx+2] = GET_RED ( &Pal , BufS [ scx ]);
                        dcx +=3 ;
                        scx ++ ;
                    }
                    dcy += BD->BPL ;
                    scy += BS->BPL ;
                }
            } else if (( BD->BPP == 24 ) && ( BS->BPP == 24 ))
            {


				//***********************************
				#if DEBUG_LIB2DOS
				MMechostr (0, "\nGRCopyBitmap 24bits -> 24bits copy ");
				MMechostr (0, ": SRC [%d  BPP %d  BytesPP %d  BPL %d   w %d   h %d]   DST [%d  BPP %d  BytesPP %d  BPL %d   w %d   h %d]",
					BS->handler, BS->BPP, BS->BytesPP, BS->BPL, BS->TailleW, BS->TailleH, BD->handler, BD->BPP, BD->BytesPP, BD->BPL, BD->TailleW, BD->TailleH);
				#endif
				//***********************************


                dcy = dposy * BD->BPL + (dposx * BD->BytesPP) ;
                scy = sposy * BS->BPL + (sposx * BS->BytesPP) ;

                if ( couleur == NIL ) 
                {     
                    BufS = (OBJBITMAP_BUFFER)( BS->bits + scy);
                    BufD = (OBJBITMAP_BUFFER) (BD->bits  + dcy);

                    for ( j = 0 ; j < tailleh ; j ++ )
                    {                 
                       memcpy( BufD, BufS, taillew * BS->BytesPP) ;                   
                        BufD += BD->BPL ;
                        BufS += BS->BPL ;
                    }

                }
                else 
                {
				int srcColor;

                    for ( j = 0 ; j < tailleh ; j ++ )
                    {
                        dcx = dcy ;
                        scx = scy ;
                        for ( i = 0 ; i < taillew ; i ++ , dcx +=3 , scx +=3 )
						{
							srcColor = _COLOR_BGR_TO_I ((char)BS->bits[scx], (char)BS->bits[scx+1], (char)BS->bits[scx+2]);
							if ( srcColor != couleur ) 
							{
								BD->bits [ dcx   ] = BS->bits [ scx   ] ;
								BD->bits [ dcx+1 ] = BS->bits [ scx+1 ] ;
								BD->bits [ dcx+2 ] = BS->bits [ scx+2 ] ;
							}
						}
                        dcy += BD->BPL ;
                        scy += BS->BPL ;
                    }

                }
            }
        }
                                   
        res = MMpush(m,s) ;

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRCopyBitmap end");
#endif
//***********************************

        return res ;
}


/**************************************************************************************/
/*                                                                                    */
/*  int GRSetBitmapPalette ( mmachine m ) ;                                           */
/*                                                                                    */
/* correspond a la focntion magma ObjBitmap8 _set_bitmap_palette ( ObjBitmap8 , tab[i]*/
/* laquelle affecte une nouvelle palette a un objet bitmap palettee                   */
/*                                                                                    */
/**************************************************************************************/

int GRAffBitmapPalette ( mmachine m )
{

    int s , j  , i ;
    PtrObjVoid O ;
    PtrObjBitmap M ;
    struct Palette PalSource , PalDest ;
    unsigned int * Tablo ;
    int Convert [ 256 ] ;
    OBJBITMAP_BUFFER Image ;

 //***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRAffBitmapPalette");
#endif
//***********************************

    s = MMpull(m) ;
    if ( s == NIL ) return 0 ;
    i = MMsize ( m , s >> 1 ) ;
    if ( i != 768 )
    {
        MMechostr ( 1 , "The Palette Array haven't the good size == %d\n" , i ) ;
        return 0 ;
    }
    Tablo = ( unsigned int * ) MMstart(m,(s>>1) );

    s = MMget(m,0) ;
    if ( s == NIL ) 
    {
        MMset(m,0,0) ;
        return 0 ;
    }

    O = ( PtrObjVoid ) MMstart(m,(s>>1) ) ;
    M = ( PtrObjBitmap ) MMstart(m,(O->Buffer>>1) ) ;  

	if (M->bits == NULL)
	{
		MMechostr(MSKTRACE,"AffBitmapPalette : Bitmap already destroyed %x\n",M->handler);
        MMset(m,0,0) ;
		return 0;
	}

	//$ LB (13/06/2002) : create DIBSection from bitmap buffer
	if (!M->DIBhandler) ObjBitmap_CreateDIBSection (M);


    i = 0 ;
    for ( j = 0 ; j < 256 ; j ++ )
    {
        GET_RED   (&PalDest,j) = Tablo [ i ++ ] >> 1;
        GET_GREEN (&PalDest,j) = Tablo [ i ++ ] >> 1;
        GET_BLUE  (&PalDest,j) = Tablo [ i ++ ] >> 1;
    }
    GetBitmapPalette ( M , &PalSource ) ;
    SetBitmapPalette ( M , &PalDest ) ;
    ProjectionPalette ( &PalDest , &PalSource , Convert ) ;

    Image = (OBJBITMAP_BUFFER) M->bits;

    for ( j = 0 ; j < M->TailleH ; j ++ )
    for ( i = 0 ; i < M->TailleW ; i ++ ) 
    Image [ i + j * M->BPL ] = Convert [ Image [i + j * M->BPL ] ] ;
   

 //***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRAffBitmapPalette end");
#endif
//***********************************
    
    return 0 ;
}






/*************************************************************************************/
/*                                                                                   */
/*  int GRGetBitma p( mmachine m ) ;                                                 */
/*                                                                                   */
/* correspond a la fonction S _get_bitmap ( ObjBitmap )                              */
/*                                                                                   */
/*************************************************************************************/

int GRGetBitmap ( mmachine m ) 
{
    int s , res , j, k,l ; 
    PtrObjVoid O ;
    PtrObjBitmap B ;
    OBJBITMAP_BUFFER BS;
	OBJBITMAP_BUFFER BB;
    
//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRGetBitmap");
#endif
//***********************************
    


    s = MMpull(m) ;
    if ( s == NIL ) res = MMpush(m,NIL ) ;
    else
    {
        O = ( PtrObjVoid ) MMstart(m,(s>>1) ) ;
        B = ( PtrObjBitmap ) MMstart(m,(O->Buffer>>1) ) ;

		//$LB (16/12/2002) : windows bitmap are 32bits aligned !!
		l = B->BPL * B->TailleH;


        BB = (OBJBITMAP_BUFFER) B->bits;

		if (B->bits == NULL)
		{
			MMechostr(MSKTRACE,"GETnitmap : Bitmap already destroyed %x\n",B->handler);
			return MMpush(m,NIL);
		}

		//$LB : push S to avoid gc crash
		if (k=(MMpush (m, s))) return k;

        res = MMmalloc (m,((l+4)>>2)+1,TYPEBUF) ;

        if ( res == NIL )
        {
             MMechostr ( 1 , "Not enough memory to store the bitmap of size %d" , l ) ;
             return MERRMEM ;
        }
        else 
        {
			//$LB : retrieve the bitmap scol pointer
			s = MMpull(m);

			O = ( PtrObjVoid ) MMstart(m,(s>>1) ) ;
			B = ( PtrObjBitmap ) MMstart(m,(O->Buffer>>1) ) ;
			BB = (OBJBITMAP_BUFFER) B->bits;

             *( int * ) MMstart(m, res ) = l ;
             BS = (OBJBITMAP_BUFFER) MMstart(m,res  + 1) ;


			 //$LB
             for ( j = 0 ; j < B->TailleH ; j ++ )
             {     
			    memcpy( BS, BB, B->BPL) ;                   
				BS += B->BPL;
                BB += B->BPL;
             }


        }                            
        res = MMpush(m,( res<<1) + 1 ) ;
    }

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRGetBitmap end");
#endif
//***********************************

    return res ;
}





/*********************************************************************************************/
/*                                                                                           */
/*  int GRSetBitmap ( mmachine m )                                                           */
/*                                                                                           */
/* correspond a la fonction ObjBitmap _set_bitmap ( ObjBitmap  , S )                         */
/*                                                                                           */
/*********************************************************************************************/

  int GRSetBitmap ( mmachine m ) 
{
    int s , res , s2 , l , j , l2 ; 
    PtrObjVoid O ;
    PtrObjBitmap B ;
    OBJBITMAP_BUFFER Buf ; 
	OBJBITMAP_BUFFER BB;
    
//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRSetBitmap");
#endif
//***********************************


    s2 = MMpull(m) ;
    s = MMpull(m) ;
    if (( s == NIL ) ||  ( s2 == NIL ))
    {
        MMechostr( 1 , "Bitmap or Buffer is NIL\n" ) ;
        return MMpush(m,s) ; 
    }

    O = ( PtrObjVoid ) MMstart(m,(s>>1 ) ) ;
    B = ( PtrObjBitmap ) MMstart(m,(O->Buffer>>1) ) ;
	
	if (B->bits == NULL)
	{
		MMechostr(MSKTRACE,"SETbitmap : Bitmap already destroyed %x\n",B->handler);
		return MMpush(m,NIL);
	}

    l2 =  MMsizestr ( m , s2 >>1 ) ;
    if ( s == NIL ) res = MMpush(m,s) ;
    else
    {
		//$LB (16/12/2002) : windows bitmap are 32bits aligned !!
        l = B->TailleH * B->BPL;

        if ( l!= l2 ) MMechostr ( 1 , "Wrong size for the string. (bmp %d!= str %d)\n",l,l2 ) ;
		else
        {
            O = ( PtrObjVoid ) MMstart(m,(s>>1) ) ;
            B = ( PtrObjBitmap ) MMstart(m,(O->Buffer>>1) ) ;
			BB = (OBJBITMAP_BUFFER) B->bits;
            Buf = (OBJBITMAP_BUFFER) MMstart(m,(s2>>1) +  1) ;            

			 //$LB
             for ( j = 0 ; j < B->TailleH ; j ++ )
             {   
				memcpy( BB, Buf, B->BPL) ;                   
                BB += B->BPL;
                Buf += B->BPL;
             }


        }        
    }
    res = MMpush(m,s) ;

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRSetBitmap end");
#endif
//***********************************

    return res ;
}




/***********************************************************************************************/
/*                                                                                             */
/*      int GRStretchBitmap ( mmachine m )                                                     */
/*                                                                                             */
/* correspond aux fonction de copy avec strectch _SCPbitmap                                    */
/* ( ObjBitmap dest , I dposx1 , I dposy1 , I dposx2 , I dposy2 , ObjBitmap src , I sposx1 ,   */
/* I sposY1 , I sposX2 , I sposY2 , I couleur ) ;                                              */
/*                                                                                             */
/***********************************************************************************************/

//#define DEBUG_STRETCH

int GRStretchBitmap ( mmachine m )
{
    int couleur , sposy2 , sposx2 , sposy1 , sposx1 , dposy2 , dposy1 , dposx2 , dposx1 ;
    int i , j ;
    int ss , sd , res ;
    int ddx , ddy , dsx , dsy , dex , dey  ;
    int ody , odx , ocy , ocx ;
    PtrObjVoid OS , OD ;
    PtrObjBitmap BS , BD ;

 //***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRStretchBitmap");
#endif
//***********************************

    couleur = MMpull(m) >> 1 ;   
    sposy2 = MMpull(m) >> 1 ;
    sposx2 = MMpull(m) >> 1 ;
    sposy1 = MMpull(m) >> 1 ;
    sposx1 = MMpull(m) >> 1 ;
    ss = MMpull(m) ;
    dposy2 = MMpull(m) >> 1 ;
    dposx2 = MMpull(m) >> 1 ;
    dposy1 = MMpull(m) >> 1 ;
    dposx1 = MMpull(m) >> 1 ;
    sd = MMpull(m) ;




    
    if ( ss == NIL || sd == NIL )
    {
        MMechostr ( 1 , "stretch _bitmap source or destination bitrmap is NIL\n" ) ;
        return MMpush(m,sd ) ;
    }

    OS = ( PtrObjVoid ) MMstart(m, ( ss >> 1 ) ) ;
    BS = ( PtrObjBitmap )  MMstart(m, ( OS->Buffer>>1) ) ;
    OD = ( PtrObjVoid ) MMstart(m, ( sd >> 1 ) ) ;
    BD = ( PtrObjBitmap ) MMstart(m, ( OD->Buffer>>1) ) ;


	if (BS->bits == NULL)
	{
		MMechostr(MSKTRACE,"STRETCHbitmap : Source Bitmap already destroyed %x\n",BS->handler);
		return MMpush(m,NIL);
	}

	if (BD->bits == NULL)
	{
		MMechostr(MSKTRACE,"STRETCHbitmap : Dest Bitmap already destroyed %x\n",BD->handler);
		return MMpush(m,NIL);
	}

    #ifdef DEBUG_STRETCH

        MMechostr ( 1 , "Avant Clip : Taille D %d %d S %d %d SRECT %d %d %d %d SD %d %d %d %d\n" ,
        BD->TailleW , BD->TailleH , BS->TailleW , BS->TailleH , sposx1 , sposy1 , sposx2 ,
        sposy2 , dposx1 , dposy1 , dposx2 , dposy2 ) ;

    #endif

    if ( ClipStretch ( BD->TailleW , BD->TailleH , BS->TailleW , BS->TailleH ,
        &dposx1 , &dposy1 , &dposx2 , &dposy2 , &sposx1 , &sposy1, &sposx2, &sposy2 ))

    {
    #ifdef DEBUG_STRETCH

        MMechostr ( 1 , "Apres Clip : Taille D %d %d S %d %d SRECT %d %d %d %d SD %d %d %d %d\n" ,
        BD->TailleW , BD->TailleH , BS->TailleW , BS->TailleH , sposx1 , sposy1 , sposx2 ,
        sposy2 , dposx1 , dposy1 , dposx2 , dposy2 ) ;

    #endif

    
      
        ddx = dposx2 - dposx1 + 1 ;
        ddy = dposy2 - dposy1 + 1 ;
        dsx = sposx2 - sposx1 + 1 ;
        dsy = sposy2 - sposy1 + 1 ;
        dex = 0 ;
        dey = 0 ;
        
    #ifdef DEBUG_STRETCH
        MMechostr ( 1 , "Deltas values : ddx%d ddy %d dsx %d dsy %d\r\n",ddx,ddy,dsx,dsy);
    #endif

        if (( BD->BPP == 8 ) && ( BS->BPP == 8 )) 
        {
            ody = dposy1 * BD->BPL + dposx1 ;
            ocy = sposy1 * BS->BPL + sposx1 ;

            for ( j = dposy1 ; j <= dposy2 ; j ++ )
            {
                odx = ody ;
                ocx = ocy ;
                dex = 0 ;
                for ( i = dposx1 ; i <= dposx2 ; i ++ )
                {
                    if ( couleur != ((OBJBITMAP_BUFFER) BS->bits) [ ocx ] )
                    ((OBJBITMAP_BUFFER) BD->bits) [ odx ] = 
                    ((OBJBITMAP_BUFFER) BS->bits) [ ocx ] ;
                    odx ++ ;
                    dex += dsx ;
                    while ( dex >= ddx ) 
                    {
                        ocx ++ ;
                        dex -= ddx ;
                    }
                }
                ody += BD->BPL ;
                dey += dsy ;
                while ( dey >= ddy )
                {
                    ocy += BS->BPL ;
                    dey -= ddy ;
                }
            }
        }
        else if (( BS->BPP == 24 ) && ( BD->BPP == 24 ))
        {
		int srcColor;

            ody = (dposy1 * BD->BPL)   + (dposx1 * BD->BytesPP);
            ocy = (sposy1 * BS->BPL)   + (sposx1 * BS->BytesPP);
        
            for ( j = dposy1 ; j <= dposy2 ; j ++ )
            {
                odx = ody ;
                ocx = ocy ;
                dex = 0 ;
                for ( i = dposx1 ; i <= dposx2 ; i ++ )
                {
					srcColor = _COLOR_BGR_TO_I (BS->bits [ocx ], BS->bits [ocx+1 ], BS->bits [ocx+2 ]);

                    if ( couleur != srcColor ) 
					{
						BD->bits [ odx   ] = BS->bits [ ocx   ] ;
						BD->bits [ odx+1 ] = BS->bits [ ocx+1 ] ;
						BD->bits [ odx+2 ] = BS->bits [ ocx+2 ] ;
					}

                    odx +=3 ;
                    dex += dsx ;
                    while ( dex >= ddx ) 
                    {
                        ocx +=3;
                        dex -= ddx ;
                    }
                }

                ody += BD->BPL;
                dey += dsy ;

                while ( dey >= ddy )
                {
                    ocy += BS->BPL ;
                    dey -= ddy ;
                }
            }
        }
    }










    res = MMpush(m,sd ) ;


//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRStretchBitmap end");
#endif
//***********************************

    return res ;
}







/************************************************************************************/
/*                                                                                  */
/*  int GRMapBitmap ( mmachine m ) ;                                                */
/*   correspond a la fonction Objbitmap _map_bitmap ( ObjBitmap Destination         */
/* I x1 , I y1 , I x2 , I y2 , I x3 , I y3 , I x4 , I y4 , ObjBitmap Source         */
/*  I sx1 , I sy1 , I Taillew , I TailleH , I couleur )                             */
/*                                                                                  */
/************************************************************************************/

//#define DEBUG_2DMAP ;
int GRMapBitmap ( mmachine m ) 
{
    int xd [ 4 ] ;
    int yd [ 4 ] ;
    int xs [ 4 ] ;
    int ys [ 4 ] ;
    int couleur , res , ss , sd ; 
    char lps , lpe , rps , rpe ;
  
    int xdl ,       /* x courant sur le cote LEFT du polygone destination  */
        ydl ,       /* y courant sur le cote LEFT du polygone destination  */
        xdr ,       /* x courant sur le cote RIGHT du polygone destiantion */
        ydr ,       /* y courant sur le cote RIGHT du polygone destination */
        xsl ,       /* x courant cote LEFT de la map source                */
        ysl ,       /* y courant cote LEFT de la map source                */
        xsr ,       /* x courant cote RIGHT map source                     */
        ysr ,       /* y courant cote RIGHT map source                     */
        deltaleft , /* points verticaux a tracer , polygone dest , LEFT    */
        points ,    /* points a tracer avant que le polygone soit complet  */
        dlx ,       /* delta X cote left polygone destination              */
        dly ,       /* delta Y cote ledt polygone destination              */
        drx ,       /* delta X cote right polygone destination             */
        dry ,       /* delta Y cote right polygone destination             */
        deltaright ,/* points verticaux a tracer , polygone dest , RIGHT   */
        erl ,       /* terme d'erreur pour le pas X , polygone dest LEFT   */
        err ,       /* terme d'erreur pour le pas X , polygone dest , RIGHT*/
        deplx ,     /* pas de deplacement X poly dest , LEFT               */
        deprx ,     /* pas de deplacement Y poly dest , RIGHT              */
        emlx ,      /* terme d'erreur MAP LEFT X                           */
        emly ,      /* terme d'erreur MAP LEFT Y                           */
        emrx ,      /* terme d'erreur MAP RIGHT X                          */
        emry ,      /* terme d'erreur MAP RIGHT Y                          */
        movlx ,     /* pas X MAP LEFT                                      */
        movly ,     /* pas Y MAP LEFT                                      */
        movrx ,     /* pas X MAP RIGHT                                     */
        movry ,     /* pas Y MAP RIGHT                                     */
        delslx ,    /* delta X MAP LEFT                                    */
        delsly ,    /* delta Y MAP LEFT                                    */
        delsrx ,    /* delta X MAP RIGHT                                   */
        delsry ,    /* delta Y MAP RIGHT                                   */
        delmapx,    /* delta X MAP MAPPING                                 */
        delmapy,    /* delta Y MAP MAPPING                                 */
        movmapx,    /* pas X MAP MAPPING                                   */
        movmapy,    /* pas Y MAP MAPPING                                   */
        delmap ,    /* taille du segment a mapper                          */
        movmap,     /* sens                                                */
        xdest ,     /* x du MAPPING                                        */
        mapx ,      /* X MAP MAPPING                                       */
        mapy ,      /* Y MAP MAPPING                                       */
        maperrx ,   /* terme d'errreur X du MAPPER                         */
        maperry ,   /* terme d'erreur Y du MAPPER                          */
        //offread ,   /* offset de lecture                                   */
        i ;

    PtrObjVoid OS , OD ;
    PtrObjBitmap BS , BD ;

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRMapBitmap");
#endif
//***********************************

    /***************** LECTURE DES VALEURS DANS LA PILE ******************************/
    couleur = MMpull ( m ) >> 1 ;

    ys [ 2 ] = MMpull ( m ) >> 1 ;
    xs [ 2 ] = MMpull ( m ) >> 1 ;
    ys [ 0 ] = MMpull ( m ) >> 1 ;
    xs [ 0 ] = MMpull ( m ) >> 1 ;
    ss = MMpull ( m ) ;
    yd [ 3 ] = MMpull ( m ) >> 1 ;
    xd [ 3 ] = MMpull ( m ) >> 1 ;
    yd [ 2 ] = MMpull ( m ) >> 1 ;
    xd [ 2 ] = MMpull ( m ) >> 1 ;
    yd [ 1 ] = MMpull ( m ) >> 1 ;
    xd [ 1 ] = MMpull ( m ) >> 1 ;
    yd [ 0 ] = MMpull ( m ) >> 1 ;
    xd [ 0 ] = MMpull ( m ) >> 1 ;
    sd = MMpull ( m ) ;

    if (( ss == NIL ) || ( sd == NIL ))
            MMechostr ( 1 , "Source or Destination bitmap is NIL\n" ) ;
    else
    {
        OS = ( PtrObjVoid ) MMstart(m,(ss>>1) ) ;
        OD = ( PtrObjVoid ) MMstart(m,(sd>>1) ) ;
        BS = ( PtrObjBitmap ) MMstart(m,(OS->Buffer>>1) ) ;
        BD = ( PtrObjBitmap ) MMstart(m,(OD->Buffer>>1) ) ;

		if (BS->bits == NULL)
		{
			MMechostr(MSKTRACE,"STRETCHbitmap : Source Bitmap already destroyed %x\n",BS->handler);
			return MMpush(m,NIL);
		}

		if (BD->bits == NULL)
		{
			MMechostr(MSKTRACE,"STRETCHbitmap : Dest Bitmap already destroyed %x\n",BD->handler);
			return MMpush(m,NIL);
		}

        /* refaire les points pour le 2eme rectangle */
        xs [ 1 ] = xs [ 0 ] ;
        ys [ 1 ] = ys [ 2 ] ;     
        xs [ 3 ] = xs [ 2 ] ;
        ys [ 3 ] = ys [ 0 ] ;

        /* recherche du point le plus haut */
        lps = 0 ;
        for ( lpe = 1 ; lpe <= 3 ; lpe ++ )
        if ( yd [ lpe ] < yd [ lps ] ) lps = lpe ;

        /************** CALCUL DES POINTS COURANT - DESTINATION ************************/
        rps = lps ;
        lpe = lps - 1 ;
        if ( lpe < 0 ) lpe = 3 ;
        rpe = rps + 1 ;
        if ( rpe >= 4 ) rpe = 0 ;

        xdl = xd [ lps ] ;
        ydl = yd [ lps ] ;
        xdr = xd [ lps ] ;
        ydr = yd [ lps ] ;

        xsl = xs [ lps ] ;
        ysl = ys [ lps ] ;
        xsr = xs [ lps ] ;
        ysr = ys [ lps ] ;   

        /************** CALCUL DES DELTAS - DESTINATION ***********************************/
        dlx = ( xd [ lpe ] - xd [ lps ] ) ;
        dly = ( yd [ lpe ] - yd [ lps ] ) ;
        drx = ( xd [ rpe ] - xd [ rps ] ) ;
        dry = ( yd [ rpe ] - yd [ rps ] ) ;
        if ( dlx < 0 )
        {
            deplx = -1 ; dlx = - dlx ; 
        } else deplx = 1 ;

        if ( drx < 0 )
        {
             drx = - drx ;
             deprx = -1 ;
        } else deprx = 1 ;

        #ifdef DEBUG_2DMAP
            MMechostr ( 1 , "DEST LEFT : go from %d <%d,%d> to %d<%d,%d>\n" ,
                        lps , xd [ lps ] , yd [ lps ] , lpe , xd [ lpe ] , yd [ lpe ]) ;
            MMechostr ( 1 , "DEST : RIGHT : go from %d <%d,%d> to %d<%d,%d>\n" ,
                        rps , xd [ rps ] , yd [ rps ] , rpe , xd [ rpe ] , yd [ rpe ]) ;
        #endif
        if (( dly < 0 ) || ( dry < 0 ))
        {
            res = MMpush(m,sd ) ;
            MMechostr ( 1 , "Polygone concave \n" ) ;
            return res ;
        }

        deltaleft = dly ;        
        deltaright = dry ;

        /************* INIT DES TERMES D'ERREURS ********************************/
        erl = 0 ; 
        err = 0 ;
        emlx = 0 ;
        emly = 0 ;
        emrx = 0 ;
        emry = 0;

        /************* CALCUL DES DELTA - SOURCE ****************************/
        delslx  = xs [ lpe ] - xs [ lps ] ;
        if ( delslx < 0 )
        {
            delslx = - delslx ;
            movlx = -1 ;
        } else movlx = 1 ;

        delsly = ys [ lpe ] - ys [ lps ] ;
        if ( delsly < 0 )
        {
            delsly = - delsly ;
            movly = -1 ;
        } else movly = 1 ;

        delsrx = xs [ rpe ] - xs [ rps ] ;
        if ( delsrx < 0 )
        {
            delsrx = - delsrx ;
            movrx = -1 ;
        } else movrx = 1 ; 

        delsry = ys [ rpe ] - ys [ rps ] ;
        if ( delsry < 0 )
        {
            delsry = - delsry ;
            movry = -1 ;
        } else movry = 1 ;

        points = 3 ;      
        #ifdef DEBUG_2DMAP                
                    MMechostr ( 1 , "MAP LEFT go from <%d,%d> to <%d,%d>\n",
                        xs [ lps ] , ys [ lps ] , xs [ lpe ] , ys [ lpe ] ) ;                    
                    MMechostr ( 1 , "MAP RIGHT : go from <%d,%d> to <%d,%d>\n" ,
                        xs [ rps ] , ys [ rps ] , xs [ rpe ] , ys [ rpe ] ) ;
        #endif        
        /******************** BOUCLE PRINCIPALE *********************************/
        while ( points != 0 )
        {
            /************** MESSAGE DEBUGGAGE **********************************/
            #ifdef DEBUG_2DMAP
                MMechostr ( 1 , "LEFT : del %d lps %d lpe %d xdl %d ydl %d xsl %d ysl %d\n",
                    deltaleft , lps , lpe , xdl , ydl , xsl , ysl ) ;               
                MMechostr ( 1 , "RIGHT:  del %d rps %d rpe %d xdr %d ydr %d xsr %d ysr %d\n" ,
                    deltaright , rps , rpe , xdr , ydr , xsr , ysr ) ;
                MMechostr ( 1 , "MAP : xl %d yl %d xr %d yr %d\n" , xsl , ysl , xsr , ysr ) ;
                MMechostr ( 1 , "MAP : DLX %d DLY %d DRX %d DRY %d ERLX %d ERLY %d ERRX %d ERRY %d\n",
                        delslx , delsly , delsrx , delsry , emlx , emly , emrx , emry ) ;
                MMechostr ( 1 , "MAP : MLX %d MLY %d MRX %d MRY %d\n" ,
                        movlx , movly , movrx , movry ) ;
            #endif
            
            /* effectue le mapping de la ligne xsl,ysl - xsr,ysr */
                /* sur la ligne xdl , ydl , xdr , ydr */
            /* test de synchronisation des cote LEFT et RIGHT */
            if ( ydl != ydr )
            {
                MMechostr ( 1 , "Y not synchro LEFT %d RIGHT %d\n" , ydl , ydr ) ;
                break ;
            }
            /* test de clipping Y */
            if ( ydl > 0 && ydl < BD->TailleH )
            {
			int BSptr, BDptr;
			unsigned char r, g, b;
			int srcColor;

                /* regarde le sens */
                delmap = xdr - xdl ;
                if ( delmap < 0 )
                {
                    movmap = -1 ;
                    delmap = - delmap ;                
                } else movmap = 1 ;
                                 
                delmapx = xsr - xsl ;
                delmapy = ysr - ysl ;
                if ( delmapx < 0 )
                {
                    delmapx = - delmapx ;
                    movmapx = -1 ;
                } else movmapx = 1 ;

                if ( delmapy < 0 )
                {
                    delmapy = - delmapy ;
                    movmapy =-1 ;
                } else movmapy = 1 ;

                xdest = xdl ;
                mapx = xsl ;
                mapy = ysl ;
                maperrx = 0 ;
                maperry = 0 ;
                #ifdef DEBUG_2DMAP
                    MMechostr ( 1 , "LDX %d LDY %d LSX %d LSY %d RDX %d RDY %d RSX %d RSY %d\n" ,
                        xdl , ydl , xsl , ysl , xdr , ydr , xsr , ysr ) ;
                #endif


                for ( i = 0 ; i < delmap ; i ++ )
                {
				    if ( xdest > 0 && xdest < BD->TailleW )
                    if ( mapx > 0 && mapx < BS->TailleW )
                    if ( mapy > 0 && mapy < BS->TailleH )
                    {                                            
						BSptr =  (mapx * BS->BytesPP) + mapy * BS->BPL ;
						BDptr =  (xdest * BD->BytesPP) + ydl * BD->BPL; 
						r = BS->bits [BSptr] ;
						g = BS->bits [BSptr+1] ;
						b = BS->bits [BSptr+2] ;

						srcColor = _COLOR_BGR_TO_I (b, g, r);
                        if ( srcColor != couleur )
						{
                            BD->bits [BDptr  ] = r;
							BD->bits [BDptr+1] = g;
							BD->bits [BDptr+2] = b;
						}
                    }

                    xdest += movmap ;
                    maperrx += delmapx ;
                    while ( maperrx > delmap )
                    {
                        mapx += movmapx ;
                        maperrx -= delmap ;
                    }
                    maperry += delmapy ;
                    while ( maperry > delmap )
                    {
                        mapy += movmapy ;
                        maperry -= delmap ;
                    }
                }
            } else if ( ydl >= BD->TailleH ) break ;
            
            /* TEST FIN DE PARCOURS SEGMENT GAUCHE ******************/
            while ( !deltaleft )
            {
                points -- ;
                if ( ! points ) break ;
                lps = lpe ;
                lpe -- ;
                if ( lpe < 0 ) lpe = 3 ;
                #ifdef DEBUG_2DMAP
                    MMechostr ( 1 , "DEST LEFT : go from %d <%d,%d> to %d<%d,%d>\n" ,
                        lps , xd [ lps ] , yd [ lps ] , lpe , xd [ lpe ] , yd [ lpe ]) ;
                    MMechostr ( 1 , "MAP LEFT go from <%d,%d> to <%d,%d>\n",
                        xs [ lps ] , ys [ lps ] , xs [ lpe ] , ys [ lpe ] ) ;
                #endif
                xdl = xd [ lps ] ;
                ydl = yd [ lps ] ;
                xsl = xs [ lps ] ;
                ysl = ys [ lps ] ;
                dlx = ( xd [ lpe ] - xd [ lps ] ) ;
                dly = ( yd [ lpe ] - yd [ lps ] ) ;
                if ( dlx < 0 )
                {
                    deplx = -1 ; dlx = - dlx ; 
                } else deplx = 1 ;

                if ( dly < 0 )
                {

                    res = MMpush(m,sd ) ;
                    MMechostr ( 1 , "Polygone concave  ys %d ye %d \n", yd [ lps ] , yd [ lpe ] ) ;
                    return res ;
                }
                deltaleft = dly ;
                erl = 0 ;
                emlx = 0 ;
                emly = 0 ;
                delslx  = xs [ lpe ] - xs [ lps ] ;
                if ( delslx < 0 )
                {
                    delslx = - delslx ;
                    movlx = -1 ;
                } else movlx = 1 ;

                delsly = ys [ lpe ] - ys [ lps ] ;
                if ( delsly < 0 )
                {
                    delsly = - delsly ;
                    movly = -1 ;
                } else movly = 1 ;
            }

            /* AVANCEMENT SEGMENT  GAUCHE ******************************/
            if ( ! points ) break ;
            deltaleft -- ;
            ydl ++ ;
            erl += dlx ;
            while ( erl >= dly ) 
            {
                erl -= dly ; xdl += deplx ;
            }
            if ( delslx )
            {
                emlx += delslx ;
                while ( emlx >= dly )
                {
                    emlx -= dly ; xsl += movlx ;
                }
            }
            if ( delsly )
            {
                emly += delsly ;
                while ( emly >= dly )
                {
                    emly -= dly ; ysl += movly ;
                }
            }
            
            /* TEST FIN AVANCEMENT SEGMENT DROIT **********************/
            while ( !deltaright )
            {
                points -- ;
                if ( ! points ) break ;
                rps = rpe ;
                rpe ++ ;
                if ( rpe >= 4 ) rpe = 0 ;
                #ifdef DEBUG_2DMAP
                    MMechostr ( 1 , "DEST : RIGHT : go from %d <%d,%d> to %d<%d,%d>\n" ,
                        rps , xd [ rps ] , yd [ rps ] , rpe , xd [ rpe ] , yd [ rpe ]) ;
                    MMechostr ( 1 , "MAP RIGHT : go from <%d,%d> to <%d,%d>\n" ,
                        xs [ rps ] , ys [ rps ] , xs [ rpe ] , ys [ rpe ] ) ;
                #endif
                ydr = yd [ rps ] ;
                xdr = xd [ rps ] ;
                xsr = xs [ rps ] ;
                ysr = ys [ rps ] ;
                drx = ( xd [ rpe ] - xd [ rps ] ) ;
                dry = ( yd [ rpe ] - yd [ rps ] ) ;
                if ( drx < 0 )
                {
                     drx = - drx ;
                     deprx = -1 ;
                } else deprx = 1 ;
                if (dry < 0 )
                {
                    res = MMpush(m,sd ) ;
                    MMechostr ( 1 , "Polygone concave yds %d yde %d\n", yd [ rpe ] , yd [ rps ] ) ;
                    return res ;
                }
                deltaright = dry ;
                err = 0 ;
                emrx = 0 ; 
                emry = 0 ;
                delsrx = xs [ rpe ] - xs [ rps ] ;
                if ( delsrx < 0 )
                {
                    delsrx = - delsrx ;
                    movrx = -1 ;
                } else movrx = 1 ; 

                delsry = ys [ rpe ] - ys [ rps ] ;
                if ( delsry < 0 )
                {
                    delsry = - delsry ;
                    movry = -1 ;
                } else movry = 1 ;
            }

            /* AVANCE SUR LE SEGMENT DROIT **********************/
            if ( ! points ) break ;
            deltaright -- ;
            ydr ++ ;
            err += drx ;
            while ( err >= dry )
            {
                err -= dry ; xdr += deprx ;
            }
            if ( delsrx )
            {
                emrx += delsrx ;
                while ( emrx >= dry )
                {
                    emrx -= dry ; xsr += movrx ;
                }   
            }
            if ( delsry )
            {
                emry += delsry ;
                while ( emry >= dry )
                {
                    emry -= dry ; ysr += movry ;
                }
            }
        }
        /**************** FIN BOUCLE PRINCIPALE **************************/

    }
   

    res = MMpush( m , sd ) ;


 //***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRMapBitmap end");
#endif
//***********************************

    return res ;



}


/******************************************************************************************/
/*                                                                                        */
/*    int GRFILEbitmap ( mmachine m );                                                    */
/*                                                                                        */
/*  correspond a la fonction magma S _FILEbitmap ( ObjBitmap )                            */
/*  laquelle fabrique un buffer archivable                                                */
/*                                                                                        */
/******************************************************************************************/

int GRFileBitmap ( mmachine m )
{
    int res ;
    int s , l , offset , i , j , l2 ;
    PtrObjVoid O ;
    PtrObjBitmap B ;
    OBJBITMAP_BUFFER Bu;
	OBJBITMAP_BUFFER Bub ;
    OBJBITMAP_BUFFER Bu24 ;
    BITMAPFILEHEADER * Bfh ;
    BITMAPINFOHEADER * Bih ;
    struct Palette Pal ;
    RGBQUAD * Rgb ;


 //***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRFileBitmap");
#endif
//***********************************



    s = MMpull(m ) ;
    if ( s== NIL ) 
    res = MMpush(m,NIL ) ;
    else
    {
        O = ( PtrObjVoid ) MMstart(m, (s>>1) ) ;
        B = ( PtrObjBitmap ) MMstart(m, ( O->Buffer>>1) ) ;
        if ( B->BPP == 24 ) l = 1 + sizeof ( BITMAPFILEHEADER ) + sizeof ( BITMAPINFOHEADER ) +
                B->BPL * B->TailleH ;
        else if ( B->BPP == 8 ) l = 1 + sizeof ( BITMAPFILEHEADER ) + sizeof ( BITMAPINFOHEADER ) +
            B->BPL * B->TailleH + 1024 ;
        else 
        {
            l = 0 ;
            MMechostr ( 1 , "_file_bitmap ; unsupported BPP %d\n" , B->BPP ) ;
        }
        if ( l > 0 )
        {
            if (l%3==0) l2 = l>>2 ; else l2 = (l+4)>>2 ;
            MMechostr(MSKDEBUG,"Taille de base l = %d, l2 = %d\n",l,l2);
            res = MMmalloc (m,l2+1,TYPEBUF) ;

            if ( res == NIL )
            {
                 MMechostr ( 1 , "Not enough memory to create the bitmap file of size %d" , l ) ;
                return MERRMEM ;
            }
            else 
            {

                    *( int * ) MMstart(m, res ) = l ;
                    /* ecriture du file header */
                    Bu = (OBJBITMAP_BUFFER) MMstart(m,res  + 1) ;
                    Bfh = ( BITMAPFILEHEADER * ) Bu ;
                    Bfh -> bfType = FILE_TYPE_BMP ;
                    Bfh->bfSize = l ;
                    Bfh->bfReserved1 = 0 ;
                    Bfh->bfReserved2 = 0 ;
                    Bfh->bfOffBits  = sizeof ( BITMAPFILEHEADER ) + sizeof ( BITMAPINFOHEADER ) ;
                    if( B->BPP == 8 ) Bfh->bfOffBits += 1024 ;
                    /* ecriture du ifno header */
                    Bih = ( BITMAPINFOHEADER * ) ( Bu + sizeof ( BITMAPFILEHEADER )) ;
                    Bih->biSize = sizeof ( BITMAPINFOHEADER ) ;
                    Bih->biWidth = B->TailleW ;
                    Bih->biHeight = B->TailleH ;
                    Bih->biPlanes = 1 ;
                    Bih->biBitCount = B->BPP ;
                    Bih->biCompression = 0 ;
                    Bih->biSizeImage = B->BPL * B->TailleH ;
                    Bih->biXPelsPerMeter = 0 ;
                    Bih->biYPelsPerMeter = 0 ;
                    if ( B->BPP == 8 ) Bih->biClrUsed = 256 ;
                    else Bih->biClrUsed = 0 ;
                    Bih->biClrImportant = Bih->biClrUsed ;
                    /* ecriture des couleurs */
                    if ( B->BPP == 8 )
                    {
                        GetBitmapPalette ( B , &Pal ) ;
                        for ( i = 0 ; i < 256 ; i ++ )
                        {
                            Rgb =  ( RGBQUAD * ) & (Bu [ 54 + (  i << 2 )]) ;
                            Rgb->rgbBlue = GET_BLUE(&Pal,i) ;
                            Rgb->rgbGreen = GET_GREEN(&Pal,i) ;
                            Rgb->rgbRed = GET_RED(&Pal,i) ;
                            Rgb->rgbReserved = 0 ;
                        }
                    }

                    /* ecriture du bitmap */
                    if ( B->BPP == 8 )
                    {
                        offset = B->BPL * B->TailleH ;
                        Bub = Bu + Bfh -> bfOffBits ;
                        for ( j = 0 ; j < B->TailleH ; j ++ )
                        for ( i = 0 ; i < B->BPL ; i ++ )
                            Bub [ i + j * B->BPL ] = 
                            ((OBJBITMAP_BUFFER) B->bits ) [ i + ( offset - (j+1) * B->BPL) ] ;
                    }
                    if ( B->BPP == 24 )
                    {
                        offset = B->BPL * B->TailleH ;
                        Bu24 = (OBJBITMAP_BUFFER) ( Bu + Bfh->bfOffBits ) ;
                        for ( j =0 ; j < B->TailleH ; j ++ )
                        for ( i = 0 ; i < B->BPL ; i ++ )
                            Bu24 [ i + j * B->BPL ] = B->bits [ i + ( offset - ( j+1) * B->BPL) ] ;
                    }


                    /* 0 terminal */
                    Bu [ l - 1 ] = 0 ;

                    res = MMpush(m,(res << 1) + 1) ;
            }
        }   
        else res = MMpush(m,NIL ) ;
        

        
    }

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRFileBitmap end");
#endif
//***********************************


    return res ;

        
}


/**********************************************************************************************/
/*                                                                                            */
/*  int GRCopyWinBitmap ( mmachine m ) ;                                                      */
/*                                                                                            */
/*  correspond a la fonction magma ObjWin _copybitmap_to_win ( ObjWin , I , I , ObjBitmap , I */
/*  I I I ) ;                                                                                 */
/*                                                                                            */
/**********************************************************************************************/

int GRCopyWinBitmap ( mmachine m )
{
    int sx1 , sy1 , sx2 , sy2 , ss , dx , dy , sd , res ;
    PtrObjVoid OS , OD ;
    PtrObjBitmap B ;
    PtrObjWindow W ;
    HDC Dcb , Dcw ;
    HBITMAP OldBitmap ;


//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRCopyWinBitmap");
#endif
//***********************************

    sy2 = MMpull(m) >> 1 ;
    sx2 = MMpull(m) >> 1 ;
    sy1 = MMpull(m) >> 1 ;
    sx1 = MMpull(m) >> 1 ;
    ss = MMpull(m) ;
    dy = MMpull(m) >> 1 ;
    dx = MMpull(m) >> 1 ;
    sd = MMpull(m) ;
   
    if ( ss == NIL || sd == NIL )
    {
        MMechostr ( 1 , "_copy_bitmap_to_win : The window Obj or the bitmap is NIL\n" ) ;
         return MMpush(m,sd) ;
    }

 
    OS = ( PtrObjVoid ) MMstart(m,(ss>>1) ) ;
    OD = ( PtrObjVoid ) MMstart(m,(sd>>1) ) ;
    B = ( PtrObjBitmap ) MMstart(m,(OS->Buffer>>1) ) ;
    W = ( PtrObjWindow ) MMstart(m,(OD->Buffer>>1) );

					
	//$ LB (13/06/2002) : create DIBSection from bitmap buffer
	if (!B->DIBhandler) ObjBitmap_CreateDIBSection (B);


    Dcw = GetDC ( W->WHandler ) ;       
    Dcb = CreateCompatibleDC ( Dcw ) ;
    OldBitmap = SelectObject ( Dcb , B->DIBhandler) ;
    BitBlt ( Dcw , dx , dy , sx2 , sy2 , Dcb , sx1 , sy1 , SRCCOPY ) ;
 
    SelectObject ( Dcb , OldBitmap ) ;
    DeleteDC ( Dcb ) ;    
	ReleaseDC (W->WHandler, Dcw);

    res = MMpush(m,sd) ;


//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRCopyWinBitmap end");
#endif
//***********************************

    return res ;
}





/****************************************************************************************************/
/*                                                                                                  */
/*  int GRGetPixel ( mmachine m ) ;                                                                 */
/*                                                                                                  */
/* donne la couleur d'un pixel d'un bitmap au format 24 bits                                        */
/* correspond a la fonction magma I _get_pixel ( Obj X Y  )                                         */
/*                                                                                                  */
/****************************************************************************************************/

int GRGetPixel ( mmachine m ) 
{
    int s , x , y ;
    PtrObjVoid O ;
    PtrObjBitmap B ;
    struct Palette MaPal ;

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRGetPixel");
#endif
//***********************************

    y = MMpull ( m ) >> 1 ;
    x = MMpull ( m ) >> 1 ;
    s = MMpull ( m ) ;
    if ( s == NIL )
    {
        MMechostr ( 1 , "Bitmap is NIL in _GETPixel\n" ) ;
        return MMpush ( m , NIL ) ;
    } ;

    O = ( PtrObjVoid ) MMstart(m,(s>>1) ) ;
    B = ( PtrObjBitmap ) MMstart(m,(O->Buffer>>1) ) ;

	if (B->bits == NULL)
	{
		MMechostr(MSKTRACE,"GETpixel : Bitmap already destroyed %x\n",B->handler);
		return MMpush(m,NIL);
	}

    if ( x < 0 || x >= B->TailleW || y < 0 ||y >= B->TailleH )
    {
        MMechostr ( 1 , "Coordonates outside bitmap in _GETpixel\n" ) ;
        return MMpush(m,NIL);    
    }
   
    if ( B->BPP == 24 )
    {      
	int ptr = (x * B->BytesPP) + y * B->BPL;

       s = _COLOR_BGR_TO_I (B->bits [ptr], B->bits [ptr+1], B->bits [ptr+2]) ;          
       s = MMpush(m,s<<1);

    }
    else if ( B->BPP == 8 )
    {
        
        s = ((OBJBITMAP_BUFFER) B->bits  ) [ x + y * B->BPL ] ;
        GetBitmapPalette ( B , & MaPal ) ;
       
        s = GET_RED(&MaPal,s) + ( GET_GREEN(&MaPal,s) << 8 ) + ( GET_BLUE(&MaPal,s) << 16 ) ;
      
        s = MMpush(m,s<<1) ;
    } else MMpush(m,NIL ) ;

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRGetPixel end");
#endif
//***********************************

    return s ;

}





/*******************************************************************************************/
/*                                                                                         */
/*  int GRDrawPoly ( mmachine m ) ;                                                        */
/*                                                                                         */
/*      Cette fonction correspond a la fonction magma _draw_poly ,                         */
/*  (ObjBitmap , tab [ I I ] , I mode contour , I taille contour , I couleur contour       */
/*  I mode fill,  I couleur fill ) laquelle dessine un polygone plein dans un bitmap       */
/*                                                                                         */
/*******************************************************************************************/

int GRDrawPoly ( mmachine m ) 
{
    int couleur_fill, mode_fill , couleur_contour, taille_contour , mode_contour , tablo , s ,
        np , i , ti , np2 ;
    PtrObjVoid O ;
    PtrObjBitmap B ;
    POINT p [ 1024 ] ;
    HPEN Pinceau , OldPen ;
    HDC Dc ;
    HWND Item , OldItem ;
    LOGBRUSH Brush ;
    HBRUSH HBrush , OldBrush ;


//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRDrawPoly");
#endif
//***********************************

    couleur_fill = MMpull ( m ) >> 1 ;
    mode_fill = MMpull(m) >> 1 ;
    couleur_contour = MMpull(m) >> 1 ;
    taille_contour = MMpull(m) >> 1 ;
    mode_contour = MMpull(m) >> 1 ;

    tablo = MMpull(m) ;
    np2 = MMpull(m) >> 1 ;
    s = MMpull(m) ;

    if ( tablo == NIL || s == NIL )
    {
        MMechostr ( 1 , "(ERR) _DRAWpoly: Array of points empty or object bitmap nil\n" ) ;
        return MMpush(m,NIL);
    }

    O = (PtrObjVoid)  MMstart(m,(s>>1) ) ;
    B = ( PtrObjBitmap )MMstart(m,(O->Buffer>>1) ) ;   

    //$ LB (13/06/2002) : create DIBSection from bitmap buffer
	if (!B->DIBhandler) ObjBitmap_CreateDIBSection (B);

   
    np = MMsize ( m , tablo >> 1 ) ;
    if ( np2 > 1024 || np2 <= 0 || np2 > np)
    {
        MMechostr ( 1 , "(ERR) _Drawpoly : polygon size is wrong. ARRAY SIZE = %d , POINTS = %d \n",np,np2 ) ;
        return MMpush(m,s);
    }
    for ( i = 0 ; i < np2 ; i ++ )
    {
        ti = *MMstart(m, ( tablo >> 1 ) + i ) ;
        p [ i ] . x = ( *MMstart(m, ( ti >> 1 ) ) ) >> 1 ;
        p [ i ] . y = ( *MMstart(m, ( ti >> 1 ) + 1) ) >> 1 ;
    }

    Dc = CreateCompatibleDC ( NULL ) ;

    Item = (HWND)B->DIBhandler;


    if ( taille_contour <= 0 ) { taille_contour = 0 ; mode_contour = DRAW_INVISIBLE; }

    if ( mode_contour == DRAW_INVISIBLE )
        Pinceau = CreatePen ( PS_NULL  , taille_contour , couleur_contour ) ;
    else Pinceau = CreatePen ( PS_SOLID , taille_contour , couleur_contour ) ;
    OldPen = SelectObject ( Dc , Pinceau ) ;
    OldItem = SelectObject ( Dc , Item ) ;
    if ( mode_fill == DRAW_INVISIBLE ) Brush.lbStyle = BS_NULL ;
    else Brush.lbStyle = BS_SOLID ;
    Brush.lbColor = couleur_fill ;
      
    HBrush = CreateBrushIndirect ( & Brush ) ;
    OldBrush = SelectObject ( Dc , HBrush ) ;

    Polygon ( Dc , p , np2 ) ;
    SetPolyFillMode ( Dc , ALTERNATE ) ;

    SelectObject ( Dc , OldItem ) ;
    OldPen = SelectObject ( Dc , OldPen ) ;
    OldBrush = SelectObject ( Dc , OldBrush ) ;
    DeleteDC ( Dc ) ;
    DeleteObject ( OldPen ) ;
    DeleteObject ( OldBrush ) ;
    s = MMpush(m,s) ;

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRDrawPoly end");
#endif
//***********************************
    
    return s ;

}





/****************************************************************************************/
/*                                                                                      */
/*  int GRPutPixel ( mmachine m ) ;                                                     */
/*                                                                                      */
/*  Correspond a la fonction magma ObjBitmap _PUTpixel ObjBitmap I I I                  */
/*  laquelle definit la couleur d'un pixel dans un objet bitmap                         */
/*                                                                                      */
/****************************************************************************************/

int GRPutPixel ( mmachine m )
{
    int s , x , y , c ;
    PtrObjVoid O ;
    PtrObjBitmap B ;
	

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRPutPixel");
#endif
//***********************************

    c = MMpull(m) >> 1 ;
    y = MMpull(m) >> 1 ;
    x = MMpull(m) >> 1 ;
    s = MMpull(m) ;

    if ( s != NIL )
    {
        O = ( PtrObjVoid ) MMstart(m,(s>>1) ) ;
        B = ( PtrObjBitmap ) MMstart(m,(O->Buffer>>1) ) ;

		if (B->bits == NULL)
		{
			MMechostr(MSKTRACE,"PUTpixel : Bitmap already destroyed %x\n",B->handler);
			return MMpush(m,NIL);
		}

        if ( x < 0 || x >= B->TailleW || y < 0 ||y >= B->TailleH )
        {
            MMechostr ( 1 , "Coordonates outside bitmap in _PUTpixel\n" ) ;
            return MMpush(m,s);    
        }
   
       
        if ( B->BPP == 24 )
		{
		unsigned char r, g, b;
		int ptr = (x * B->BytesPP) + y * B->BPL;

			_COLOR_I_TO_BGR (c, &b, &g, &r);

            B->bits [ ptr   ] = b;
			B->bits [ ptr+1 ] = g;
			B->bits [ ptr+2 ] = r;
		}
        else if ( B->BPP == 8 )
            ((OBJBITMAP_BUFFER) B->bits ) [ x + y * B->TailleW ] = ( unsigned char ) c ;
       
    }

    s = MMpush(m,s);

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRPutPixel end");
#endif
//***********************************
        
    return s ;
}






/********************************************************************************************/
/*                                                                                          */
/*  int GRAndBitmap ( mmachine m ) ;                                                        */
/*                                                                                          */
/*  correspond a la fonction _ANDbitmap ( Dest,Xd,Yd,W,H,Source,Sx,Sy);                     */
/*  qui effectue une operation AND entre 2 bitmap                                           */
/*                                                                                          */
/********************************************************************************************/

#define BITMAP_AND      0
#define BITMAP_OR       1
#define BITMAP_XOR      2
#define BITMAP_PLUS     3
#define BITMAP_MINUS    4
#define BITMAP_PLUS2    5
#define BITMAP_MINUS2   6

int GenericOpBitmap ( mmachine m , int Op )
{
    int sx,sy,h,w,dy,dx,ss,sd;
    int i , j ,dcx,dcy,scx,scy;

    unsigned char rd,gd,bd, rs,gs,bs ;

    PtrObjVoid OS ;
    PtrObjVoid OD ;
    PtrObjBitmap FS ;
    PtrObjBitmap FD ;


//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGenericOpBitmap");
#endif
//***********************************
   
    sy = MMpull(m)>>1;
    sx = MMpull(m)>>1;
    ss = MMpull(m);
    h=MMpull(m)>>1;
    w=MMpull(m)>>1;
    dy=MMpull(m)>>1;
    dx=MMpull(m)>>1;
    sd=MMpull(m);

    if (sd == NIL || ss == NIL )
    {
        MMechostr (1,"Source or Destination is NIL in _ANDbitmap\n");
        return MMpush(m,sd);
    }

    OS = ( PtrObjVoid ) MMstart(m,(ss>>1)) ;
    OD = ( PtrObjVoid ) MMstart(m,(sd>>1)) ;
    FS = ( PtrObjBitmap ) MMstart(m,(OS->Buffer>>1));
    FD = ( PtrObjBitmap ) MMstart(m,(OD->Buffer>>1));

	if (FS->bits == NULL)
	{
		MMechostr(MSKTRACE,"OPcopy : Source Bitmap already destroyed %x\n",FS->handler);
		return MMpush(m,NIL);
	}

	if (FD->bits == NULL)
	{
		MMechostr(MSKTRACE,"OPcopy : Dest Bitmap already destroyed %x\n",FD->handler);
		return MMpush(m,NIL);
	}

    if ( !ClipBlit ( FD->TailleW , FD->TailleH , FS->TailleW , FS->TailleH ,
                &dx , &dy , &sx , &sy , &w , &h ) )
    {        
        return MMpush(m,sd);
    }   

    dcy = (dy * FD->BPL) + (dx * FD->BytesPP) ;
    scy = (sy * FS->BPL) + (sx  * FS->BytesPP);
    
    switch ( Op)
    {
        case BITMAP_AND:
        for ( j = 0 ; j < h ; j ++ )
        { dcx = dcy ; scx = scy ;
                for ( i = 0 ; i < w ; i ++ , dcx +=3 , scx +=3 )
				{
                    FD->bits [ dcx   ] &= FS->bits [ scx   ] ;
					FD->bits [ dcx+1 ] &= FS->bits [ scx+1 ] ;
					FD->bits [ dcx+2 ] &= FS->bits [ scx+2 ] ;
				}
                dcy += FD->BPL; scy += FS->BPL; 
        } break;

        case BITMAP_OR:
        for (j=0;j<h;j++)
        { dcx = dcy ; scx = scy ;
               for ( i = 0 ; i < w ; i ++ , dcx +=3 , scx +=3 )
			   {
                    FD->bits [ dcx   ] |= FS->bits [ scx   ] ;
					FD->bits [ dcx+1 ] |= FS->bits [ scx+1 ] ;
					FD->bits [ dcx+2 ] |= FS->bits [ scx+2 ] ;
			   }
                dcy += FD->BPL; scy += FS->BPL;
        } break;

        case BITMAP_XOR:
        for (j=0;j<h;j++)
        { dcx = dcy ; scx = scy ;
               for ( i = 0 ; i < w ; i ++ , dcx +=3 , scx +=3 )
			   {
                    FD->bits [ dcx   ] ^= FS->bits [ scx   ] ;
					FD->bits [ dcx+1 ] ^= FS->bits [ scx+1 ] ;
					FD->bits [ dcx+2 ] ^= FS->bits [ scx+2 ] ;
			   }
                dcy += FD->BPL; scy += FS->BPL;
        } break;

        case BITMAP_PLUS2:
        for (j=0;j<h;j++)
        { dcx = dcy ; scx = scy ;
               for ( i = 0 ; i < w ; i ++ , dcx +=3 , scx +=3 )
               {
					rd = FD->bits [ dcx   ];
					gd = FD->bits [ dcx+1 ];
					bd = FD->bits [ dcx+2 ];
					
                    rs = FS->bits [ scx   ] ;
                    gs = FS->bits [ scx+1 ] ;
                    bs = FS->bits [ scx+2 ] ;
                                    
                    rd+=rs ;
                    if (rd>255) rd = 255 ;
                    gd+=gs;
                    if(gd>255) gd=255;
                    bd+=bs;
                    if(bd>255) bd=255;

                    FD->bits [ dcx   ] = rd;
					FD->bits [ dcx+1 ] = gd;
					FD->bits [ dcx+2 ] = bd;
               }
               dcy += FD->BPL ; scy += FS->BPL ;
               
        } break;

        case BITMAP_MINUS2:
        for (j=0;j<h;j++)
        { dcx = dcy ; scx = scy ;
               for ( i = 0 ; i < w ; i ++ , dcx +=3 , scx +=3 )
                  {
                    rd = FD->bits [ dcx   ];
					gd = FD->bits [ dcx+1 ];
					bd = FD->bits [ dcx+2 ];
					
                    rs = FS->bits [ scx   ] ;
                    gs = FS->bits [ scx+1 ] ;
                    bs = FS->bits [ scx+2 ] ;

                    rd-=rs ;
                    if (rd<0) rd =0 ;
                    gd-=gs;
                    if(gd<0) gd=0;
                    bd-=bs;
                    if(bd<0) bd=0;

                    FD->bits [ dcx   ] = rd;
					FD->bits [ dcx+1 ] = gd;
					FD->bits [ dcx+2 ] = bd;                                  
               }                                  
                dcy += FD->BPL ; scy += FS->BPL ;
        } break;

        case BITMAP_PLUS:
        for (j=0;j<h;j++)
        { dcx = dcy ; scx = scy ;
               for ( i = 0 ; i < w ; i ++ , dcx +=3 , scx +=3 )
                 {
                    rd = FD->bits [ dcx   ];
					gd = FD->bits [ dcx+1 ];
					bd = FD->bits [ dcx+2 ];
					
                    rs = FS->bits [ scx   ] ;
                    gs = FS->bits [ scx+1 ] ;
                    bs = FS->bits [ scx+2 ] ;

                    rd+=rs ;
                    if (rd>255) rd -= 255 ;
                    gd+=gs;
                    if(gd>255) gd-=255;
                    bd+=rs;
                    if(bd>255) bd-=255;

                    FD->bits [ dcx   ] = rd;
					FD->bits [ dcx+1 ] = gd;
					FD->bits [ dcx+2 ] = bd;                                         
               }                             
                dcy += FD->BPL; scy += FS->BPL;
        } break;

        case BITMAP_MINUS:
        for (j=0;j<h;j++)
        { dcx = dcy ; scx = scy ;
               for ( i = 0 ; i < w ; i ++ , dcx +=3 , scx +=3 )
                  {
                    rd = FD->bits [ dcx   ];
					gd = FD->bits [ dcx+1 ];
					bd = FD->bits [ dcx+2 ];
					
                    rs = FS->bits [ scx   ] ;
                    gs = FS->bits [ scx+1 ] ;
                    bs = FS->bits [ scx+2 ] ;

                    rd-=rs ;
                    if (rd<0) rd += 255 ;
                    gd-=gs;
                    if(gd<0) gd+=255;
                    bd-=bs;
                    if(bd<0) bd+=255;

                    FD->bits [ dcx   ] = rd;
					FD->bits [ dcx+1 ] = gd;
					FD->bits [ dcx+2 ] = bd;                                        
               }                              
                dcy += FD->BPL; scy += FS->BPL;
        } break;
          
     }

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGenericOpBitmap end");
#endif
//***********************************

    return MMpush(m,sd);
}

int GRAndBitmap ( mmachine m )
{return GenericOpBitmap ( m , BITMAP_AND );}

int GROrBitmap ( mmachine m )
{return GenericOpBitmap ( m,BITMAP_OR);}

int GRXorBitmap (mmachine m)
{return GenericOpBitmap(m,BITMAP_XOR);}

int GRPlusBitmap(mmachine m)
{return GenericOpBitmap(m,BITMAP_PLUS);}

int GRMinusBitmap(mmachine m)
{return GenericOpBitmap(m,BITMAP_MINUS);}

int GRSPlusBitmap(mmachine m)
{return GenericOpBitmap(m,BITMAP_PLUS2);}

int GRSMinusBitmap(mmachine m)
{return GenericOpBitmap(m,BITMAP_MINUS2);}

int GRNotBitmap(mmachine m)
{
    int s,x,y,w,h,i,j,dcy,dcx;
    PtrObjVoid O ;
    PtrObjBitmap B ;

	//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRNotBitmap");
#endif
//***********************************

    h=MMpull(m)>>1;
    w=MMpull(m)>>1;
    y=MMpull(m)>>1;
    x=MMpull(m)>>1;
    s=MMpull(m);
    
    if (s!=NIL)
    {    
        O=(PtrObjVoid) MMstart(m,(s>>1));
        B=(PtrObjBitmap) MMstart(m,(O->Buffer>>1));

		if (B->bits == NULL)
		{
			MMechostr(MSKTRACE,"NOTbitmap : Bitmap already destroyed %x\n",B->handler);
			return MMpush(m,NIL);
		}

        if (ClipSimple(B->TailleW,B->TailleH,&x,&y,&w,&h))
        {
            dcy = (y * B->BPL) + (x * B->BytesPP) ;
            for ( j = 0 ; j < h ; j ++ )
            { 
                dcx = dcy ;
                for ( i = 0 ; i < w ; i ++ , dcx +=3 )
				{
                    B->bits [ dcx   ] = 0xFF - B->bits [ dcx   ] ;
					B->bits [ dcx+1 ] = 0xFF - B->bits [ dcx+1 ] ;
					B->bits [ dcx+2 ] = 0xFF - B->bits [ dcx+2 ] ;
				}

                dcy += B->BPL; 
            }
        }
     }


//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRNotBitmap end");
#endif
//***********************************

    return MMpush(m,s);
}






/**********************************************************************************/
/*                                                                                */
/*      int GRMulBitmap ( mmachine m ) ;                                          */
/*                                                                                */
/*  correspond ala fonction magma ObjBitmap _MULbitmap ( ObjBitmap , I I I I F F F*/
/*  laquelle multiplie dans une section d'un bitmap, les composantes couleurs par */
/* des flottants                                                                  */
/*                                                                                */
/**********************************************************************************/

int GRMulBitmap ( mmachine m )
{
    float fr , fg , fb ;
    int x , y , w , h , col ;
	unsigned char r , g , b;
    int s , dcx , dcy , i , j , Color , s1 , s2 , s3;
    PtrObjVoid O ;
    PtrObjBitmap B ;

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRMulBitmap");
#endif
//***********************************
    col = MMpull(m)>>1;

    s1 = MMpull(m);

    //$LB (10/05/2004) : fixed float number reading if(s1==NIL) fb = (float)1 ; else fb = *((float *) MMstart(m,(s1>>1)));
    if(s1==NIL) fb = (float)1 ; else fb = (float)MTOF (s1);

    s2=MMpull(m) ;
    if(s2==NIL) fg = (float)1 ; else fg = (float)MTOF (s2);

    s3=MMpull(m) ;
    if(s3==NIL) fr = (float)1 ; else fr = (float)MTOF (s3);

    h = MMpull(m)>>1; 
    w = MMpull(m)>>1;
    y = MMpull(m)>>1;
    x = MMpull(m)>>1;
    s=MMpull(m);
    
    if (s!=NIL)
    {        
        O=(PtrObjVoid) MMstart(m,(s>>1));
        B=(PtrObjBitmap) MMstart(m,(O->Buffer>>1));

		if (B->bits == NULL)
		{
			MMechostr(MSKTRACE,"MULbitmap : Bitmap already destroyed %x\n",B->handler);
			return MMpush(m,NIL);
		}


        if (ClipSimple(B->TailleW,B->TailleH,&x,&y,&w,&h))
        {
           dcy = (y * B->BPL)  + (x * B->BytesPP) ;
            for ( j = 0 ; j < h ; j ++ )
            { 
               dcx = dcy ;
                for ( i = 0 ; i < w ; i ++ , dcx +=3 )
                {
                        b = B->bits [ dcx   ] ;
						g = B->bits [ dcx+1 ] ;
						r = B->bits [ dcx+2 ] ;
                        Color = _COLOR_BGR_TO_I (b,g,r);
                        if ( col == Color ) continue ;
                       
                        b = ( unsigned char ) ((( float ) b ) * fb );
                        g = ( unsigned char ) ((( float ) g ) * fg );
                        r = ( unsigned char ) ((( float ) r ) * fr );

                        if(b>255) b = 255;
                        if(r>255) r = 255;
                        if(g>255) g = 255;

                        B->bits [ dcx   ] = b;
						B->bits [ dcx+1 ] = g;
						B->bits [ dcx+2 ] = r;
                }                                          
                dcy += B->BPL; 
            }
        }
    }

    s =  MMpush(m,s) ;

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRMulBitmap end");
#endif
//***********************************

    return s ;
}

/********************************************************************************************************/
/*                                                                                                      */
/*  int GRDrawRectangleText ( mmachine m ) ;                                                            */
/*  correspond a la fonction ObjBitmap _DRAWrectangleText (ObjBitmap,Font,I,I,I,I,I,I,S);               */
/*  laquelle dessine un rectangle transparent de texte                                                  */
/*                                                                                                      */
/********************************************************************************************************/

int GRDrawRectangleText ( mmachine m )
{

    RECT r ;
    int s,sf,sb,flag,color,oldbk,TFlag ;
    char * texte ;
    PtrObjVoid OB , OF ;
    PtrObjFont F ;
    PtrObjBitmap B ;
    HBITMAP OldBuffer ;
    HDC Dc ;
    HWND Hw ; 
    HFONT OldFont ; 

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRDrawRectangleText");
#endif
//***********************************

    s = MMpull(m);
    flag = MMpull(m)>>1;
    color = MMpull(m)>>1;
    r.bottom = MMpull(m)>>1;
    r.right = MMpull(m)>>1;
    r.top = MMpull(m)>>1;
    r.left = MMpull(m)>>1;

    sf = MMpull(m) ;
    sb = MMpull(m) ;

    if (sf != NIL && sb != NIL && s != NIL)
    {
        texte = ( char * ) MMstart(m,(s>>1)+1) ; 
        OB= ( PtrObjVoid ) MMstart(m,(sb>>1));
        OF = ( PtrObjVoid ) MMstart(m,(sf>>1));
        B = ( PtrObjBitmap ) MMstart(m,(OB->Buffer>>1));
        F = ( PtrObjFont ) MMstart(m,(OF->Buffer>>1)) ;


        switch ( OB->Type >> 1 )
        {
            case OBJ_TYPE_BITMAP :
                   B = ( PtrObjBitmap ) MMstart(m, ( OB->Buffer >> 1 ) ) ;

				   //$ LB (13/06/2002) : create DIBSection from bitmap buffer
				   if (!B->DIBhandler) ObjBitmap_CreateDIBSection (B);

                   Dc = CreateCompatibleDC ( NULL ) ;                 
                   OldBuffer = SelectObject ( Dc , B->DIBhandler) ;        
                   break ;

           case OBJ_TYPE_WINDOW :
                   Hw = (( PtrObjWindow ) MMstart(m,( OB->Buffer>>1) ) ) -> WHandler ;
                   Dc = GetDC ( Hw ) ;
                   break ;
                
            default :
    
            MMechostr ( 1 , "TextOut : Parameter Win/Bitmap is type %d\n" , OB->Type >> 1) ;
            return MMpush(m,s) ;
        }
   
    

        TFlag = DT_EDITCONTROL|DT_WORDBREAK ;
    
        if ( flag & TD_BOTTOM ) TFlag |= DT_BOTTOM ;
        if ( flag & TD_TOP ) TFlag |= DT_TOP ;
        if ( flag & TD_CENTER ) TFlag |= DT_CENTER ;
        if ( flag & TD_LEFT ) TFlag |= DT_LEFT ;
        if ( flag & TD_RIGHT ) TFlag |= DT_RIGHT ;
    
    
        OldFont = SelectObject ( Dc , F->WHandler ) ;
   
        SetTextColor ( Dc , color ) ;
        oldbk = SetBkMode ( Dc , TRANSPARENT ) ;       

        /* etend le rectangle car c'est x1 y1 w h qu'on a passe en parametre */
        r.bottom += r.top ;
        r.right += r.left ;
        DrawText (Dc , texte , strlen ( texte ) , &r , TFlag ) ;   

        SetBkMode ( Dc , oldbk ) ;
        SelectObject ( Dc , OldFont ) ;
  
        if ( OB->Type == ( OBJ_TYPE_BITMAP << 1 )  )
        {
              OldBuffer = SelectObject ( Dc , OldBuffer ) ;         
            DeleteDC ( Dc ) ;
        }
    }

    s = MMpush(m,sb);

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRDrawRectangleText end");
#endif
//***********************************

    return s ;
}



/* fonction indiquant si une surface est dotée d'un z-buffer,
en mode soft, elle retourne toujours 1 */
int GRtstzbuf(mmachine m)
{
	if (MMget(m,0)==NIL) return 0;
	MMset(m,0,1<<1);
	return 0;
}





int GRCopyWindow ( mmachine m )
{
    int sx1 , sy1 , sx2 , sy2 , ss , dx , dy , sd , res ;
    PtrObjVoid OS , OD ;
    PtrObjBitmap B ;
    PtrObjWindow W ;
    HDC Dcb , Dcw ;
    HBITMAP OldBitmap ;

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRCopyWindow");
#endif
//***********************************


    sy2 = MMpull(m) >> 1 ;
    sx2 = MMpull(m) >> 1 ;
    dy = MMpull(m) >> 1 ;
    dx = MMpull(m) >> 1 ;
    sd = MMpull(m) ;
    sy1 = MMpull(m) >> 1 ;
    sx1 = MMpull(m) >> 1 ;
    ss = MMpull(m) ;
   
    if ( ss == NIL || sd == NIL )
    {
        MMechostr ( 1 , "_copy_win_to_bitmap : The window Obj or the bitmap is NIL\n" ) ;
         return MMpush(m,ss) ;
    }

 
    OS = ( PtrObjVoid ) MMstart(m,(ss>>1) ) ;
    OD = ( PtrObjVoid ) MMstart(m,(sd>>1) ) ;
    B = ( PtrObjBitmap ) MMstart(m,(OS->Buffer>>1) ) ;
    W = ( PtrObjWindow ) MMstart(m,(OD->Buffer>>1) );

	
    //$ LB (13/06/2002) : create DIBSection from bitmap buffer
	if (!B->DIBhandler) ObjBitmap_CreateDIBSection (B);


    Dcw = GetDC ( W->WHandler ) ;       
    Dcb = CreateCompatibleDC ( Dcw ) ;
    OldBitmap = SelectObject ( Dcb , B->DIBhandler) ;
    BitBlt ( Dcb , sx1 , sy1 , sx2 , sy2 , Dcw , dx , dy , SRCCOPY ) ;
 
    SelectObject ( Dcb , OldBitmap ) ;
    DeleteDC ( Dcb ) ;    
	ReleaseDC (W->WHandler, Dcw);

    res = MMpush(m,ss) ;


//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRCopyWindow end");
#endif
//***********************************

    return res ;
}


