
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///																																  ///
///		FICHIER :	ZooSCOL.cpp																									  ///
///																																  ///
///		NATURE	:	Defines The SCOL functions and management of the Hash table   												  ///
///																																  ///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////




//
// Modifications History
//
//$ LB (13/06/2002) : changed the objbitmap struct to manage the GDI problem.
//
//$LB (10/12/2003) : BPL compute was wrong in BlitTexture : windows 24 bits bitmaps are 32 bits aligned
//
//$LB (31/10/2004) : added the M3topoScale function
//
//$LB (23/11/2004) : Surface2Bitmap : fixed a bug about the offset compute
//
//$LBDEBUG //$LB (24/11/2004) : // this is a hack in order to fix a bug about the process of particles
// <=> choose an algo in fonction of the 3d card vendor
//
//$BLG (29/05/2005) : M3filter(): multiple fixes (Full size filtering, misc. filters fixes).
//
//$BLG (29/05/2005) : Surface2Bitmap(): fixed a bug about the offset compute (32Bytes Surface data packs handling).
//


//$BLG - v5.3.01: Add
#include "blg_memory.h"

#include	"..\SCOL\ZooSCOL.h"
#include "../scol/colors.h"
using namespace std ;


#ifdef	__OPTI_P4__
#include	<emmintrin.h>
#endif



//#define		_SCOL_DEBUG_

 



#define		HASH_SIZE				256

#define		MYWND_WINDOWED			0
#define		MYWND_FULLSCREEN		2


#define		TYP_MESH_STATIC			1
#define		TYP_MESH_MULTI_TOPO		2
#define		TYP_MESH_NOT_CLICKABLE	4

#define		RANGE_INFINITY			-10
#define		RANGE_INFINITY_F		-20

#define		TEX_MIPMAP				2



cbmachine	ww;
mmachine	mm;
PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB ;   // Pour l'utilisation des extensions



int			typeSurface;								// id Type pour les ObjSurfaces
int			typeSession;								// id Type pour les sessions


DWORD		dwSurfaceCount;

HWND		HScol;										// handle de fenêtre SCOL principale

int			num3d = 0;


int 		fullscreenMode	= 0;
int			windowedMode	= 0;
int			VENDOR_ATI ;
int			VENDOR_NVD ;


int			tmp_i;
int			tmp_f;


//$BLG - v5.3.01: Add (Cosinus and Sinus tables)
float tabCos[360];
float tabSin[360];


////////////----MultiSampling-------//////////////


bool arbMultisampleSupported = false ;
int arbMultisampleFormat = 0 ;
int Multi_Pass = 2 ;
/* $MS : add to save the max value for Sample Buffers */
int maxSamples = 0 ;
// $MS
////////////----Mipmapping-------//////////////
int mainMIPMAP = 0 ;

////////////////---Multitexturing----////////////////
bool arbMultitexturingSupported = false ;

/////////-----  Animations par Squelette   ------------  /////////
int count = 0 ;

/* $MS : System Path */
//$BLG - v5.2.06: Add
char execpath[1024];					// Path to scol.exe: path
char execsubdir[MAX_PATH];		// Subdir install directory:					path = subpath/subdir
char mydcmtspath[MAX_PATH];	// Path to Common App Data directory: commonappdatapath/subdir
char mydcmtspath2[MAX_PATH];	// Path to Common App Data directory: commonappdatapath/subdir/
HRESULT hr_mydcmtspath;
///////////////////////////////////
///		FENETRE OpenGL MERE		///
///////////////////////////////////

HGLRC		CreateMainContext();

HINSTANCE	hInstance;

HGLRC		mainglrc = NULL;
HDC			mainhdc  = NULL;
HWND		mainhwnd = NULL;

int			mainPIXELFORMAT = 0;
int			mainBPP		= 0;
//$BLG - v5.24: Del
//int			mainDEPTH	= 0;
//int			mainDBLBUF	= 0;

bool		userACCEL;

bool		infoP3;
bool		infoP4;

bool		monClavier[256];


///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////


#ifdef _INFO_SCREEN_

extern bool	focusTreeGraph;
extern bool blockRendering;
extern bool refreshInfos;

HWND		mainInfoWND = NULL;
HGLRC		mainInfoRC	= NULL;
HDC			mainInfoDC	= NULL;

int			mainInfoWW = 0;
int			mainInfoWH = 0;

int			mainMouseX, mainMouseY;

HINSTANCE	hInstINFO;

bool		keysPressed[256];

bool	g_fDragging = false;


void Main_OnBeginSelect(HWND hwndTV, LPNMTREEVIEW lpnmtv) 
{
	selectedITEM = lpnmtv->itemNew.hItem;
}


void Main_OnBeginDrag(HWND hwndTV, LPNMTREEVIEW lpnmtv) 
{
    HIMAGELIST	himl;			// handle to image list 
    RECT		rcItem;			// bounding rectangle of item 
    DWORD		dwLevel;		// heading level of item 
    DWORD		dwIndent;		// amount that child items are indented 

    // Tell the tree view control to create an image to use for dragging. 
    himl = TreeView_CreateDragImage(hwndTV, lpnmtv->itemNew.hItem); 
 
    // Get the bounding rectangle of the item being dragged. 
    TreeView_GetItemRect(hwndTV, lpnmtv->itemNew.hItem, &rcItem, TRUE); 
 
    // Get the heading level and the amount that the child items are indented. 
    dwLevel		= lpnmtv->itemNew.lParam; 
    dwIndent	= (DWORD) SendMessage(hwndTV, TVM_GETINDENT, 0, 0);

	// Start the drag operation. 
	ImageList_BeginDrag(himl, 0, 0, 0); 
 
    // Hide the mouse pointer, and direct mouse input to the 
    // parent window. 
    ShowCursor(FALSE); 
    SetCapture(GetParent(hwndTV)); 
    g_fDragging = true;
    return; 
} 


void Main_OnMouseMove(HWND hwndParent, HWND hwndTV, int xCur, int yCur) 
{ 
    HTREEITEM		htiTarget;  // handle to target item 
    TVHITTESTINFO	tvht;  // hit test information 

	if(g_fDragging) 
	{ 
		// Drag the item to the current position of the mouse pointer. 
        ImageList_DragMove(xCur, yCur);
 
        // Find out if the pointer is on the item. If it is, highlight the item as a drop target. 
        tvht.pt.x = xCur;
        tvht.pt.y = yCur;

		if((htiTarget = TreeView_HitTest(hwndTV, &tvht)) != NULL)		TreeView_SelectDropTarget(hwndTV, htiTarget);
    } 
    return;
}


void Main_OnLButtonUp(void) 
{ 
    if(g_fDragging) 
	{
        ImageList_EndDrag(); 
        ReleaseCapture(); 
        ShowCursor(TRUE); 
        g_fDragging = false; 
    } 
    return; 
} 

void Main_OnLButtonDown(int x, int y)
{
	if(y<mainInfoWH-InfoScreenHH)
	{
		if(x<mainInfoWW/2)		focusTreeGraph = true;
		else					focusTreeGraph = false;
		focusInfo = 0;
	}
	else if(y<mainInfoWH-InfoMouseHH)
	{
		SetFocus(mainInfoWND);
		focusInfo = 1;
	}
	else if(y<mainInfoWH)
	{
		SetFocus(mainInfoWND);
		focusInfo = 2;
	}


	if( x<mainInfoWW-10 && x>mainInfoWW-20 && y<mainInfoWH-InfoScreenHH+20 && y>mainInfoWH-InfoScreenHH+10)
	{
		blockRendering = !blockRendering;
	}

	if( x<mainInfoWW-30 && x>mainInfoWW-40 && y<mainInfoWH-InfoScreenHH+20 && y>mainInfoWH-InfoScreenHH+10)
	{
		refreshInfos = true;
	}
}


#define LOWORD(l)					((WORD)(l))
#define HIWORD(l)					((WORD)(((DWORD)(l) >> 16) & 0xFFFF))
#define GET_X_LPARAM(lp)			((int)(short)LOWORD(lp))
#define GET_Y_LPARAM(lp)			((int)(short)HIWORD(lp))



LRESULT CALLBACK InfoWndProc(HWND thisWindow, UINT msgType, WPARAM wParam, LPARAM lParam)
{
	int		xPos, yPos;

	switch ( msgType )
	{
		case WM_LBUTTONDOWN:
			xPos = GET_X_LPARAM(lParam);
			yPos = GET_Y_LPARAM(lParam);
			Main_OnLButtonDown(xPos, yPos);
			break;

		case WM_NOTIFY: 
			switch (((LPNMHDR) lParam)->code) 
			{
				case TVN_BEGINDRAG:
					Main_OnBeginDrag(TreeGraph, (LPNMTREEVIEW) lParam);
					break; 

				case TVN_SELCHANGED:
					Main_OnBeginSelect(TreeGraph, (LPNMTREEVIEW) lParam);
					break;
			}
			break; 

		case WM_MOUSEMOVE:
			xPos = GET_X_LPARAM(lParam);
			yPos = GET_Y_LPARAM(lParam);
			Main_OnMouseMove(thisWindow, TreeGraph, xPos, yPos);
			break;

		case WM_CREATE:
			return 0;
			break;

		case WM_DESTROY:
			return 0;

		case WM_KEYUP:
			keysPressed[wParam] = false;
			break;

		case WM_KEYDOWN:
			keysPressed[wParam] = true;
			break;

		case WM_CHAR:

		case WM_LBUTTONUP:
			Main_OnLButtonUp();
			break;

		case WM_MBUTTONDOWN:
			break;

		case WM_RBUTTONDOWN:
			break;

		case WM_CLOSE:
			mainInfoWND = NULL;
			mainInfoDC	= NULL;
			mainInfoRC	= NULL;
	//		PostQuitMessage(0);
//			return 0;

		case WM_RBUTTONUP:
		case WM_MBUTTONUP:
		case WM_LBUTTONDBLCLK:
		case WM_RBUTTONDBLCLK:
		case WM_MBUTTONDBLCLK:
		case WM_CAPTURECHANGED:
//		case WM_MOUSEWHEEL:

		
		case WM_SETFOCUS:
		case WM_KILLFOCUS:
		case WM_PAINT:
			break;
	}

	return DefWindowProc(thisWindow,msgType,wParam,lParam);
}


//////////////////////////////////////////////////////////////////////////////////////////////
///		CreateWinInfoSCREEN
//////////////////////////////////////////////////////////////////////////////////////////////
void CreateWinInfoSCREEN(int w, int h)
{
	for(int ii=0; ii<255; ii++)		keysPressed[ii] = false;

	// Register the window-class
	WNDCLASS	infownd;

	infownd.style			= 0;
	infownd.cbClsExtra		= 0;
	infownd.cbWndExtra		= 0;
	infownd.hbrBackground	= 0;
	infownd.hCursor			= LoadCursor(NULL,IDC_ARROW);
	infownd.hIcon			= NULL;
	infownd.hInstance		= hInstance;
	infownd.lpfnWndProc		= InfoWndProc;
	infownd.lpszClassName	= "InfoGL";
	infownd.lpszMenuName	= NULL;

	RegisterClass(&infownd);



	HWND	hwnd;

	RECT	WindowRect;						// Grabs Rectangle Upper Left / Lower Right Values
	
	WindowRect.left		= (long) 0;			// Set Left Value To 0
	WindowRect.right	= (long) w;			// Set Right Value To Requested Width
	WindowRect.top		= (long) 0;			// Set Top Value To 0
	WindowRect.bottom	= (long) h;			// Set Bottom Value To Requested Height

	AdjustWindowRectEx(&WindowRect, WS_OVERLAPPEDWINDOW, FALSE, WS_EX_APPWINDOW | WS_EX_WINDOWEDGE);

	// Create The Window
	hwnd = CreateWindowEx(	WS_EX_APPWINDOW | WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW,				// Extended Style For The Window
							"InfoGL",										// Class Name
							"InfoGL",										// Window Title
							WS_SYSMENU | WS_CAPTION | WS_OVERLAPPED | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,	// Required Window Style
							0, 0,											// Window Position
							WindowRect.right-WindowRect.left,				// Calculate Window Width
							WindowRect.bottom-WindowRect.top,				// Calculate Window Height
							NULL,											// No Parent Window
							NULL,											// No Menu
							NULL,											// Instance
							NULL );											// Dont Pass Anything To WM_CREATE
	ShowWindow(hwnd, SW_SHOW);
	SetForegroundWindow(hwnd);
	SetFocus(hwnd);
	UpdateWindow(hwnd);

	HDC hdc = GetDC(hwnd);

	PIXELFORMATDESCRIPTOR pfd; 

	ZeroMemory(&pfd, sizeof(pfd)); 
	pfd.nSize	 = sizeof(pfd); 
	pfd.nVersion = 1;

	SetPixelFormat(hdc, mainPIXELFORMAT, &pfd);

	HGLRC hglrc	= wglCreateContext(hdc);

	if(wglGetCurrentContext()!=hglrc)
	{
		wglMakeCurrent(hdc,hglrc);
	}

	wglShareLists(mainglrc, hglrc);

	glViewport(0,0,w,h);												// Reset The Current Viewport

	mainInfoWW	= w;
	mainInfoWH	= h;
	mainInfoWND = hwnd;
	mainInfoDC	= hdc;
	mainInfoRC	= hglrc;
}

#endif


LONG WINAPI
WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{ 
    static PAINTSTRUCT ps;

    switch(uMsg) {


    case WM_SIZE:
	glViewport(0, 0, LOWORD(lParam), HIWORD(lParam));
	PostMessage(hWnd, WM_PAINT, 0, 0);
	return 0;

    case WM_CHAR:
	switch (wParam) {
	case 27:			/* ESC key */
	    PostQuitMessage(0);
	    break;
	}
	return 0;

    case WM_CLOSE:
	PostQuitMessage(0);
	return 0;
    }

    return DefWindowProc(hWnd, uMsg, wParam, lParam); 
} 


//////////////////////////////////////////////////////////////////////////////////////////////
///		CreateWinInfoTest
//////////////////////////////////////////////////////////////////////////////////////////////
void CreateWinInfoTest(int w, int h)
{
	
	ZDetector detect ;
	char vendor[256] ;
	int i ;
  int         pf;
  HDC         hdc;
  HWND        hwnd;
  WNDCLASS    wc;

  static HINSTANCE hInstance = 0;

  /* only register the window class once - use hInstance as a flag. */
  if (!hInstance) 
	{
		hInstance = GetModuleHandle(NULL);
		wc.style         = CS_OWNDC;
		wc.lpfnWndProc   = (WNDPROC)WindowProc;
		wc.cbClsExtra    = 0;
		wc.cbWndExtra    = 0;
		wc.hInstance     = hInstance;
		wc.hIcon         = LoadIcon(NULL, IDI_WINLOGO);
		wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
		wc.hbrBackground = NULL;
		wc.lpszMenuName  = NULL;
		wc.lpszClassName = "OpenGL";
	
		//$BLG - v5.22: Modif
		//if (!RegisterClass(&wc)) { MMechostr (1,"---Impossible d'enregistrer la classe de fenêtre------\n") ;}
		if (!RegisterClass(&wc)) { MMechostr (1,"> --> Impossible to register window class\n") ;}
	}
	
	//// Création de la fenêtre !! 

  hwnd = CreateWindow("OpenGL", "OpenGL", WS_OVERLAPPEDWINDOW|WS_CLIPSIBLINGS|WS_CLIPCHILDREN, 0, 0, w, h, NULL, NULL, hInstance, NULL);

  if (hwnd == NULL) { }
	// Récupération du contexte

  hdc = GetDC(hwnd);
	if (hdc == NULL) { }

	// Format de pixel
	//$BLG Note: http://msdn2.microsoft.com/en-us/library/ms537569(VS.85).aspx
 	PIXELFORMATDESCRIPTOR pfd =					// pfd Tells Windows How We Want Things To Be
	{
		sizeof (PIXELFORMATDESCRIPTOR),		// nSize: Size Of This Pixel Format Descriptor
		1,																// nVersion: Version Number
																			// dwFlags:
		PFD_DRAW_TO_WINDOW |							// - Format Must Support Window
		PFD_SUPPORT_OPENGL |							// - Format Must Support OpenGL
		PFD_DOUBLEBUFFER,									// - Must Support Double Buffering
		PFD_TYPE_RGBA,										// iPixelType: Request An RGBA Format
		32,																// cColorBits: number of color bitplanes in each color buffer -> Select Our Color Depth
		//$BLG - v5.24: Modif
		//0, 0, 0, 0, 0, 0,									// Color Bits Ignored
		8, 0, 8, 0, 8, 0,									// cRedBits, ... ,cBlueShift -> Color Bits & Shifts
		//$BLG - v5.24: Modif
		//1,																// Alpha Buffer
		8,																// cAlphaBits: number of alpha bitplanes in each RGBA color buffer (Not supported) -> Alpha Buffer 1
		0,																// cAlphaShift shift count for alpha bitplanes in each RGBA color buffer (Not supported) -> Shift Bit Ignored
		//$BLG - v5.24: Modif
		//0,																// cAccumBits: total number of bitplanes in the accumulation buffer -> No Accumulation Buffer
		//0, 0, 0, 0,												// cAccumRedBits, ... ,cAccumAlphaBits: number of bitplanes for each color in the accumulation buffer -> Accumulation Bits set to 0
		64,																// cAccumBits: total number of bitplanes in the accumulation buffer -> No Accumulation Buffer
		16, 16, 16, 16,										// cAccumRedBits, ... ,cAccumAlphaBits: number of bitplanes for each color in the accumulation buffer -> Accumulation Bits set to 0
		//$BLG - v5.24: Modif
		//16,																// 16Bit Z-Buffer (Depth Buffer)  
		24,																// cDepthBits: depth of the depth (z-axis) buffer -> 24Bits Z-Buffer (Depth Buffer)  
		//$BLG - v5.24: Modif
		//0,																// No Stencil Buffer
		8,																// cStencilBits: depth of the stencil buffer -> 8Bits Stencil Buffer
		0,																// cAuxBuffers: number of auxiliary buffers (Not supported) -> No Auxiliary Buffer
		PFD_MAIN_PLANE,										// iLayerType (Ignored)
		0,																// bReserved
		0, 																// dwLayerMask (Ignored)
		0, 																// dwVisibleMask: transparent color of underlay plane
		0																	// dwDamageMask (Ignored)
	};

  pf = ChoosePixelFormat(hdc, &pfd);
  if (pf == 0) { } 

	//$BLG - v5.24: Add
	//MMechostr(0, "pf: %d\n", pf);

  //$BLG - v5.22: Modif
  //if (SetPixelFormat(hdc, pf, &pfd) == FALSE) {MMechostr(1,"---Impossible de setter le format de pixel----\n") ;} 
  if (SetPixelFormat(hdc, pf, &pfd) == FALSE) {MMechostr(1,"> --> Impossible to set pixel format\n") ;} 
  
  hdc = GetDC(hwnd);
  HGLRC hglrc = wglCreateContext(hdc);
  wglMakeCurrent(hdc, hglrc);

	if ( hglrc == NULL ) { }

	
	// Déclaration du process et vérification multisampling
	
	wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB");



	// Le multisampling
	sprintf (&vendor[0], "%s", detect.CheckOpenGLvendor());

      

  for (i=0; i < strlen (vendor); i++)
	  if ((vendor[i] >= 97) && (vendor[i] <= 122))
		  vendor[i] -= 32;
	
	if (strstr (vendor, "ATI ") != NULL)
	{
		VENDOR_ATI = 1;
	}
	else 
	{
		VENDOR_ATI = 0;
	}

	if (strstr (vendor, "NVIDIA ") != NULL)
	{
		VENDOR_NVD = 1;
	}
	else 
	{
		VENDOR_NVD = 0;
	}

	/* $MS : Test of multisampling on Windaube Vista need to be test on vista */
	
	if (detect.WGLisExtensionSupported("GL_ARB_multisample") == true /*&& detect.GetOSVersion() != 8 */)
	{
		arbMultisampleSupported = true ;
		//MMechostr(1,"---------Le multisampling est supporté----------------------\n") ;
	}
	if (detect.WGLisExtensionSupported("GL_ARB_multisample") == false /*|| (detect.GetOSVersion() == 8 && VENDOR_NVD != 1)*/ )
	{
		arbMultisampleSupported = false ;
		//MMechostr(1,"---------Le multisampling n'est pas supporté----------------------\n") ;
	}

	/* $MS : Pour le multitexturing  */

    if (detect.WGLisExtensionSupported("GL_ARB_multitexture") == false )
	{
		arbMultitexturingSupported = false ;
		MMechostr(1,"----------Le multitexturing n'est pas supporté--------------\n") ;
	}
	if (detect.WGLisExtensionSupported("GL_ARB_multitexture") == true )
	{
		arbMultitexturingSupported = true ;
		MMechostr(1,"----------Le multitexturing est supporté----------------\n") ;
		glActiveTextureARB  =	(PFNGLACTIVETEXTUREARBPROC)wglGetProcAddress("glActiveTextureARB");
		glMultiTexCoord2fvARB =		(PFNGLMULTITEXCOORD2FVARBPROC)wglGetProcAddress("glMultiTexCoord2fvARB");
		glClientActiveTextureARB = (PFNGLCLIENTACTIVETEXTUREARBPROC) wglGetProcAddress("glClientActiveTextureARB");
	}

	//$BLG - v5.22: Modif
	//if(arbMultisampleSupported == false) {  MMechostr(1,"---------Le multisampling n'est pas supporté----------------------\n") ;}
	//if(arbMultisampleSupported == true) {  MMechostr(1,"---------Le multisampling est supporté----------------------\n") ; }
	if(arbMultisampleSupported == false) 	{  MMechostr(1,"> --> Multisampling is not supported\n") ;}
	if(arbMultisampleSupported == true) 	{  MMechostr(1,"> --> Multisampling is supported\n") ; }

	// Suppression du contexte 

	//$BLG - v5.22: Modif
	/*
	if(hglrc)
	{
		if(wglMakeCurrent(NULL,NULL)==FALSE)		MMechostr(1, "------ Can't set the current rendering context to NULL ! ------\n" );
		
		if(wglDeleteContext(hglrc)==FALSE)		MMechostr(1, "------ Can't delete the MAIN rendering context ! ------\n" );
		else										MMechostr(1, "--> mainglrc released : OK\n" );
	}
	*/
	if(hglrc)
	{
		if(wglMakeCurrent(NULL,NULL)==FALSE)	MMechostr(1, "> --> Can't set the current rendering context to NULL !\n" );
		
		if(wglDeleteContext(hglrc)==FALSE)		MMechostr(1, "> -->  Can't delete the MAIN rendering context !\n" );
		else																	MMechostr(1, "> --> Main GL RC released : OK\n" );
	}

	//$BLG - v5.22: Modif
	/*
	if(hdc) 
	{
		if(ReleaseDC(hwnd, hdc)==0)			MMechostr(1, "------ Can't release the MAIN device context ! ------\n" );
		else								MMechostr(1, "--> mainhdc released : OK\n" );
	}
	*/
	if(hdc) 
	{
		if(ReleaseDC(hwnd, hdc)==0)			MMechostr(1, "> --> Can't release the main device context !\n" );
		else														MMechostr(1, "> --> Main HDC released : OK\n" );
	}

	//$BLG - v5.22: Modif
	/*
	if(hwnd)
	{
		if(DestroyWindow(hwnd)==0)				MMechostr(1, "------ Can't destroy the MAIN window ! ------\n" );
		else										MMechostr(1, "--> mainhwnd released : OK\n" );
	}
	*/
	if(hwnd)
	{
		if(DestroyWindow(hwnd)==0)			MMechostr(1, "> --> Can't destroy the main window !\n" );
		else														MMechostr(1, "> --> Main HWND released : OK\n" );
	}

	hglrc  = NULL;
	hdc   = NULL;
	hwnd  = NULL;
	
	//$BLG - v5.22: Modif
	/*
	if(!UnregisterClass("OpenGL", hInstance))
	{
		MMechostr(1, "----> Could Not Unregister Class !\n");
		hInstance=NULL;         // Set hInstance To NULL
	}
	else
		MMechostr(1, "--> class scolGL unregistred : OK\n" );
	*/
	if(!UnregisterClass("OpenGL", hInstance))
	{
		MMechostr(1, "> --> Could not unregister ScolGL class !\n");
		hInstance=NULL;         // Set hInstance To NULL
	}
	else
		MMechostr(1, "> --> ScolGL class unregistred : OK\n" );
}

///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////




////////////////////////////////////////////////////////////////////////
//////////////// Initialisation de la 3D par le fichier usmress.ini////
//////////////////////////////////////////////////////////////////////////

void Init3DConfig()
{
	// Déclaration	des variables
	char lpBuffer[256];
	std::string CurPath ;
	std::string IniPath ;
	std::string s = "usmuser.ini";
	std::string file ;
    int Count = 0;
	std::string ligne ;
	std::string trouve = "3DMultisampling" ;
	std::string trouve2 = "3DMipmap" ;
	std::string s2 ;
	std::string s1 ;
	// On récupère la chemin de fichier courant :
	GetCurrentDirectory(sizeof(lpBuffer),lpBuffer);


  
  //$BLG - v5.2.06: Add
  char *ptr;

	//$BLG - v5.2.06: Modif (Sources from Kernel45/myloop.cpp)
	/*
	if (f=fopen("usm.ini","rb"))
	*/
	// execpath
	GetCurrentDirectory (512, execpath);
	if ((execpath[strlen(execpath)-1] == '\\') || (execpath[strlen(execpath)-1] == '/'))
		execpath[strlen(execpath)-1] = 0;
	//execsubdir
	ptr = strrchr(execpath, '\\');
	if (ptr == NULL)
		ptr = strrchr(execpath, '/');
	if (ptr == NULL)
		execsubdir[0] = 0;
	else
		strncpy(execsubdir, ptr+1, strlen(execpath)+execpath-ptr);
	//cappdatapath & cappdatapath2
	mydcmtspath[MAX_PATH-1] = 0;
	mydcmtspath2[0] = 0;
	hr_mydcmtspath = SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, 0, mydcmtspath);
	if (SUCCEEDED(hr_mydcmtspath))
	{
		strcat(mydcmtspath, "/");
		strcat(mydcmtspath, execsubdir);
		strcpy(mydcmtspath2, mydcmtspath);
		strcat(mydcmtspath2, "/");
		//$BLG - Note: Scol root directory in Common App Data is created during Voyager install
	}

	CurPath = mydcmtspath2 ;

	// On ajoute le chemin du fichier cad \usmress.ini
	IniPath = CurPath + s ;


	// On ouvre le fichier .ini
	std::ifstream Ini(IniPath.c_str()) ;
	 if ( Ini ) 
	 {
		while (std::getline(Ini,ligne)) 
		{
			Count++ ;
			if(ligne.find(trouve)!= string::npos)
			{ 
 
				// On vérifie si on a un chiffre ou un nombre
				if(ligne.length() > 16 ) { s2 = ligne.substr(16,2) ;}
				else {  s2 = ligne.substr(16,1) ; }

				// On récupère la valeur du multisampling
			
				 istringstream istr(s2); 
				 // On affecte la valeure lue au multisampling
				 istr>>Multi_Pass ;
			}
		}
	 }
	 //$BLG - v5.22: Modif
	 //else {MMechostr(1,"Could not load Config 3D!!") ; }
	 else {MMechostr(1,"> --> Could not load 3D config !\n") ; }

}

////////////////////////////////////////////////////////////////////////
//////////////// Initialisation de la 3D par le fichier usmress.ini////
//////////////////////////////////////////////////////////////////////////
/* $MS : Init MipMapping */
void Init3DMipMapping()
{
	// Déclaration	des variables
	char lpBuffer[256];
	std::string CurPath ;
	std::string IniPath ;
	std::string s = "usmuser.ini";
	std::string file ;
    int Count = 0;
	std::string ligne ;
	std::string trouve = "3DMultisampling" ;
	std::string trouve2 = "3DMipmap" ;
	std::string s2 ;
	std::string s1 ;
	// On récupère la chemin de fichier courant :
	GetCurrentDirectory(sizeof(lpBuffer),lpBuffer);


  
  //$BLG - v5.2.06: Add
  char *ptr;

	//$BLG - v5.2.06: Modif (Sources from Kernel45/myloop.cpp)
	/*
	if (f=fopen("usm.ini","rb"))
	*/
	// execpath
		GetCurrentDirectory (512, execpath);
	if ((execpath[strlen(execpath)-1] == '\\') || (execpath[strlen(execpath)-1] == '/'))
		execpath[strlen(execpath)-1] = 0;
	//execsubdir
	ptr = strrchr(execpath, '\\');
	if (ptr == NULL)
		ptr = strrchr(execpath, '/');
	if (ptr == NULL)
		execsubdir[0] = 0;
	else
		strncpy(execsubdir, ptr+1, strlen(execpath)+execpath-ptr);
	//cappdatapath & cappdatapath2
	mydcmtspath[MAX_PATH-1] = 0;
	mydcmtspath2[0] = 0;
	hr_mydcmtspath = SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, 0, mydcmtspath);
	if (SUCCEEDED(hr_mydcmtspath))
	{
		strcat(mydcmtspath, "/");
		strcat(mydcmtspath, execsubdir);
		strcpy(mydcmtspath2, mydcmtspath);
		strcat(mydcmtspath2, "/");
		//$BLG - Note: Scol root directory in Common App Data is created during Voyager install
	}

	CurPath = mydcmtspath2 ;
		// On ajoute le chemin du fichier cad \usmress.ini
	IniPath = CurPath + s ;

	// On ouvre le fichier .ini
	std::ifstream Ini(IniPath.c_str()) ;
	 if ( Ini ) 
	 {
		while (std::getline(Ini,ligne)) 
		{
				Count++ ;
			/* $MS : Init MipMapping */
			
			if(ligne.find(trouve2)!= string::npos)
			{ 
				//MMechostr(1,"line found : ok !!\n") ;
				
				// On vérifie si on a un chiffre ou un nombre
				if(ligne.length() > 9 ) { s1 = ligne.substr(9,2) ;}
				else {  s1 = ligne.substr(9,1) ;}
				// On récupère la valeur du multisampling
				 istringstream istr2(s1); 
				 // On affecte la valeur lue au multisampling
				 istr2>>mainMIPMAP ;
				 if(mainMIPMAP>3) mainMIPMAP = 3 ;
				 if(mainMIPMAP<0) mainMIPMAP = 0 ;	 
			}
		}
	 }
	 //$BLG - v5.22: Modif
	 //else {MMechostr(1,"Could not load Config 3D!!") ; }
	 else {MMechostr(1,"> --> Could not set Mipmapping config !\n") ; }

}
///////////////////////////////////////////////////////////////////////////////////
///		createH3D																///
///////////////////////////////////////////////////////////////////////////////////
///	Crée un nouveau H3D et renvoit le pointeur SCOL correspondant (pas le mot)
int	createH3D(mmachine m, int adress, int hash_tab)
{
	MMpush(m, PTOM(hash_tab) );

	// Crée le H3D dans SCOL
	int h3d = MMmalloc(m, 3, TYPETAB);
	if(h3d==NIL)		return MERRMEM;
	MMstore(m, h3d, 0, adress);					// pointeur C sur le node
	MMstore(m, h3d, 1, NIL);						// call-back 1
	MMstore(m, h3d, 2, NIL);						// call-back 2

	MMpush(m, PTOM(h3d) );

	// Crée la case dans la hash_table
	int boxHash = MMmalloc(m, 3, TYPETAB);
	if(boxHash==NIL)		return MERRMEM;
	MMstore(m, boxHash, 1, adress);				// pointeur C sur le node
	h3d = MTOP( MMpull(m) );
	MMstore(m, boxHash, 2, PTOM(h3d) );				// MOT-pointeur SCOL sur le H3D

	hash_tab = MTOP( MMpull(m) );
	int place = (adress>>4) % HASH_SIZE;
	int	nextCase = MMfetch(m, hash_tab, place);
	MMstore(m, boxHash, 0, nextCase);				// MOT-pointeur sur la case suivante

	// Place la case dans la hash_table
	MMstore(m, hash_tab, place, PTOM(boxHash));

	return	h3d;
}



///////////////////////////////////////////////////////////////////////////////////
///		createHmatHtx															///
///////////////////////////////////////////////////////////////////////////////////
///	Crée un nouveau MAT ou TEX et renvoit le pointeur SCOL correspondant (pas le mot)
int	createHmatHtx(mmachine m, int adress, int hash_tab)
{
	MMpush(m, PTOM(hash_tab) );

	// Crée le MAT ou le TEX dans SCOL
	int mat = MMmalloc(m, 1, TYPETAB);
	if(mat==NIL)		return MERRMEM;
	MMstore(m, mat, 0, adress);						// pointeur C sur le node

	MMpush(m, PTOM(mat) );

	// Crée la case dans la hash_table
	int boxHash = MMmalloc(m, 3, TYPETAB);
	if(boxHash==NIL)		return MERRMEM;
	MMstore(m, boxHash, 1, adress);					// pointeur C sur le node
	MMstore(m, boxHash, 2, MMpull(m));				// MOT-pointeur SCOL sur le H3D

	hash_tab = MTOP( MMpull(m) );
	int place = (adress>>4) % HASH_SIZE;
	int	nextCase = MMfetch(m, hash_tab, place);
	MMstore(m, boxHash, 0, nextCase);				// MOT-pointeur sur la case suivante

	// Place la case dans la hash_table
	MMstore(m, hash_tab, place, PTOM(boxHash));

	return	mat;
}



///////////////////////////////////////////////////////////////////////////////////
///		NodeTOHandle															///
///////////////////////////////////////////////////////////////////////////////////
///	Retourne le handle correspondant à un Node -- Valable pour les ZNodes de TOUT type
int	NodeTOHandle(mmachine m, int hash_tab, int adress)
{
	int place	= (adress>>4) % HASH_SIZE;
	int	curBox	= MMfetch(m, hash_tab, place);

	while( (curBox!=NIL) && (adress!=MMfetch(m,MTOP(curBox),1)) )		curBox = MMfetch(m,MTOP(curBox),0);

	if(curBox==NIL)		return NIL;

	return	MTOP( MMfetch(m,MTOP(curBox),2) );
}



///////////////////////////////////////////////////////////////////////////////////
///		DelObj																	///
///////////////////////////////////////////////////////////////////////////////////
///	Efface un handle de TOUT type - Données passées en pointeurs SCOL (pas en mots..)
int	DelObj(mmachine m, int hash_tab, int handle)
{
	// supprime le pointeur C dans le H3D
	int adress = MMfetch(m, handle, 0);
	MMstore(m, handle, 0, (int)NULL);

	// supprime la case de la hash_table
	int place = (adress>>4) % HASH_SIZE;
	int	curBox = MMfetch(m, hash_tab, place);

	if( adress == MMfetch(m,MTOP(curBox),1) )		// CAS DU PREMIER ELEMENT
	{
		MMstore(m, MTOP(curBox), 2, NIL);
		MMstore(m, MTOP(curBox), 1, (int)NULL);

		int next = MMfetch(m,MTOP(curBox),0);
		MMstore(m, MTOP(curBox), 0, NIL);
		MMstore(m, hash_tab, place, next);
	}
	else											// CAS DES ELEMENTS SUIVANTS
	{
		int next = MMfetch(m,MTOP(curBox),0);
		
		while( (next!=NIL) && (adress!=MMfetch(m,MTOP(next),1)) )
		{
			curBox	= next;
			next	= MMfetch(m,MTOP(curBox),0);
		}

		if(next!=NIL)
		{
			MMstore(m, MTOP(next), 2, NIL);
				MMstore(m, MTOP(next), 1, (int)NULL);
				MMstore(m, MTOP(curBox), 0, MMfetch(m,MTOP(next),0) );
			MMstore(m, MTOP(next), 0, NIL);
		}
		else
			return 1;	// retour d'erreur : aucune case ne correspond
	}

	return 0;
}



///////////////////////////////////////////////////////////////////////////////////////////
///								FUNCTION WHICH	DELETE A NODE							///
///////////////////////////////////////////////////////////////////////////////////////////
void DeleteRecursiveNode(mmachine m, int hash_tab, ZNode *firstNode)
{
	ZNode	*curNode, *nodeSon, *nodeNext;
	int		h3d;

	curNode = firstNode;

	while(curNode != NULL)
	{
		nodeSon  = curNode->son;
		nodeNext = curNode->next;

		if(curNode->type != ANI_TYPE_ID)
		{
			delete curNode;
			
			h3d = NodeTOHandle(m, hash_tab, (int)curNode);
			DelObj(m, hash_tab, h3d);
		}
		else
		{
			delete curNode ;
		}
		// Test of recursion
		if(nodeSon!=NULL)			DeleteRecursiveNode(m, hash_tab, nodeSon);
		curNode = nodeNext;
	}
}


 
void DeleteNode(mmachine m, int hash_tab, ZNode *baseNode)
{
	if(baseNode->father)
	{
		// SEPARE THE NODE FROM THE HIERARCHY
		// if the son of the father link is equal to the current node (first node of the list)
		if (baseNode->father->son == baseNode)
		{
			baseNode->father->son = baseNode->next;
			if (baseNode->next)		baseNode->next->prev = baseNode->prev;
		}
		else
		{
			if (!baseNode->next)	baseNode->father->son->prev = baseNode->prev;						// If the node is the last, fix the prevlink of the first child
			baseNode->prev->next = baseNode->next;
			if (baseNode->next)		baseNode->next->prev = baseNode->prev;
		}

		baseNode->prev = baseNode->next = NULL;													// Brother links are free, but the attached tree is available
	}	

	// DELETE the attached hierarchy
	DeleteRecursiveNode(m, hash_tab, baseNode->son);

	// finally DELETE the baseNode
	delete baseNode;
}



///////////////////////////////////////////////////////////////////////////////////
///		CleanHash																///
///////////////////////////////////////////////////////////////////////////////////
///	Efface tous les éléments d'une hash table
void CleanHash(mmachine m, int hash_tab)
{
	int		i, curBox, nextBox, h3d;

	for(i=0; i<HASH_SIZE; i++)
	{
		curBox = MMfetch(m, hash_tab, i);

		while(curBox!=NIL)
		{
			MMstore(m, MTOP(curBox), 1, (int)NULL);		// efface le pointeur C dans la case de la hash_tab
			
			h3d = MMfetch(m, MTOP(curBox), 2);			// efface le pointeur C dans le H3d correspondant à la case
			MMstore(m, MTOP(h3d), 0, (int)NULL);

			MMstore(m, MTOP(curBox), 2, NIL);			// efface le pointeur C dans la case de la hash_tab

			nextBox = MMfetch(m, MTOP(curBox), 0);		// passage à l'élément suivant
			MMstore(m, MTOP(curBox), 0, NIL);			// efface le pointeur C dans la case de la hash_tab

			curBox = nextBox;
		}

		MMstore(m, hash_tab, i, NIL);
	}
}




///////////////////////////////////////////////////////////////////////////////////
///		getBigFather															///
///////////////////////////////////////////////////////////////////////////////////
ZNode*	getBigFather(ZNode* node)
{
	ZNode	*curNode = node;
	while(curNode->father->type <= MAX_NODE_SCENE)		curNode = curNode->father;
	return curNode;
}













///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////																											   ////
///										GESTION DE SESSION ET DE SURFACE											///
////																											   ////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////



//////////////////////////////////////////////////////////////////////////////////////////////
///		createScene
//////////////////////////////////////////////////////////////////////////////////////////////
// Crée une session et dépose le handler sur la pile (dépile le channel laissé en paramètre)
int createScene(mmachine m, bool accel)
{
    int		i;
	
	// Création de la scene 3D
	ZScene		*scene = NULL;
	scene = new ZScene(accel);
	if(scene==NULL)				return MERRMEM;
	scene->InitWorld();
	Init3DMipMapping() ;
	scene->generalTextureFilter = mainMIPMAP ;

	int s3d = MMmalloc(m, 4, TYPETAB);
	if(s3d==NIL)				return MERRMEM;
	for(i=0; i<4; i++)			MMstore(m, s3d, i, NIL);

	MMstore(m, s3d, 0, (int)scene);
	MMpush(m,PTOM(s3d));


	// Création de la hash_table des H3D
	int hashH3D = MMmalloc(m, HASH_SIZE, TYPETAB);
	if(hashH3D==NIL)			return MERRMEM;
	for(i=0; i<HASH_SIZE; i++)	MMstore(m, hashH3D, i, NIL);

	s3d = MTOP(MMpull(m));
	MMstore(m, s3d, 1, PTOM(hashH3D));
	MMpush(m,PTOM(s3d));


	// Création de la hash_table des MATERIAUX
	int hashMAT = MMmalloc(m, HASH_SIZE, TYPETAB);
	if(hashMAT==NIL)			return MERRMEM;
	for(i=0; i<HASH_SIZE; i++)	MMstore(m, hashMAT, i, NIL);

	s3d = MTOP(MMpull(m));
	MMstore(m, s3d, 2, PTOM(hashMAT));
	MMpush(m,PTOM(s3d));


	// Création de la hash_table des TEXTURES
	int hashTEX = MMmalloc(m, HASH_SIZE, TYPETAB);
	if(hashTEX==NIL)			return MERRMEM;
	for(i=0; i<HASH_SIZE; i++)	MMstore(m, hashTEX, i, NIL);

	s3d = MTOP(MMpull(m));
	MMstore(m, s3d, 3, PTOM(hashTEX));


	// Pose le résultat sur la pile avant l'appel de 'ObjCreate'
	if(MMpush(m, PTOM(s3d)))	return MERRMEM;

	return OBJcreate(m, typeSession, num3d++, -1, -1);
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3create														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [Chn I I I I I] S3d		--> specifique pour le rendu SOFT
int ZM3create(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"MX3create ");
#endif
	
	int		k, p;

	MMpull(m);
    MMpull(m);
    MMpull(m);
    MMpull(m);
    MMpull(m);


	#ifdef	_INFO_SCREEN_
		if(userACCEL && !mainInfoWND)	CreateWinInfoSCREEN(600, 1000);
	#endif

	if(k = createScene(m, false))	return k;			// crée une session et pose le pointeur scol sur la pile
	p = MMget(m,0);
	if(p==NIL)				return 0;


#ifdef	_SCOL_DEBUG_
	MMechostr(0," ok\n");
#endif

	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZMX3create														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [Chn I I I I I] S3d
int ZMX3create(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"MX3create ");
#endif

	int		k, p;

	MMpull(m);
    MMpull(m);
    MMpull(m);
    MMpull(m);
    MMpull(m);


	#ifdef	_INFO_SCREEN_
		if(userACCEL && !mainInfoWND)	CreateWinInfoSCREEN(600, 1000);
	#endif

	if(k = createScene(m, userACCEL))	return k;			// crée une session et pose le pointeur scol sur la pile
	p = MMget(m,0);
	if(p==NIL)				return 0;


	// ------->  C'est là !!!! qu'on place le FLAG pour le mode soft ou le mode HARD !!!!!!!  <-----

	//	ZScene	*s;
	//	s=(session3d)MMstart(m,p>>1);
	//	s->mx3=mx3value; //1 : Hardware s->mx3=0; //0 : software

#ifdef	_SCOL_DEBUG_
	MMechostr(0," ok\n");
#endif

	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZMX3createSession														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [Chn] S3d
int ZMX3createSession(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"MX3createSession ");
#endif

	int		k, p;


	#ifdef	_INFO_SCREEN_
		if(userACCEL && !mainInfoWND)	CreateWinInfoSCREEN(600, 1000);
	#endif

	if(k = createScene(m,userACCEL))	return k;			// crée une session et pose le pointeur scol sur la pile
	p = MMget(m,0);
	if(p==NIL)				return 0;

#ifdef	_SCOL_DEBUG_
	MMechostr(0," ok\n");
#endif

	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZooDestroySession														
//////////////////////////////////////////////////////////////////////////////////////////////
// fonction d'appel lors de la destruction interne d'une surface (déclarée dans le ObjRegister)
int ZooDestroySession(mmachine m, int q, int s3d)
{
	MMechostr(0,"session destroyed !!\n");

	ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);

	// Efface la scene
	MMstore(m, MTOP(s3d), 0, (int)NULL);
	delete scene;

	// Efface les Hash_tab
	int	hashTab = MMfetch(m,MTOP(s3d),1);
	CleanHash(m, MTOP(hashTab));
	MMstore(m, MTOP(s3d), 1, NIL);

	hashTab = MMfetch(m,MTOP(s3d),2);
	CleanHash(m, MTOP(hashTab));
	MMstore(m, MTOP(s3d), 2, NIL);

	hashTab = MMfetch(m,MTOP(s3d),3);
	CleanHash(m, MTOP(hashTab));
	MMstore(m, MTOP(s3d), 3, NIL);

	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3destroy
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d] I
int ZM3destroy(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3destroy ");
#endif

    int s3d	 = MMget(m,0);
    if(s3d==NIL)					{	MMset(m,0,NIL);		return 0;	}
	OBJdelTM(m, typeSession, s3d);

	MMset(m,0,0);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3freeMemory
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d] I
int ZM3freeMemory(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3freeMemory ");
#endif

    int s3d	 = MMget(m,0);

    if(s3d==NIL)					{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m, MTOP(s3d), 0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

	MMset(m,0,ITOM(4096*4096));

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

    return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3reset
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d] I
int ZM3reset(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3reset ");
#endif

    int s3d	 = MMget(m,0);

	if(s3d==NIL)					{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m, MTOP(s3d), 0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

	scene->Reset();

	// Efface les Hash_tab
	int	hashTab = MMfetch(m,MTOP(s3d),1);
	CleanHash(m, MTOP(hashTab));
//	MMstore(m, MTOP(s3d), 1, NIL);

	hashTab = MMfetch(m,MTOP(s3d),2);
	CleanHash(m, MTOP(hashTab));
//	MMstore(m, MTOP(s3d), 2, NIL);

	hashTab = MMfetch(m,MTOP(s3d),3);
	CleanHash(m, MTOP(hashTab));
//	MMstore(m, MTOP(s3d), 3, NIL);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"MX3create");
#endif
    
	MMset(m,0,0);
    return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		SetGL2D														
//////////////////////////////////////////////////////////////////////////////////////////////
bool SetGL2D(mmachine m, int surf, HDC *pdc = NULL, HWND *phwnd = NULL, HGLRC *prc = NULL)
{
	HDC		dc;
	HWND	hwnd;
	HGLRC	rc;
	RECT	rect;

	dc = (HDC) MMfetch(m, surf, 1);
	rc = (HGLRC) MMfetch(m, surf, 2);
	hwnd = (HWND) MMfetch(m, surf, 3);

	if (!rc || !dc || !hwnd)
		return false;

	if(wglGetCurrentContext() != rc)
	{
		wglMakeCurrent(dc, rc);
	}

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	GetClientRect(hwnd, &rect);
	gluOrtho2D(0, (float)rect.right, (float)rect.bottom, 0);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	glDisable(GL_TEXTURE_2D);
	glDisable(GL_FOG);
	glDisable(GL_LIGHTING);
	glDisable(GL_DEPTH_TEST);
	glDisable(GL_BLEND);
	glDisable(GL_ALPHA_TEST);

	if (pdc)		*pdc = dc;
	if (phwnd)	*phwnd = hwnd;
	if (prc)		*prc = rc;

	return true;
}












//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int ChoosePixelFormatEx(HDC hdc,int *p_bpp,int *p_depth,int *p_dbl,int *p_acc)
{ 
	int wbpp;
	if(p_bpp==NULL)			wbpp = -1; 
	else					wbpp = *p_bpp;

	int wdepth; 
	//$LB
	if(p_depth==NULL)		wdepth = 24; 
	else					wdepth = *p_depth;

	int wdbl; 
	if(p_dbl==NULL)			wdbl = -1; 
	else					wdbl = *p_dbl;

	int wacc; 
	if(p_acc==NULL)			wacc = 1; 
	else					wacc = *p_acc;

	PIXELFORMATDESCRIPTOR pfd; 
	ZeroMemory(&pfd, sizeof(pfd)); 
	pfd.nSize		= sizeof(pfd); 
	pfd.nVersion	= 1;

	int num = DescribePixelFormat(hdc, 1, sizeof(pfd), &pfd);
	if(num==0)		return 0;

	unsigned int maxqual  = 0; 
	int			 maxindex = 0;

	int max_bpp, max_depth, max_dbl, max_acc;

	for(int i=1; i<=num; i++)
	{
		ZeroMemory(&pfd, sizeof(pfd)); 
		pfd.nSize		= sizeof(pfd); 
		pfd.nVersion	= 1;

		DescribePixelFormat(hdc, i, sizeof(pfd), &pfd);
		int bpp		= pfd.cColorBits;
		int depth	= pfd.cDepthBits;

		// Mode paletté
		bool pal	= (pfd.iPixelType==PFD_TYPE_COLORINDEX);
		// Modes accelerés
		bool mcd	= ( (pfd.dwFlags & PFD_GENERIC_FORMAT) &&  (pfd.dwFlags & PFD_GENERIC_ACCELERATED));
		bool soft	= ( (pfd.dwFlags & PFD_GENERIC_FORMAT) && !(pfd.dwFlags & PFD_GENERIC_ACCELERATED));
		bool icd	= (!(pfd.dwFlags & PFD_GENERIC_FORMAT) && !(pfd.dwFlags & PFD_GENERIC_ACCELERATED));
		// Modes de tracé
		bool opengl = (0 != (pfd.dwFlags & PFD_SUPPORT_OPENGL));
		bool window = (0 != (pfd.dwFlags & PFD_DRAW_TO_WINDOW));
		bool bitmap = (0 != (pfd.dwFlags & PFD_DRAW_TO_BITMAP));
		bool dbuff	= (0 != (pfd.dwFlags & PFD_DOUBLEBUFFER));

		unsigned int	q=0;

		if(opengl && window)											q = q + 0x8000;
		if(wdepth==-1 || (wdepth>0 && depth>0))							q = q + 0x4000;
		if(wdbl==-1 || (wdbl==0 && !dbuff) || (wdbl==1 && dbuff))		q = q + 0x2000;

		if(wacc==-1 || (wacc==0 && soft) || (wacc==1 && (mcd||icd)))	q = q + 0x1000;
		if(mcd || icd)													q = q + 0x0040; 
		if(icd)															q = q + 0x0002;

		if(wbpp==-1 || (wbpp==bpp))										q = q + 0x0800;
		if(bpp>16)														q = q + 0x0020; 
		if(bpp==16)														q = q + 0x0008;
		
		if(wdepth==-1 || (wdepth==depth))								q = q + 0x0400;
		if(depth>16)													q = q + 0x0010; 
		if(depth==16)													q = q + 0x0004;
		
		if(!pal)														q = q + 0x0080;
		if(bitmap)														q = q + 0x0001;

		if(q>maxqual)
		{
			maxqual		= q; 
			maxindex	= i;
			max_bpp		= bpp;
			max_depth	= depth;
			max_dbl		= dbuff?1:0;
			max_acc		= soft?0:1;
		}
	}

	if(maxindex==0)		return maxindex;

	if(p_bpp   != NULL)			*p_bpp	 = max_bpp;
	if(p_depth != NULL)			*p_depth = max_depth;
	if(p_dbl   != NULL)			*p_dbl	 = max_dbl;
	if(p_acc   != NULL)			*p_acc	 = max_acc;

	return maxindex;
}





//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int ChoosePixelFormatExt(HDC hdc,int *p_bpp,int *p_depth,int *p_dbl,int *p_acc)
{ 
	int wbpp;
	if(p_bpp==NULL)			wbpp = -1; 
	else					wbpp = *p_bpp;

	int wdepth; 
	//$LB
	if(p_depth==NULL)		wdepth = 24; 
	else					wdepth = *p_depth;

	int wdbl; 
	if(p_dbl==NULL)			wdbl = -1; 
	else					wdbl = *p_dbl;

	int wacc; 
	if(p_acc==NULL)			wacc = 1; 
	else					wacc = *p_acc;

	PIXELFORMATDESCRIPTOR pfd; 
	ZeroMemory(&pfd, sizeof(pfd)); 
	pfd.nSize		= sizeof(pfd); 
	pfd.nVersion	= 1;

	int num = DescribePixelFormat(hdc, 1, sizeof(pfd), &pfd);
	if(num==0)		return 0;

	unsigned int maxqual  = 0; 
	int			 maxindex = 0;

	int max_bpp, max_depth, max_dbl, max_acc;

	for(int i=1; i<=num; i++)
	{
		ZeroMemory(&pfd, sizeof(pfd)); 
		pfd.nSize		= sizeof(pfd); 
		pfd.nVersion	= 1;

		DescribePixelFormat(hdc, i, sizeof(pfd), &pfd);
		int bpp		= pfd.cColorBits;
		int depth	= pfd.cDepthBits;

		// Mode paletté
		bool pal	= (pfd.iPixelType==PFD_TYPE_COLORINDEX);
		// Modes accelerés
		bool mcd	= ( (pfd.dwFlags & PFD_GENERIC_FORMAT) &&  (pfd.dwFlags & PFD_GENERIC_ACCELERATED));
		bool soft	= ( (pfd.dwFlags & PFD_GENERIC_FORMAT) && !(pfd.dwFlags & PFD_GENERIC_ACCELERATED));
		bool icd	= (!(pfd.dwFlags & PFD_GENERIC_FORMAT) && !(pfd.dwFlags & PFD_GENERIC_ACCELERATED));
		// Modes de tracé
		bool opengl = (0 != (pfd.dwFlags & PFD_SUPPORT_OPENGL));
		bool window = (0 != (pfd.dwFlags & PFD_DRAW_TO_WINDOW));
		bool bitmap = (0 != (pfd.dwFlags & PFD_DRAW_TO_BITMAP));
		bool dbuff	= (0 != (pfd.dwFlags & PFD_DOUBLEBUFFER));

		unsigned int	q=0;

		if(opengl && window)											q = q + 0x8000;
		if(wdepth==-1 || (wdepth>0 && depth>0))							q = q + 0x4000;
		if(wdbl==-1 || (wdbl==0 && !dbuff) || (wdbl==1 && dbuff))		q = q + 0x2000;

		if(wacc==-1 || (wacc==0 && soft) || (wacc==1 && (mcd||icd)))	q = q + 0x1000;
		if(mcd || icd)													q = q + 0x0040; 
		if(icd)															q = q + 0x0002;

		if(wbpp==-1 || (wbpp==bpp))										q = q + 0x0800;
		if(bpp>16)														q = q + 0x0020; 
		if(bpp==16)														q = q + 0x0008;
		
		if(wdepth==-1 || (wdepth==depth))								q = q + 0x0400;
		if(depth>16)													q = q + 0x0010; 
		if(depth==16)													q = q + 0x0004;
		
		if(!pal)														q = q + 0x0080;
		if(bitmap)														q = q + 0x0001;

		if(q>maxqual)
		{
			maxqual		= q; 
			maxindex	= i;
			max_bpp		= bpp;
			max_depth	= depth;
			max_dbl		= dbuff?1:0;
			max_acc		= soft?0:1;
		}
	}

	if(maxindex==0)		return maxindex;

	if(p_bpp   != NULL)			*p_bpp	 = max_bpp;
	if(p_depth != NULL)			*p_depth = max_depth;
	if(p_dbl   != NULL)			*p_dbl	 = max_dbl;
	if(p_acc   != NULL)			*p_acc	 = max_acc;

	return maxindex;
}





//////////////////////////////////////////////////////////////////////////////////////////////
///		CreateMainContext														
//////////////////////////////////////////////////////////////////////////////////////////////
HGLRC CreateMainContext()
{

	if (arbMultisampleSupported == false )
	{
		//$BLG - v5.22: Modif
		//MMechostr (1,"--------------Le multisampling n'est pas supporté par ta carte--------------\n") ;
		MMechostr (1,"> --> Multisampling is not supported\n") ;

		int		pf=0;
		
		//$BLG - v5.24: Modif
		//HDC		hdc, mdc;
		HDC		hdc;
		
		PIXELFORMATDESCRIPTOR pfd;
	
		HWND	hwnd = CreateWindow("scolGL", "scolGL", WS_CHILD, 0, 0, 1, 1, HScol, NULL, NULL, 0);
		
		//$BLG - v5.24: Modif
		/*
		mdc = GetDC(hwnd);
		hdc = mdc;
		*/
		hdc = GetDC(hwnd);


		///////////////////////////////////////////////////
		///		Test de meilleure qualité de rendu		///
		///////////////////////////////////////////////////
	
		int bpp		= -1; // don't care. (or a positive integer)
		int depth	= -1; // don't care. (or a positive integer)
		int dbl		=  1; // we want double-buffering. (or -1 for 'don't care', or 0 for 'none')
		int acc		=  1; // we want acceleration. (or -1 or 0)
	
		pf = ChoosePixelFormatExt(hdc, &bpp, &depth, &dbl, &acc);
	
		if(pf < 1)
		{
			//$BLG - v5.22: Modif
			//MMechostr(0,"****        Unable to select a pixel format for OpenGL         ****\n" );
			MMechostr(0,"> --> Unable to select a pixel format for OpenGL !\n" );
			return NULL;
		}
	
		ZeroMemory(&pfd, sizeof(pfd)); 
		pfd.nSize	 = sizeof(pfd); 
		pfd.nVersion = 1;
	
		if(!SetPixelFormat(hdc, pf, &pfd))
		{
			//$BLG - v5.22: Modif
			//MMechostr(0,"****         Can't Set The PixelFormat for OPENGL !!!          ****\n" );
			MMechostr(0,"> --> Can't set the pixel format for OpenGL !\n" );
			return NULL;
		}

		// Assignation des résultats globaux
		mainBPP		= bpp;
		
		//$BLG - v5.24: Del
		//mainDEPTH	= depth;
		//mainDBLBUF	= dbl;
		
		mainPIXELFORMAT = pf;
	
	
		mainhdc	 = hdc;
		mainhwnd = hwnd;
	
		mainglrc = wglCreateContext(hdc);
	
		if(wglGetCurrentContext()!=mainglrc)		wglMakeCurrent(hdc,mainglrc);
	
		// See if we are indeed accelerated
		DescribePixelFormat(hdc, pf, pfd.nSize, &pfd);

		// Driver type
		if(0 != (pfd.dwFlags & PFD_GENERIC_FORMAT))
		{
			//$BLG - v5.22: Modif
			//MMechostr(0,"**** Generic Software                                          ****\n" );
			MMechostr(0,"> --> Generic Software\n" );
			return NULL;
		}
		else
		{
			if(0 != (pfd.dwFlags & PFD_GENERIC_ACCELERATED))
				//$BLG - v5.22: Modif
				//MMechostr(0,"**** MCD ACCELERATED                                           ****\n" );
				MMechostr(0,"> --> MCD Accelerated\n" );
			else
				//$BLG - v5.22: Modif
				//MMechostr(0,"**** ICD ACCELERATED                                           ****\n" );
				MMechostr(0,"> --> ICD Accelerated\n" );
		}

		//$BLG - v5.22: Modif
		/*
		MMechostr(0,"**** Color  : %d                                               ****\n",bpp);
		MMechostr(0,"**** Depth  : %d                                               ****\n",depth);
		if(dbl)		MMechostr(0,"**** Buffer : double                                           ****\n");
		else		MMechostr(0,"**** Buffer : simple                                           ****\n");
		*/
		MMechostr(0, "> --> Color  : %d\n",bpp);
		MMechostr(0, "> --> Depth  : %d\n",depth);
		if (dbl)	MMechostr(0, "> --> Buffer : double\n");
		else			MMechostr(0, "> --> Buffer : simple\n");

		return mainglrc;
	}

	if (arbMultisampleSupported == true )
	{
		//$BLG - v5.22: Modif
		//MMechostr (1,"--------------Le multisampling est supporté par ta carte--------------\n") ;
		MMechostr (1,"> --> Multisampling is supported\n") ;

/*
		HWND	hwnd = CreateWindow("scolGL", "scolGL", WS_CHILD, 0, 0, 1, 1, HScol, NULL, NULL, 0);
		if ( hwnd == NULL ) { MMechostr(1,"-----Impossible de créer la fenêtre openGL-----\n") ; }
		HDC hdc = GetDC(hwnd);
		if ( hdc == NULL ) { MMechostr(1,"-------Impossible de créer le handle DC--------\n" ) ; }
*/
		
		// Choix du format de pixel 
		int pf = 0;
		int		valid;
		UINT	numFormats;
		float	fAttributes[] = {0,0};

		//$BLG - v5.24: Modif
		//HDC		hdc, mdc;
		HDC		hdc;
		
		PIXELFORMATDESCRIPTOR pfd;

		HWND	hwnd = CreateWindow("scolGL", "scolGL", WS_CHILD, 0, 0, 1, 1, HScol, NULL, NULL, 0);
		
		//$BLG - v5.24: Modif
		/*
		mdc = GetDC(hwnd);
		hdc = mdc;
		*/
		hdc = GetDC(hwnd);


		///////////////////////////////////////////////////
		///		Test de meilleure qualité de rendu		///
		///////////////////////////////////////////////////

		//$BLG - v5.24: Del
		/*
		int bpp		= -1; // don't care. (or a positive integer)
		int depth	= -1; // don't care. (or a positive integer)
		int dbl		=  1; // we want double-buffering. (or -1 for 'don't care', or 0 for 'none')
		int acc		=  1; // we want acceleration. (or -1 or 0)
		*/

		//$BLG - v5.24: Del
		//Why this whole part ? pf is chosen again just after this code chunk
		/*
		pf = ChoosePixelFormatExt(hdc, &bpp, &depth, &dbl, &acc);
		MMechostr(0, ">pf: %d\n", pf);

		if(pf < 1)
		{
			//$BLG - v5.22: Modif
			//MMechostr(0,"****        Unable to select a pixel format for OpenGL         ****\n" );
			MMechostr(0,"> --> Unable to select a pixel format for OpenGL\n" );
			return NULL;
		}

		ZeroMemory(&pfd, sizeof(pfd)); 
		pfd.nSize	 = sizeof(pfd); 
		pfd.nVersion = 1;

		if(!SetPixelFormat(hdc, pf, &pfd))
		{
			return NULL;
		}
		
		// See if we are indeed accelerated
		DescribePixelFormat(hdc, pf, pfd.nSize, &pfd);

		// Driver type
		if(0 != (pfd.dwFlags & PFD_GENERIC_FORMAT))
		{
			//$BLG - v5.22: Modif
			//MMechostr(0,"**** Generic Software                                          ****\n" );
			MMechostr(0,"> --> Generic Software\n" );
			return NULL;
		}
		else
		{
			if(0 != (pfd.dwFlags & PFD_GENERIC_ACCELERATED))
				//$BLG - v5.22: Modif
				//MMechostr(0,"**** MCD ACCELERATED                                           ****\n" );
				MMechostr(0,"> --> MCD Accelerated\n" );
			else
				//$BLG - v5.22: Modif
				//MMechostr(0,"**** ICD ACCELERATED                                           ****\n" );
				MMechostr(0,"> --> ICD Accelerated\n" );
		}
		
		//$BLG - v5.22: Modif
		//MMechostr(0,"**** Color  : %d                                               ****\n",bpp);
		//MMechostr(0,"**** Depth  : %d                                               ****\n",depth);
		//if(dbl)		MMechostr(0,"**** Buffer : double                                           ****\n");
		//else		MMechostr(0,"**** Buffer : simple                                           ****\n");

		MMechostr(0,"> --> Color  : %d\n",bpp);
		MMechostr(0,"> --> Depth  : %d\n",depth);
		if (dbl)	MMechostr(0, "> --> Buffer : double\n");
		else			MMechostr(0, "> --> Buffer : simple\n");
		*/ //$BLG Note: End of deletion
		
		/* $MS : Return the maximum value for Samplers*/
		pf = 1 ;
		while(pf != 0)
		{

			pf = 0 ;
			maxSamples++;
			// pfd Tells Windows How We Want Things To Be
			int iAttributes[] =
			{ 
				WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
				WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
				WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
				WGL_COLOR_BITS_ARB, 24,
				WGL_ALPHA_BITS_ARB, 8,
				WGL_DEPTH_BITS_ARB, 16,
				WGL_STENCIL_BITS_ARB, 0,
				WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
				WGL_SAMPLE_BUFFERS_ARB, GL_TRUE,
				WGL_SAMPLES_ARB, maxSamples,
				//$BLG - v5.24: Add
				WGL_ACCUM_BITS_ARB, 64,
				0,0
			};
			// First We Check To See If We Can Get A Pixel Format For Multi_Pass Samples
			valid = wglChoosePixelFormatARB(hdc,iAttributes,fAttributes,1,&pf,&numFormats);
			if (valid && numFormats >= 1){ }
		}

		if(maxSamples!=0) maxSamples-- ;

		/* $MS : End of the operation to find the better sample buffer */
		/* $MS : Integration of MultiPass test : here we had test recursively the capacity of the graphic card concerning the number of pass for Multisampling : No function at this time to back that number!  */
		while(pf == 0)
		{
			// pfd Tells Windows How We Want Things To Be
			int iAttributes[] =
			{ 
				WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
				WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
				WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
				WGL_COLOR_BITS_ARB, 24,
				WGL_ALPHA_BITS_ARB, 8,
				WGL_DEPTH_BITS_ARB, 16,
				WGL_STENCIL_BITS_ARB, 0,
				WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
				WGL_SAMPLE_BUFFERS_ARB, GL_TRUE,
				WGL_SAMPLES_ARB, Multi_Pass,
				//$BLG - v5.24: Add
				WGL_ACCUM_BITS_ARB, 64,
				0,0
			};
			// First We Check To See If We Can Get A Pixel Format For Multi_Pass Samples
			valid = wglChoosePixelFormatARB(hdc,iAttributes,fAttributes,1,&pf,&numFormats);
			if (valid && numFormats >= 1){ }
			Multi_Pass--;
		}

		//$BLG - v5.24: Add (Taken from above deleted code chunk
		ZeroMemory(&pfd, sizeof(pfd)); 
		pfd.nSize	= sizeof(pfd); 
		pfd.nVersion = 1;
				
		//$BLG - v5.24: Add (Taken from above deleted code chunk
		if(!SetPixelFormat(hdc, pf, &pfd))
		{
			return NULL;
		}
		
		DescribePixelFormat(hdc, pf, sizeof(PIXELFORMATDESCRIPTOR), &pfd);

		//$BLG - v5.24: Add
		// Driver type
		if(0 != (pfd.dwFlags & PFD_GENERIC_FORMAT))
		{
			MMechostr(0,"> --> Generic Software\n" );
			return NULL;
		}
		else
		{
			if(0 != (pfd.dwFlags & PFD_GENERIC_ACCELERATED))
				MMechostr(0,"> --> MCD Accelerated\n" );
			else
				MMechostr(0,"> --> ICD Accelerated\n" );
		}
		MMechostr(0,"> --> Accum  : %d\n", pfd.cAccumBits);
		MMechostr(0,"> --> Color  : %d\n", pfd.cColorBits);
		MMechostr(0,"> --> Depth  : %d\n", pfd.cDepthBits);
		if (pfd.dwFlags&WGL_DOUBLE_BUFFER_ARB)	MMechostr(0, "> --> Buffer : double\n");
		else																		MMechostr(0, "> --> Buffer : simple\n");

		mainglrc = wglCreateContext(hdc);
		wglMakeCurrent(hdc, mainglrc);

		// Attribution des résultats globaux
		//$BLG - v5.24: Modif
		/*
		mainBPP		= bpp;
		mainDEPTH	= depth;
		mainDBLBUF	= dbl;
		*/
		mainBPP		 = pfd.cColorBits;
		
		//$BLG - v5.24: Del
		//mainDEPTH	 = pfd.cDepthBits;
		//mainDBLBUF = pfd.dwFlags&WGL_DOUBLE_BUFFER_ARB;
		
		//$BLG Modif
		/*
		if (VENDOR_ATI == 0 ) {MMechostr(0,"> nVidia\n"); mainPIXELFORMAT = pf;}
		if (VENDOR_ATI == 1 ) 
		{
			if(Multi_Pass == 0) {MMechostr(0,"> ATI %d\n", Multi_Pass); mainPIXELFORMAT = pf;}
			//$BLG - v5.24: Modif
			else {MMechostr(0,"> ATI %d %d\n", Multi_Pass, pf); mainPIXELFORMAT = 7 ;}
		}
		*/
		/* $MS : Validation's Debug for choose of Pixel Format */
		MMechostr(1,"> Multisampling %d %d\n", Multi_Pass+1, pf);
		mainPIXELFORMAT = pf;
		
		mainhwnd = hwnd ;
		mainhdc	 = hdc ;
		return mainglrc ;
	}
	
	//$BLG - v5.22: Add
	return NULL;
}


//////////////////////////////////////////////////////////////////////////////////////////////
///		InitOpenGL														
//////////////////////////////////////////////////////////////////////////////////////////////
int InitOpenGL(mmachine m,int w,int h, HWND *resWnd)
{
	int		objSurf;
	PIXELFORMATDESCRIPTOR pfd;
	
	//$BLG - v5.24: Modif
	//HDC		hdc, mdc;
	HDC		hdc;
	
	HGLRC	hglrc;
	int 	pf = 0;

	HWND	hwnd;

	*resWnd = hwnd = CreateWindow("scolGL", "scolGL", WS_CHILD, 0, 0, w, h, HScol, NULL, NULL, 0);
	ShowWindow(hwnd, SW_SHOWNORMAL);


	UpdateWindow(hwnd);
	
	//$BLG - v5.24: Modif
	/*
	mdc = GetDC(hwnd);
	hdc = mdc;
	*/
	hdc = GetDC(hwnd);

	ZeroMemory(&pfd, sizeof(pfd)); 
	pfd.nSize	 = sizeof(pfd); 
	pfd.nVersion = 1;

	SetPixelFormat(hdc, mainPIXELFORMAT, &pfd);

	hglrc	= wglCreateContext(hdc);
	
	if (wglGetCurrentContext() != hglrc)
	{
		wglMakeCurrent(hdc, hglrc);
	}

	wglShareLists(mainglrc, hglrc);

	glViewport(0, 0, w, h);												// Reset The Current Viewport

	objSurf = MMmalloc(m, 4, TYPEBUF);
	if (!objSurf)		return MERRMEM;
	
	MMstore(m, objSurf, 0, MYWND_WINDOWED);
	MMstore(m, objSurf, 1, (int)hdc);
	MMstore(m, objSurf, 2, (int)hglrc);
	MMstore(m, objSurf, 3, (int)hwnd);

	return objSurf;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		InitOpenGLfullScreen														
//////////////////////////////////////////////////////////////////////////////////////////////
int InitOpenGLfullScreen (mmachine m,int w,int h)
{
	DWORD		dwExStyle;				// Window Extended Style
	DWORD		dwStyle;				// Window Style
	RECT		WindowRect;				// Grabs Rectangle Upper Left / Lower Right Values
	WindowRect.left=(long)0;			// Set Left Value To 0
	WindowRect.right=(long)w;			// Set Right Value To Requested Width
	WindowRect.top=(long)0;				// Set Top Value To 0
	WindowRect.bottom=(long)h;			// Set Bottom Value To Requested Height


	DEVMODE dmScreenSettings;									// Device Mode
	memset(&dmScreenSettings,0,sizeof(dmScreenSettings));		// Makes Sure Memory's Cleared
	dmScreenSettings.dmSize=sizeof(dmScreenSettings);			// Size Of The Devmode Structure
	dmScreenSettings.dmPelsWidth	= w;						// Selected Screen Width
	dmScreenSettings.dmPelsHeight	= h;						// Selected Screen Height
	dmScreenSettings.dmBitsPerPel	= mainBPP;			//32;						// Selected Bits Per Pixel		<--------------------- modifier le BPP par passage de paramètre !!
	dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;

	// Try To Set Selected Mode And Get Results.  NOTE: CDS_FULLSCREEN Gets Rid Of Start Bar.
	if (ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL)
	{
		// If The Mode Fails, Offer Two Options.  Quit Or Use Windowed Mode.
		if(MessageBox(NULL,"The Requested Fullscreen Mode Is Not Supported By\nYour Video Card.","SCOL Engine",MB_YESNO|MB_ICONEXCLAMATION)==IDYES)
		{
			fullscreenMode--;
			return NIL;											// Return FALSE
		}
		else
		{
			// Pop Up A Message Box Letting User Know The Program Is Closing.
			MessageBox(NULL,"Program Will Now Close.","ERROR",MB_OK|MB_ICONSTOP);
			return NIL;											// Return FALSE
		}
	}

	dwExStyle	= WS_EX_APPWINDOW | WS_EX_TOPMOST;										// Window Extended Style
	dwStyle		= WS_POPUP;												// Windows Style

	AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);			// Adjust Window To True Requested Size

	// Create The Window
	HWND	hwnd = CreateWindowEx(	dwExStyle,							// Extended Style For The Window
									"GenericClass",						// Class Name
									"GenericClass",						// Window Title
									dwStyle |							// Defined Window Style
									WS_CLIPSIBLINGS |					// Required Window Style
									WS_CLIPCHILDREN,					// Required Window Style
									0, 0,								// Window Position
									WindowRect.right-WindowRect.left,	// Calculate Window Width
									WindowRect.bottom-WindowRect.top,	// Calculate Window Height
									HScol,								// No Parent Window
									NULL,								// No Menu
									NULL,								// Instance
									NULL );								// Dont Pass Anything To WM_CREATE

	HDC		hdc = GetDC(hwnd);											// Did We Get A Device Context?

	PIXELFORMATDESCRIPTOR pfd;
	ZeroMemory(&pfd, sizeof(pfd)); 
	pfd.nSize	 = sizeof(pfd); 
	pfd.nVersion = 1;

	SetPixelFormat(hdc, mainPIXELFORMAT, &pfd);

	HGLRC	hglrc = wglCreateContext(hdc);								// Are We Able To Get A Rendering Context?

	if(wglGetCurrentContext()!=hglrc)
	{
		wglMakeCurrent(hdc,hglrc);
	}

	wglShareLists(mainglrc, hglrc);

	ShowWindow(hwnd,SW_SHOW);											// Show The Window

	SetForegroundWindow(hwnd);											// Slightly Higher Priority

	SetFocus(hwnd);														// Sets Keyboard Focus To The Window

	glViewport(0,0,w,h);												// Reset The Current Viewport
/*	glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
	glClearDepth( 0.5 );
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	SwapBuffers(hdc);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	SwapBuffers(hdc);
*/


	int objSurf = MMmalloc(m,4,TYPEBUF);
	if(!objSurf)		return MERRMEM;
	MMstore(m,objSurf,0,MYWND_FULLSCREEN);
	MMstore(m,objSurf,1,(int)hdc);
	MMstore(m,objSurf,2,(int)hglrc);
	MMstore(m,objSurf,3,(int)hwnd);

	return objSurf;
}


#define		TYP_ENGINE_HARDWARE		0
#define		TYP_ENGINE_SOFTWARE		1


//////////////////////////////////////////////////////////////////////////////////////////////
///		_ZGETengineState
//////////////////////////////////////////////////////////////////////////////////////////////
// fun[] I
int _ZGETengineState(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"GETengineState ");
#endif

	if(userACCEL)		MMpush(m, ITOM(TYP_ENGINE_HARDWARE));
	else				MMpush(m, ITOM(TYP_ENGINE_SOFTWARE));

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;
}





//////////////////////////////////////////////////////////////////////////////////////////////
///		RERPUL														
//////////////////////////////////////////////////////////////////////////////////////////////
#define RETPUL(x,y) {	for (int i=0;i<x-1;i++) MMpull(m);		MMset(m,0,y);	return 0;	}







typedef struct BitmapInfo2
{
	BITMAPINFO	Bit;
	RGBQUAD		Quad[256];
} BitmapInfo2;


typedef struct LPalette2
{
    WORD			Version ;
    WORD			ColorNum ;
    PALETTEENTRY	Colors[256];
} LPalette;

//$ 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 _SCOL_DEBUG_
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 _SCOL_DEBUG_
MMechostr (0, "\nObjBitmap_New end %d", newHandler);
#endif
//***********************************
      
     return newHandler; // return the new handler
}    



//$LB (21/01/2004)
//
// create an objbitmap with a dibsection
//
int ObjBitmap_NewDIBSection (PtrObjBitmap B,PtrPalette P)
{
     DIBSECTION Info;
     BITMAPINFO Bit;
     int tf,i ;
     HDC dc ;
     LPalette Pal ;
     HPALETTE HPal , HPOld ;

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nObjBitmap_NewDIBSection");
#endif 
//***********************************


     /**************** construction de la palette initiale  *****************************/
     if ( B->BPP == 8 )
     {
            Pal.Version = ( unsigned short ) GetVersion () ;
            Pal.ColorNum = 256 ;
            if ( P != NULL )
            for ( tf = 0 ; tf < 256 ; tf ++ )
            {
                Pal.Colors[tf].peRed = GET_RED(P,tf) ; 
                Pal.Colors[tf].peGreen = GET_GREEN(P,tf) ;
                Pal.Colors[tf].peBlue = GET_BLUE(P,tf) ;
                Pal.Colors[tf].peFlags = ( unsigned char ) NULL ;
            }
            HPal = CreatePalette ( (LOGPALETTE*) (&Pal) ) ;            
            dc = CreateCompatibleDC ( NULL ) ;
            HPOld = SelectPalette ( dc , HPal , FALSE ) ;
     } else dc = NULL ;

     Bit.bmiHeader.biSize = sizeof ( BITMAPINFOHEADER ) ;
     Bit.bmiHeader.biWidth = B->TailleW ;
	 Bit.bmiHeader.biHeight = - B->TailleH ;
    
     Bit.bmiHeader.biPlanes = 1 ;
     Bit.bmiHeader.biBitCount = B->BPP ;
     if ( B->BPP == 8 || B->BPP == 24 ) 
         Bit.bmiHeader.biCompression = BI_RGB ;
     else  return (-1);
     Bit.bmiHeader.biSizeImage = 0 ;
     Bit.bmiHeader.biXPelsPerMeter = 0 ;
     Bit.bmiHeader.biYPelsPerMeter = 0 ;
     if ( B->BPP == 8 )
     {
         Bit.bmiHeader.biClrUsed = 256 ;
         tf = DIB_PAL_COLORS ;
     }
     else 
     {
         Bit.bmiHeader.biClrUsed = 0 ;
         tf = DIB_RGB_COLORS ;
     }
     Bit.bmiHeader.biClrImportant = Bit.bmiHeader.biClrUsed ;

     B->DIBhandler = CreateDIBSection ( dc ,
        (BITMAPINFO * ) & Bit , tf , (void **) & B->bits ,
                NULL , 0 ) ;

    if (B->DIBhandler == NULL )
	{
		MMechostr ( 1 , "BITMAP ERROR WIN32 Num %d" , GetLastError ());
		return (-1);
	}

    i=GetObject ( B->DIBhandler, sizeof( DIBSECTION ) , &Info ) ;
	if (!i) MMechostr ( 1 , "GETOBJECT ERROR Num %d" , GetLastError ());
    B->bits = (OBJBITMAP_BUFFER)Info.dsBm.bmBits ;
	B->bits[0]=0;
    B->BPP = Info.dsBm.bmBitsPixel ;
	B->BytesPP = B->BPP >>3;

    B->BPL = Info.dsBm.bmWidthBytes ;
    if (B->BPL % 4 != 0 ) B->BPL += 4 - ( B->BPL % 4 ) ;
    
  
    if (Info.dsBmih.biHeight > 0 )
    B->Flags = 0 ;     

    if ( dc ) 
    {
        SelectPalette ( dc , HPOld , FALSE ) ;
        DeleteObject ( HPal ) ;
        DeleteDC ( dc ) ;
    }

	//$LB (13/06/2002) : we don't create a scol object for this, so we don't have to request a handler to the VM
    B->handler = (int)B->DIBhandler;

	return B->handler;


//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nObjBitmap_NewDIBSection end");
#endif
//***********************************

}





//////////////////////////////////////////////////////////////////////////////////////////////
///		_ZCRsurface														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun[Chn I I] ObjSurface
int _ZCRsurface(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"\nCRsurface ");
#endif

	if(userACCEL)
	{
		int		h = MTOI( MMpull(m) );
		int		w = MTOI( MMget(m,0) );

		// Si le mode fullscreen n'est pas activé, on crée la surface
		if(fullscreenMode == 0)
		{
			windowedMode++;
			
			HWND	hwnd;
			int		res = InitOpenGL(m, w, h, &hwnd);



			if(res<0)     RETPUL(2, NIL);

			MMset(m, 0, PTOM(res) );							// empile les données sur la surface, avant le ObjCreate


#ifdef	_SCOL_DEBUG_
			MMechostr(0,"\nCRsurface ok\n");
#endif
			// Creation de la surface
			return OBJcreate(m, typeSurface, (int)hwnd, -1, -1);				// !!! ObjCreate dépile les données jusqu'à l'obtention du channel !!!
		}
		// Si le mode fullscreen EST activé, on ne fait rien..
		else
		{
			MMpull(m);
			MMset(m,0,NIL);
#ifdef	_SCOL_DEBUG_
			MMechostr(0,"\nCRsurface ok\n");
#endif
			return 0;
		}
	}
	else
	{
		int		s, s2, l,res;
		PtrObjVoid		O;
		PtrObjBitmap	B;
		int			R;

		windowedMode++;

		if ((MMget(m,0)<=0)||(MMget(m,1)<=0))
		{
			// W or H negative value -> error
			MMpull(m);
			MMpull(m);
			MMpull(m);
			return MMpush(m,NIL);
		}

		l = (sizeof(struct ObjVoid)+3) >> 2 ;
		s = MMmalloc(m,l,TYPETAB);
		if(s==NIL)					return MERRMEM;
		for(int iii=0; iii<l; iii++)	MMstore(m, s, iii, NIL);


		if(MMpush(m,PTOM(s)))		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, MTOP(s));
		B = (PtrObjBitmap) MMstart(m, s2);
 
		O->Buffer	= PTOM(s2);
		O->Tab		= NIL;
		O->Father	= NIL;
		O->Type		= ITOM(OBJ_TYPE_BITMAP);

		B->TailleH	= MTOI(MMpull(m));
		B->TailleW	= MTOI(MMpull(m));
		B->BPP		= 24;
		B->BytesPP = B->BPP >>3;
		//B->handler	= ObjBitmap_New(B, NULL);
		B->handler = ObjBitmap_NewDIBSection (B, NULL);

		if(B->bits == NULL)
		{
			// No buffer created -> error
			MMpull(m);							// Dépile le channel
			return MMpush(m,NIL);
		}

		R = B->handler;
		MMpush(m,s);

		res = OBJcreate(m, OBJtypebyname("OBJTYPBITMAP"), (int)R, 0, (int)NULL);
#ifdef	_SCOL_DEBUG_
			MMechostr(0,"\nCRsurface %d ok\n", R);
#endif
		return res;
	}
}

//$BLG 
//Same as _ZCRsurface, but windowed/fullscreen surface control has been removed.
//Function is designed to be concurently used with _ZCRforcedFullscreenSurface.
//As such, it can only be used in hardware acceleration mode (so software mode
//code has been removed too).
//Note: _GETsurfaceState is not reliable if you use this function !!!
//////////////////////////////////////////////////////////////////////////////////////////////
///		_ZCRforcedSurface														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun[Chn I I] ObjSurface
int _ZCRforcedSurface(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"_ZCRforcedSurface\n");
#endif
	if(userACCEL)
	{
		int		h = MTOI( MMpull(m) );
		int		w = MTOI( MMget(m,0) );

		windowedMode++;
		
		HWND	hwnd;
		int		res = InitOpenGL(m, w, h, &hwnd);

		if(res<0)     RETPUL(2, NIL);

		MMset(m, 0, PTOM(res) );							// empile les données sur la surface, avant le ObjCreate





		// Creation de la surface
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
		return OBJcreate(m, typeSurface, (int)hwnd, -1, -1);				// !!! ObjCreate dépile les données jusqu'à l'obtention du channel !!!
	}
	else
	{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
    MMset(m,0,NIL);
		return 0;
	}
}




//////////////////////////////////////////////////////////////////////////////////////////////
///		_ZCRfullscreenSurface
//////////////////////////////////////////////////////////////////////////////////////////////
// fun[Chn I I] ObjSurface
int _ZCRfullscreenSurface(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"CRfullscreenSurface ");
#endif

	int		h = MTOI( MMpull(m) );
	int		w = MTOI( MMget(m,0) );


	// Si aucune fenêtre d'aucune sorte n'a encore été crée, on crée le FullScreen
	if( (windowedMode == 0) && (fullscreenMode==0) && userACCEL)
	{
		fullscreenMode++;

		///////////////////////////////////
		/// CREATION de l'ObjSurface	///
		///////////////////////////////////

		int		res = InitOpenGLfullScreen(m, w, h);

		if(res<0)     RETPUL(2, NIL);

		MMset(m, 0, PTOM(res) );							// empile les données sur la surface, avant le ObjCreate




		// on insere un second canal afin de ne pas perdre cette donnée après l'OBJcreate
		// --> ETAT DE LA PILE : Chn ObjSurfPtrData
		int		tmp_res, i;
		if((tmp_res=MMpush(m,NIL))<0)		return MERRMEM;
		for(i=0;i<2;i++)		MMset(m,i,MMget(m,i+1));

		// --> ETAT DE LA PILE : Chn Chn ObjSurfPtrData
		OBJcreate(m, typeSurface, 0, -1, -1);		// !!! ObjCreate dépile les données jusqu'à l'obtention du channel !!!

		// --> ETAT DE LA PILE : Chn ObjSurface
		INVERT(m,0,1);

		// --> ETAT DE LA PILE : ObjSurface Chn


		///////////////////////////////////
		/// CREATION de l'ObjWin		///
		///////////////////////////////////

        // Creation de la zone memoire pour l'objet de base
        int	l = ( sizeof ( struct ObjVoid ) + 3 ) >> 2;
        int	s = MMmallocCLR(m,l,TYPETAB);
        if(s==NIL)				{	MMechostr(MSKDEBUG,"_create_window : Error in Alloc OpenGL memory\n" );		return MERRMEM;   }               

        if(MMpush(m,PTOM(s)))		return MERRMEM ;

        // Creation de la zone memoire pour les donnees propres aux fenetres
        l = ( sizeof ( struct ObjWindow ) + 3 ) >> 2 ;
        int	s2 = MMmalloc(m,l,TYPEBUF);
        if(s2==NIL )			{			return MERRMEM;   }

        PtrObjWindow	Wnd = ( PtrObjWindow ) MMstart(m, s2);
        s = MMpull(m) ;
        PtrObjVoid		O = ( PtrObjVoid ) MMstart(m, MTOP(s));

		// Initialisation de la structure fenetre
        O -> Type           = ITOM(OBJ_TYPE_WINDOW);
        Wnd -> Flags        = WN_MENU|WN_MINBOX;
        Wnd -> TailleH      = h;
        Wnd -> TailleW      = w;
        Wnd -> PosY         = 0;
        Wnd -> PosX         = 0;
        Wnd -> MinW         = w;
        Wnd -> MinH         = h;
        Wnd -> MaxW         = w;
        Wnd -> MaxH         = h;
        Wnd -> Child        = NULL;
        Wnd -> Cursor       = NULL;
        O -> Father         = NIL;
        O -> Tab            = NIL;
        O -> Buffer			= PTOM(s2);

        HWND	hwnd = (HWND) MMfetch(m, MTOP(MMget(m,1)), 3);
		Wnd->WHandler		= hwnd;

        MMpush(m,s);
        OBJcreate(m,OBJtypebyname("OBJTYPWINDOW"),(int)hwnd,OBJtypebyname("OBJTYPWINDOW"),(int)NULL);		// le NULL correspond au parent-wnd : aucun

		// --> ETAT DE LA PILE : ObjSurface ObjWin
	    MMpull(m);
		// --> ETAT DE LA PILE : ObjSurface
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
		return 0;
	}
	// sinon, on ne fait rien..
	else
	{
		MMpull(m);
		MMset(m,0,NIL);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
		return 0;
	}
}

//$BLG 
//Same as _ZCRfullscreenSurface, but windowed/fullscreen surface control has been removed.
//Function is designed to be concurently used with _ZCRforcedSurface.
//As its model, it can only be used in hardware acceleration mode.
//Note: _GETsurfaceState is not reliable if you use this function !!!
//////////////////////////////////////////////////////////////////////////////////////////////
///		_ZCRforcedFullscreenSurface
//////////////////////////////////////////////////////////////////////////////////////////////
// fun[Chn I I] ObjSurface
int _ZCRforcedFullscreenSurface(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"_ZCRforcedFullscreenSurface\n");
#endif
	int		h = MTOI( MMpull(m) );
	int		w = MTOI( MMget(m,0) );

  if(userACCEL)
	{
		fullscreenMode++;

		///////////////////////////////////
		/// CREATION de l'ObjSurface	///
		///////////////////////////////////

		int		res = InitOpenGLfullScreen(m, w, h);

		if(res<0)     RETPUL(2, NIL);

		MMset(m, 0, PTOM(res) );							// empile les données sur la surface, avant le ObjCreate



		// on insere un second canal afin de ne pas perdre cette donnée après l'OBJcreate
		// --> ETAT DE LA PILE : Chn ObjSurfPtrData
		int		tmp_res, i;
		if((tmp_res=MMpush(m,NIL))<0)		return MERRMEM;
		for(i=0;i<2;i++)		MMset(m,i,MMget(m,i+1));

		// --> ETAT DE LA PILE : Chn Chn ObjSurfPtrData
		OBJcreate(m, typeSurface, 0, -1, -1);		// !!! ObjCreate dépile les données jusqu'à l'obtention du channel !!!

		// --> ETAT DE LA PILE : Chn ObjSurface
		INVERT(m,0,1);

		// --> ETAT DE LA PILE : ObjSurface Chn


		///////////////////////////////////
		/// CREATION de l'ObjWin		///
		///////////////////////////////////

        // Creation de la zone memoire pour l'objet de base
        int	l = ( sizeof ( struct ObjVoid ) + 3 ) >> 2;
        int	s = MMmallocCLR(m,l,TYPETAB);
        if(s==NIL)				{	MMechostr(MSKDEBUG,"_create_window : Error in Alloc OpenGL memory\n" );		return MERRMEM;   }               

        if(MMpush(m,PTOM(s)))		return MERRMEM ;

        // Creation de la zone memoire pour les donnees propres aux fenetres
        l = ( sizeof ( struct ObjWindow ) + 3 ) >> 2 ;
        int	s2 = MMmalloc(m,l,TYPEBUF);
        if(s2==NIL )			{	return MERRMEM;   }

        PtrObjWindow	Wnd = ( PtrObjWindow ) MMstart(m, s2);
        s = MMpull(m) ;
        PtrObjVoid		O = ( PtrObjVoid ) MMstart(m, MTOP(s));

		// Initialisation de la structure fenetre
        O -> Type           = ITOM(OBJ_TYPE_WINDOW);
        Wnd -> Flags        = WN_MENU|WN_MINBOX;
        Wnd -> TailleH      = h;
        Wnd -> TailleW      = w;
        Wnd -> PosY         = 0;
        Wnd -> PosX         = 0;
        Wnd -> MinW         = w;
        Wnd -> MinH         = h;
        Wnd -> MaxW         = w;
        Wnd -> MaxH         = h;
        Wnd -> Child        = NULL;
        Wnd -> Cursor       = NULL;
        O -> Father         = NIL;
        O -> Tab            = NIL;
        O -> Buffer			= PTOM(s2);

        HWND	hwnd = (HWND) MMfetch(m, MTOP(MMget(m,1)), 3);
		    Wnd->WHandler		= hwnd;

        MMpush(m,s);
        OBJcreate(m,OBJtypebyname("OBJTYPWINDOW"),(int)hwnd,OBJtypebyname("OBJTYPWINDOW"),(int)NULL);		// le NULL correspond au parent-wnd : aucun

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
		// --> ETAT DE LA PILE : ObjSurface ObjWin
	    MMpull(m);
		// --> ETAT DE LA PILE : ObjSurface
		return 0;
	}
	// sinon, on ne fait rien..
	else
	{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
		MMpull(m);
		MMset(m,0,NIL);
		return 0;
	}
}




//////////////////////////////////////////////////////////////////////////////////////////////
///		_GETwindowFromFullscreenSurface
//////////////////////////////////////////////////////////////////////////////////////////////
// fun[ObjSurface] ObjWin
int _ZGETwindowFromFullscreenSurface (mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"GETwindowFromFullscreenSurface ");
#endif

	int surf = MMget(m,0);
	if(surf==NIL)		{	MMset(m,0,NIL);		return 0;	}

	int	 mode = MMfetch(m, MTOP(surf), 0);
	HWND hwnd = (HWND) MMfetch(m, MTOP(surf), 3);

	if(mode==MYWND_WINDOWED || userACCEL==false)
	{
		MMset(m,0,NIL);
	}
	else
	{
		int objwin = MMfetch(m, OBJfindTH(m, OBJtypebyname("OBJTYPWINDOW"), (int)hwnd), OFFOBJMAG);
		MMset(m,0,objwin);
	}

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		_GETsurfaceState
//////////////////////////////////////////////////////////////////////////////////////////////
// fun[] I
int _ZGETsurfaceState(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"GETsurfaceState ");
#endif

	if(fullscreenMode)			MMpush(m, 0);
	else if(windowedMode)		MMpush(m, 2);
	else						MMpush(m, 4);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		_ZDSsurface														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun[ObjSurface] I
int _ZDSsurface (mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"DSsurface ");
#endif

	if(userACCEL)
	{
		int surf = MMget(m,0);
		if(surf==NIL)		{	MMset(m,0,NIL);		return 0;	}

		OBJdelTM(m,typeSurface,surf);
			
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
		MMset(m,0,0);
		return 0;
	}
	else
	{
		int				s;
		PtrObjVoid		O;
		PtrObjBitmap	M;

		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) ) ;  
		OBJdelTH(m, OBJtypebyname("OBJTYPBITMAP"), (int)M->handler);

		windowedMode--;
     
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
		MMset(m,0,0) ;
		return 0 ;
	}
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZooDestroySurface														
//////////////////////////////////////////////////////////////////////////////////////////////
// fonction d'appel lors de la destruction interne d'une surface (déclarée dans le ObjCreate)
int ZooDestroySurface(mmachine m, int q, int p)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ZooDestroySurface ");
#endif

	HDC		hdc;
	HGLRC	rc;
	HWND	hwnd;

	p >>= 1;

	int mode = MMfetch(m, p, 0);
	hdc		 = (HDC)	MMfetch(m, p, 1);
	rc		 = (HGLRC)	MMfetch(m, p, 2);
	hwnd	 = (HWND)	MMfetch(m, p, 3);

	if(!rc && !hdc && !hwnd)		return 0;

	

	if(mode == MYWND_WINDOWED)
	{
		windowedMode--;

		if(rc)
		{
			if(wglMakeCurrent(NULL,NULL)==FALSE)		MMechostr(1, "------ Can't set the current rendering context to NULL ! ------\n" );
			if(wglDeleteContext(rc)==FALSE)				MMechostr(1, "------ Can't delete rendering context ! ------\n" );
		}

		if(hdc)
		{
			if(ReleaseDC(hwnd, hdc)==0)					MMechostr(1, "------ Can't release device context ! ------\n" );
		}

		if(SetParent(hwnd, HScol)==NULL)				MMechostr(1, "------ Can't set the window parent ! ------\n" );

		if(DestroyWindow(hwnd)==0)						MMechostr(1, "------ Can't destroy the window ! ------\n" );
	}
	else
	{
		fullscreenMode = 0;
		ChangeDisplaySettings(NULL,0);					// If So Switch Back To The Desktop
		
		if(rc)
		{
			if(wglMakeCurrent(NULL,NULL)==FALSE)		MMechostr(1, "------ Can't set the current rendering context to NULL ! ------\n" );
			if(wglDeleteContext(rc)==FALSE)				MMechostr(1, "------ Can't delete rendering context ! ------\n" );
		}

		if(hdc)
		{
			if(ReleaseDC(hwnd, hdc)==0)					MMechostr(1, "------ Can't release device context ! ------\n" );
		}
		
		if(SetParent(hwnd, HScol)==NULL)				MMechostr(1, "------ Can't set the window parent ! ------\n" );
		
		// Destruction de l'ObjWin
		OBJdelTH(m, OBJtypebyname("OBJTYPWINDOW"), (int)hwnd);
	}


	if(wglMakeCurrent(mainhdc, mainglrc)==FALSE)		MMechostr(1, "------ Can't set the current rendering context to MAINcontext ! ------\n" );


	MMechostr(1, "------ .. surface destroyed\n\n" );

	MMstore(m, p, 1, NIL);
	MMstore(m, p, 2, NIL);
	MMstore(m, p, 3, NIL);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		_ZFILLsurface														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun[ObjSurface I] ObjSurface
int _ZFILLsurface (mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"\nFILLsurface\n ");
#endif

	if(userACCEL)
	{
		HDC		dc;
		HGLRC	rc;

		int color	= MTOI( MMpull(m) );
		int surf	= MTOP( MMget(m,0) );
		
		if(surf==NIL)		return 0;

		dc = (HDC)	 MMfetch(m,surf,1);
		rc = (HGLRC) MMfetch(m,surf,2);
		
		if(!rc || !dc)		return 0;

		if(wglGetCurrentContext()!=rc)
		{
			wglMakeCurrent(dc,rc);
		}

		glDrawBuffer(GL_BACK);

		float r= (float)((color)    &0xFF) / CONST_COLOR;
		float g= (float)((color>>8) &0xFF) / CONST_COLOR;
		float b= (float)((color>>16)&0xFF) / CONST_COLOR;

		glClearColor(r, g, b, 0);
		glClear(GL_COLOR_BUFFER_BIT);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"\nFILLsurface ok\n");
#endif
		return 0;
	}
	else
	{
        PtrObjVoid		O;
        PtrObjBitmap	B;

		int				i,j,dcx,dcy;
        OBJBITMAP_BUFFER Image;
		unsigned char bufr, bufg, bufb;

        int color = MTOI( MMpull(m) );
        int	surf  = MMpull(m);

		if(surf==NIL)				return MMpush(m,NIL);

        O = (PtrObjVoid)	MMstart(m, MTOP(surf) );
        B = (PtrObjBitmap)	MMstart(m, MTOP(O->Buffer) );
		
		if(B->bits==NULL)			return MMpush(m,NIL);

        Image = (OBJBITMAP_BUFFER) B->bits;

		//$LB
		_COLOR_I_TO_BGR (color, &bufb, &bufg, &bufr);

//$LB
#ifndef _SUPPORT_ASM_

            dcy = 0;

            for (j=0; j < B->TailleH; j++) 
			{
				for (i=0, dcx=dcy; i < B->TailleW; i++, dcx+=3)
				{
					Image [ dcx   ] = (unsigned char)bufr;
					Image [ dcx+1 ] = (unsigned char)bufg;
					Image [ dcx+2 ] = (unsigned char)bufb;
				}

				dcy += B->BPL;
			}



#else
		//$LB TO DO : update this old 16bits algo to 24bits algo
		_asm
		{															
				pushad
				xor		eax, eax
				xor		edi, edi
				mov		ax,	 fond16
				mov		edi, Image
				mov		ecx,i
				rep		stosw
				popad
		}
#endif

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"\nFILLsurface ok\n");
#endif
        return MMpush(m,surf);
	}
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		_ZGetsurfaceSize
//////////////////////////////////////////////////////////////////////////////////////////////
// fun[ObjSurface] [I I]
int _ZGETsurfaceSize (mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"GETsurfaceSize ");
#endif

	if(userACCEL)
	{
		HWND	hwnd;
		RECT	rect;

		int surf = MTOP(MMpull(m));
		if(surf==NIL)		return MMpush(m,NIL);

		SetGL2D(m, surf, NULL, &hwnd);
		GetClientRect(hwnd, &rect);

		if(MMpush(m, ITOM(rect.right)))			return MERRMEM;
		if(MMpush(m, ITOM(rect.bottom)))		return MERRMEM;
		if(MMpush(m, 2*2))					return MERRMEM;
  
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
		return MBdeftab(m);
	}
	else
	{
		PtrObjVoid O ;
		PtrObjBitmap B ;
		int s , h , w ; 

		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 ) ;

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
		return s ;
	}
}


















///////////////////////////////////////////////////////////////////////////////////:
///////////////////////////////////////////////////////////////////////////////////
//   $LBDEBUG
/////////////////////////////////////////////////////////////////////////////////





//#define FILE_TYPE_BMP 19778


//$LB
/////////////////////////////////////////////////////////

/*
int WriteInt1 ( FILE * F , unsigned char *I) 
{
    return fwrite ( (void*)I , 1 , 1 , F);
}

int WriteInt2 ( FILE * F , unsigned short int *I )
{
    unsigned char a , b ;

	a = (*I) &0xFF;
	b = ((*I)>>8) &0xFF;

    fwrite ((void*)&a , 1 , 1 , F );
    fwrite ((void*)&b , 1 , 1 , F );

    return 1;
}



int WriteInt4 ( FILE * F , unsigned long int* I ) 
{
    unsigned char a , b , c , d ;

    a  = (unsigned char)((*I) &0xFF); b = (unsigned char)(((*I)>>8) &0xFF); c = (unsigned char)(((*I)>>16) &0xFF); d = (unsigned char)(((*I)>>24) &0xFF);

    fwrite ( (void*)&a , 1 , 1 , F );
    fwrite ( (void*)&b , 1 , 1 , F );
    fwrite ( (void*)&c , 1 , 1 , F );
    fwrite ( (void*)&d , 1 , 1 , F );

    return 1 ;
}
*/

/***********************************************************************************************************/
/*                                                                                                         */
/*   Sauvegarde d'un fichier BMP  : fun [ObjBitmap W] I                                                    */
/*                                                                                                         */
/***********************************************************************************************************/
/*
int _SAVEbitmap (mmachine m, PtrObjBitmap B, char* filename)
{
	FILE* F; 
	OBJBITMAP_BUFFER buf;

    unsigned short int Is;
    unsigned long int Il;
	unsigned char rgb ;
	int i , j , offset, delta, BPLReste;
    

  if ((F = fopen(filename, "wb")) == NULL)
  {
	  MMechostr(MSKDEBUG,"_SAVEbitmap : unable to create file %s\n",filename);
	  MMpull(m);
      return MMpush(m,NIL);
  }

  buf = (OBJBITMAP_BUFFER)B->bits;


  // star wrting data
  Is = FILE_TYPE_BMP; WriteInt2 (F, &Is);
  Il = (B->BPL * B->TailleH) + sizeof ( BITMAPFILEHEADER ) + sizeof ( BITMAPINFOHEADER ); WriteInt4 ( F , &Il) ; 
  Is = 0; WriteInt2 ( F , &Is) ; 
  Is = 0; WriteInt2 ( F , &Is) ; 

  Il = sizeof ( BITMAPFILEHEADER ) + sizeof ( BITMAPINFOHEADER );   WriteInt4 ( F , &Il) ;


  Il = sizeof ( BITMAPINFOHEADER );   WriteInt4 ( F , &Il) ;
  Il = B->TailleW; WriteInt4 ( F , &Il) ;
  Il = B->TailleH; WriteInt4 ( F , &Il) ;
  Is = 1; WriteInt2 ( F , &Is) ;
  Is = 24; WriteInt2 ( F , &Is);
  Il = BI_RGB; WriteInt4 ( F , &Il) ;
  Il = 0; WriteInt4 ( F , &Il) ;

  Il = 0; WriteInt4 ( F , &Il) ;
  Il = 0; WriteInt4 ( F , &Il) ;

  Il = 0; WriteInt4 ( F , &Il) ;
  Il = 0; WriteInt4 ( F , &Il) ;

  
        if ( B->TailleH < 0 )
        {            
            offset = 0 ;
			//$LB
            delta =  B->BPL  - (B->TailleW*3) ;
        } else
        {            
			//$LB
            delta = - B->BPL - (B->TailleW*3) ;
            offset = ( B->BPL * B->TailleH - B->BPL ) ;
        }

            BPLReste = (B->BPL - ( B->TailleW * 3 )) ; 
			
            for ( j = 0 ; j < B->TailleH ; j ++ )
            {
      
                for ( i = 0 ; i < B->TailleW ; i ++ )
                {            
					rgb = B->bits[offset++]; WriteInt1 ( F , &rgb) ;
					rgb = B->bits[offset++]; WriteInt1 ( F , &rgb) ;
					rgb = B->bits[offset++]; WriteInt1 ( F , &rgb) ;
                }
                
				offset+=delta;
                for ( i = 0 ; i < BPLReste ; i ++ ){ WriteInt1 ( F , &rgb ) ;}
            }
       
   

    fclose ( F ) ;
	return 0;




} ;

//////////////////////////////////////////////////////////////





int mycount = 0;


*/
///////////////////////////////////////////////////////////////////////////////////:
///////////////////////////////////////////////////////////////////////////////////
//   $LBDEBUG
/////////////////////////////////////////////////////////////////////////////////















//////////////////////////////////////////////////////////////////////////////////////////////
///		_ZBLTsurface
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [ObjWin I I ObjSurface I I I I] ObjWin
int _ZBLTsurface (mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"BLTsurface ");
#endif

	if(userACCEL)
	{
		int		surf, ox, oy, x, y, w, h, win;
		HWND	hwnd, parent;
		HDC		hdc;
		HGLRC	hglrc;

		PtrObjVoid		OB;
		PtrObjWindow	W;

		h	 = MTOI( MMpull(m) );
		w	 = MTOI( MMpull(m) );
		oy	 = MTOI( MMpull(m) );
		ox	 = MTOI( MMpull(m) );
		surf = MTOP( MMpull(m) );
		y	 = MTOI( MMpull(m) );
		x	 = MTOI( MMpull(m) );
		win	 = MTOP( MMget(m,0) );

		if(win==NIL || surf==NIL)		{	MMset(m,0,NIL);		return 0;	}

		int	 mode = MMfetch(m, surf, 0);
		if(mode == MYWND_FULLSCREEN)	{	MMset(m,0,NIL);		return 0;	}

		// Récupération de la wnd OpenGL
		hdc		= (HDC)		MMfetch(m, surf, 1);
		hglrc	= (HGLRC)	MMfetch(m, surf, 2);
		hwnd	= (HWND)	MMfetch(m, surf, 3);

		// Récupération de la wnd SCOL
		OB		= (PtrObjVoid)		MMstart(m, win);
		W		= (PtrObjWindow)	MMstart(m, OB->Buffer>>1);
		parent	= (HWND)			W->WHandler;

		// Modifications des paramètres
		if(GetParent(hwnd)!=parent)
		{
			SetParent(hwnd, parent);
			ShowWindow(hwnd, SW_SHOWNORMAL);
		}
		MoveWindow(hwnd, x, y, w, h, true);

		if(wglGetCurrentContext()!=hglrc)
		{
			wglMakeCurrent(hdc,hglrc);
		}

		SwapBuffers(hdc);


		/////////////////////////
		//$LBDEBUG
		/////////////////////////////
		/*
		{
			HDC myDcw, myDcb;
			HBITMAP myOldBitmap;
			PtrObjBitmap my = (PtrObjBitmap) malloc (sizeof (ObjBitmap)); 
			char filename[128];

			my->TailleH	= h;
			my->TailleW	= w;
			my->BPP		= 24;
			my->BytesPP = my->BPP >>3;
			my->handler = ObjBitmap_NewDIBSection (my, NULL);

		myDcw = GetDC( (HWND)hwnd );
		myDcb = CreateCompatibleDC (myDcw);


		myOldBitmap = (HBITMAP) SelectObject( myDcb, my->DIBhandler);
		BitBlt(myDcb, 0, 0, w, h, myDcw, 0, 0, SRCCOPY);

		SelectObject( myDcb, myOldBitmap );
		DeleteDC( myDcb );
		ReleaseDC (hwnd, myDcw);

			sprintf (&filename[0], "C:/Program Files/devel/EasyPHP/www/tmp2/render/renderscol/%d.bmp", mycount);
			mycount++;


			_SAVEbitmap (m, my, filename);


			DeleteObject (my->DIBhandler);
			free (my);
		}
		*/
		////////////////////////////
		//$LBDEBUG
			///////////////////////











		POINT	curseurPos;
		GetCursorPos(&curseurPos);
		
		if( hwnd == WindowFromPoint(curseurPos) )
		{
			if(W->Cursor != (HCURSOR)GetClassLong(hwnd, GCL_HCURSOR) )
			{
				if(W->Cursor==0)		SetClassLong(hwnd, GCL_HCURSOR, (long)LoadCursor(NULL,IDC_ARROW) ) ;
				else					SetClassLong(hwnd, GCL_HCURSOR, (long)W->Cursor ) ;
			}
		}
		

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
		return 0;
	}
	else
	{
		int				surf, ox, oy, x, y, w, h, win;
		PtrObjVoid		OS, OD;
		PtrObjBitmap	B;
		PtrObjWindow	W;
		HDC				Dcb, Dcw;
		HBITMAP			OldBitmap;





		h	 = MTOI( MMpull(m) );
		w	 = MTOI( MMpull(m) );
		oy	 = MTOI( MMpull(m) );
		ox	 = MTOI( MMpull(m) );
		surf = MMpull(m);
		y	 = MTOI( MMpull(m) );
		x	 = MTOI( MMpull(m) );
		win	 = MMpull(m);
 

		if( surf==NIL || win==NIL )		return MMpush(m,win);


		OS = (PtrObjVoid)	MMstart(m, MTOP(surf));
		OD = (PtrObjVoid)	MMstart(m, MTOP(win));
		B  = (PtrObjBitmap) MMstart(m, MTOP(OS->Buffer));
		W  = (PtrObjWindow) MMstart(m, MTOP(OD->Buffer));

		Dcw = GetDC( W->WHandler );
		Dcb = CreateCompatibleDC( Dcw );

		OldBitmap = (HBITMAP) SelectObject( Dcb, B->DIBhandler );
		BitBlt(Dcw, x, y, w, h, Dcb, ox, oy, SRCCOPY);

		SelectObject( Dcb, OldBitmap );
		DeleteDC( Dcb );

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
		return MMpush(m,win);
	}
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		_ZBLTsurfaceFullScreen														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [ObjSurface] ObjWin
int _ZBLTsurfaceFullScreen (mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"BLTsurfaceFullscreen ");
#endif
	int		surf;
	HWND	hwnd;
	HDC		hdc;
	HGLRC	hglrc;

	surf = MTOP( MMget(m,0) );

	if(surf==NIL)			{	MMset(m,0,NIL);		return 0;	}


	int	 mode = MMfetch(m, surf, 0);
	if(mode == MYWND_WINDOWED)
	{
		MMset(m,0,NIL);
		return 0;
	}

	// Récupération de la wnd OpenGL
	hdc		= (HDC)		MMfetch(m, surf, 1);
	hglrc	= (HGLRC)	MMfetch(m, surf, 2);
	hwnd	= (HWND)	MMfetch(m, surf, 3);

	if(hdc!=NULL)		SwapBuffers(hdc);

	int objwin = MMfetch(m, OBJfindTH(m, OBJtypebyname("OBJTYPWINDOW"), (int)hwnd), OFFOBJMAG);
	MMset(m,0,objwin);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}





//////////////////////////////////////
//////////////////////////////////////
////
////		MANISSE World....
////
//////////////////////////////////////
//////////////////////////////////////
void GetBitmapPalette ( PtrObjBitmap B , PtrPalette P )
{
    RGBQUAD Pal [ 256 ] ;
    HDC dc ;
    int i ;
    HBITMAP OldBitmap ;

    dc = CreateCompatibleDC ( NULL ) ;
    OldBitmap = (HBITMAP) 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 ;
    
    }
}




int ClipBlit ( int dtaillew , int dtailleh , int staillew , int stailleh ,
                int *dposx , int *dposy , int *sposx , int *sposy , int *taillew , int *tailleh ) 
{       

    /* step 1 verification de dposx */
    if ( *dposx < 0 )
    {
        *sposx -= *dposx ;
        *taillew += *dposx ;
        *dposx = 0 ;
    } else if ( *dposx >= dtaillew ) return 0 ;
   

    /* step 2 verification de dposy */
    if ( *dposy < 0 )
    {
        *sposy -= *dposy ;
        *tailleh += *dposy ;
        *dposy = 0 ;
    } else if ( *dposy >= dtailleh ) return 0 ;

    /* step 3 verification de sposx */
    if ( *sposx < 0 )
    {
        *taillew += *sposx ;
        *dposx -= *sposx;
        *sposx = 0 ;
       
    } else if ( *sposx >= staillew ) return 0 ;

    /* step 4 verification de sposy */
    if ( *sposy < 0 )
    {
        *tailleh  += *sposy ;
        *dposy -= *sposy;
        *sposy = 0 ;
    } else if ( *sposy >= stailleh ) return 0 ;

    /* step 4 verification de taillew */
    if ( *taillew < 0 ) return 0 ;
    if ( *taillew + *sposx >= staillew )
    {   
         *taillew -=  ( *taillew + *sposx ) - staillew ;     
         if ( * taillew < 0 ) return 0 ;
    }
    if ( *taillew + *dposx >= dtaillew )
    {
        *taillew -= ( *taillew + *dposx ) - dtaillew ;
        if ( * taillew  < 0 ) return 0 ;
    }

    /* step 5 verification de tailleh */
    if ( *tailleh < 0 ) return 0 ;
    if ( *tailleh + *sposy >= stailleh )
    {
        *tailleh -= ( *tailleh + *sposy ) - stailleh ;
        if ( *tailleh < 0 ) return 0 ;
    }
    if ( *tailleh + *dposy >= dtailleh ) 
    {
        *tailleh -= ( *tailleh + *dposy ) -dtailleh ;
        if ( *tailleh < 0 ) return 0 ;
    }

    return 1 ;    
}



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 ;       



        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 ))
            {

                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 ++ )
                {                     
                   //$BLG - v5.3.01: Modif
                   //CopyMemory(BufD + dcy , BufS + scy , taillew ) ;
                   BLG_memcpy8(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 ))
            {

				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 ))
            {
                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 ++ )
                    {                 
                       //$BLG - v5.3.01: Modif
                       //memcpy( BufD, BufS, taillew * BS->BytesPP) ;                   
                       BLG_memcpy8(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) ;


        return res ;
}





//////////////////////////////////////////////////////////////////////////////////////////////
///		_ZBitmap2Surface														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun[ObjSurface I I ObjBitmap I I I I I] ObjSurface
int _ZBitmap2Surface (mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"Bitmap2Surface ");
#endif

	if(userACCEL)
	{
		unsigned char	*buffer;
		unsigned char	r,g,b;

		int		c, idx, couleur, coulBase;
		RECT	rect;
		HWND	hwnd;
		int		x, y, yoffset, Y;
		int		sh, sw, sy, sx, bitmap, dy, dx, surf;
		OBJBITMAP_BUFFER bitmapBuf;

		coulBase = couleur = MMpull(m)>>1;
		sh = MMpull(m)>>1;
		sw = MMpull(m)>>1;
		sy = MMpull(m)>>1;
		sx = MMpull(m)>>1;
		bitmap = MMpull(m)>>1;
		dy = MMpull(m)>>1;
		dx = MMpull(m)>>1;
		surf = MMget(m,0)>>1;

		if(surf==NIL || bitmap==NIL || sx==NIL || sy==NIL || dx==NIL || dy==NIL || sh==NIL || sw==NIL)	return 0;

		PtrObjVoid		OB = (PtrObjVoid)	MMstart(m, bitmap);
		PtrObjBitmap	B  = (PtrObjBitmap)	MMstart(m, OB->Buffer>>1);


		SetGL2D(m, surf, NULL, &hwnd);
		GetClientRect(hwnd, &rect);

		if(dx>rect.right)		return 0;
		if(dy>rect.bottom-1)	return 0;

		//$BLG - v5.3.01: Modif
		//if(dx<0)				{	sx+=dx; dx=0; }
		//if(dy<0)				{	sy+=dy; dy=0; }
		if(dx < 0)				{sx -= dx; dx = 0;}
		if(dy < 0)				{sy -= dy; dy = 0;}
		//$BLG - End
		if(dx+sw>rect.right)		sw = rect.right-dx;
		if(dy+sh>rect.bottom-1)		sh = rect.bottom-1-dy;

		if(B->BPP!=24)		return 0;
		if(sx<0)				{	sw+=sx; sx=0; }
		if(sy<0)				{	sh+=sy; sy=0; }
		if(sx+sw>B->TailleW)		sw = B->TailleW-sx;
		if(sy+sh>B->TailleH)		sh = B->TailleH-sy;

		if(sw<=0)				return 0;
		if(sh<=0)				return 0;

		buffer = (unsigned char*) malloc(sizeof(char)*sw*sh*4);
		if(!buffer)				return 0;

		//$LB
		bitmapBuf = (OBJBITMAP_BUFFER) B->bits;
		bitmapBuf += sx*B->BytesPP + sy*B->BPL;

		yoffset=0;
		for(y=0; y<sh; y++)
		{
			Y = (sh-y-1)*sw*4;
			//$LB
			for(x=0; x<sw; x++)
			{
				idx = x*3 + yoffset;
				
				b = bitmapBuf[idx+0];
				g = bitmapBuf[idx+1];
				r = bitmapBuf[idx+2];

				c = ((b<<16) &0xFF0000) | ((g<<8) &0xFF00) | (r &0xFF);

				buffer[Y+0] = r;
				buffer[Y+1] = g;
				buffer[Y+2] = b;

				if(couleur==c)		buffer[Y+3] = 0;
				else				buffer[Y+3] = 255;
				Y+=4;
			}
			yoffset+=B->BPL;
		}

		glPixelStorei(GL_PACK_LSB_FIRST,	GL_FALSE);
		glPixelStorei(GL_UNPACK_LSB_FIRST,	GL_FALSE);
		glRasterPos2i(dx, dy+sh);

		if(coulBase!=NIL)
		{
			glEnable(GL_ALPHA_TEST);
			glDisable(GL_BLEND);
			glAlphaFunc(GL_EQUAL,1);
		}
		glDrawPixels(sw, sh, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
		if(coulBase!=NIL)		glDisable(GL_ALPHA_TEST);

		free(buffer);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
		return 0;
	}
	else
	{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
		return GRCopyBitmap(m);
	}
}

//$BLG
//This function allows to blend a bitmap on a surface. It accepts a (0-255) transparency color
//as well as a transparency factor (0->255) for the rest of the bitmap.
//Base code from Bitmap2Surface.
//////////////////////////////////////////////////////////////////////////////////////////////
///		_ZBlendBitmap2Surface														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun[ObjSurface I I ObjBitmap I I I I I I I] ObjSurface
int _ZBlendBitmap2Surface (mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"BlendBitmap2Surface ");
#endif

	if(userACCEL)
	{
		unsigned char	*buffer;
		unsigned char	r,g,b;

		int		c, idx, couleur, coulBase, c_transp, transparency;
		RECT	rect;
		HWND	hwnd;
		int		x, y, yoffset, Y;
		int		sh, sw, sy, sx, bitmap, dy, dx, surf;
		OBJBITMAP_BUFFER bitmapBuf;

		transparency = MMpull(m)>>1;
		c_transp = MMpull(m)>>1;
		coulBase = couleur = MMpull(m)>>1;
		sh = MMpull(m)>>1;
		sw = MMpull(m)>>1;
		sy = MMpull(m)>>1;
		sx = MMpull(m)>>1;
		bitmap = MMpull(m)>>1;
		dy = MMpull(m)>>1;
		dx = MMpull(m)>>1;
		surf = MMget(m,0)>>1;

		if(surf==NIL || bitmap==NIL || sx==NIL || sy==NIL || dx==NIL || dy==NIL || sh==NIL || sw==NIL)	return 0;
    if (transparency == NIL) transparency = 255;
    if ((couleur != NIL) && (c_transp == NIL)) c_transp = 0;

		PtrObjVoid		OB = (PtrObjVoid)	MMstart(m, bitmap);
		PtrObjBitmap	B  = (PtrObjBitmap)	MMstart(m, OB->Buffer>>1);


		SetGL2D(m, surf, NULL, &hwnd);
		GetClientRect(hwnd, &rect);

		if(dx>rect.right)		return 0;
		if(dy>rect.bottom-1)	return 0;

		//$BLG - v5.3.01: Modif
		//if(dx<0)				{	sx+=dx; dx=0; }
		//if(dy<0)				{	sy+=dy; dy=0; }
		if(dx < 0)				{sx -= dx; dx = 0;}
		if(dy < 0)				{sy -= dy; dy = 0;}
		//$BLG - End
		if(dx+sw>rect.right)		sw = rect.right-dx;
		if(dy+sh>rect.bottom-1)		sh = rect.bottom-1-dy;

		if(B->BPP!=24)		return 0;
		if(sx<0)				{	sw+=sx; sx=0; }
		if(sy<0)				{	sh+=sy; sy=0; }
		if(sx+sw>B->TailleW)		sw = B->TailleW-sx;
		if(sy+sh>B->TailleH)		sh = B->TailleH-sy;

		if(sw<=0)				return 0;
		if(sh<=0)				return 0;

		buffer = (unsigned char*) malloc(sizeof(char)*sw*sh*4);
		if(!buffer)				return 0;

		//$LB
		bitmapBuf = (OBJBITMAP_BUFFER) B->bits;
		bitmapBuf += sx*B->BytesPP + sy*B->BPL;

		yoffset=0;
		for(y=0; y<sh; y++)
		{
			Y = (sh-y-1)*sw*4;
			//$LB
			for(x=0; x<sw; x++)
			{
				idx = x*3 + yoffset;
				
				b = bitmapBuf[idx+0];
				g = bitmapBuf[idx+1];
				r = bitmapBuf[idx+2];

				c = ((b<<16) &0xFF0000) | ((g<<8) &0xFF00) | (r &0xFF);

				buffer[Y+0] = r;
				buffer[Y+1] = g;
				buffer[Y+2] = b;

				//$BLG Modif
				/*
				if(couleur==c)		buffer[Y+3] = 0;
				else if(transparency==NIL)				buffer[Y+3] = 255;
				else buffer[Y+3] = transparency;
				*/
				if (couleur == c) buffer[Y+3] = c_transp;
				else buffer[Y+3] = transparency;
				Y+=4;
			}
			yoffset+=B->BPL;
		}

		glPixelStorei(GL_PACK_LSB_FIRST,	GL_FALSE);
		glPixelStorei(GL_UNPACK_LSB_FIRST,	GL_FALSE);
		glRasterPos2i(dx, dy+sh);


		if(coulBase!=NIL)
		{
			glEnable(GL_ALPHA_TEST);
			//if(transparency==NIL)    glDisable(GL_BLEND);   // $BLG: Handled below
			//glAlphaFunc(GL_EQUAL,1);                        // $BLG: Removed. This is a threshold which optimizes the management of transparency, but in this case, this limits the transparency to 0 or 1.
		}
		if(transparency!=NIL)
		{
			glEnable(GL_BLEND);
			//if(coulBase==NIL)    glDisable(GL_ALPHA_TEST);  // $BLG: Handled below
			glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
		}
		
		glDrawPixels(sw, sh, GL_RGBA, GL_UNSIGNED_BYTE, buffer);

		if(coulBase!=NIL)		glDisable(GL_ALPHA_TEST);
		if(transparency!=NIL)    glDisable(GL_BLEND);


		free(buffer);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
		return 0;
	}
	else
	{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
		return GRCopyBitmap(m);
	}
}


/*
//////////////////////////////////////////////////////////////////////////////////////////////
///		_ZSurface2Bitmap														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun[ObjBitmap I I ObjSurface I I I I I] ObjBitmap
int _ZSurface2Bitmap (mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"Surface2Bitmap ");
#endif

	if(userACCEL)
	{
		unsigned char	*buffer;
		unsigned char	r, g, b;

		int 	couleur = MMpull(m)>>1;
		RECT	rect;
		HWND	hwnd;
		int		x, y, c, bw, offset, yoffset, Y;
		int		sh = MMpull(m)>>1,
				sw = MMpull(m)>>1,
				sy = MMpull(m)>>1,
				sx = MMpull(m)>>1,
				surf = MMpull(m)>>1,
				dy = MMpull(m)>>1,
				dx = MMpull(m)>>1,
				bitmap = MMget(m,0)>>1;

		if(surf==NIL || bitmap==NIL || sx==NIL || sy==NIL || dx==NIL || dy==NIL || sh==NIL || sw==NIL)	    return 0;

		PtrObjVoid		OB = (PtrObjVoid)   MMstart(m, bitmap);
		PtrObjBitmap	B  = (PtrObjBitmap) MMstart(m, OB->Buffer>>1);

		if(dx>B->TailleW)		return 0;
		if(dy>B->TailleH)		return 0;
		if(dx<0)			{	sx+=dx; dx=0; }
		if(dy<0)			{	sy+=dy; dy=0; }
		if(B->BPP!=16)			return 0;
		if(dx+sw>B->TailleW)	sw = B->TailleW-dx;
		if(dy+sh>B->TailleH)	sh = B->TailleH-dy;

		SetGL2D(m, surf, NULL, &hwnd);
		GetClientRect(hwnd, &rect);

		if(sx<0)			{	sw+=sx; sx=0; }
		if(sy<0)			{	sh+=sy; sy=0; }
		if(sx+sw>rect.right)	sw = rect.right-sx;
		if(sy+sh>rect.bottom-1)	sh = rect.bottom-1-sy;

		if(sw<=0)				return 0;
		if(sh<=0)				return 0;

		buffer = (unsigned char*) malloc(sw*sh*3);
		if(!buffer)				return 0;

		int lastPackAlign, lastUnPackAlign;
		glGetIntegerv(GL_PACK_ALIGNMENT,	&lastPackAlign);
		glGetIntegerv(GL_UNPACK_ALIGNMENT,	&lastUnPackAlign);
		glPixelStorei(GL_PACK_ALIGNMENT,	1);
		glPixelStorei(GL_UNPACK_ALIGNMENT,	1);
		glPixelStorei(GL_PACK_LSB_FIRST,	GL_FALSE);
		glPixelStorei(GL_UNPACK_LSB_FIRST,	GL_FALSE);
		glReadPixels(sx, sy, sw, sh, GL_RGB, GL_UNSIGNED_BYTE, buffer);

		bw = B->BPL/2;

		unsigned char	*image8  = (unsigned char*) (B->bits);
		unsigned short	*image16;

		if(couleur!=NIL)		// couleur de transparence
		{
			r = (couleur>>3 ) & 31;
			g = (couleur>>11) & 31;
			b = (couleur>>19) & 31;
			couleur = b+(g<<5)+(r<<10);

			image8 += (dx*2 + dy*B->BPL);

			for(y=0; y<sh; y++)
			{
				Y = (sh-y-1)*sw*3;

				image16 = (unsigned short*) (image8);

				for(x=0; x<sw; x++)
				{
					b = buffer[Y+0];
					g = buffer[Y+1];
					r = buffer[Y+2];
					c = (r>>3) + ((g>>3)<<5) + ((b>>3)<<10);
					if(couleur!=c)        image16[x] = c;
					Y+=3;
				}

				image8 += B->BPL;
			}
		}
		else					// pas de transparence : copie intégrale
		{
			image8 += (dx*2 + dy*B->BPL);

			for(y=0; y<sh; y++)
			{
				Y = (sh-y-1)*sw*3;

				image16 = (unsigned short*) (image8);

				for(x=0; x<sw; x++)
				{
					b = buffer[Y+0];
					g = buffer[Y+1];
					r = buffer[Y+2];
					c = (r>>3) + ((g>>3)<<5) + ((b>>3)<<10);
					image16[x] = c;
					Y+=3;
				}

				image8 += B->BPL;
			}
		}

		free(buffer);

		glPixelStorei(GL_PACK_ALIGNMENT,	lastPackAlign);
		glPixelStorei(GL_UNPACK_ALIGNMENT,	lastUnPackAlign);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
		return 0;
	}
	else
	{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
		return GRCopyBitmap(m);
	}
}
*/


//////////////////////////////////////////////////////////////////////////////////////////////
///		_ZSurface2Bitmap														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun[ObjBitmap I I ObjSurface I I I I I] ObjBitmap
int _ZSurface2Bitmap (mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"Surface2Bitmap ");
#endif

//$BLG: Debug
//char buf[256];
//MMechostr(0,"Debug: _SURFACE2BITMAP\n");

	if(userACCEL)
	{
		unsigned char	*buffer;
		unsigned char	r, g, b;

		int 	couleur = MMpull(m)>>1;
		RECT	rect;
		HWND	hwnd;
		int		x, y, c, bw, offset, yoffset, Y;
		int		sh = MMpull(m)>>1,
				sw = MMpull(m)>>1,
				sy = MMpull(m)>>1,
				sx = MMpull(m)>>1,
				surf = MMpull(m)>>1,
				dy = MMpull(m)>>1,
				dx = MMpull(m)>>1,
				bitmap = MMget(m,0)>>1;

		if(surf==NIL || bitmap==NIL || sx==NIL || sy==NIL || dx==NIL || dy==NIL || sh==NIL || sw==NIL)	    return 0;

		PtrObjVoid		OB = (PtrObjVoid)   MMstart(m, bitmap);
		PtrObjBitmap	B  = (PtrObjBitmap) MMstart(m, OB->Buffer>>1);

		if(dx>B->TailleW)		return 0;
		if(dy>B->TailleH)		return 0;
		//$BLG - v5.3.01: Modif
		//if(dx<0)			{	sx+=dx; dx=0; }
		//if(dy<0)			{	sy+=dy; dy=0; }
		if(dx < 0)			{sx -= dx; dx = 0;}
		if(dy < 0)			{sy -= dy; dy = 0;}
		//$BLG - End
		if(B->BPP!=24)			return 0;
		if(dx+sw>B->TailleW)	sw = B->TailleW-dx;
		if(dy+sh>B->TailleH)	sh = B->TailleH-dy;

		SetGL2D(m, surf, NULL, &hwnd);
		GetClientRect(hwnd, &rect);

		if(sx<0)			{	sw+=sx; sx=0; }
		if(sy<0)			{	sh+=sy; sy=0; }
		if(sx+sw>rect.right)	sw = rect.right-sx;
		//$BLG: Removing -1 removes a black line at bottom of bitmap
		//if(sy+sh>rect.bottom-1)	sh = rect.bottom-1-sy;
		if(sy+sh>rect.bottom)	sh = rect.bottom-sy;

		if(sw<=0)				return 0;
		if(sh<=0)				return 0;

    //$BLG
    //buffer = (unsigned char*) malloc(sizeof(char)*sw*sh*3);
    //Bytes alignment set to 32bits: solves memory offsets problems
		int sizew;
		sizew = sw * 3;
		if (sizew % 4 != 0) sizew += 4 - (sizew % 4);
		buffer = (unsigned char*) malloc(sizeof(char)*sizew*sh);
		if(!buffer)				return 0;

		glPixelStorei(GL_PACK_LSB_FIRST,	GL_FALSE);
		glPixelStorei(GL_UNPACK_LSB_FIRST,	GL_FALSE);
		glReadPixels(sx, sy, sw, sh, GL_RGB, GL_UNSIGNED_BYTE, buffer);

		bw = B->BPL;
//$BLG
//sprintf(buf, "bw:%d\n", bw);
//MMechostr(0,buf);

		yoffset = 0;

		//$LB (23/11/2004) : fixed a bug about the offset compute

		if(couleur!=NIL)		// couleur de transparence
		{
			offset = dx*B->BytesPP + dy*bw;
			
			for(y=0; y<sh; y++, offset+=bw)
			{
				//$BLG
				//Y = (sh-y-1) * sw*3;
				Y = (sh-y-1) * sizew;
				
				for(x=0; x<sw; x++, Y+=3)
				{
					r = buffer[Y+0];
					g = buffer[Y+1];
					b = buffer[Y+2];

					c = ((b<<16) &0xFF0000) | ((g<<8) &0xFF00) | (r &0xFF);

					if(couleur!=c)       
					{
						yoffset = offset + x*3;
						((OBJBITMAP_BUFFER)B->bits)[yoffset +0] = b;
						((OBJBITMAP_BUFFER)B->bits)[yoffset +1] = g;
						((OBJBITMAP_BUFFER)B->bits)[yoffset +2] = r;
					}
				}
				
			}
		}
		else					// pas de transparence : copie intégrale
		{
			offset = dx*B->BytesPP + dy*bw;
			for(y=0; y<sh; y++, offset+=bw)
			{		
				//$BLG
				//Y = (sh-y-1) * sw*3;
				Y = (sh-y-1) * sizew;
				
				for(x=0; x<sw; x++, Y+=3)
				{
					yoffset = offset + x*3;
					((OBJBITMAP_BUFFER)B->bits)[yoffset +0] = buffer[Y+2];
					((OBJBITMAP_BUFFER)B->bits)[yoffset +1] = buffer[Y+1];
					((OBJBITMAP_BUFFER)B->bits)[yoffset +2] = buffer[Y+0];
				}
			}
		}

		free(buffer);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
		return 0;
	}
	else
	{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
		return GRCopyBitmap(m);
	}
}




//////////////////////////////////////////////////////////////////////////////////////////////
///		_ZSurface2Surface														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun[ObjSurface I I ObjSurface I I I I I] ObjSurface
int _ZSurface2Surface (mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"surface2surface ");
#endif
	if(userACCEL)
	{
		unsigned char	*buffer;
		
		int		couleur = MMpull(m)>>1;
		RECT	rectS, rectD; 
		HWND	hwndS, hwndD;
		
		int		i, c;
		int		sh = MMpull(m)>>1,
				sw = MMpull(m)>>1,
				sy = MMpull(m)>>1,
				sx = MMpull(m)>>1,
				surfS = MMpull(m)>>1,
				dy = MMpull(m)>>1,
				dx = MMpull(m)>>1,
				surfD = MMget(m,0)>>1;

		if(surfS==NIL || surfD==NIL || sx==NIL || sy==NIL || dx==NIL || dy==NIL || sh==NIL || sw==NIL)    return 0;

		SetGL2D(m, surfD, NULL, &hwndD);
		SetGL2D(m, surfS, NULL, &hwndS);

		GetClientRect(hwndS, &rectS);
		GetClientRect(hwndD, &rectD);

		if(dx>rectD.right)			return 0;
		if(dy>rectD.bottom)			return 0;
		//$BLG - v5.3.01: Modif
		//if(dx<0)				{	sx+=dx; dx=0;	}
		//if(dy<0)				{	sy+=dy; dy=0;	}
		if(dx < 0)				{sx -= dx; dx = 0;}
		if(dy < 0)				{sy -= dy; dy = 0;}
		//$BLG - End
		if(dx+sw>rectD.right)		sw = rectD.right-dx;
		if(dy+sh>rectD.bottom)		sh = rectD.bottom-dy;

		if(sx<0)				{	sw+=sx; sx=0;	}
		if(sy<0)				{	sh+=sy; sy=0;	}
		if(sx+sw>rectS.right)		sw = rectS.right-sx;
		if(sy+sh>rectS.bottom)		sh = rectS.bottom-sy;

		if(sw<=0)					return 0;
		if(sh<=0)					return 0;

		SetGL2D(m, surfS, NULL, &hwndS);
		glPixelStorei(GL_PACK_LSB_FIRST,	GL_FALSE);
		glPixelStorei(GL_UNPACK_LSB_FIRST,	GL_FALSE);

		if(couleur==NIL)
		{
			buffer = (unsigned char*) malloc(sizeof(char)*sw*sh*4);
			if(!buffer)		return 0;

			glReadPixels(sx, rectS.bottom-sh-sy, sw, sh, GL_RGBA, GL_UNSIGNED_BYTE, buffer);

			SetGL2D(m, surfD, NULL, &hwndD);
			glRasterPos2i(dx, dy+sh);
			glDrawPixels(sw, sh, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
		}
		else
		{
			int	rr = couleur       &0xFF;
			int gg = (couleur>>8)  &0xFF;
			int bb = (couleur>>16) &0XFF;
			couleur = bb | ((gg<<8)&0xFF00) | ((rr<<16) &0xFF0000);

			buffer = (unsigned char*) malloc(sizeof(char)*sw*sh*4);
			if(!buffer)		return 0;

			glReadPixels(sx, rectS.bottom-sh-sy, sw, sh, GL_RGBA, GL_UNSIGNED_BYTE, buffer);

			glEnable(GL_ALPHA_TEST);
			glAlphaFunc(GL_EQUAL,0);
// $BLG: Optimized next part of the code (10% performance gained on test program)
/*			
			for(i=0; i<sw*sh; i++)
			{
				c = (buffer[i*4]) | ((buffer[i*4+1]<<8) &0xFF00) | ((buffer[i*4+2]<<16) &0xFF0000);
				if (c==couleur)		buffer[i*4+3]=255;
				else				buffer[i*4+3]=0;
			}
*/			
			for(i=0; i<sw*sh*4; i+=4)
			{
				c = (buffer[i]) | ((buffer[i+1]<<8) &0xFF00) | ((buffer[i+2]<<16) &0xFF0000);
				if (c==couleur)		buffer[i+3]=255;
				else				buffer[i+3]=0;
			}
			SetGL2D(m, surfD, NULL, &hwndD);
			glRasterPos2i(dx, dy+sh);
			glDrawPixels(sw, sh, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
			glDisable(GL_ALPHA_TEST);
		}

		free(buffer);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
		return 0;
	}
	else
	{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
		return GRCopyBitmap(m);
	}
}


//$BLG
//This function allows to blend a surface on a surface. It accepts a (0-255) transparency color
//as well as a transparency factor (0->255) for the rest of the surface.
//Base code from Surface2Surface. Blending part from _BlendBitmap2Surface.
//////////////////////////////////////////////////////////////////////////////////////////////
///		_ZBlendSurface2Surface														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun[ObjSurface I I ObjSurface I I I I I I I] ObjSurface
int _ZBlendSurface2Surface (mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"_ZBlendSurface2Surface\n");
#endif
	if(userACCEL)
	{
		unsigned char	*buffer;
		
		int		transparency = MMpull(m)>>1;
		int   c_transp = MMpull(m)>>1;
		int		couleur = MMpull(m)>>1;
		RECT	rectS, rectD; 
		HWND	hwndS, hwndD;
		
		int		i, c;
		int		sh = MMpull(m)>>1,
				sw = MMpull(m)>>1,
				sy = MMpull(m)>>1,
				sx = MMpull(m)>>1,
				surfS = MMpull(m)>>1,
				dy = MMpull(m)>>1,
				dx = MMpull(m)>>1,
				surfD = MMget(m,0)>>1;

		if(surfS==NIL || surfD==NIL || sx==NIL || sy==NIL || dx==NIL || dy==NIL || sh==NIL || sw==NIL)    return 0;

		SetGL2D(m, surfD, NULL, &hwndD);
		SetGL2D(m, surfS, NULL, &hwndS);

		GetClientRect(hwndS, &rectS);
		GetClientRect(hwndD, &rectD);

		if(dx>rectD.right)			return 0;
		if(dy>rectD.bottom)			return 0;
		//$BLG - v5.3.01: Modif
		//if(dx<0)				{	sx+=dx; dx=0;	}
		//if(dy<0)				{	sy+=dy; dy=0;	}
		if (dx < 0)				{sx -= dx; dx = 0;}
		if (dy < 0)				{sy -= dy; dy = 0;}
		//$BLG - End
		if(dx+sw>rectD.right)		sw = rectD.right-dx;
		if(dy+sh>rectD.bottom)		sh = rectD.bottom-dy;

		if(sx<0)				{	sw+=sx; sx=0;	}
		if(sy<0)				{	sh+=sy; sy=0;	}
		if(sx+sw>rectS.right)		sw = rectS.right-sx;
		if(sy+sh>rectS.bottom)		sh = rectS.bottom-sy;

		if(sw<=0)					return 0;
		if(sh<=0)					return 0;

		SetGL2D(m, surfS, NULL, &hwndS);
		glPixelStorei(GL_PACK_LSB_FIRST,	GL_FALSE);
		glPixelStorei(GL_UNPACK_LSB_FIRST,	GL_FALSE);

		if((couleur==NIL) && (transparency==NIL))
		{
			buffer = (unsigned char*) malloc(sizeof(char)*sw*sh*4);
			if(!buffer)		return 0;

			glReadPixels(sx, rectS.bottom-sh-sy, sw, sh, GL_RGBA, GL_UNSIGNED_BYTE, buffer);

			SetGL2D(m, surfD, NULL, &hwndD);
			glRasterPos2i(dx, dy+sh);
			glDrawPixels(sw, sh, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
		}
		else
		{
			//int	rr = couleur       &0xFF;
			//int gg = (couleur>>8)  &0xFF;
			//int bb = (couleur>>16) &0XFF;
      if (transparency == NIL)  transparency = 255;
      if ((couleur != NIL) && (c_transp == NIL))  c_transp = 0;
			//couleur = bb | ((gg<<8)&0xFF00) | ((rr<<16) &0xFF0000);

			buffer = (unsigned char*) malloc(sizeof(char)*sw*sh*4);
			if(!buffer)		return 0;

			glReadPixels(sx, rectS.bottom-sh-sy, sw, sh, GL_RGBA, GL_UNSIGNED_BYTE, buffer);

// $BLG: Optimized next part of the code (10% performance gain on test program)
/*
			for(i=0; i<sw*sh; i++)
			{
				c = (buffer[i*4]) | ((buffer[i*4+1]<<8) &0xFF00) | ((buffer[i*4+2]<<16) &0xFF0000);
				if (couleur==c)		buffer[i*4+3]=0;
				else if (transparency==NIL)  buffer[i*4+3]=255;
				else				buffer[i*4+3]=transparency;
			}
*/
			for(i=0; i<sw*sh*4; i+=4)
			{
				c = (buffer[i]) | ((buffer[i+1]<<8) &0xFF00) | ((buffer[i+2]<<16) &0xFF0000);
				//$BLG Modif
				/*
				if (couleur==c)		buffer[i+3]=0;
				else if (transparency==NIL)  buffer[i+3]=255;
				else				buffer[i+3]=transparency;
				*/
				if (couleur == c)	buffer[i+3] = c_transp;
				else buffer[i+3] = transparency;
			}
			SetGL2D(m, surfD, NULL, &hwndD);
			glRasterPos2i(dx, dy+sh);
		  if(couleur!=NIL)
		  {
  			glEnable(GL_ALPHA_TEST); 
	  	}
		  if(transparency!=NIL)
		  {
			  glEnable(GL_BLEND);
			  glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
		  }			
			glDrawPixels(sw, sh, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
		  if(couleur!=NIL)		glDisable(GL_ALPHA_TEST);
		  if(transparency!=NIL)    glDisable(GL_BLEND);
		}
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
		free(buffer);
		return 0;
	}
	else
	{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
		return GRCopyBitmap(m);
	}
}









int		valDST=0;
int		valSRC=0;



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZTest
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [I] I
int ZTest(mmachine m)
{
	int	val = MMget(m,0);


	if(val)
	{
		valSRC++;
		if(valSRC>10)	valSRC=0;
	}
	else
	{
		valDST++;
		if(valDST>10)	valDST=0;
	}


	return 0;
}


//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3isValidObj
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d] I
int ZM3isValidObj(mmachine m)
{
    int h3d = MMpull(m);
    int s3d = MMget(m,0);

    if(s3d==NIL)					{	MMset(m,0,ITOM(4));		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,ITOM(3));		return 0;	}

	if(h3d==NIL)					{	MMset(m,0,ITOM(2));		return 0;	}
    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL)					{	MMset(m,0,ITOM(1));		return 0;	}

	MMset(m,0,ITOM(0));

	return 0;
}





///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////																											   ////
///												GESTION DES OBJETS													///
////																											   ////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////



///////////////////////////////////////////////////////////////////////////////////////////
////																				   ////
///								GESTION HIERARCHIQUE									///
////																				   ////
///////////////////////////////////////////////////////////////////////////////////////////



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3load														
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d S H3d] I
int ZM3load(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3load ");
#endif

  FILE *f;
  char name[SIZESIGN];

  int	pere = MMpull(m);
  int nam	 = MMpull(m);
  int s3d	 = MMget(m,0);
  
  if((nam==NIL)||(s3d==NIL))		{	MMset(m,0,NIL);		return 0;	}

  ZScene	*scene = (ZScene*) MMfetch(m, MTOP(s3d), 0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

	//MMechostr(0,"M3load SPfindfile %s\n", MMstartstr(m, MTOP(nam)));

  if (SPfindfile((packdir)SCgetExtra("FirstPack"), MMstartstr(m, MTOP(nam)), NULL, name) == -1)		{	MMechostr(0,"M3load -1\n"); MMset(m,0,NIL);	return 0;	}

  f = fopen(name,"rb");

	int res;

	if(f)
  {
		if(pere==NIL)
		{
			res = ZM3DloadFILE(m, MTOP(s3d), f, scene->World, 100.0f);
		}
		else
		{		
			ZNode	*node = (ZNode*) MMfetch(m, MTOP(pere), 0);
			if(node!=NULL)		res = ZM3DloadFILE(m, MTOP(s3d), f, node, 100.0f);
		}
		fclose(f);
  }
  else
	{
		MMset(m,0,NIL);
		return 0;
	}

	
	scene->updateGraphList		= true;

	scene->textureModified		= true;
	scene->materialModified		= true;
	scene->meshModified			= true;

	MMset(m,0,res*2);


#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3loadString														
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d S H3d] I
int ZM3loadString(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3loadString ");
#endif
    int	pere = MMpull(m);
    int fich = MMpull(m);
    int s3d	 = MMget(m,0);

//$BLG
//MMechostr(0, "$BLG\n");
//MMechostr(0, (char*)MMstartstr(m,fich>>1));

    if((fich==NIL)||(s3d==NIL))		{	MMset(m,0,NIL);		return 0;	}

    ZScene	*scene = (ZScene*) MMfetch(m, MTOP(s3d), 0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    int	res;
	if(pere==NIL)
	{
		res = ZM3Dloadbuf(m, MTOP(s3d), (char*)MMstartstr(m,fich>>1), scene->World, 100.0f);
	}
	else
	{
		ZNode	*node = (ZNode*) MMfetch(m, MTOP(pere), 0);
		if(node!=NULL)		res = ZM3Dloadbuf(m, MTOP(s3d), (char*)MMstartstr(m,fich>>1), node, 100.0f);
	}

	scene->updateGraphList		= true;

	scene->textureModified		= true;
	scene->materialModified		= true;
	scene->meshModified			= true;


	MMset(m,0,res*2);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////		Set anim file for a skelet //////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

int M3CleanAnimationData(mmachine m,ZNode *node,ZScene *scene,ZNode *fatherNode,int s3d)
{


	ZNode*		curNode;
	ZBone *fatherBone = (ZBone*)node ;
	ZBone *SKL = (ZBone*)fatherNode ;

	curNode = node ;

		ZNode	 *nodeSon, *nodeNext;
		//$BLG - v5.22: Del
		//int		h3d;


		while(curNode != NULL)
		{
			nodeSon  = curNode->son;
			nodeNext = curNode->next;
			if(curNode->type == ANI_TYPE_ID)
			{
			
				if(curNode->father)
				{
					if (curNode->father->son == curNode)
					{
						curNode->father->son = curNode->next;
						if (curNode->next)		curNode->next->prev = curNode->prev;
					}
					else
					{
						if (!curNode->next)	curNode->father->son->prev = curNode->prev;						
						curNode->prev->next = curNode->next;
						if (curNode->next)		curNode->next->prev = curNode->prev;
					}
					curNode->prev = curNode->next = NULL;													 
				}	
				delete curNode;
			}
			// Test of recursion
			if(nodeSon!=NULL)			M3CleanAnimationData(m,nodeSon,scene,fatherNode,s3d);
		    curNode = nodeNext;
		}
		scene->updateGraphList = true;
		return 0;
} 


int M3Check(ZNode *node,ZScene *scene,ZNode *fatherNode)
{


	ZNode*		curNode;
	ZBone *fatherBone = (ZBone*)node ;
	ZBone *SKL = (ZBone*)fatherNode ;

	curNode = node ;

		ZNode	 *nodeSon, *nodeNext;
		//$BLG - v5.22: Del
		//int		h3d;


		while(curNode != NULL)
		{
			nodeSon  = curNode->son;
			nodeNext = curNode->next;

			//MMechostr(1,"curNode : %s \n",curNode->name.c_str()) ;

			if(curNode->type == ANI_TYPE_ID)
			{
			
			}
			// Test of recursion
			if(nodeSon!=NULL)			M3Check(nodeSon,scene,fatherNode);
			curNode = nodeNext;

			
		}
		scene->updateGraphList = true;
		return 0;
} 

//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3loadAnimationFileWithSKL														
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d S H3d] I
int ZM3loadAnimationFileWithSKL(mmachine m)
{
    FILE *f;
    char name[SIZESIGN];

    int	skl = MMpull(m);
    int nam	 = MMpull(m);
    int s3d	 = MMget(m,0);
    
    if((nam==NIL)||(s3d==NIL)||(skl==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m, MTOP(s3d), 0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}


    if( SPfindfile((packdir)SCgetExtra("FirstPack"),MMstartstr(m,MTOP(nam)),NULL,name) == -1 )		{	MMset(m,0,NIL);		return 0;	}


    f = fopen(name,"rb");

	//$BLG - v5.22: Modif
	//int res;
	int res = 0;
	
	float coeff = 100.0f ;


	ZNode	*node = (ZNode*) MMfetch(m, MTOP(skl), 0);
	if(node->type !=BON_TYPE_ID)	{MMset(m,0,NIL);		return 0;}
	ZBone		*curbone = (ZBone*) node;

	ZArray<ZAnim*> tempAnim ;

//	MMechostr(1,"******************Tableau des animations avant le changement**********************************\n") ;

	if(f)
    {
		if(skl==NIL)
		{
			MMset(m,0,NIL);
			return 0;
		}
		else
		{	
			if(curbone!=NULL)		
			{
						
						struct Load3d l;

						if (curbone==NULL)		{MMset(m,0,NIL);		return 0;}
						if(curbone->bones.Size() == 0 ) {MMset(m,0,NIL);		return 0;} 


						/* Suppression des anciennes données d'animation */
						count = 0 ;
						if(curbone->isAnimed == true )
						{
							//MMechostr(1,"Premier noeud : %s \n",curbone->son->name.c_str()) ;
							//M3Check(curbone->son->next,scene,curbone->son->next) ;
							//MMechostr(1,"*******************************Fin verification ***********************\n") ;
							M3CleanAnimationData(m,curbone->son,scene,curbone->son,s3d) ;
							curbone->animBones.Empty() ;
						}
						
						l.f = f;
						int p = 0 ;
						while(M3Dnextline(&l)==0)		
						{	

							if(curbone->isAnimed == false )
							{

								curbone->animBones.Add(M3DloadAnimationFile(scene, &l, curbone,coeff));
							}
							else
							{
								curbone->animBones.Add(M3DloadAnimationFile(scene, &l, curbone,coeff));
								
							}
							p = p+1 ;

						}	
						
			}

		}
		fclose(f);
    }
    else
	{
		MMset(m,0,NIL);
		return 0;
	}

	if(curbone->animBones.Size() == 0) { return 0 ;}
	else
	{
			// On construit la hierarchie des animations
			for(int k=0;k<curbone->bones.Size(); k++)
			{
				if(curbone->isAnimed == false )
				{
					curbone->initBones.Add(curbone->bones[k]) ;
				}
				if(curbone->isAnimed == false )
				{
					curbone->animBones[k]->InsertAsChildOf(curbone->bones[k]) ;
				}
				else
				{
					curbone->animBones[k]->InsertAsChildOf(curbone->initBones[k]) ;
				}

			}

	}



	
	curbone->isAnimed			= true;
	scene->updateGraphList		= true;
	scene->textureModified		= true;
	scene->materialModified		= true;
	scene->meshModified			= true;

	MMset(m,0,res*2);

	return 0;
}

//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3createShell
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d] H3d
int ZM3createShell(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3createShell ");
#endif
    int s3d;

    s3d = MMget(m,0);

    if(s3d==NIL)		{	MMset(m,0,NIL);		return 0;	}
	ZScene	*scene = (ZScene*) MMfetch(m, MTOP(s3d), 0);
	if(scene==NULL)		{	MMset(m,0,NIL);		return 0;	}

	// Crée le ZShell
	ZShell	*shell;
	shell = new ZShell((int)scene);
	shell->SetName("");
	shell->InsertAsChildOf(scene->World);

	ZPRS	*shlPRS;
	shlPRS = shell->GetPRS();

	shlPRS->coeffM3D = 100.0f;

	int hash_tab = MTOP( MMfetch(m,MTOP(s3d),1) );
	int	h3d = createH3D(m, (int)shell, hash_tab);
	
	scene->updateGraphList = true;

	// Pose le résultat sur la pile
	if(h3d!=NIL)	h3d = PTOM(h3d);
    MMset(m,0,h3d);
    
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3delObj														
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d] I
int ZM3delObj(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3delObj ");
#endif

    int h3d = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

	ZNode	*curNode = (ZNode*) MMfetch(m, MTOP(h3d), 0);

	if(curNode)
	{
		if(curNode->type==MSH_TYPE_ID)		{	MMset(m,0,NIL);		return 0;	}

		DeleteNode(m, MTOP(MMfetch(m,MTOP(s3d),1)), curNode);	// supprime réellement le pointeur C et sa descendance
		DelObj(m, MTOP(MMfetch(m,MTOP(s3d),1)), MTOP(h3d));		// supprime le pointeur C dans le H3d et dans la hash_tab

		scene->updateGraphList = true;
	    MMset(m,0,0);
	}
	else
		MMset(m,0,NIL);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
    return 0;
}


void copyCollision(ZColl *newcol, ZColl *col)
{
	newcol->rayon	 = col->rayon;
	newcol->typeColl = col->typeColl;
	newcol->u		 = col->u;
	newcol->v		 = col->v;
	newcol->w		 = col->w;

	if(col->colA)
	{
		newcol->colA = new ZColl(col->scene3D, col->colA->typeColl);
		copyCollision(newcol->colA, col->colA);
	}

	if(col->colB)
	{
		newcol->colB = new ZColl(col->scene3D, col->colB->typeColl);
		copyCollision(newcol->colB, col->colB);
	}
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3copyObj														
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d] H3d
int ZM3copyObj(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3copyObj ");
#endif

    int h3d = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

	ZNode	*curNode = (ZNode*) MMfetch(m, MTOP(h3d), 0);
	if(curNode==NULL)				{	MMset(m,0,NIL);		return 0;	}

	h3d = NIL;


	//*********** OBJ ***********//
	if (curNode->type == OBJ_TYPE_ID)
	{
		ZObject		*curObj = (ZObject*) curNode;
		ZObject		*newObj = new ZObject((int)scene);
		if (newObj==NULL)		{	MMset(m,0,NIL);		return 0;	}
		newObj->InsertAsChildOf(scene->World);
		newObj->SetName(curObj->name);

		h3d = createH3D(m, (int)newObj, MTOP(MMfetch(m,MTOP(s3d),1)));

		ZPRS	*newPRS;
		ZPRS	*prs = curObj->GetPRS();
		newPRS = newObj->GetPRS();
		newPRS->coeffM3D = prs->coeffM3D;
		newPRS->SetPos(prs->GetPos());
		newPRS->SetAng(prs->GetAng());
		newPRS->SetScale(prs->GetScale());

		newObj->name	 = curObj->name;
		newObj->rangeMAX = curObj->rangeMAX;
		newObj->rangeMIN = curObj->rangeMIN;


		// Copie du mesh également...
		if(curObj->IsMultiMeshes()==false)
		{
			ZMesh	*msh = curObj->GetMesh();
			ZMesh	*curMsh = NULL;

			if(msh)
			{
				curMsh = new ZMesh((int)scene, msh->NbVerts, msh->NbFaces);
				if(curMsh==NULL)		{	MMset(m,0,NIL);		return 0;	}
				scene->MshList.Add(curMsh);

				curMsh->name			  = msh->name;
				curMsh->dependency		  = msh->dependency;
				curMsh->displayListCreate = msh->displayListCreate;

				createH3D(m, (int)curMsh, MTOP(MMfetch(m,MTOP(s3d),1)));

				ZFace	*curFace, *face;
				for(int i=0; i<msh->Faces.size(); i++)
				{
					curFace = &(curMsh->Faces[i]);
					face	= &(msh->Faces[i]);

					curFace->initFace();
					curFace->SetMaterial(face->GetMaterial());

					curFace->SetVertsRef(face->VertRef[0], face->VertRef[1], face->VertRef[2]);
					curFace->dependency = face->dependency;

					curFace->UV1[0] = face->UV1[0];
					curFace->UV1[1] = face->UV1[1];
					curFace->UV1[2] = face->UV1[2];
					curFace->UV2[0] = face->UV2[0];
					curFace->UV2[1] = face->UV2[1];
					curFace->UV2[2] = face->UV2[2];
					curFace->UV3[0] = face->UV3[0];
					curFace->UV3[1] = face->UV3[1];
					curFace->UV3[2] = face->UV3[2];
					curFace->UV4[0] = face->UV4[0];
					curFace->UV4[1] = face->UV4[1];
					curFace->UV4[2] = face->UV4[2];

					curFace->clampU1 = face->clampU1;
					curFace->clampV1 = face->clampV1;
					curFace->clampU2 = face->clampU2;
					curFace->clampV2 = face->clampV2;
					curFace->clampU3 = face->clampU3;
					curFace->clampV3 = face->clampV3;
					curFace->clampU4 = face->clampU4;
					curFace->clampV4 = face->clampV4;

					curFace->index	= face->index;
				}

				ZVert	*curVert, *vert;
				for(i=0; i<msh->Verts.size(); i++)
				{
					curVert = &(curMsh->Verts[i]);
					vert	= &(msh->Verts[i]);

					curVert->color1 = vert->color1;
					curVert->color2 = vert->color2;
					curVert->Normal = vert->Normal;
					curVert->SetCoord(vert->x, vert->y, vert->z);
				}

				curMsh->hasTopoChanged = true;
				curMsh->hasViewChanged = true;

				newObj->SetMesh(curMsh);

				scene->meshModified	= true;
			}
		}
		else
		{
			ZArray<ZMesh*>		*mshList  = curObj->GetMeshList();
			ZArray<float>		*rangeSQR = curObj->GetRangeSQRList();

			newObj->setFlagMulti(true);

			for(int i=0; i<rangeSQR->Size(); i++)		newObj->AddMeshInList((*mshList)[i], (*rangeSQR)[i]);
		}
	}
	//*********** CAM ***********//
	else if (curNode->type == CAM_TYPE_ID)
	{
		ZCamera		*cam = (ZCamera*) curNode;
		ZCamera		*curCam = new ZCamera((int)scene);
		if(curCam==NULL)		{	MMset(m,0,NIL);		return 0;	}
		curCam->InsertAsChildOf(scene->World);
		curCam->SetName(cam->name);
		curCam->dx  = cam->dx;			curCam->dy = cam->dy;
		curCam->fov = cam->fov;			
		curCam->width = cam->width;		curCam->height = cam->height;

		h3d = createH3D(m, (int)curCam, MTOP(MMfetch(m,MTOP(s3d),1)));

		ZPRS	*curPRS;
		ZPRS	*prs = cam->GetPRS();
		curPRS = curCam->GetPRS();
		curPRS->coeffM3D = prs->coeffM3D;
		curPRS->SetPos(prs->GetPos());
		curPRS->SetAng(prs->GetAng());
		curPRS->SetScale(prs->GetScale());

		curCam->name	 = cam->name;
		curCam->rangeMAX = cam->rangeMAX;
		curCam->rangeMIN = cam->rangeMIN;
	}
	//*********** LGH ***********//
	else if (curNode->type == LGH_TYPE_ID)
	{
		ZLight	*lgh = (ZLight*) curNode;
		ZLight	*curLgh = new ZLight((int)scene);
		if(curLgh==NULL)		{	MMset(m,0,NIL);		return 0;	}
		curLgh->InsertAsChildOf(scene->World);
		
		curLgh->SetName(lgh->name);
		
		curLgh->SetAmbient(lgh->ambient);
		curLgh->SetDiffuse(lgh->diffuse);
		curLgh->SetSpecular(lgh->specular);
		
		curLgh->alpha = lgh->alpha;
		curLgh->beta  = lgh->beta;
		curLgh->dist  = lgh->dist;
		curLgh->target	  = lgh->target;
		curLgh->distance  = lgh->distance;
		curLgh->exponent  = lgh->exponent;
		curLgh->LightType = lgh->LightType;
		curLgh->oldStyle  = lgh->oldStyle;
		curLgh->attenuate_const = lgh->attenuate_const;
		curLgh->attenuate_quadr = lgh->attenuate_quadr;
		curLgh->spot_cut_off	= lgh->spot_cut_off;
		
		h3d = createH3D(m, (int)curLgh, MTOP(MMfetch(m,MTOP(s3d),1)));

		ZPRS	*curPRS;
		ZPRS	*prs = lgh->GetPRS();
		curPRS = curLgh->GetPRS();
		curPRS->coeffM3D = prs->coeffM3D;
		curPRS->SetPos( prs->GetPos() );
		curPRS->SetAng( prs->GetAng() );
		curPRS->SetScale(prs->GetScale());

		curLgh->rangeMAX = lgh->rangeMAX;
		curLgh->rangeMIN = lgh->rangeMIN;
	}
	//*********** SHL ***********//
	else if (curNode->type == SHL_TYPE_ID)
	{
		ZShell	*shl = (ZShell*) curNode;
		ZShell	*curShell = new ZShell((int)scene);
		if(curShell == NULL)	{	MMset(m,0,NIL);		return 0;	}
		curShell->InsertAsChildOf(scene->World);
		curShell->SetName(shl->name);

		h3d = createH3D(m, (int)curShell, MTOP(MMfetch(m,MTOP(s3d),1)));

		ZPRS	*shlPRS;
		ZPRS	*prs = shl->GetPRS();
		shlPRS = curShell->GetPRS();
		shlPRS->coeffM3D = prs->coeffM3D;
		shlPRS->SetPos( prs->GetPos() );
		shlPRS->SetAng( prs->GetAng() );
		shlPRS->SetScale(prs->GetScale());

		curShell->rangeMAX = shl->rangeMAX;
		curShell->rangeMIN = shl->rangeMIN;
	}
	//*********** ANI ***********//
	else if (curNode->type == ANI_TYPE_ID)
	{
		ZAnim	*an = (ZAnim*) curNode;
		ZAnim	*anim = new ZAnim((int)scene);
		if(!anim)				{	MMset(m,0,NIL);		return 0;	}
		anim->InsertAsChildOf(scene->World);
		anim->SetName(an->name);

		h3d = createH3D(m, (int)anim, MTOP(MMfetch(m,MTOP(s3d),1)));
		
		ZPRS	*animPRS;
		ZPRS	*prs = an->GetPRS();
		animPRS = anim->GetPRS();
		animPRS->coeffM3D = prs->coeffM3D;
		animPRS->SetPos( prs->GetPos() );
		animPRS->SetAng( prs->GetAng() );
		animPRS->SetScale(prs->GetScale());

		anim->setLength(an->getLength());
		anim->minKeyPos = an->minKeyPos;
		anim->maxKeyPos = an->maxKeyPos;
		anim->minKeyRot = an->minKeyRot;
		anim->maxKeyRot = an->maxKeyRot;
		
		anim->listPos.resize(an->listPos.size());
		anim->listRot.resize(an->listRot.size());
		int i;
		for(i=0; i<an->listPos.size(); i++)		{	anim->listPos[i].key = an->listPos[i].key;		anim->listPos[i].pos = an->listPos[i].pos;	}
		for(i=0; i<an->listRot.size(); i++)		{	anim->listRot[i].key = an->listRot[i].key;		anim->listRot[i].rot = an->listRot[i].rot;	}
	}
	//*********** COL ***********//
	else if (curNode->type == COL_TYPE_ID)
	{
		ZColl	*col = (ZColl*) curNode;
		ZColl	*newcol = new ZColl((int)scene, col->typeColl);
		if(!newcol)				{	MMset(m,0,NIL);		return 0;	}
		newcol->InsertAsChildOf(scene->World);
		newcol->name = col->name;

		h3d = createH3D(m, (int)newcol, MTOP(MMfetch(m,MTOP(s3d),1)));

		ZPRS	*colPRS;
		ZPRS	*prs = col->GetPRS();
		colPRS = newcol->GetPRS();
		colPRS->coeffM3D = prs->coeffM3D;
		colPRS->SetPos( prs->GetPos() );
		colPRS->SetAng( prs->GetAng() );
		colPRS->SetScale(prs->GetScale());

		copyCollision(newcol, col);
	}
	//*********** SPR ***********//
	else if (curNode->type == SPR_TYPE_ID)
	{
		ZSprite	*spr = (ZSprite*) curNode;
		ZSprite	*newspr = new ZSprite((int)scene);
		if(!newspr)				{	MMset(m,0,NIL);		return 0;	}
		newspr->InsertAsChildOf(scene->World);

		h3d = createH3D(m, (int)newspr, MTOP(MMfetch(m,MTOP(s3d),1)));

		ZPRS	*newPRS;
		ZPRS	*prs = spr->GetPRS();
		newPRS = newspr->GetPRS();
		newPRS->coeffM3D = prs->coeffM3D;
		newPRS->SetPos( prs->GetPos() );
		newPRS->SetAng( prs->GetAng() );
		newPRS->SetScale(prs->GetScale());

		newspr->SetMaterial(spr->GetMaterial());
		newspr->CameraOriented = spr->CameraOriented;
		newspr->clampU1 = spr->clampU1;
		newspr->clampU2 = spr->clampU2;
		newspr->clampV1 = spr->clampV1;
		newspr->clampV2 = spr->clampV2;
		newspr->halfH   = spr->halfH;
		newspr->halfW   = spr->halfW;
		newspr->rotationZ = spr->rotationZ;

		for(int i=0; i<4; i++)
		{
			newspr->UV1[i] = spr->UV1[i];
			newspr->UV2[i] = spr->UV2[i];
			newspr->vertColor1[i] = spr->vertColor1[i];
			newspr->vertColor2[i] = spr->vertColor2[i];
		}

		newspr->name	 = spr->name;
		newspr->rangeMAX = spr->rangeMAX;
		newspr->rangeMIN = spr->rangeMIN;
	}
	//*********** PCL ***********//
	else if (curNode->type == PCL_TYPE_ID)
	{
		ZEmitter	*pcl = (ZEmitter*) curNode;
		ZEmitter	*newPcl = new ZEmitter((int)scene, pcl->mask, pcl->life, pcl->volume);
		if(!newPcl)				{	MMset(m,0,NIL);		return 0;	}
		newPcl->InsertAsChildOf(scene->World);

		newPcl->name	 = pcl->name;
		newPcl->rangeMAX = pcl->rangeMAX;
		newPcl->rangeMIN = pcl->rangeMIN;

		h3d = createH3D(m, (int)newPcl, MTOP(MMfetch(m,MTOP(s3d),1)));
		
		ZPRS	*newPRS;
		ZPRS	*prs = pcl->GetPRS();
		newPRS = newPcl->GetPRS();
		newPRS->coeffM3D = prs->coeffM3D;
		newPRS->SetPos( prs->GetPos() );
		newPRS->SetAng( prs->GetAng() );
		newPRS->SetScale(prs->GetScale());

		newPcl->pFather = pcl->pFather;
		newPcl->state	= pcl->state&PCL_ENABLE;

		std::vector<ZEffect*>::iterator	eit = pcl->effectlist.begin();	
		for(;eit!=pcl->effectlist.end();eit++)
			newPcl->effectlist.push_back(*eit);
		if(newPcl->effectlist.size())	newPcl->hasEffects = true;

		std::vector<T_PCL_LIST>::iterator	pit = pcl->particlelist.begin();	
		for(;pit!=pcl->particlelist.end();pit++)
		{
			T_PCL_LIST t;
			t.list.resize(0);
			t.nbpart	= 0;
			t.parttype	= pit->parttype;
			newPcl->particlelist.push_back(t);
		}
	}
	//*********** MSH ***********//
	else if (curNode->type == MSH_TYPE_ID)
	{
		ZMesh	*msh = (ZMesh*) curNode;
		
		ZMesh	*curMsh = new ZMesh((int)scene, msh->NbVerts, msh->NbFaces);
		if(curMsh==NULL)		{	MMset(m,0,NIL);		return 0;	}
		scene->MshList.Add(curMsh);

		curMsh->name			  = msh->name;
		curMsh->dependency		  = msh->dependency;
		curMsh->displayListCreate = msh->displayListCreate;
		
		h3d = createH3D(m, (int)curMsh, MTOP(MMfetch(m,MTOP(s3d),1)));

		ZFace	*curFace, *face;
		for(int i=0; i<msh->Faces.size(); i++)
		{
			curFace = &(curMsh->Faces[i]);
			face	= &(msh->Faces[i]);
			
			curFace->initFace();
			curFace->SetMaterial(face->GetMaterial());
			
			curFace->SetVertsRef(face->VertRef[0], face->VertRef[1], face->VertRef[2]);
			curFace->dependency = face->dependency;
			
			curFace->UV1[0] = face->UV1[0];
			curFace->UV1[1] = face->UV1[1];
			curFace->UV1[2] = face->UV1[2];
			curFace->UV2[0] = face->UV2[0];
			curFace->UV2[1] = face->UV2[1];
			curFace->UV2[2] = face->UV2[2];
			curFace->UV3[0] = face->UV3[0];
			curFace->UV3[1] = face->UV3[1];
			curFace->UV3[2] = face->UV3[2];
			curFace->UV4[0] = face->UV4[0];
			curFace->UV4[1] = face->UV4[1];
			curFace->UV4[2] = face->UV4[2];

			curFace->clampU1 = face->clampU1;
			curFace->clampV1 = face->clampV1;
			curFace->clampU2 = face->clampU2;
			curFace->clampV2 = face->clampV2;
			curFace->clampU3 = face->clampU3;
			curFace->clampV3 = face->clampV3;
			curFace->clampU4 = face->clampU4;
			curFace->clampV4 = face->clampV4;
			
			curFace->index	= face->index;
		}

		ZVert	*curVert, *vert;
		for(i=0; i<msh->Verts.size(); i++)
		{
			curVert = &(curMsh->Verts[i]);
			vert	= &(msh->Verts[i]);

			curVert->color1 = vert->color1;
			curVert->color2 = vert->color2;
			curVert->Normal = vert->Normal;
			curVert->SetCoord(vert->x, vert->y, vert->z);
		}

		curMsh->hasTopoChanged = true;
		curMsh->hasViewChanged = true;

		scene->meshModified		= true;
	}

	// Pose le résultat sur la pile
	if(h3d!=NIL)	h3d = PTOM(h3d);
    MMset(m,0,h3d);

	scene->updateGraphList = true;

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
    return 0;
}



void GetFirstRecentName(ZNode *baseNode, ZNode **result, string testName)
{
	ZNode	* curNode = baseNode->son;
	
	while(curNode!=NULL)
	{
		//Test the Node
		if ((curNode->name == testName) && ( ((*result)==NULL) || (curNode->version>(*result)->version)  ) ) 		*result = curNode;

		//If the search is recursive
		GetFirstRecentName(curNode, result, testName);

		curNode = curNode->next;
	}
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getObj
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d S] H3d
int ZM3getObj(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getObj ");
#endif

	int name = MMpull(m);
    int s3d  = MMget(m,0);
    
    if((name==NIL)||(s3d==NIL))		{	MMset(m,0,NIL);		return 0;	}

    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

	ZNode	*curNode;
	curNode = NULL;
	GetFirstRecentName(scene->World, &curNode, string(MMstartstr(m,MTOP(name))) );

	if(curNode==NULL)				{	MMset(m,0,NIL);		return 0;	}

	int	h3d = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)curNode);

	if(h3d!=NIL)	h3d = PTOM(h3d);
	MMset(m,0,h3d);
	
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}

//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3listMeshFromNode
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d] [H3d r1]
int ZM3listMeshFromNode(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ZM3listMeshFromNode");
#endif

	int		j, k, n, tmp_res;
	n=0;
	int h3d = MMpull(m);
    int s3d = MMget(m,0);

    if(s3d==NIL)					{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

	if(h3d==NIL)					{MMset(m,0,NIL);		return 0;}
    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL)					{MMset(m,0,NIL);		return 0;}

	scene->World->createNodeLists(node);

	for(int i=0; i<scene->World->objList.Size(); i++)
    {
			h3d = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(MMget(m,0)),1)), (int)scene->World->objList[i]);
			if (MMpush(m,PTOM(h3d)))		return MERRMEM;
			n++;
			INVERT(m,0,1);
			node = node->next;
	}

	MMpull(m);

	if(MMpush(m,NIL))		return MERRMEM;
	for(j=0;j<n;j++)
	{
    	if (MMpush(m,2*2)) return MERRMEM;
		if (k=MBdeftab(m)) return k;
	}
	
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;
}

//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getH3dType
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d] I
int ZM3getH3dType(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ZM3getH3dType ");
#endif
     int h3d = MMpull(m);
    int s3d = MMget(m,0);

    if(s3d==NIL)					{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

	if(h3d==NIL)					{	MMset(m,0,NIL);		return 0;	}
    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL)					{	MMset(m,0,NIL);		return 0;	}
	

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	MMset(m, 0, ITOM(node->type));

	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3objName
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d] S
int ZM3objName(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3objName ");
#endif

    int h3d = MMpull(m);
    int s3d = MMget(m,0);

    if(s3d==NIL)					{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

	MMpull(m);

	if(h3d==NIL)					return Mpushstrbloc(m, NULL);
    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL)					return Mpushstrbloc(m, NULL);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return Mpushstrbloc(m, (char*)node->name.c_str());
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getFather
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d] H3d
int ZM3getFather(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getFather ");
#endif
    int h3d = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL||node->type==MSH_TYPE_ID)				{	MMset(m,0,NIL);		return 0;	}

    node = node->father;

	if((node->type>MAX_NODE_SCENE)||(node==NULL))		{	MMset(m,0,NIL);		return 0;	}

	h3d = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)node);

	if(h3d!=NIL)	h3d = PTOM(h3d);
	MMset(m,0,h3d);
	
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getFirstSon
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d] H3d
int ZM3getFirstSon(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getFirstSon ");
#endif

  int h3d = MMpull(m);
  int s3d = MMget(m,0);

  if((s3d==NIL)||(h3d==NIL))		{	MMset(m,0,NIL);		return 0;	}

	ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

  ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL||node->type==MSH_TYPE_ID)					{	MMset(m,0,NIL);		return 0;	}

  node = node->son;
	if(node==NULL)		{	MMset(m,0,NIL);		return 0;	}
	
	h3d = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)node);

	if(h3d!=NIL)	h3d = PTOM(h3d);
	MMset(m,0,h3d);
	
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getBrother														
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d] H3d
int ZM3getBrother(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getBrother ");
#endif
    int h3d = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL||node->type==MSH_TYPE_ID)					{	MMset(m,0,NIL);		return 0;	}

    if(node->father==scene->World)	{	MMset(m,0,NIL);		return 0;	}

	node = node->next;

	if(node==NULL)		{	MMset(m,0,NIL);		return 0;	}

	h3d = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)node);

	if(h3d!=NIL)	h3d = PTOM(h3d);
	MMset(m,0,h3d);
	
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3bigFather
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d] H3d
int ZM3bigFather(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3bigFather ");
#endif
    int h3d = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL||node->type==MSH_TYPE_ID)					{	MMset(m,0,NIL);		return 0;	}

    ZNode	*nodeSon;
	while((node!=NULL)&&(node!=scene->World))	{	nodeSon = node;		node = node->father;	}

	h3d = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)nodeSon);

	if(h3d!=NIL)	h3d = PTOM(h3d);
	MMset(m,0,h3d);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3isFather
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d H3d] I

///////// ATTENTION !!! FONCTION QUI CHIE LA MORT !!! RENVOIT "true" si pere==fils !!!!!! //////////
int ZM3isFather(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3isFather ");
#endif

    int pere = MMpull(m);
    int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL))		{	MMset(m,0,NIL);		return 0;	}
    
	if(pere==NIL)					{	MMset(m,0,ITOM(0));	return 0;	}

	ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL||node->type==MSH_TYPE_ID)					{	MMset(m,0,NIL);		return 0;	}
	ZNode	*papa = (ZNode*) MMfetch(m,MTOP(pere),0);
	if(papa==NULL||papa->type==MSH_TYPE_ID)					{	MMset(m,0,ITOM(0));		return 0;	}

    int	result = 0;
	while((node!=NULL)&&(node!=scene->World)&&(!result))	{	if(papa==node)	result = 1;		node = node->father;	}

	if(result==1)		MMset(m,0,ITOM(1));
	else				MMset(m,0,ITOM(0));

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3unLink
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d] I
int ZM3unLink(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3unlink ");
#endif

    int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL||node->type==MSH_TYPE_ID)					{	MMset(m,0,NIL);		return 0;	}

	if(node->father!=scene->World)		node->InsertAsChildOf(scene->World);

	scene->updateGraphList = true;

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	MMset(m,0,0);
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3link														
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d H3d] I
int ZM3link(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3link ");
#endif

    int pere = MMpull(m);
    int h3d	 = MMpull(m);
    int s3d	 = MMget(m,0);
    
	if((s3d==NIL)||(h3d==NIL))		return 0;
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)		{	MMset(m,0,NIL);		return 0;	}

	if(pere == NIL)		{	MMset(m,0,NIL);		return 0;	}

	ZNode	*nodePERE = (ZNode*) MMfetch(m,MTOP(pere),0);
	if(nodePERE==NULL/*||nodePERE->type==MSH_TYPE_ID*/)	{	MMset(m,0,NIL);		return 0;	}
//	if(nodePERE->type == MSH_TYPE_ID)	{	MMset(m,0,NIL);		return 0;	}

	ZNode	*nodeFILS = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(nodeFILS==NULL/*||nodeFILS->type==MSH_TYPE_ID*/)	{	MMset(m,0,NIL);		return 0;	}
//	if(nodeFILS->type == MSH_TYPE_ID)	{	MMset(m,0,NIL);		return 0;	}


	// test de validité du pere par rapport au fils : on ne doit pas "boucler"
	bool	impossible = false;
	ZNode	*curNode = nodePERE;
	while(curNode && !(impossible|=(curNode==nodeFILS)) )			curNode = curNode->father;
	if(impossible)		{	MMset(m,0,NIL);		return 0;	}
	
	// Effectue le link
	nodeFILS->InsertAsChildOf(nodePERE);
	
	scene->updateGraphList = true;
	
    MMset(m, 0, 0);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
    return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3renameObj
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d S] I
int ZM3renameObj(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3renameObj ");
#endif
    int name = MMpull(m);
    int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL)||(name==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL/*||node->type==MSH_TYPE_ID*/)					{	MMset(m,0,NIL);		return 0;	}

	node->SetName((char*)MMstartstr(m,MTOP(name)));

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	MMset(m,0,0);
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3listOfBigFathers
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d] [H3d r1]
int ZM3listOfBigFathers(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3listOfBigFather ");
#endif
	// Version MBdeftab non buggée

	int		h3d;
	int		j, k, n, tmp_res;

	n=0;

	int s3d = MMpull(m);
    if(s3d==NIL)			return MMpush(m,NIL);
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)			return MMpush(m,NIL);

	ZNode	*node = scene->World->son;
	if(node==NULL)					{	MMset(m,0,NIL);		return 0;	}

	MMpush(m, s3d);

	while(node!=NULL)
	{
		h3d = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(MMget(m,0)),1)), (int)node);
		if (MMpush(m,PTOM(h3d)))		return MERRMEM;
		n++;

		INVERT(m,0,1);
		
		node = node->next;
	}
	
	MMpull(m);
	
	if(MMpush(m,NIL))		return MERRMEM;
	for(j=0;j<n;j++)
	{
    	if (MMpush(m,2*2)) return MERRMEM;
		if (k=MBdeftab(m)) return k;
	}
	
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;
}






//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getObjType
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d] I
int ZM3getObjType(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getObjType ");
#endif

    int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL||node->type==MSH_TYPE_ID)					{	MMset(m,0,NIL);		return 0;	}

    if(node->type==LGH_TYPE_ID)
	{
		if(((ZLight*)node)->oldStyle == true)		MMset(m,0,ITOM(node->type));
		else										MMset(m,0,ITOM(50));
		return 0;
	}

	if(node->type==SND_TYPE_ID)
	{
		if(((ZSound*)node)->pWSound->pHListener )	MMset(m,0,ITOM(55));
		else										MMset(m,0,ITOM(60));
		return 0;
	}
	
	MMset(m,0,ITOM(node->type));
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}





//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3listALLObj
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d] [H3d r1]
int ZM3listALLObj(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3listOfBigFather ");
#endif
	// Version MBdeftab non buggée

	int		h3d;
	int		j, k, n, tmp_res;

	n=0;


	int s3d = MMpull(m);
    if(s3d==NIL)			return MMpush(m,NIL);
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)			return MMpush(m,NIL);

	ZNode	*node = scene->World->son;
	if(node==NULL)					{	MMset(m,0,NIL);	return 0;	}

	MMpush(m, s3d);

	for(int i=0; i<scene->MshList.Size(); i++)
    {
		h3d = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(MMget(m,0)),1)), (int)scene->MshList[i]);
		if (MMpush(m,PTOM(h3d)))		return MERRMEM;
		n++;

		INVERT(m,0,1);
		
		node = node->next;
	}

	MMpull(m);

	if(MMpush(m,NIL))		return MERRMEM;
	for(j=0;j<n;j++)
	{
    	if (MMpush(m,2*2)) return MERRMEM;
		if (k=MBdeftab(m)) return k;
	}
	
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;
}


//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3listALLLight
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d] [H3d r1]
int ZM3listALLLight(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ZM3listALLLight ");
#endif
	// Version MBdeftab non buggée

	int		h3d;
	int		j, k, n, tmp_res;

	n=0;


	int s3d = MMpull(m);
    if(s3d==NIL)			return MMpush(m,NIL);
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)			return MMpush(m,NIL);

	ZNode	*node = scene->World->son;
	if(node==NULL)					{	MMset(m,0,NIL);	return 0;	}

	MMpush(m, s3d);

	scene->World->createNodeLists(scene->World);

	for(int i=0; i<scene->World->lghList.Size(); i++)
    {
		h3d = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(MMget(m,0)),1)), (int)scene->World->lghList[i]);
		if (MMpush(m,PTOM(h3d)))		return MERRMEM;
		n++;
		INVERT(m,0,1);
		node = node->next;
	}

	MMpull(m);

	if(MMpush(m,NIL))		return MERRMEM;
	for(j=0;j<n;j++)
	{
    	if (MMpush(m,2*2)) return MERRMEM;
		if (k=MBdeftab(m)) return k;
	}
	
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;
}

//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3listALLCam
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d] [H3d r1]
int ZM3listALLCam(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ZM3listALLCam");
#endif
	// Version MBdeftab non buggée

	int		h3d;
	int		j, k, n, tmp_res;

	n=0;


	int s3d = MMpull(m);
    if(s3d==NIL)			return MMpush(m,NIL);
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)			return MMpush(m,NIL);

	ZNode	*node = scene->World->son;
	if(node==NULL)					{	MMset(m,0,NIL);	return 0;	}

	MMpush(m, s3d);

	scene->World->createNodeLists(scene->World);

	
	
	for(int i=0; i<scene->World->lghList.Size(); i++)
    {
		h3d = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(MMget(m,0)),1)), (int)scene->World->camList[i]);

		if (MMpush(m,PTOM(h3d)))		return MERRMEM;
		n++;

		INVERT(m,0,1);
		node = node->next;
	}

	MMpull(m);

	if(MMpush(m,NIL))		return MERRMEM;
	for(j=0;j<n;j++)
	{
    	if (MMpush(m,2*2)) return MERRMEM;
		if (k=MBdeftab(m)) return k;
	}
	
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;
}


//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3listALLShl
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d] [H3d r1]
int ZM3listALLShl(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ZM3listALLShl");
#endif
	// Version MBdeftab non buggée

	int		h3d;
	int		j, k, n, tmp_res;

	n=0;


	int s3d = MMpull(m);
    if(s3d==NIL)			return MMpush(m,NIL);
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)			return MMpush(m,NIL);

	ZNode	*node = scene->World->son;
	if(node==NULL)					{	MMset(m,0,NIL);	return 0;	}

	MMpush(m, s3d);

	scene->World->createNodeLists(scene->World);

	for(int i=0; i<scene->World->shlList.Size(); i++)
    {
		h3d = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(MMget(m,0)),1)), (int)scene->World->shlList[i]);
		if (MMpush(m,PTOM(h3d)))		return MERRMEM;
		n++;

		INVERT(m,0,1);
		node = node->next;
	}

	MMpull(m);

	if(MMpush(m,NIL))		return MERRMEM;
	for(j=0;j<n;j++)
	{
    	if (MMpush(m,2*2)) return MERRMEM;
		if (k=MBdeftab(m)) return k;
	}
	
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;
}

//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3listALLSpr
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d] [H3d r1]
int ZM3listALLSpr(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ZM3listALLSpr");
#endif
	// Version MBdeftab non buggée

	int		h3d;
	int		j, k, n, tmp_res;

	n=0;


	int s3d = MMpull(m);
    if(s3d==NIL)			return MMpush(m,NIL);
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)			return MMpush(m,NIL);

	ZNode	*node = scene->World->son;
	if(node==NULL)					{	MMset(m,0,NIL);	return 0;	}

	MMpush(m, s3d);

	scene->World->createNodeLists(scene->World);
	
	
	for(int i=0; i<scene->World->sprList.Size(); i++)
    {
		h3d = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(MMget(m,0)),1)), (int)scene->World->sprList[i]);
		if (MMpush(m,PTOM(h3d)))		return MERRMEM;
		n++;

		INVERT(m,0,1);
		node = node->next;
	}

	MMpull(m);

	if(MMpush(m,NIL))		return MERRMEM;
	for(j=0;j<n;j++)
	{
    	if (MMpush(m,2*2)) return MERRMEM;
		if (k=MBdeftab(m)) return k;
	}
	
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;
}

//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3listALLPcl
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d] [H3d r1]
int ZM3listALLPcl(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ZM3listALLPcl");
#endif
	// Version MBdeftab non buggée

	int		h3d;
	int		j, k, n, tmp_res;

	n=0;


	int s3d = MMpull(m);
    if(s3d==NIL)			return MMpush(m,NIL);
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)			return MMpush(m,NIL);

	ZNode	*node = scene->World->son;
	if(node==NULL)					{	MMset(m,0,NIL);	return 0;	}

	MMpush(m, s3d);

	scene->World->createNodeLists(scene->World);

	for(int i=0; i<scene->World->pclList.Size(); i++)
    {
		h3d = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(MMget(m,0)),1)), (int)scene->World->pclList[i]);
		if (MMpush(m,PTOM(h3d)))		return MERRMEM;
		n++;

		INVERT(m,0,1);
		node = node->next;
	}

	MMpull(m);

	if(MMpush(m,NIL))		return MERRMEM;
	for(j=0;j<n;j++)
	{
    	if (MMpush(m,2*2)) return MERRMEM;
		if (k=MBdeftab(m)) return k;
	}
	
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;
}

//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3listALLPclEff
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d] [H3d r1]
int ZM3listALLPclEff(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ZM3listALLPclEff");
#endif
	// Version MBdeftab non buggée

	int		h3d;
	int		j, k, n, tmp_res;

	n=0;


	int s3d = MMpull(m);
    if(s3d==NIL)			return MMpush(m,NIL);
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)			return MMpush(m,NIL);

	ZNode	*node = scene->World->son;
	if(node==NULL)					{	MMset(m,0,NIL);	return 0;	}

	MMpush(m, s3d);



	for(int i=0; i<scene->PclEff.Size(); i++)
    {
		h3d = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(MMget(m,0)),1)), (int)scene->PclEff[i]);
		if (MMpush(m,PTOM(h3d)))		return MERRMEM;
		n++;

		INVERT(m,0,1);
		node = node->next;
	}

	MMpull(m);

	if(MMpush(m,NIL))		return MERRMEM;
	for(j=0;j<n;j++)
	{
    	if (MMpush(m,2*2)) return MERRMEM;
		if (k=MBdeftab(m)) return k;
	}
	
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;
}

//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3listALLFont
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d] [H3d r1]
int ZM3listALLFont(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ZM3listALLFont");
#endif
	// Version MBdeftab non buggée

	int		h3d;
	int		j, k, n, tmp_res;

	n=0;


	int s3d = MMpull(m);
    if(s3d==NIL)			return MMpush(m,NIL);
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)			return MMpush(m,NIL);

	ZNode	*node = scene->World->son;
	if(node==NULL)					{	MMset(m,0,NIL);	return 0;	}

	MMpush(m, s3d);


	for(int i=0; i<scene->FntList.Size(); i++)
    {
		h3d = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(MMget(m,0)),1)), (int)scene->FntList[i]);
		if (MMpush(m,PTOM(h3d)))		return MERRMEM;
		n++;

		INVERT(m,0,1);
		node = node->next;
	}

	MMpull(m);

	if(MMpush(m,NIL))		return MERRMEM;
	for(j=0;j<n;j++)
	{
    	if (MMpush(m,2*2)) return MERRMEM;
		if (k=MBdeftab(m)) return k;
	}
	
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;
}

//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3listALLSkl
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d] [H3d r1]
int ZM3listALLSkl(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ZM3listALLSkl");
#endif
	// Version MBdeftab non buggée

	int		h3d;
	int		j, k, n, tmp_res;

	n=0;


	int s3d = MMpull(m);
    if(s3d==NIL)			return MMpush(m,NIL);
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)			return MMpush(m,NIL);

	ZNode	*node = scene->World->son;
	if(node==NULL)					{	MMset(m,0,NIL);	return 0;	}

	MMpush(m, s3d);

	scene->World->createNodeLists(scene->World);
	for(int i=0; i<scene->World->sklList.Size(); i++)
    {
		h3d = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(MMget(m,0)),1)), (int)scene->World->sklList[i]);
		if (MMpush(m,PTOM(h3d)))		return MERRMEM;
		n++;

		INVERT(m,0,1);
		node = node->next;
	}

	MMpull(m);

	if(MMpush(m,NIL))		return MERRMEM;
	for(j=0;j<n;j++)
	{
    	if (MMpush(m,2*2)) return MERRMEM;
		if (k=MBdeftab(m)) return k;
	}
	
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;
}

//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3listALLSound
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d] [H3d r1]
int ZM3listALLSound(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ZM3listALLSound");
#endif
	// Version MBdeftab non buggée

	int		h3d;
	int		j, k, n, tmp_res;

	n=0;


	int s3d = MMpull(m);
    if(s3d==NIL)			return MMpush(m,NIL);
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)			return MMpush(m,NIL);

	ZNode	*node = scene->World->son;
	if(node==NULL)					{	MMset(m,0,NIL);	return 0;	}

	MMpush(m, s3d);

	scene->World->createNodeLists(scene->World);
	for(int i=0; i<scene->World->sndList.Size(); i++)
    {
		h3d = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(MMget(m,0)),1)), (int)scene->World->sndList[i]);
		if (MMpush(m,PTOM(h3d)))		return MERRMEM;
		n++;

		INVERT(m,0,1);
		node = node->next;
	}

	MMpull(m);

	if(MMpush(m,NIL))		return MERRMEM;
	for(j=0;j<n;j++)
	{
    	if (MMpush(m,2*2)) return MERRMEM;
		if (k=MBdeftab(m)) return k;
	}
	
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;
}

//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3listALLBones
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d] [H3d r1]
int ZM3listALLBones(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ZM3listALLBones");
#endif
	// Version MBdeftab non buggée

	int		h3d;
	int		j, k, n, tmp_res;

	n=0;


	int s3d = MMpull(m);
    if(s3d==NIL)			return MMpush(m,NIL);
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)			return MMpush(m,NIL);

	ZNode	*node = scene->World->son;
	if(node==NULL)					{	MMset(m,0,NIL);	return 0;	}

	MMpush(m, s3d);

	scene->World->createNodeLists(scene->World);
	for(int i=0; i<scene->World->boneList.Size(); i++)
    {
		h3d = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(MMget(m,0)),1)), (int)scene->World->boneList[i]);
		if (MMpush(m,PTOM(h3d)))		return MERRMEM;
		n++;

		INVERT(m,0,1);
		node = node->next;
	}

	MMpull(m);

	if(MMpush(m,NIL))		return MERRMEM;
	for(j=0;j<n;j++)
	{
    	if (MMpush(m,2*2)) return MERRMEM;
		if (k=MBdeftab(m)) return k;
	}
	
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;
}
///////////////////////////////////////////////////////////////////////////////////////////
////																				   ////
///								GESTION GEOMETRIQUE										///
////																				   ////
///////////////////////////////////////////////////////////////////////////////////////////




//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3setObjRange
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d [I I]] I
int ZM3setObjRange(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3setObjRange ");
#endif
    int	rang = MTOP(MMpull(m));
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL)||(rang==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)								{	MMset(m,0,NIL);		return 0;	}

    ZNodeGraph	*node = (ZNodeGraph*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL||node->type==MSH_TYPE_ID)								{	MMset(m,0,NIL);		return 0;	}

	int		rangeMIN = MTOI(MMfetch(m,rang,0));
	int		rangeMAX = MTOI(MMfetch(m,rang,1));

	if( (rangeMIN < 0) || ((rangeMAX < 0)&&(rangeMAX!=RANGE_INFINITY)) )		{	MMset(m,0,NIL);		return 0;	}

	// vecteur à utiliser
	node->rangeMIN = (((float)rangeMIN)/100.0f) * (((float)rangeMIN)/100.0f);

	if(rangeMAX==RANGE_INFINITY)		node->rangeMAX = RANGE_INFINITY;
	else								node->rangeMAX = (((float)rangeMAX)/100.0f) * (((float)rangeMAX)/100.0f);

    MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3setObjRangeF
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d [F F]] I
int ZM3setObjRangeF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3setObjRangeF ");
#endif
	int	rang = MTOP(MMpull(m));
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL)||(rang==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)								{	MMset(m,0,NIL);		return 0;	}

    ZNodeGraph	*node = (ZNodeGraph*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL||node->type==MSH_TYPE_ID)								{	MMset(m,0,NIL);		return 0;	}

	int		rangeMIN = MTOF(MMfetch(m,rang,0));
	int		rangeMAX = MTOF(MMfetch(m,rang,1));

	if( (rangeMIN < 0) || ((rangeMAX < 0)&&(rangeMAX!=RANGE_INFINITY_F)) )		{	MMset(m,0,NIL);		return 0;	}

	// vecteur à utiliser
	node->rangeMIN = (rangeMIN/100.0f) * (rangeMIN/100.0f);
	
	if(rangeMAX==RANGE_INFINITY_F)		node->rangeMAX = RANGE_INFINITY;	// ok !! ligne valide !!
	else								node->rangeMAX = (rangeMAX/100.0f) * (rangeMAX/100.0f);

    MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getObjRange
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d] [I I]
int ZM3getObjRange(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getObjRange ");
#endif

    int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNodeGraph	*node = (ZNodeGraph*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL||node->type==MSH_TYPE_ID)					{	MMset(m,0,NIL);		return 0;	}

	int		rangeMIN = ITOM( AROUNDINT( sqrt(node->rangeMIN) * 100.0f ) );

	int		rangeMAX;
	if(node->rangeMAX < 0)		rangeMAX = ITOM(RANGE_INFINITY);
	else						rangeMAX = ITOM( AROUNDINT( sqrt(node->rangeMAX) * 100.0f ) );


	int tuple = MMmalloc(m, 2, TYPETAB);
	if(tuple==NIL)					{	MMset(m,0,NIL);		return MERRMEM;		}

	MMstore(m, tuple, 0, rangeMIN);
	MMstore(m, tuple, 1, rangeMAX);

    MMset(m,0,PTOM(tuple));
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getObjRangeF
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d] [F F]
int ZM3getObjRangeF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getObjRangeF ");
#endif
    int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNodeGraph	*node = (ZNodeGraph*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL||node->type==MSH_TYPE_ID)					{	MMset(m,0,NIL);		return 0;	}

	int		rangeMIN = FTOM( sqrt(node->rangeMIN) * 100.0f );

	int		rangeMAX;
	if(node->rangeMAX < 0)		rangeMAX = FTOM(RANGE_INFINITY_F);
	else						rangeMAX = FTOM( sqrt(node->rangeMAX) * 100.0f );


	int tuple = MMmalloc(m, 2, TYPETAB);
	if(tuple==NIL)					{	MMset(m,0,NIL);		return MERRMEM;		}
	MMstore(m, tuple, 0, rangeMIN);
	MMstore(m, tuple, 1, rangeMAX);

    MMset(m,0,PTOM(tuple));
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3setObjVec
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d [I I I]] I
int ZM3setObjVec(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3setObjVec ");
#endif
    int	vec  = MTOP(MMpull(m));
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL)||(vec==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNodeGraph	*node = (ZNodeGraph*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL||node->type==MSH_TYPE_ID)					{	MMset(m,0,NIL);		return 0;	}

//	if( (MMfetch(m,vec,0)==NIL) || (MMfetch(m,vec,1)==NIL) || (MMfetch(m,vec,2)==NIL) )			{	MMset(m,0,NIL);		return 0;	}

	// vecteur à utiliser
	ZVector3	vect;
	vect.SetCoord(MTOI(MMfetch(m,vec,0)), MTOI(MMfetch(m,vec,1)), - MTOI(MMfetch(m,vec,2)));

	// utilisation..
	ZPRS	*prs = node->GetPRS();
	prs->SetPos( vect*(1.0f/100.0f) );

    MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3setObjVecF
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d [F F F]] I
int ZM3setObjVecF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3setObjVecF ");
#endif
    int	vec  = MTOP(MMpull(m));
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL)||(vec==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNodeGraph	*node = (ZNodeGraph*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL||node->type==MSH_TYPE_ID)					{	MMset(m,0,NIL);		return 0;	}

//	if( (MMfetch(m,vec,0)==NIL) || (MMfetch(m,vec,1)==NIL) || (MMfetch(m,vec,2)==NIL) )			{	MMset(m,0,NIL);		return 0;	}

	// vecteur à utiliser
	ZVector3	vect;
	vect.SetCoord( MTOF(MMfetch(m,vec,0)), MTOF(MMfetch(m,vec,1)), - MTOF(MMfetch(m,vec,2)));

	// utilisation..
	ZPRS	*prs = node->GetPRS();
	prs->SetPos(vect*(1.0f/100.0f));

    MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getObjVec
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d] [I I I]
int ZM3getObjVec(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getObjVec ");
#endif
    int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNodeGraph	*node = (ZNodeGraph*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL||node->type==MSH_TYPE_ID)					{	MMset(m,0,NIL);		return 0;	}

	ZVector3	vect;

	ZPRS	*prs = node->GetPRS();
	vect = prs->GetPos() * 100.0f;

	int tuple = MMmalloc(m, 3, TYPETAB);
	if(tuple==NIL)				{	MMset(m,0,NIL);		return MERRMEM;		}
	MMstore(m, tuple, 0, ITOM(AROUNDINT(vect.x)));
	MMstore(m, tuple, 1, ITOM(AROUNDINT(vect.y)));
	MMstore(m, tuple, 2, ITOM(AROUNDINT(-vect.z)));

    MMset(m,0,PTOM(tuple));
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getObjVecF
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d] [F F F]
int ZM3getObjVecF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getObjVecF ");
#endif
    int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNodeGraph	*node = (ZNodeGraph*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL||node->type==MSH_TYPE_ID)					{	MMset(m,0,NIL);		return 0;	}

	ZVector3	vect;

	ZPRS	*prs = node->GetPRS();
	vect = prs->GetPos() * 100.0f;

	int tuple = MMmalloc(m, 3, TYPETAB);
	if(tuple==NIL)					{	MMset(m,0,NIL);		return MERRMEM;	}
	MMstore(m, tuple, 0, FTOM(vect.x));
	MMstore(m, tuple, 1, FTOM(vect.y));
	MMstore(m, tuple, 2, FTOM(-vect.z));

    MMset(m,0,PTOM(tuple));
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3setObjAng
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d [I I I]] I
int ZM3setObjAng(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3setObjAng ");
#endif
    int	vec  = MTOP(MMpull(m));
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL)||(vec==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNodeGraph	*node = (ZNodeGraph*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL||node->type==MSH_TYPE_ID)					{	MMset(m,0,NIL);		return 0;	}


//	if( (MMfetch(m,vec,0)==NIL) || (MMfetch(m,vec,1)==NIL) || (MMfetch(m,vec,2)==NIL) )			{	MMset(m,0,NIL);		return 0;	}

	ZVector3	angl;
	angl.SetCoord(MTOI(MMfetch(m,vec,1)), MTOI(MMfetch(m,vec,0)), MTOI(MMfetch(m,vec,2)));
	angl *= 360.0f/CONST_ANGLE;


	ZPRS	*prs = node->GetPRS();
	prs->SetAng( angl );


    MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3setObjAngF
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d [F F F]] I
int ZM3setObjAngF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3setObjAngF ");
#endif
    int	vec  = MTOP(MMpull(m));
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL)||(vec==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)								{	MMset(m,0,NIL);		return 0;	}

    ZNodeGraph	*node = (ZNodeGraph*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL||node->type==MSH_TYPE_ID)								{	MMset(m,0,NIL);		return 0;	}


//	if( (MMfetch(m,vec,0)==NIL) || (MMfetch(m,vec,1)==NIL) || (MMfetch(m,vec,2)==NIL) )			{	MMset(m,0,NIL);		return 0;	}

	ZVector3	angl;
	angl.SetCoord( MTOF(MMfetch(m,vec,1)), MTOF(MMfetch(m,vec,0)), MTOF(MMfetch(m,vec,2)));
	angl *= 180.0f/ MY_PI;


	ZPRS	*prs = node->GetPRS();
	prs->SetAng( angl );


    MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getObjAng
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d] [I I I]
int ZM3getObjAng(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getObjAng ");
#endif
    int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNodeGraph	*node = (ZNodeGraph*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL||node->type==MSH_TYPE_ID)					{	MMset(m,0,NIL);		return 0;	}

	ZVector3	angl;

	ZPRS	*prs = node->GetPRS();
	angl = prs->GetAng() * (CONST_ANGLE/360.0f);


	int tuple = MMmalloc(m, 3, TYPETAB);
	if(tuple==NIL)				{	MMset(m,0,NIL);		return MERRMEM;		}
	MMstore(m, tuple, 0, ITOM(AROUNDINT(angl.y)));
	MMstore(m, tuple, 1, ITOM(AROUNDINT(angl.x)));
	MMstore(m, tuple, 2, ITOM(AROUNDINT(angl.z)));

    MMset(m,0,PTOM(tuple));
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getObjAngF
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d] [F F F]
int ZM3getObjAngF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getObjAngF ");
#endif
    int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNodeGraph	*node = (ZNodeGraph*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL||node->type==MSH_TYPE_ID)					{	MMset(m,0,NIL);		return 0;	}

	ZVector3	angl;

	ZPRS	*prs = node->GetPRS();
	angl = prs->GetAng() * (MY_PI/180.0f);


	int tuple = MMmalloc(m, 3, TYPETAB);
	if(tuple==NIL)				{	MMset(m,0,NIL);		return MERRMEM;		}
	MMstore(m, tuple, 0, FTOM(angl.y));
	MMstore(m, tuple, 1, FTOM(angl.x));
	MMstore(m, tuple, 2, FTOM(angl.z));

    MMset(m,0,PTOM(tuple));
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3setObjScale
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d I] I
int ZM3setObjScale(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3setObjScale ");
#endif
    int	scal = MTOI(MMpull(m));
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL)||(scal==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNodeGraph	*node = (ZNodeGraph*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL||node->type==MSH_TYPE_ID)					{	MMset(m,0,NIL);		return 0;	}

	ZPRS	*prs = node->GetPRS();
	prs->SetScale( ((float)(scal))/100.0f );


    MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3setObjScaleF
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d F] I
int ZM3setObjScaleF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3setObjScaleF ");
#endif
    int	scal = MMpull(m);
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL)||(scal==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNodeGraph	*node = (ZNodeGraph*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL||node->type==MSH_TYPE_ID)					{	MMset(m,0,NIL);		return 0;	}

	ZPRS	*prs = node->GetPRS();
	prs->SetScale( (MTOF(scal))/100.0f );


    MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getObjScale
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d] I
int ZM3getObjScale(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getObjScale ");
#endif
    int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNodeGraph	*node = (ZNodeGraph*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL||node->type==MSH_TYPE_ID)					{	MMset(m,0,NIL);		return 0;	}


	ZPRS	*prs = node->GetPRS();
	float scal = (prs->GetScale() * 100.0f);


    MMset(m,0,ITOM(AROUNDINT(scal)));
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getObjScaleF
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d] F
int ZM3getObjScaleF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getObjScaleF ");
#endif
    int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNodeGraph	*node = (ZNodeGraph*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL||node->type==MSH_TYPE_ID)					{	MMset(m,0,NIL);		return 0;	}


	ZPRS	*prs = node->GetPRS();
	float scal = prs->GetScale() * 100.0f;


    MMset(m,0, FTOM(scal));
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3movObj
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d [I I I]] I
int ZM3movObj(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3movObj ");
#endif
    int	vec  = MTOP(MMpull(m));
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL)||(vec==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNodeGraph	*node = (ZNodeGraph*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL||node->type==MSH_TYPE_ID)					{	MMset(m,0,NIL);		return 0;	}

//	if( (MMfetch(m,vec,0)==NIL) || (MMfetch(m,vec,1)==NIL) || (MMfetch(m,vec,2)==NIL) )			{	MMset(m,0,NIL);		return 0;	}

	ZVector3	vect;
	vect.SetCoord(MTOI(MMfetch(m,vec,0)), MTOI(MMfetch(m,vec,1)), - MTOI(MMfetch(m,vec,2)));



	ZPRS	*prs = node->GetPRS();

	ZMatrix	mat;
	mat  = prs->mat;
	mat.SetTrans(0.0f, 0.0f, 0.0f);
	mat *= ScaleMatrix(1.0f / prs->GetScale());

	prs->AddPos( mat * (vect *(1.0f/100.0f)) );

    MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3movObjF
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d [F F F]] I
int ZM3movObjF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3movObjF ");
#endif
    int	vec  = MTOP(MMpull(m));
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL)||(vec==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNodeGraph	*node = (ZNodeGraph*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL||node->type==MSH_TYPE_ID)					{	MMset(m,0,NIL);		return 0;	}

//	if( (MMfetch(m,vec,0)==NIL) || (MMfetch(m,vec,1)==NIL) || (MMfetch(m,vec,2)==NIL) )			{	MMset(m,0,NIL);		return 0;	}

	ZVector3	vect;
	vect.SetCoord( MTOF(MMfetch(m,vec,0)), MTOF(MMfetch(m,vec,1)), - MTOF(MMfetch(m,vec,2)) );


	ZPRS	*prs = node->GetPRS();

	ZMatrix	mat;
	mat  = prs->mat;
	mat.SetTrans(0.0f, 0.0f, 0.0f);
	mat *= ScaleMatrix(1.0f / prs->GetScale());

	prs->AddPos( mat * (vect *(1.0f/100.0f)) );

    MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3rotateObj
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d [I I I]] I
int ZM3rotateObj(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3rotateObj ");
#endif
    int	ang  = MTOP(MMpull(m));
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL)||(ang==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNodeGraph	*node = (ZNodeGraph*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL||node->type==MSH_TYPE_ID)					{	MMset(m,0,NIL);		return 0;	}

//	if( (MMfetch(m,ang,0)==NIL) || (MMfetch(m,ang,1)==NIL) || (MMfetch(m,ang,2)==NIL) )			{	MMset(m,0,NIL);		return 0;	}

	ZVector3	angl;
	angl.SetCoord( MTOI(MMfetch(m,ang,1)), MTOI(MMfetch(m,ang,0)), MTOI(MMfetch(m,ang,2)));
	angl *= 360.0f/CONST_ANGLE;

	ZMatrix		mat;


	ZPRS	*prs = node->GetPRS();

	mat  = prs->mat;
	mat.SetTrans(0.0f, 0.0f, 0.0f);
	mat *= ScaleMatrix(1.0f / prs->GetScale());
	mat *= RotateYXZMatrix(0.0174532925f * angl);	

	prs->SetAng( mat.GetAnglesYXZ() );

    MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3rotateObjF
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d [F F F]] I
int ZM3rotateObjF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3rotateObjF ");
#endif

    int	ang  = MTOP(MMpull(m));
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL)||(ang==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNodeGraph	*node = (ZNodeGraph*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL||node->type==MSH_TYPE_ID)					{	MMset(m,0,NIL);		return 0;	}

//	if( (MMfetch(m,ang,0)==NIL) || (MMfetch(m,ang,1)==NIL) || (MMfetch(m,ang,2)==NIL) )			{	MMset(m,0,NIL);		return 0;	}

	ZVector3	angl;
	angl.SetCoord( MTOF(MMfetch(m,ang,1)), MTOF(MMfetch(m,ang,0)), MTOF(MMfetch(m,ang,2)));

	ZMatrix		mat;

	ZPRS	*prs = node->GetPRS();

	mat  = prs->mat;
	mat.SetTrans(0.0f, 0.0f, 0.0f);
	mat *= ScaleMatrix(1.0f / prs->GetScale());
	mat *= RotateYXZMatrix(angl);	

	prs->SetAng( mat.GetAnglesYXZ() );

    MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3movObjExt
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d [I I I]] I
int ZM3movObjExt(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3movObjExt ");
#endif
    int	vec  = MTOP(MMpull(m));
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL)||(vec==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNodeGraph	*node = (ZNodeGraph*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL||node->type==MSH_TYPE_ID)					{	MMset(m,0,NIL);		return 0;	}

//	if( (MMfetch(m,vec,0)==NIL) || (MMfetch(m,vec,1)==NIL) || (MMfetch(m,vec,2)==NIL) )			{	MMset(m,0,NIL);		return 0;	}

	ZVector3	vect;
	vect.SetCoord(MTOI(MMfetch(m,vec,0)), MTOI(MMfetch(m,vec,1)), - MTOI(MMfetch(m,vec,2)));

	ZPRS	*prs = node->GetPRS();
	prs->AddPos( vect *(1.0f/100.0f) );

    MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3movObjExtF
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d [F F F]] I
int ZM3movObjExtF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3movObjExtF ");
#endif
    int	vec  = MTOP(MMpull(m));
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL)||(vec==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNodeGraph	*node = (ZNodeGraph*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL||node->type==MSH_TYPE_ID)					{	MMset(m,0,NIL);		return 0;	}

//	if( (MMfetch(m,vec,0)==NIL) || (MMfetch(m,vec,1)==NIL) || (MMfetch(m,vec,2)==NIL) )			{	MMset(m,0,NIL);		return 0;	}

	ZVector3	vect;
	vect.SetCoord( MTOF(MMfetch(m,vec,0)), MTOF(MMfetch(m,vec,1)), - MTOF(MMfetch(m,vec,2)));

	ZPRS	*prs = node->GetPRS();
	prs->AddPos( vect *(1.0f/100.0f) );

    MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3rotateObjExt
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d [I I I]] I
int ZM3rotateObjExt(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3rotateObjExt ");
#endif

    int	vec  = MTOP(MMpull(m));
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL)||(vec==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNodeGraph	*node = (ZNodeGraph*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL||node->type==MSH_TYPE_ID)					{	MMset(m,0,NIL);		return 0;	}

//	if( (MMfetch(m,vec,0)==NIL) || (MMfetch(m,vec,1)==NIL) || (MMfetch(m,vec,2)==NIL) )			{	MMset(m,0,NIL);		return 0;	}

	ZVector3	vect;
	vect.SetCoord( MTOI(MMfetch(m,vec,1)), MTOI(MMfetch(m,vec,0)), MTOI(MMfetch(m,vec,2)));
	vect *= 360.0f/CONST_ANGLE;

	ZPRS	*prs = node->GetPRS();
	prs->AddAng( vect );

    MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3rotateObjExtF
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d [F F F]] I
int ZM3rotateObjExtF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3rotateObjExtF ");
#endif
    int	vec  = MTOP(MMpull(m));
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL)||(vec==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNodeGraph	*node = (ZNodeGraph*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL||node->type==MSH_TYPE_ID)					{	MMset(m,0,NIL);		return 0;	}

//	if( (MMfetch(m,vec,0)==NIL) || (MMfetch(m,vec,1)==NIL) || (MMfetch(m,vec,2)==NIL) )			{	MMset(m,0,NIL);		return 0;	}

	ZVector3	vect;
	vect.SetCoord( MTOF(MMfetch(m,vec,1)), MTOF(MMfetch(m,vec,0)), MTOF(MMfetch(m,vec,2)));
	vect *= 180.0f/MY_PI;

	ZPRS	*prs = node->GetPRS();
	prs->AddAng( vect );

    MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}






//////////////////////////////////////////////////////////////////////////////////////////////
///		ComputeWorldMatrix : calcule la matrice d'un objet dans le World Space
//////////////////////////////////////////////////////////////////////////////////////////////
ZMatrix	ComputeWorldMatrix(ZNode *node)
{
	ZPRS		*prs;
	ZMatrix		mat;
	
	mat.IdentityMatrix();
	
	ZNode		*curNode = node;

	while( curNode->type <= MAX_NODE_SCENE )
	{
		prs = ((ZNodeGraph*)curNode)->GetPRS();		
		mat = prs->mat * mat;
		
		curNode = curNode->father;
	}

	return mat;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3calcMat
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d] I
int ZM3calcMat(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3calcMat ");
#endif
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNodeGraph	*node = (ZNodeGraph*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL||node->type==MSH_TYPE_ID)					{	MMset(m,0,NIL);		return 0;	}


	// Prépare la matrice de l'objet de référence
	ZMatrix		mat = ComputeWorldMatrix(node);
	node->worldMat = mat;
	node->worldPos.SetCoord(mat(0,3), mat(1,3), mat(2,3));



	// ----> Create the lists <---- //
	ZNodeGraph	*father = (ZNodeGraph*) getBigFather(node);

	if( scene->updateGraphList || (scene->lastBaseNodeList != (ZNode*)father) )
	{
		scene->World->createNodeLists(father);								// Create the linear lists of OBJECT & LIGHT & CAMS
		scene->updateGraphList  = false;
		scene->lastBaseNodeList = (ZNode*)father;
	}

	
	// ----> Prepare the NODE matrix inversed <----
	ZMatrix		matx;
	matx = node->worldMat;// * (1.0f/node->worldScale);
	matx._14 = matx._24 = matx._34 = 0.0f;

	ZVector3	angles;
	angles = matx.GetAnglesYXZ();		// YXZ car provient de la matrice de rotation calculée par :  Ry.Rx.Rz

	matx.RotateYXZMatrix(0.0174532925f * angles );
	matx.Transpose();
	matx *= TranslateMatrix(-node->worldPos.x, -node->worldPos.y, -node->worldPos.z);


	// ----> Compute the matrices <----
	scene->World->ComputeMatrices(node, father, matx, 1.0f, true);


#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	

	MMset(m,0,0);
    return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getObjVecRender
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d] [I I I]
int ZM3getObjVecRender(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getObjVecRender ");
#endif

	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNodeGraph	*node = (ZNodeGraph*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL||node->type==MSH_TYPE_ID)					{	MMset(m,0,NIL);		return 0;	}

	ZVector3	pos;

	pos  = node->worldPos;	
	pos *= 100.0f;

	int tuple = MMmalloc(m, 3, TYPETAB);
	if(tuple==NIL)					{	MMset(m,0,NIL);		return MERRMEM;	}
	MMstore(m, tuple, 0, ITOM(AROUNDINT(pos.x)));
	MMstore(m, tuple, 1, ITOM(AROUNDINT(pos.y)));
	MMstore(m, tuple, 2, ITOM(AROUNDINT(-pos.z)));

    MMset(m,0,PTOM(tuple));	
    
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}


//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getObjVecRenderF
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d] [F F F]
int ZM3getObjVecRenderF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getObjVecRenderF ");
#endif

	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNodeGraph	*node = (ZNodeGraph*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL||node->type==MSH_TYPE_ID)					{	MMset(m,0,NIL);		return 0;	}

	ZVector3	pos;

	pos  = node->worldPos;	
	pos *= 100.0f;

	int tuple = MMmalloc(m, 3, TYPETAB);
	if(tuple==NIL)					{	MMset(m,0,NIL);		return MERRMEM;	}
	MMstore(m, tuple, 0, FTOM(pos.x));
	MMstore(m, tuple, 1, FTOM(pos.y));
	MMstore(m, tuple, 2, FTOM(-pos.z));

    MMset(m,0,PTOM(tuple));	
    
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}




//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getObjMatrixRender
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d] [[I I I] [I I I] [I I I]]
int ZM3getObjMatrixRender(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getObjMatrixRender ");
#endif

	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNodeGraph	*node = (ZNodeGraph*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL||node->type==MSH_TYPE_ID)					{	MMset(m,0,NIL);		return 0;	}

	ZMatrix		matx;

	matx = node->worldMat;
	matx *= CONST_ANGLE;

	int ligne1 = MMmalloc(m, 3, TYPETAB);
	if(ligne1==NIL)					{	MMset(m,0,NIL);		return MERRMEM;	}
	MMstore(m, ligne1, 0, ITOM(AROUNDINT(matx._11)));
	MMstore(m, ligne1, 1, ITOM(AROUNDINT(matx._12)));
	MMstore(m, ligne1, 2, ITOM(AROUNDINT(matx._13)));

	MMpush(m, PTOM(ligne1));
	int ligne2 = MMmalloc(m, 3, TYPETAB);
	if(ligne2==NIL)					{	MMset(m,0,NIL);		return MERRMEM;	}
	MMstore(m, ligne2, 0, ITOM(AROUNDINT(matx._21)));
	MMstore(m, ligne2, 1, ITOM(AROUNDINT(matx._22)));
	MMstore(m, ligne2, 2, ITOM(AROUNDINT(matx._23)));

	MMpush(m, PTOM(ligne2));
	int ligne3 = MMmalloc(m, 3, TYPETAB);
	if(ligne3==NIL)					{	MMset(m,0,NIL);		return MERRMEM;	}
	MMstore(m, ligne3, 0, ITOM(AROUNDINT(matx._31)));
	MMstore(m, ligne3, 1, ITOM(AROUNDINT(matx._32)));
	MMstore(m, ligne3, 2, ITOM(AROUNDINT(matx._33)));

	// TUPLE FINAL
	MMpush(m, PTOM(ligne3));
	int matrice = MMmalloc(m, 3, TYPETAB);
	if(matrice==NIL)					{	MMset(m,0,NIL);		return MERRMEM;	}
	MMstore(m, matrice, 2, MMpull(m) );
	MMstore(m, matrice, 1, MMpull(m) );
	MMstore(m, matrice, 0, MMpull(m) );


    MMset(m,0,PTOM(matrice));	
    
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getObjMatrixRenderF
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d] [[F F F] [F F F] [F F F]]
int ZM3getObjMatrixRenderF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getObjMatrixRenderF ");
#endif

	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNodeGraph	*node = (ZNodeGraph*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL||node->type==MSH_TYPE_ID)					{	MMset(m,0,NIL);		return 0;	}

	ZMatrix		matx;

	matx = node->worldMat;

	int ligne1 = MMmalloc(m, 3, TYPETAB);
	if(ligne1==NIL)					{	MMset(m,0,NIL);		return MERRMEM;	}
	MMstore(m, ligne1, 0, FTOM(matx._11));
	MMstore(m, ligne1, 1, FTOM(matx._12));
	MMstore(m, ligne1, 2, FTOM(matx._13));

	MMpush(m, PTOM(ligne1));
	int ligne2 = MMmalloc(m, 3, TYPETAB);
	if(ligne2==NIL)					{	MMset(m,0,NIL);		return MERRMEM;	}
	MMstore(m, ligne2, 0, FTOM(matx._21));
	MMstore(m, ligne2, 1, FTOM(matx._22));
	MMstore(m, ligne2, 2, FTOM(matx._23));

	MMpush(m, PTOM(ligne2));
	int ligne3 = MMmalloc(m, 3, TYPETAB);
	if(ligne3==NIL)					{	MMset(m,0,NIL);		return MERRMEM;	}
	MMstore(m, ligne3, 0, FTOM(matx._31));
	MMstore(m, ligne3, 1, FTOM(matx._32));
	MMstore(m, ligne3, 2, FTOM(matx._33));

	// TUPLE FINAL
	MMpush(m, PTOM(ligne3));
	int matrice = MMmalloc(m, 3, TYPETAB);
	if(matrice==NIL)					{	MMset(m,0,NIL);		return MERRMEM;	}
	MMstore(m, matrice, 2, MMpull(m) );
	MMstore(m, matrice, 1, MMpull(m) );
	MMstore(m, matrice, 0, MMpull(m) );


    MMset(m,0,PTOM(matrice));	
    
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getCamera
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d] [[I I] [I I] [I I I]]
int ZM3getCamera(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getCamera ");
#endif
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=CAM_TYPE_ID))			{	MMset(m,0,NIL);		return 0;	}

	ZCamera	 *cam  = (ZCamera*)node;
	float	 coeff = 100.0f;

	int dist = MMmalloc(m, 2, TYPETAB);
	if(dist==NIL)					{	MMset(m,0,NIL);		return MERRMEM;	}
	MMstore(m, dist, 0, ITOM(cam->dx));
	MMstore(m, dist, 1, ITOM(cam->dy));

	MMpush(m, PTOM(dist));
	int taille = MMmalloc(m, 2, TYPETAB);
	if(taille==NIL)					{	MMset(m,0,NIL);		return MERRMEM;	}
	MMstore(m, taille, 0, ITOM(cam->width/2));
	MMstore(m, taille, 1, ITOM(cam->height/2));

	MMpush(m, PTOM(taille));
	int Zprop = MMmalloc(m, 3, TYPETAB);
	if(Zprop==NIL)					{	MMset(m,0,NIL);		return MERRMEM;	}
	MMstore(m, Zprop, 0, ITOM(AROUNDINT(cam->Znear*coeff)));
	MMstore(m, Zprop, 1, ITOM(AROUNDINT(cam->Zfog*coeff)));
	MMstore(m, Zprop, 2, ITOM(AROUNDINT(cam->Zfar*coeff)));

	// TUPLE FINAL
	MMpush(m, PTOM(Zprop));
	int result = MMmalloc(m, 3, TYPETAB);
	if(result==NIL)					{	MMset(m,0,NIL);		return MERRMEM;	}
	MMstore(m, result, 2, MMpull(m) );
	MMstore(m, result, 1, MMpull(m) );
	MMstore(m, result, 0, MMpull(m) );


    MMset(m,0,PTOM(result));	

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3setCamera
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d [[I I] [I I] [I I I]] ] I
int ZM3setCamera(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3setCamera ");
#endif

	int info = MMpull(m);
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL)||(info==NIL))				{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=CAM_TYPE_ID))			{	MMset(m,0,NIL);		return 0;	}
	ZCamera	 *cam  = (ZCamera*)node;

	int data, res;

	data = MTOP(MMfetch(m,MTOP(info),0));
	if(data!=NIL)
	{
		res = MTOI(MMfetch(m,data,0));		if(res>0)	cam->dx = res;
		res = MTOI(MMfetch(m,data,1));		if(res>0)	cam->dy = res;
	}

	data = MTOP(MMfetch(m,MTOP(info),1));
	if(data!=NIL)
	{
		res = MTOI(MMfetch(m,data,0));		if(res>0)	cam->width  = res*2;
		res = MTOI(MMfetch(m,data,1));		if(res>0)	cam->height = res*2;
	}

	float	coeff = 100.0f;
	data = MTOP(MMfetch(m,MTOP(info),2));
	if(data!=NIL)
	{
		res = MTOI(MMfetch(m,data,0));		if(res>0)	cam->Znear = ((float)res) / coeff;
		res = MTOI(MMfetch(m,data,1));		if(res>0)	cam->Zfog  = ((float)res) / coeff;
		res = MTOI(MMfetch(m,data,2));		if(res>0)	cam->Zfar  = ((float)res) / coeff;
	}

	MMset(m,0,0);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3calcPosRef
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d H3d] [[I I I] [[I I I][I I I][I I I]]]
int ZM3calcPosRef(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3calcPosRef ");
#endif

	int ref  = MMpull(m);
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL)||(ref==NIL))				{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL||node->type==MSH_TYPE_ID)					{	MMset(m,0,NIL);		return 0;	}

    ZNode	*refer = (ZNode*) MMfetch(m,MTOP(ref),0);
	if(refer==NULL||refer->type==MSH_TYPE_ID)					{	MMset(m,0,NIL);		return 0;	}


	ZMatrix		refMat = ComputeWorldMatrix(refer);
	refMat.Inverse();
	ZMatrix		result = refMat * ComputeWorldMatrix(node);


	// CALCUL DE LA POSITION
	// attention le coeffM3D de la PRS est pris à 100.0f ICI !!!!!
	int posi = MMmalloc(m, 3, TYPETAB);
	if(posi==NIL)					{	MMset(m,0,NIL);		return MERRMEM;	}
	MMstore(m, posi, 0, ITOM(AROUNDINT(100.0f*result(0,3))) );
	MMstore(m, posi, 1, ITOM(AROUNDINT(100.0f*result(1,3))) );
	MMstore(m, posi, 2, ITOM(AROUNDINT(-100.0f*result(2,3))) );


	// CALCUL DE LA MATRICE
	result *= CONST_ANGLE;

	MMpush(m, PTOM(posi));

	int ligne1 = MMmalloc(m, 3, TYPETAB);
	if(ligne1==NIL)					{	MMset(m,0,NIL);		return MERRMEM;	}
	MMstore(m, ligne1, 0, ITOM(AROUNDINT(result._11)));
	MMstore(m, ligne1, 1, ITOM(AROUNDINT(result._12)));
	MMstore(m, ligne1, 2, ITOM(AROUNDINT(result._13)));

	MMpush(m, PTOM(ligne1));
	int ligne2 = MMmalloc(m, 3, TYPETAB);
	if(ligne2==NIL)					{	MMset(m,0,NIL);		return MERRMEM;	}
	MMstore(m, ligne2, 0, ITOM(AROUNDINT(result._21)));
	MMstore(m, ligne2, 1, ITOM(AROUNDINT(result._22)));
	MMstore(m, ligne2, 2, ITOM(AROUNDINT(result._23)));

	MMpush(m, PTOM(ligne2));
	int ligne3 = MMmalloc(m, 3, TYPETAB);
	if(ligne3==NIL)					{	MMset(m,0,NIL);		return MERRMEM;	}
	MMstore(m, ligne3, 0, ITOM(AROUNDINT(result._31)));
	MMstore(m, ligne3, 1, ITOM(AROUNDINT(result._32)));
	MMstore(m, ligne3, 2, ITOM(AROUNDINT(result._33)));

	MMpush(m, PTOM(ligne3));
	int matrice = MMmalloc(m, 3, TYPETAB);
	if(matrice==NIL)					{	MMset(m,0,NIL);		return MERRMEM;	}
	MMstore(m, matrice, 2, MMpull(m) );
	MMstore(m, matrice, 1, MMpull(m) );
	MMstore(m, matrice, 0, MMpull(m) );


	// CREATION DU TUPLE FINAL
	MMpush(m, PTOM(matrice));
	int tuple = MMmalloc(m, 2, TYPETAB);
	if(tuple==NIL)					{	MMset(m,0,NIL);		return MERRMEM;	}
	MMstore(m, tuple, 1, MMpull(m) );
	MMstore(m, tuple, 0, MMpull(m) );


	MMset(m,0,PTOM(tuple));
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}


//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3calcPosRefF
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d H3d] [[F F F] [[F F F][F F F][F F F]]]
int ZM3calcPosRefF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3calcPosRefF ");
#endif

	int ref  = MMpull(m);
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL)||(ref==NIL))				{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL||node->type==MSH_TYPE_ID)					{	MMset(m,0,NIL);		return 0;	}

    ZNode	*refer = (ZNode*) MMfetch(m,MTOP(ref),0);
	if(refer==NULL||refer->type==MSH_TYPE_ID)					{	MMset(m,0,NIL);		return 0;	}


	ZMatrix		refMat = ComputeWorldMatrix(refer);
	refMat.Inverse();
	ZMatrix		result = refMat * ComputeWorldMatrix(node);


	// CALCUL DE LA POSITION
	int posi = MMmalloc(m, 3, TYPETAB);
	if(posi==NIL)					{	MMset(m,0,NIL);		return MERRMEM;	}
	MMstore(m, posi, 0, FTOM(100.0f*result(0,3))  );
	MMstore(m, posi, 1, FTOM(100.0f*result(1,3))  );
	MMstore(m, posi, 2, FTOM(-100.0f*result(2,3)) );


	// CALCUL DE LA MATRICE
	MMpush(m, PTOM(posi));

	int ligne1 = MMmalloc(m, 3, TYPETAB);
	if(ligne1==NIL)					{	MMset(m,0,NIL);		return MERRMEM;	}
	MMstore(m, ligne1, 0, FTOM(result._11));
	MMstore(m, ligne1, 1, FTOM(result._12));
	MMstore(m, ligne1, 2, FTOM(result._13));

	MMpush(m, PTOM(ligne1));
	int ligne2 = MMmalloc(m, 3, TYPETAB);
	if(ligne2==NIL)					{	MMset(m,0,NIL);		return MERRMEM;	}
	MMstore(m, ligne2, 0, FTOM(result._21));
	MMstore(m, ligne2, 1, FTOM(result._22));
	MMstore(m, ligne2, 2, FTOM(result._23));

	MMpush(m, PTOM(ligne2));
	int ligne3 = MMmalloc(m, 3, TYPETAB);
	if(ligne3==NIL)					{	MMset(m,0,NIL);		return MERRMEM;	}
	MMstore(m, ligne3, 0, FTOM(result._31));
	MMstore(m, ligne3, 1, FTOM(result._32));
	MMstore(m, ligne3, 2, FTOM(result._33));

	MMpush(m, PTOM(ligne3));
	int matrice = MMmalloc(m, 3, TYPETAB);
	if(matrice==NIL)				{	MMset(m,0,NIL);		return MERRMEM;	}
	MMstore(m, matrice, 2, MMpull(m) );
	MMstore(m, matrice, 1, MMpull(m) );
	MMstore(m, matrice, 0, MMpull(m) );


	// CREATION DU TUPLE FINAL
	MMpush(m, PTOM(matrice));
	int tuple = MMmalloc(m, 2, TYPETAB);
	if(tuple==NIL)					{	MMset(m,0,NIL);		return MERRMEM;	}
	MMstore(m, tuple, 1, MMpull(m) );
	MMstore(m, tuple, 0, MMpull(m) );


	MMset(m,0,PTOM(tuple));
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3angularFromMatrix
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [ [[I I I][I I I][I I I]] ]	[I I I]
int ZM3angularFromMatrix(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3angularFromMatrix ");
#endif

	ZMatrix		mat;
	ZVector3	angl;
	
	mat.IdentityMatrix();

	int	matrix = MTOP(MMget(m,0));
	if((matrix==NIL)||(MMfetch(m,matrix,0)==NIL)||(MMfetch(m,matrix,1)==NIL)||(MMfetch(m,matrix,2)==NIL))		{	MMset(m,0,NIL);		return 0;	}


	int	ligne = MTOP(MMfetch(m,matrix,0));
	if( (MMfetch(m,ligne,0)==NIL) || (MMfetch(m,ligne,1)==NIL) || (MMfetch(m,ligne,2)==NIL) )			{	MMset(m,0,NIL);		return 0;	}
	mat._11 = ((float)(MTOI(MMfetch(m,ligne,0)))) / CONST_ANGLE;
	mat._12 = ((float)(MTOI(MMfetch(m,ligne,1)))) / CONST_ANGLE;
	mat._13 = ((float)(MTOI(MMfetch(m,ligne,2)))) / CONST_ANGLE;

	ligne = MTOP(MMfetch(m,matrix,1));
	if( (MMfetch(m,ligne,0)==NIL) || (MMfetch(m,ligne,1)==NIL) || (MMfetch(m,ligne,2)==NIL) )			{	MMset(m,0,NIL);		return 0;	}
	mat._21 = ((float)(MTOI(MMfetch(m,ligne,0)))) / CONST_ANGLE;
	mat._22 = ((float)(MTOI(MMfetch(m,ligne,1)))) / CONST_ANGLE;
	mat._23 = ((float)(MTOI(MMfetch(m,ligne,2)))) / CONST_ANGLE;

	ligne = MTOP(MMfetch(m,matrix,2));
	if( (MMfetch(m,ligne,0)==NIL) || (MMfetch(m,ligne,1)==NIL) || (MMfetch(m,ligne,2)==NIL) )			{	MMset(m,0,NIL);		return 0;	}
	mat._31 = ((float)(MTOI(MMfetch(m,ligne,0)))) / CONST_ANGLE;
	mat._32 = ((float)(MTOI(MMfetch(m,ligne,1)))) / CONST_ANGLE;
	mat._33 = ((float)(MTOI(MMfetch(m,ligne,2)))) / CONST_ANGLE;

	//angl  = mat.GetAnglesZXY();
	angl  = mat.GetAnglesYXZ();
	angl *= CONST_ANGLE / 360.0f;

	// CREATION DU TUPLE FINAL
	int tuple = MMmalloc(m, 3, TYPETAB);
	if(tuple==NIL)					{	MMset(m,0,NIL);		return MERRMEM;	}
	MMstore(m, tuple, 0, ITOM(AROUNDINT(angl.y)));
	MMstore(m, tuple, 1, ITOM(AROUNDINT(angl.x)));
	MMstore(m, tuple, 2, ITOM(AROUNDINT(angl.z)));

	MMset(m,0,PTOM(tuple));

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3angularFromMatrixF
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [ [[F F F][F F F][F F F]] ]	[F F F]
int ZM3angularFromMatrixF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3angularFromMatrixF ");
#endif

	ZMatrix		mat;
	ZVector3	angl;
	
	mat.IdentityMatrix();

	int	matrix = MTOP(MMget(m,0));
	if((matrix==NIL)||(MMfetch(m,matrix,0)==NIL)||(MMfetch(m,matrix,1)==NIL)||(MMfetch(m,matrix,2)==NIL))		{	MMset(m,0,NIL);		return 0;	}


	int	ligne = MTOP(MMfetch(m,matrix,0));
	if( (MMfetch(m,ligne,0)==NIL) || (MMfetch(m,ligne,1)==NIL) || (MMfetch(m,ligne,2)==NIL) )			{	MMset(m,0,NIL);		return 0;	}
	mat._11 = FTOM(MMfetch(m,ligne,0));
	mat._12 = FTOM(MMfetch(m,ligne,1));
	mat._13 = FTOM(MMfetch(m,ligne,2));

	ligne = MTOP(MMfetch(m,matrix,1));
	if( (MMfetch(m,ligne,0)==NIL) || (MMfetch(m,ligne,1)==NIL) || (MMfetch(m,ligne,2)==NIL) )			{	MMset(m,0,NIL);		return 0;	}
	mat._21 = FTOM(MMfetch(m,ligne,0));
	mat._22 = FTOM(MMfetch(m,ligne,1));
	mat._23 = FTOM(MMfetch(m,ligne,2));

	ligne = MTOP(MMfetch(m,matrix,2));
	if( (MMfetch(m,ligne,0)==NIL) || (MMfetch(m,ligne,1)==NIL) || (MMfetch(m,ligne,2)==NIL) )			{	MMset(m,0,NIL);		return 0;	}
	mat._31 = FTOM(MMfetch(m,ligne,0));
	mat._32 = FTOM(MMfetch(m,ligne,1));
	mat._33 = FTOM(MMfetch(m,ligne,2));

	//angl  = mat.GetAnglesZXY();
	angl  = mat.GetAnglesYXZ();
	angl *= (MY_PI/180.0f);

	// CREATION DU TUPLE FINAL
	int tuple = MMmalloc(m, 3, TYPETAB);
	if(tuple==NIL)					{	MMset(m,0,NIL);		return MERRMEM;	}
	MMstore(m, tuple, 0, FTOM(angl.y));
	MMstore(m, tuple, 1, FTOM(angl.x));
	MMstore(m, tuple, 2, FTOM(angl.z));

	MMset(m,0,PTOM(tuple));
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getRadius
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d] I
int ZM3getRadius(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getRadius ");
#endif
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||((node->type!=OBJ_TYPE_ID)&&(node->type!=MSH_TYPE_ID)))	{	MMset(m,0,NIL);		return 0;	}
	if( ((ZObject*)node)->GetMesh() == NULL)										{	MMset(m,0,NIL);		return 0;	}

	vector<ZVert>		*verts;
	if(node->type == OBJ_TYPE_ID)		verts = &(((ZObject*)node)->GetMesh()->Verts);
	else								verts = &(((ZMesh*)node)->Verts);

	float	dist = 0;
	for(int i=0; i<verts->size(); i++)			if(dist < (*verts)[i].Length())		dist = (*verts)[i].Length();

	MMset(m,0,ITOM(AROUNDINT(dist*100.0f)));
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getRadiusF
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d] F
int ZM3getRadiusF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getRadiusF ");
#endif
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||((node->type!=OBJ_TYPE_ID)&&(node->type!=MSH_TYPE_ID)))	{	MMset(m,0,NIL);		return 0;	}
	if( ((ZObject*)node)->GetMesh() == NULL)										{	MMset(m,0,NIL);		return 0;	}

	vector<ZVert>		*verts;
	if(node->type == OBJ_TYPE_ID)		verts = &(((ZObject*)node)->GetMesh()->Verts);
	else								verts = &(((ZMesh*)node)->Verts);

	float	dist = 0;
	for(int i=0; i<verts->size(); i++)			if(dist < (*verts)[i].Length())		dist = (*verts)[i].Length();

	MMset(m,0, FTOM(dist*100.0f));
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3calcProj
//////////////////////////////////////////////////////////////////////////////////////////////
//	fun [S3d H3d H3d] [I I I I]
//	calcule la projection d'un objet sur une camera (x,y) ecran et z
//	le rayon apparent, et pose NIL sur la pile si objet invisible ou erreur
int ZM3calcProj(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3calcProj ");
#endif
	int h3d  = MMpull(m);
	int cam  = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL)||(cam==NIL))				{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)										{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if( (node==NULL) ||
		((node->type!=OBJ_TYPE_ID)&&(node->type!=CAM_TYPE_ID)&&(node->type!=LGH_TYPE_ID)&&
		 (node->type!=SHL_TYPE_ID)&&(node->type!=COL_TYPE_ID)&&(node->type!=SPR_TYPE_ID)&&
		 (node->type!=PCL_TYPE_ID)&&(node->type!=SND_TYPE_ID)))
														{	MMset(m,0,NIL);		return 0;	}

    ZNode	*camer = (ZNode*) MMfetch(m,MTOP(cam),0);
	if((camer==NULL)||(camer->type!=CAM_TYPE_ID))		{	MMset(m,0,NIL);		return 0;	}

	int tuple = MMmalloc(m, 4, TYPETAB);
	if(tuple==NIL)										{	MMset(m,0,NIL);		return MERRMEM;	}
	for(int iii=0; iii<4; iii++)	MMstore(m, tuple, iii, NIL);


	// Calcul de la position projetée
	ZMatrix		objMat = ComputeWorldMatrix(node);

	ZVector3	worldPos;
	worldPos.SetCoord(objMat(0,3), objMat(1,3), objMat(2,3));

	ZCamera		*curCam = (ZCamera*)camer;
	curCam->worldMat = ComputeWorldMatrix(camer);
	curCam->worldPos.SetCoord(curCam->worldMat(0,3), curCam->worldMat(1,3), curCam->worldMat(2,3));
	curCam->ComputeMatrix();

	worldPos *= curCam->cameraMatx;


	// utilisation des clipping BACK et FRONT
	if((-worldPos.z<curCam->Znear)||(-worldPos.z>curCam->Zfar))				{	MMset(m,0,NIL);		return 0;	}
	MMstore(m, tuple, 2, ITOM(AROUNDINT(-worldPos.z*100.0f)));


	// On projette la position 3D sur le plan Znear (Thalès)
	float	coeff = -curCam->Znear / worldPos.z;
	worldPos *= coeff;

	// On calcule les valeurs des bords écran en 3D (plan Znear)
	float	top		= curCam->Znear * ((double)(curCam->height/2)) / ((double)curCam->dy);
	float	right	= top * ((float)curCam->width / (float)curCam->height);

	// On détermine les positions écran finales
	float	posX =  (curCam->width *worldPos.x) / (2.0f*right);
	float	posY =  (curCam->height*worldPos.y) / (2.0f*top);
	MMstore(m, tuple, 0, ITOM(AROUNDINT(posX)));
	MMstore(m, tuple, 1, ITOM(AROUNDINT(posY)));

	// Rayon apparent
	if(node->type!=OBJ_TYPE_ID)			MMstore(m, tuple, 3, 0);
	else
	{
		ZMesh*	msh = ((ZObject*)node)->GetMesh();

		if(msh)
		{
			float	rayon = (msh->xmax - msh->xmin)*(msh->xmax - msh->xmin) + (msh->ymax - msh->ymin)*(msh->ymax - msh->ymin) + (msh->zmax - msh->zmin)*(msh->zmax - msh->zmin);
			rayon = coeff * sqrt(rayon) / 2.0f;

			float	rayonX = (curCam->width *rayon) / (2.0f*right);
			float	rayonY = (curCam->height*rayon) / (2.0f*top);

			if(rayonX > rayonY)			MMstore(m, tuple, 3, ITOM(AROUNDINT(rayonX)));
			else						MMstore(m, tuple, 3, ITOM(AROUNDINT(rayonY)));
		}
		else
			MMstore(m, tuple, 3, NIL);
	}


	MMset(m,0,PTOM(tuple));
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3calcProjF
//////////////////////////////////////////////////////////////////////////////////////////////
//	fun [S3d H3d H3d] [I I F F]
//	calcule la projection d'un objet sur une camera (x,y) ecran et z
//	le rayon apparent, et pose NIL sur la pile si objet invisible ou erreur
int ZM3calcProjF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3calcProjF ");
#endif
	int h3d  = MMpull(m);
	int cam  = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL)||(cam==NIL))				{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)										{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if( (node==NULL) ||
		((node->type!=OBJ_TYPE_ID)&&(node->type!=CAM_TYPE_ID)&&(node->type!=LGH_TYPE_ID)&&
		 (node->type!=SHL_TYPE_ID)&&(node->type!=COL_TYPE_ID)&&(node->type!=SPR_TYPE_ID)&&
		 (node->type!=PCL_TYPE_ID)&&(node->type!=SND_TYPE_ID)))
														{	MMset(m,0,NIL);		return 0;	}

    ZNode	*camer = (ZNode*) MMfetch(m,MTOP(cam),0);
	if((camer==NULL)||(camer->type!=CAM_TYPE_ID))		{	MMset(m,0,NIL);		return 0;	}

	int tuple = MMmalloc(m, 4, TYPETAB);
	if(tuple==NIL)										{	MMset(m,0,NIL);		return MERRMEM;	}
	for(int iii=0; iii<4; iii++)	MMstore(m, tuple, iii, NIL);


	// Calcul de la position projetée
	ZMatrix		objMat = ComputeWorldMatrix(node);

	ZVector3	worldPos;
	worldPos.SetCoord(objMat(0,3), objMat(1,3), objMat(2,3));

	ZCamera		*curCam = (ZCamera*)camer;
	curCam->worldMat = ComputeWorldMatrix(camer);
	curCam->worldPos.SetCoord(curCam->worldMat(0,3), curCam->worldMat(1,3), curCam->worldMat(2,3));
	curCam->ComputeMatrix();

	worldPos *= curCam->cameraMatx;


	// utilisation des clipping BACK et FRONT
	if((-worldPos.z<curCam->Znear)||(-worldPos.z>curCam->Zfar))				{	MMset(m,0,NIL);		return 0;	}
	MMstore(m, tuple, 2, FTOM(-worldPos.z*100.0f) );


	// On projette la position 3D sur le plan Znear (Thalès)
	float	coeff = -curCam->Znear / worldPos.z;
	worldPos *= coeff;

	// On calcule les valeurs des bords écran en 3D (plan Znear)
	float	top		= curCam->Znear * ((double)(curCam->height/2)) / ((double)curCam->dy);
	float	right	= top * ((float)curCam->width / (float)curCam->height);

	// On détermine les positions écran finales
	float	posX =  (curCam->width *worldPos.x) / (2.0f*right);
	float	posY =  (curCam->height*worldPos.y) / (2.0f*top);
	MMstore(m, tuple, 0, ITOM(AROUNDINT(posX)));
	MMstore(m, tuple, 1, ITOM(AROUNDINT(posY)));

	// Rayon apparent
	if(node->type!=OBJ_TYPE_ID)			MMstore(m, tuple, 3, 0);
	else
	{
		ZMesh*	msh = ((ZObject*)node)->GetMesh();

		if(msh)
		{
			float	rayon = (msh->xmax - msh->xmin)*(msh->xmax - msh->xmin) + (msh->ymax - msh->ymin)*(msh->ymax - msh->ymin) + (msh->zmax - msh->zmin)*(msh->zmax - msh->zmin);
			rayon = coeff * sqrt(rayon) / 2.0f;

			float	rayonX = (curCam->width *rayon) / (2.0f*right);
			float	rayonY = (curCam->height*rayon) / (2.0f*top);

			if(rayonX > rayonY)			MMstore(m, tuple, 3, FTOM(rayonX));
			else						MMstore(m, tuple, 3, FTOM(rayonY));
		}
		else
			MMstore(m, tuple, 3, NIL);
	}


	MMset(m,0,PTOM(tuple));
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3areMeshesCulled
//////////////////////////////////////////////////////////////////////////////////////////////
//	Cette fonction n'est utilisable qu'après un rendu à l'écran : elle utilise la camera qui a permis le rendu
//
//	fun [S3d H3d [H3d r1]] [I r1]
//
int ZM3areMeshesCulled(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3areMeshesCulled ");
#endif
	int list = MTOP(MMpull(m));
	int h3d  = MMpull(m);
    int s3d  = MMpull(m);

	if((s3d==NIL)||(h3d==NIL)||(list==NIL))					{	MMpush(m,NIL);	return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)											{	MMpush(m,NIL);	return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if( (node==NULL) ||(node->type!=OBJ_TYPE_ID) )			{	MMpush(m,NIL);	return 0;	}
	ZObject	*obj = (ZObject*) node;

	if(scene->activeCam == NULL)							{	MMpush(m,NIL);	return 0;	}

	ZVector3	origine, rayon;
	float		distanceTmp;
	int			curH3D, tmp_res;
	int			n=0;

	while(list!=NIL)
	{
		curH3D = MTOP(MMfetch(m,list,0));
		node = (ZNode*) MMfetch(m, curH3D, 0);

		if( node && (node->type==OBJ_TYPE_ID) && (((ZObject*)node)->GetMesh()) )
		{
			origine = scene->activeCam->worldPos;
			rayon	= ((ZObject*)node)->worldPos;
			distanceTmp = rayon.Length();

			if( TestObject(scene->activeCam->worldMat, obj, origine, rayon, &distanceTmp, scene->activeCam->Znear, NULL, NULL, NULL, NULL) )
			{
				// "obj" cache le curH3D
				if(MMpush(m, PTOM(list)))		return MERRMEM;
				if(MMpush(m, ITOM(1)))			return MERRMEM;
				INVERT(m,0,1);
				list = MTOP(MMpull(m));
			}
			else
			{
				// "obj" ne cache pas le curH3D
				if(MMpush(m, PTOM(list)))		return MERRMEM;
				if(MMpush(m, 0))				return MERRMEM;
				INVERT(m,0,1);
				list = MTOP(MMpull(m));
			}
		}
		else
		{
			if(MMpush(m, PTOM(list)))		return MERRMEM;
			if(MMpush(m,NIL))				return MERRMEM;
			INVERT(m,0,1);
			list = MTOP(MMpull(m));
		}

		list = MTOP(MMfetch(m,list,1));
		n++;
	}

	int k;

	if(MMpush(m,NIL))		return MERRMEM;
	for(int j=0; j<n; j++)
	{
    	if(MMpush(m,2*2))		return MERRMEM;
		if(k=MBdeftab(m))		return k;
	}
	
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3isMeshCulledByOthers
//////////////////////////////////////////////////////////////////////////////////////////////
//	Cette fonction n'est utilisable qu'après un rendu à l'écran : elle utilise la camera qui a permis le rendu
//
//	fun [S3d H3d [H3d r1]] [I r1]
//
int ZM3isMeshCulledByOthers(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3isMeshCulledByOthers ");
#endif

//	_asm{int 3};

	int list = MTOP(MMpull(m));
	int h3d  = MMpull(m);
    int s3d  = MMpull(m);

	if((s3d==NIL)||(h3d==NIL)||(list==NIL))					{	MMpush(m,NIL);	return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)											{	MMpush(m,NIL);	return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if( (node==NULL) ||(node->type!=OBJ_TYPE_ID) )			{	MMpush(m,NIL);	return 0;	}
	ZObject	*obj = (ZObject*) node;

	if(scene->activeCam == NULL)							{	MMpush(m,NIL);	return 0;	}

	ZVector3	origine, rayon;
	float		distanceTmp;
	int			curH3D, tmp_res;
	int			n=0;


	while(list!=NIL)
	{
		curH3D = MTOP(MMfetch(m,list,0));
		node = (ZNode*) MMfetch(m, curH3D, 0);

		if( node && (node->type==OBJ_TYPE_ID) && (((ZObject*)node)->GetMesh()) )
		{
			//origine = scene->activeCam->worldPos;
			origine.SetNull();
			rayon	= obj->worldPos;
			distanceTmp = rayon.Length();
			rayon.Normalize();

			if( TestObject(scene->activeCam->worldMat, (ZObject*)node, origine, rayon, &distanceTmp, scene->activeCam->Znear, NULL, NULL, NULL, NULL) )
			{
				// "obj" est caché par le curH3D
				if(MMpush(m, PTOM(list)))		return MERRMEM;
				if(MMpush(m, ITOM(1)))			return MERRMEM;
				INVERT(m,0,1);
				list = MTOP(MMpull(m));
			}
			else
			{
				// "obj" n'est pas caché par le curH3D
				if(MMpush(m, PTOM(list)))		return MERRMEM;
				if(MMpush(m, 0))				return MERRMEM;
				INVERT(m,0,1);
				list = MTOP(MMpull(m));
			}
		}
		else
		{
			if(MMpush(m, PTOM(list)))		return MERRMEM;
			if(MMpush(m,NIL))				return MERRMEM;
			INVERT(m,0,1);
			list = MTOP(MMpull(m));
		}

		list = MTOP(MMfetch(m,list,1));
		n++;
	}


	int k;

	if(MMpush(m,NIL))		return MERRMEM;
	for(int j=0; j<n; j++)
	{
    	if(MMpush(m,2*2))		return MERRMEM;
		if(k=MBdeftab(m))		return k;
	}

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}




//////////////////////////////////////////////////////////////////////////////////////////////
///		AngularTarget
//////////////////////////////////////////////////////////////////////////////////////////////
//	positionnement d'un objet vers une cible determinee
ZVector3 AngularTarget(ZVector3 src, ZVector3 dest)
{
	ZVector3	angl;
	float		dx, dy, dh, d;

	dx =  dest.z - src.z;
	dy = -dest.x + src.x;
	dh =  dest.y - src.y;

	d = sqrt(dx*dx+dy*dy);

	if(d>0.001f)
	{
		angl.y = atan2(dy,dx) * 32768.0f / 3.14159f;
		d = sqrt(dx*dx+dy*dy);
		angl.x = atan(dh/d) * 32768.0f / 3.14159f;
	}
	else
	{
		angl.x = 0;
		angl.y = 0;
	}
	angl.z = 0;

	return angl;
}
//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3angularTarget
//////////////////////////////////////////////////////////////////////////////////////////////
//	fun [[I I I] [I I I]] [I I I]
int ZM3angularTarget(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3angularTarget ");
#endif
	int dst  = MTOP(MMpull(m));
	int src  = MTOP(MMget(m,0));

	if((src==NIL)||(dst==NIL))		{	MMset(m,0,NIL);		return 0;	}

	ZVector3	srce, dest, result;

	if( (MMfetch(m,src,0)==NIL) || (MMfetch(m,src,1)==NIL) || (MMfetch(m,src,2)==NIL) )			{	MMset(m,0,NIL);		return 0;	}
	srce.SetCoord(MTOI(MMfetch(m,src,0)), MTOI(MMfetch(m,src,1)), MTOI(MMfetch(m,src,2)));

	if( (MMfetch(m,dst,0)==NIL) || (MMfetch(m,dst,1)==NIL) || (MMfetch(m,dst,2)==NIL) )			{	MMset(m,0,NIL);		return 0;	}
	dest.SetCoord(MTOI(MMfetch(m,dst,0)), MTOI(MMfetch(m,dst,1)), MTOI(MMfetch(m,dst,2)));

	result = AngularTarget(srce, dest);

	int tuple = MMmalloc(m, 3, TYPETAB);
	if(tuple==NIL)					{	MMset(m,0,NIL);		return MERRMEM;	}

	MMstore(m, tuple, 0, ITOM(AROUNDINT(result.y)));
	MMstore(m, tuple, 1, ITOM(AROUNDINT(result.x)));
	MMstore(m, tuple, 2, ITOM(AROUNDINT(result.z)));

	MMset(m,0,PTOM(tuple));
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3angularTargetF
//////////////////////////////////////////////////////////////////////////////////////////////
//	fun [[F F F] [F F F]] [F F F]
int ZM3angularTargetF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3angularTargetF ");
#endif
	int dst  = MTOP(MMpull(m));
	int src  = MTOP(MMget(m,0));

	if((src==NIL)||(dst==NIL))		{	MMset(m,0,NIL);		return 0;	}

	ZVector3	srce, dest, result;

	if( (MMfetch(m,src,0)==NIL) || (MMfetch(m,src,1)==NIL) || (MMfetch(m,src,2)==NIL) )			{	MMset(m,0,NIL);		return 0;	}
	srce.SetCoord(MTOF(MMfetch(m,src,0)), MTOF(MMfetch(m,src,1)), MTOF(MMfetch(m,src,2)));

	if( (MMfetch(m,dst,0)==NIL) || (MMfetch(m,dst,1)==NIL) || (MMfetch(m,dst,2)==NIL) )			{	MMset(m,0,NIL);		return 0;	}
	dest.SetCoord(MTOF(MMfetch(m,dst,0)), MTOF(MMfetch(m,dst,1)), MTOF(MMfetch(m,dst,2)));

	result = AngularTarget(srce, dest) * (MY_PI / 32768.0f);

	int tuple = MMmalloc(m, 3, TYPETAB);
	if(tuple==NIL)					{	MMset(m,0,NIL);		return MERRMEM;	}

	MMstore(m, tuple, 0, FTOM(result.y));
	MMstore(m, tuple, 1, FTOM(result.x));
	MMstore(m, tuple, 2, FTOM(result.z));

	MMset(m,0,PTOM(tuple));
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getGlobalVec
//////////////////////////////////////////////////////////////////////////////////////////////
//	fun [S3d H3d [I I I]] [I I I]
int ZM3getGlobalVec(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getGlobalVec ");
#endif
	int vect = MTOP(MMpull(m));
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL)||(vect==NIL))				{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL||node->type==MSH_TYPE_ID)					{	MMset(m,0,NIL);		return 0;	}

	if( (MMfetch(m,vect,0)==NIL) || (MMfetch(m,vect,1)==NIL) || (MMfetch(m,vect,2)==NIL) )			{	MMset(m,0,NIL);		return 0;	}
	ZVector4	vector;
	vector.SetCoord(MTOI(MMfetch(m,vect,0)), MTOI(MMfetch(m,vect,1)), -MTOI(MMfetch(m,vect,2)), 0.0f);

	vector *= ComputeWorldMatrix(node);

	int tuple = MMmalloc(m, 3, TYPETAB);
	if(tuple==NIL)					{	MMset(m,0,NIL);		return MERRMEM;	}

	MMstore(m, tuple, 0, ITOM(AROUNDINT(vector.x)));
	MMstore(m, tuple, 1, ITOM(AROUNDINT(vector.y)));
	MMstore(m, tuple, 2, ITOM(AROUNDINT(-vector.z)));

	MMset(m,0,PTOM(tuple));
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getGlobalVecF
//////////////////////////////////////////////////////////////////////////////////////////////
//	fun [S3d H3d [F F F]] [F F F]
int ZM3getGlobalVecF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getGlobalVecF ");
#endif
	int vect = MTOP(MMpull(m));
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL)||(vect==NIL))				{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL||node->type==MSH_TYPE_ID)					{	MMset(m,0,NIL);		return 0;	}

	if( (MMfetch(m,vect,0)==NIL) || (MMfetch(m,vect,1)==NIL) || (MMfetch(m,vect,2)==NIL) )			{	MMset(m,0,NIL);		return 0;	}
	ZVector4	vector;
	vector.SetCoord( MTOF(MMfetch(m,vect,0)), MTOF(MMfetch(m,vect,1)), - MTOF(MMfetch(m,vect,2)), 0.0f);

	vector *= ComputeWorldMatrix(node);

	int tuple = MMmalloc(m, 3, TYPETAB);
	if(tuple==NIL)					{	MMset(m,0,NIL);		return MERRMEM;	}

	// pas de multiplication par 100.0f, c'est NORMAL !!
	MMstore(m, tuple, 0, FTOM(vector.x));
	MMstore(m, tuple, 1, FTOM(vector.y));
	MMstore(m, tuple, 2, FTOM(-vector.z));

	MMset(m,0,PTOM(tuple));
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}











///////////////////////////////////////////////////////////////////////////////////////////
////																				   ////
///								GESTION TOPOLOGIQUE										///
////																				   ////
///////////////////////////////////////////////////////////////////////////////////////////



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3listALLtopos
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d] [H3d r1]
int ZM3listALLtopos(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ZM3listALLtopos ");
#endif
    int s3d = MMget(m,0);

    if(s3d==NIL)					{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

	int	n=0;
	int tx, tmp_res;

	for(int k=0; k<scene->MshList.Size(); k++)
    {
		int s3d = MMget(m,0);
		int hash = MTOP(MMfetch(m,MTOP(s3d),1));

		tx = NodeTOHandle(m, hash, (int)scene->MshList[k]);
		if(tx!=NIL)
		{
			tx = PTOM(tx);
			if(MMpush(m,tx))			return MERRMEM;
			INVERT(m,0,1);
			n++;
		}
    }

	if(n==0)		{	MMset(m,0,NIL);		return n;	}
	MMpull(m);
	if(MMpush(m,NIL))		return MERRMEM;

	for(int j=0;j<n;j++)
	{
    	if(MMpush(m,2*2))		return MERRMEM;
		if(k=MBdeftab(m))		return k;
	}

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getTopo
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d S] H3d
int ZM3getTopo(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ZM3getTopo ");
#endif
	int name = MMpull(m);
    int s3d  = MMget(m,0);

    if((name==NIL)||(s3d==NIL))		{	MMset(m,0,NIL);		return 0;	}

    ZScene	*scene = (ZScene*)MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

	string	matName = string(MMstartstr(m,MTOP(name)));

	ZMesh	*topo = NULL;

	for(int k=0; k<scene->MshList.Size(); k++)
	{
		if( scene->MshList[k]->name==matName && (topo==NULL || scene->MshList[k]->version>topo->version) )		topo = scene->MshList[k];
	}

	if(topo==NULL)		{	MMset(m,0,NIL);		return 0;	}

	int	top = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)topo);
	if(top!=NIL)		top = PTOM(top);
	MMset(m,0,top);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3createTopo														
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d] H3d
int ZM3createTopo(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3createTopo ");
#endif
    int s3d;

    s3d = MMget(m,0);
    if(s3d==NIL)		{	MMset(m,0,NIL);		return 0;	}

	ZScene	*scene = (ZScene*) MMfetch(m, MTOP(s3d), 0);
	if(scene==NULL)		{	MMset(m,0,NIL);		return 0;	}

	// Crée la topologie
	ZMesh	*topo = new ZMesh((int)scene, 0, 0);
	if(topo==NULL)	{	MMset(m,0,NIL);		return 0;	}
	scene->MshList.Add(topo);

	topo->SetName("");

	int hash_tab = MTOP( MMfetch(m,MTOP(s3d),1) );
	int	h3d = createH3D(m, (int)topo, hash_tab);

	scene->meshModified		= true;

	// Pose le résultat sur la pile
	if(h3d!=NIL)	h3d = PTOM(h3d);
    MMset(m,0,h3d);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3cleanTopo
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d] I
int ZM3cleanTopo(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3cleanTopo ");
#endif

	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=MSH_TYPE_ID))					{	MMset(m,0,NIL);		return 0;	}
    
	// Nettoie la topologie..

	ZMesh	*topo = (ZMesh*) node;
	for(int i=0; i<topo->NbFaces; i++)		topo->Faces[i].DeleteFace();
	
	topo->FacesFlat.gour.resize(0);
	topo->FacesFlat.flat.resize(0);
	topo->FacesFlat.no.resize(0);



	for(i=0; i<topo->FacesTex1.size(); i++)	
	{
		topo->FacesTex1[i].ClampUV.flat.resize(0);	topo->FacesTex1[i].ClampUV.gour.resize(0);	topo->FacesTex1[i].ClampUV.no.resize(0);
		topo->FacesTex1[i].ClampU. flat.resize(0);	topo->FacesTex1[i].ClampU. gour.resize(0);	topo->FacesTex1[i].ClampU .no.resize(0);
		topo->FacesTex1[i].ClampV. flat.resize(0);	topo->FacesTex1[i].ClampV. gour.resize(0);	topo->FacesTex1[i].ClampV .no.resize(0);
		topo->FacesTex1[i].NoClamp.flat.resize(0);	topo->FacesTex1[i].NoClamp.gour.resize(0);	topo->FacesTex1[i].NoClamp.no.resize(0);
	}
	topo->FacesTex1.resize(0);

	for(i=0; i<topo->FacesLightMap.size(); i++)	
	{
		topo->FacesLightMap[i].ClampUV.flat.resize(0);	topo->FacesLightMap[i].ClampUV.gour.resize(0);	topo->FacesLightMap[i].ClampUV.no.resize(0);
		topo->FacesLightMap[i].ClampU. flat.resize(0);	topo->FacesLightMap[i].ClampU. gour.resize(0);	topo->FacesLightMap[i].ClampU .no.resize(0);
		topo->FacesLightMap[i].ClampV. flat.resize(0);	topo->FacesLightMap[i].ClampV. gour.resize(0);	topo->FacesLightMap[i].ClampV .no.resize(0);
		topo->FacesLightMap[i].NoClamp.flat.resize(0);	topo->FacesLightMap[i].NoClamp.gour.resize(0);	topo->FacesLightMap[i].NoClamp.no.resize(0);
	}
	topo->FacesLightMap.resize(0);

	for(i=0; i<topo->FacesEnv.size(); i++)	
	{
		topo->FacesEnv[i].NoClamp.flat.resize(0);
		topo->FacesEnv[i].NoClamp.gour.resize(0);
		topo->FacesEnv[i].NoClamp.no.resize(0);
	}
	topo->FacesEnv.resize(0);

	for(i=0; i<topo->FacesColTransp.size(); i++)	
	{
		topo->FacesColTransp[i].ClampUV.flat.resize(0);	topo->FacesColTransp[i].ClampUV.gour.resize(0);	topo->FacesColTransp[i].ClampUV.no.resize(0);
		topo->FacesColTransp[i].ClampU. flat.resize(0);	topo->FacesColTransp[i].ClampU. gour.resize(0);	topo->FacesColTransp[i].ClampU .no.resize(0);
		topo->FacesColTransp[i].ClampV. flat.resize(0);	topo->FacesColTransp[i].ClampV. gour.resize(0);	topo->FacesColTransp[i].ClampV .no.resize(0);
		topo->FacesColTransp[i].NoClamp.flat.resize(0);	topo->FacesColTransp[i].NoClamp.gour.resize(0);	topo->FacesColTransp[i].NoClamp.no.resize(0);
	}
	topo->FacesColTransp.resize(0);

	for(i=0; i<topo->FacesTex2.size(); i++)
	{
		topo->FacesTex2[i].ClampUV.flat.resize(0);	topo->FacesTex2[i].ClampUV.gour.resize(0);	topo->FacesTex2[i].ClampUV.no.resize(0);
		topo->FacesTex2[i].ClampU. flat.resize(0);	topo->FacesTex2[i].ClampU. gour.resize(0);	topo->FacesTex2[i].ClampU .no.resize(0);
		topo->FacesTex2[i].ClampV. flat.resize(0);	topo->FacesTex2[i].ClampV. gour.resize(0);	topo->FacesTex2[i].ClampV .no.resize(0);
		topo->FacesTex2[i].NoClamp.flat.resize(0);	topo->FacesTex2[i].NoClamp.gour.resize(0);	topo->FacesTex2[i].NoClamp.no.resize(0);
	}
	topo->FacesTex2.resize(0);



	for(i=0; i<topo->FacesMatGour.size(); i++)
	{
		topo->FacesMatGour[i].faces.resize(0);
	}
	topo->FacesMatGour.resize(0);

	for(i=0; i<topo->FacesMatFlat.size(); i++)
	{
		topo->FacesMatFlat[i].faces.resize(0);
	}
	topo->FacesMatFlat.resize(0);

	for(i=0; i<topo->FacesMatNo.size(); i++)
	{
		topo->FacesMatNo[i].faces.resize(0);
	}
	topo->FacesMatNo.resize(0);

	topo->FacesTransp.resize(0);
	
	topo->Verts.resize(0);
	topo->Faces.resize(0);

	topo->NbFaces = topo->NbVerts = 0;

	topo->dependency		= false;
	topo->displayListCreate = true;
	topo->multiTex			= false;

	topo->DeleteRapidModel();

	topo->hasTopoChanged = true;
	topo->hasViewChanged = true;

	
	topo->DeleteDisplayList();

	
	scene->meshModified	 = true;


    MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
    return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3topoCount
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d] I
int ZM3topoCount(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3topoCount ");
#endif
	int h3d = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZData	*topo = (ZData*) MMfetch(m,MTOP(h3d),0);
	if(topo==NULL || topo->type!=MSH_TYPE_ID)					{	MMset(m,0,NIL);		return 0;	}

	MMset(m,0,ITOM(topo->nbRef));
	
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3topoAddFace
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d [I I I] [[I I][I I][I I]] [[I I][I I][I I]] HMat3d] I
//
//	Attention !! Le sens direct n'est ici pas respecté pour le passage des params en SCOL !!
//
int ZM3topoAddFace(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3topoAddFace ");
#endif

	int mat	 = MMpull(m);
	int tex2 = MMpull(m);
	int tex1 = MMpull(m);
	int Vref = MMpull(m);
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL)||(Vref==NIL)||(tex1==NIL)||(mat==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=MSH_TYPE_ID))					{	MMset(m,0,NIL);		return 0;	}
    ZMesh	*topo = (ZMesh*) node;


	// Recupère le materiau
    node = (ZNode*) MMfetch(m,MTOP(mat),0);
	if((node==NULL)||(node->type!=MAT_TYPE_ID))					{	MMset(m,0,NIL);		return 0;	}
    ZMaterial	*materio = (ZMaterial*) node;

	// Recupère les vert-refz
	int	vert0 = MTOI(MMfetch(m,MTOP(Vref),0));
	int	vert1 = MTOI(MMfetch(m,MTOP(Vref),1));
	int	vert2 = MTOI(MMfetch(m,MTOP(Vref),2));

	// Recupère les textures coordinates n°1
	int	coord0 = MTOP(MMfetch(m,MTOP(tex1),0));
	int	coord1 = MTOP(MMfetch(m,MTOP(tex1),1));
	int	coord2 = MTOP(MMfetch(m,MTOP(tex1),2));
	ZVector3	U1, V1;
	U1.SetCoord( MTOI(MMfetch(m,coord0,0)), MTOI(MMfetch(m,coord1,0)), MTOI(MMfetch(m,coord2,0)) );
	V1.SetCoord( MTOI(MMfetch(m,coord0,1)), MTOI(MMfetch(m,coord1,1)), MTOI(MMfetch(m,coord2,1)) );
	
	// Recupère les textures coordinates n°2
	ZVector3	U2, V2;
	if(tex2!=NIL)
	{
		coord0 = MTOP(MMfetch(m,MTOP(tex2),0));
		coord1 = MTOP(MMfetch(m,MTOP(tex2),1));
		coord2 = MTOP(MMfetch(m,MTOP(tex2),2));
		U2.SetCoord( MTOI(MMfetch(m,coord0,0)), MTOI(MMfetch(m,coord1,0)), MTOI(MMfetch(m,coord2,0)) );
		V2.SetCoord( MTOI(MMfetch(m,coord0,1)), MTOI(MMfetch(m,coord1,1)), MTOI(MMfetch(m,coord2,1)) );
	}


	// Crée la face correspondante
	ZFace	face;
	face.initFace();

	face.SetVertsRef( vert0, vert1, vert2 );
	face.SetMaterial(materio);

	U1 *= 1.0f/CONST_TEX_COORD;
	U2 *= 1.0f/CONST_TEX_COORD;
	V1 *= 1.0f/CONST_TEX_COORD;
	V2 *= 1.0f/CONST_TEX_COORD;

	face.UV1[0].SetCoord( U1.x, V1.x );
	face.UV1[1].SetCoord( U1.y, V1.y );
	face.UV1[2].SetCoord( U1.z, V1.z );

	if( face.UV1[0].u<0.0f || face.UV1[1].u<0.0f || face.UV1[2].u<0.0f ||
		face.UV1[0].u>1.0f || face.UV1[1].u>1.0f || face.UV1[2].u>1.0f )	face.clampU1 = false;
	else																	face.clampU1 = true;

	if( face.UV1[0].v<0.0f || face.UV1[1].v<0.0f || face.UV1[2].v<0.0f || 
		face.UV1[0].v>1.0f || face.UV1[1].v>1.0f || face.UV1[2].v>1.0f )	face.clampV1 = false;
	else																	face.clampV1 = true;


	if(tex2!=NIL)
	{
		face.UV2[0].SetCoord( U2.x, V2.x );
		face.UV2[1].SetCoord( U2.y, V2.y );
		face.UV2[2].SetCoord( U2.z, V2.z );

		if( face.UV2[0].u<0.0f || face.UV2[1].u<0.0f || face.UV2[2].u<0.0f ||
			face.UV2[0].u>1.0f || face.UV2[1].u>1.0f || face.UV2[2].u>1.0f )	face.clampU2 = false;
		else																	face.clampU2 = true;

		if( face.UV2[0].v<0.0f || face.UV2[1].v<0.0f || face.UV2[2].v<0.0f || 
			face.UV2[0].v>1.0f || face.UV2[1].v>1.0f || face.UV2[2].v>1.0f )	face.clampV2 = false;
		else																	face.clampV2 = true;
	}
	else
	{
		face.UV2[0].SetCoord(0.0f, 0.0f);	
		face.UV2[1].SetCoord(1.0f, 0.0f);	
		face.UV2[2].SetCoord(0.0f, 1.0f);
		face.clampU2 = face.clampV2 = true;
	}
	
	topo->addFace(face);
	face.SetMaterial(NULL);

	scene->meshModified	= true;

	MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3topoAddFaceF
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d [I I I] [[F F][F F][F F]] [[F F][F F][F F]] HMat3d] I
//
//	Attention !! Le sens direct n'est ici pas respecté pour le passage des params en SCOL !!
//
int ZM3topoAddFaceF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3topoAddFaceF ");
#endif
	int mat	 = MMpull(m);
	int tex2 = MMpull(m);
	int tex1 = MMpull(m);
	int Vref = MMpull(m);
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL)||(Vref==NIL)||(tex1==NIL)||(mat==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=MSH_TYPE_ID))					{	MMset(m,0,NIL);		return 0;	}
    ZMesh	*topo = (ZMesh*) node;


	// Recupère le materiau
    node = (ZNode*) MMfetch(m,MTOP(mat),0);
	if((node==NULL)||(node->type!=MAT_TYPE_ID))					{	MMset(m,0,NIL);		return 0;	}
    ZMaterial	*materio = (ZMaterial*) node;

	// Recupère les vert-refz
	int	vert0 = MTOI(MMfetch(m,MTOP(Vref),0));
	int	vert1 = MTOI(MMfetch(m,MTOP(Vref),1));
	int	vert2 = MTOI(MMfetch(m,MTOP(Vref),2));

	// Recupère les textures coordinates n°1
	int	coord0 = MTOP(MMfetch(m,MTOP(tex1),0));
	int	coord1 = MTOP(MMfetch(m,MTOP(tex1),1));
	int	coord2 = MTOP(MMfetch(m,MTOP(tex1),2));
	ZVector3	U1, V1;
	U1.SetCoord( MTOF(MMfetch(m,coord0,0)), MTOF(MMfetch(m,coord1,0)), MTOF(MMfetch(m,coord2,0)) );
	V1.SetCoord( MTOF(MMfetch(m,coord0,1)), MTOF(MMfetch(m,coord1,1)), MTOF(MMfetch(m,coord2,1)) );
	
	// Recupère les textures coordinates n°2
	ZVector3	U2, V2;
	if(tex2!=NIL)
	{
		coord0 = MTOP(MMfetch(m,MTOP(tex2),0));
		coord1 = MTOP(MMfetch(m,MTOP(tex2),1));
		coord2 = MTOP(MMfetch(m,MTOP(tex2),2));
		U2.SetCoord( MTOF(MMfetch(m,coord0,0)), MTOF(MMfetch(m,coord1,0)), MTOF(MMfetch(m,coord2,0)) );
		V2.SetCoord( MTOF(MMfetch(m,coord0,1)), MTOF(MMfetch(m,coord1,1)), MTOF(MMfetch(m,coord2,1)) );
	}


	// Crée la face correspondante
	ZFace	face;
	face.initFace();

	face.SetVertsRef( vert0, vert1, vert2 );
	face.SetMaterial(materio);

	face.UV1[0].SetCoord( U1.x, V1.x );
	face.UV1[1].SetCoord( U1.y, V1.y );
	face.UV1[2].SetCoord( U1.z, V1.z );

	if( face.UV1[0].u<0.0f || face.UV1[1].u<0.0f || face.UV1[2].u<0.0f ||
		face.UV1[0].u>1.0f || face.UV1[1].u>1.0f || face.UV1[2].u>1.0f )	face.clampU1 = false;
	else																	face.clampU1 = true;

	if( face.UV1[0].v<0.0f || face.UV1[1].v<0.0f || face.UV1[2].v<0.0f || 
		face.UV1[0].v>1.0f || face.UV1[1].v>1.0f || face.UV1[2].v>1.0f )	face.clampV1 = false;
	else																	face.clampV1 = true;
	
	if(tex2!=NIL)
	{
		face.UV2[0].SetCoord( U2.x, V2.x );
		face.UV2[1].SetCoord( U2.y, V2.y );
		face.UV2[2].SetCoord( U2.z, V2.z );
		
		if( face.UV2[0].u<0.0f || face.UV2[1].u<0.0f || face.UV2[2].u<0.0f ||
			face.UV2[0].u>1.0f || face.UV2[1].u>1.0f || face.UV2[2].u>1.0f )	face.clampU2 = false;
		else																	face.clampU2 = true;

		if( face.UV2[0].v<0.0f || face.UV2[1].v<0.0f || face.UV2[2].v<0.0f || 
			face.UV2[0].v>1.0f || face.UV2[1].v>1.0f || face.UV2[2].v>1.0f )	face.clampV2 = false;
		else																	face.clampV2 = true;
	}
	else
	{
		face.UV2[0].SetCoord(0.0f, 0.0f);	
		face.UV2[1].SetCoord(1.0f, 0.0f);	
		face.UV2[2].SetCoord(0.0f, 1.0f);
		face.clampU2 = face.clampV2 = true;
	}
	
	topo->addFace(face);
	face.SetMaterial(NULL);

	scene->meshModified		= true;

	MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3setFaceVertRef
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d I [I I I]] I
int ZM3setFaceVertRef(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3setFaceVertRef ");
#endif
	int Vref = MMpull(m);
	int num	 = MMpull(m);
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL)||(Vref==NIL)||(num==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)											{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=MSH_TYPE_ID))				{	MMset(m,0,NIL);		return 0;	}
    ZMesh	*topo = (ZMesh*) node;


	int index = MTOI(num);
	if(index >= topo->Faces.size())		{	MMset(m,0,NIL);		return 0;	}

	int	vert0 = MTOI(MMfetch(m,MTOP(Vref),0));
	int	vert1 = MTOI(MMfetch(m,MTOP(Vref),1));
	int	vert2 = MTOI(MMfetch(m,MTOP(Vref),2));

	topo->Faces[index].SetVertsRef(vert0, vert1, vert2);

	topo->hasTopoChanged = true;
	topo->hasViewChanged = true;

	// Désactive la compilation des displays lists
	topo->displayListCreate = false;

	scene->meshModified	 = true;

	MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getFaceVertRef
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d I] [I I I]
int ZM3getFaceVertRef(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getFaceVertRef ");
#endif
	int num	 = MMpull(m);
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL)||(num==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)								{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=MSH_TYPE_ID))				{	MMset(m,0,NIL);		return 0;	}
    ZMesh	*topo = (ZMesh*) node;

	int index = MTOI(num);
	if(index >= topo->Faces.size())		{	MMset(m,0,NIL);		return 0;	}

	// création du tuple de résultat
	int tuple = MMmalloc(m, 3, TYPETAB);
	if(tuple==NIL)						{	MMset(m,0,NIL);		return MERRMEM;	}

	MMstore(m, tuple, 0, ITOM(topo->Faces[index].VertRef[0]));
	MMstore(m, tuple, 1, ITOM(topo->Faces[index].VertRef[1]));
	MMstore(m, tuple, 2, ITOM(topo->Faces[index].VertRef[2]));

	MMset(m,0,PTOM(tuple));
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3setFaceMaterial
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d I HMat3d] I
int ZM3setFaceMaterial(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3setFaceMaterial ");
#endif
	int mat	 = MMpull(m);
	int num	 = MMpull(m);
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL)||(num==NIL)||(mat==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)											{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=MSH_TYPE_ID))				{	MMset(m,0,NIL);		return 0;	}
    ZMesh	*topo = (ZMesh*) node;

	int index = MTOI(num);
	if(index >= topo->Faces.size())		{	MMset(m,0,NIL);		return 0;	}
	
    node = (ZNode*) MMfetch(m,MTOP(mat),0);
	if((node==NULL)||(node->type!=MAT_TYPE_ID))				{	MMset(m,0,NIL);		return 0;	}
    ZMaterial	*materio = (ZMaterial*) node;

	topo->Faces[index].SetMaterial(materio);

	topo->hasTopoChanged = true;
	topo->hasViewChanged = true;

	// Désactive la compilation des displays lists
	topo->displayListCreate = false;

	scene->meshModified		= true;

	MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getFaceMaterial
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d I] HMat3d
int ZM3getFaceMaterial(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getFaceMaterial ");
#endif
	int num	 = MMpull(m);
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL)||(num==NIL))					{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)											{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=MSH_TYPE_ID))				{	MMset(m,0,NIL);		return 0;	}
    ZMesh	*topo = (ZMesh*) node;

	int index = MTOI(num);
	if(index >= topo->Faces.size())		{	MMset(m,0,NIL);		return 0;	}
	
	ZMaterial	*mat = topo->Faces[index].GetMaterial();
	if(mat==NULL)						{	MMset(m,0,NIL);		return 0;	}
	
	int	mat3d = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),2)), (int)mat);
	if(mat3d!=NIL)	mat3d = PTOM(mat3d);
	MMset(m,0,mat3d);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3setFaceTexCoord
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d I I [[I I][I I][I I]] ] I
int ZM3setFaceTexCoord(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3setFaceTexCoord ");
#endif
	int texC = MMpull(m);
	int numT = MMpull(m);
	int face = MMpull(m);
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL)||(face==NIL)||(texC==NIL)||(numT==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=MSH_TYPE_ID))					{	MMset(m,0,NIL);		return 0;	}
    ZMesh	*topo = (ZMesh*) node;

	int numTex = MTOI(numT);
	if((numTex>3)||(numTex<1))			{	MMset(m,0,NIL);		return 0;	}

	int index = MTOI(face);
	if(index >= topo->Faces.size())		{	MMset(m,0,NIL);		return 0;	}

	// Recupère les textures coordinates
	int	coord0 = MTOP(MMfetch(m,MTOP(texC),0));
	int	coord1 = MTOP(MMfetch(m,MTOP(texC),1));
	int	coord2 = MTOP(MMfetch(m,MTOP(texC),2));
	ZVector3	U, V;
	U.SetCoord( MTOI(MMfetch(m,coord0,0)), MTOI(MMfetch(m,coord1,0)), MTOI(MMfetch(m,coord2,0)) );
	V.SetCoord( MTOI(MMfetch(m,coord0,1)), MTOI(MMfetch(m,coord1,1)), MTOI(MMfetch(m,coord2,1)) );
	U *= 1.0f/CONST_TEX_COORD;
	V *= 1.0f/CONST_TEX_COORD;


	if(numTex==1)
	{
		topo->Faces[index].UV1[0].SetCoord( U.x, V.x);
		topo->Faces[index].UV1[1].SetCoord( U.y, V.y);
		topo->Faces[index].UV1[2].SetCoord( U.z, V.z);

		if( topo->Faces[index].UV1[0].u<0.0f || topo->Faces[index].UV1[1].u<0.0f || topo->Faces[index].UV1[2].u<0.0f ||
			topo->Faces[index].UV1[0].u>1.0f || topo->Faces[index].UV1[1].u>1.0f || topo->Faces[index].UV1[2].u>1.0f )	topo->Faces[index].clampU1 = false;
		else																											topo->Faces[index].clampU1 = true;

		if( topo->Faces[index].UV1[0].v<0.0f || topo->Faces[index].UV1[1].v<0.0f || topo->Faces[index].UV1[2].v<0.0f || 
			topo->Faces[index].UV1[0].v>1.0f || topo->Faces[index].UV1[1].v>1.0f || topo->Faces[index].UV1[2].v>1.0f )	topo->Faces[index].clampV1 = false;
		else																											topo->Faces[index].clampV1 = true;
	}
	else
	if(numTex==2)
	{
		topo->Faces[index].UV2[0].SetCoord( U.x, V.x);
		topo->Faces[index].UV2[1].SetCoord( U.y, V.y);
		topo->Faces[index].UV2[2].SetCoord( U.z, V.z);

		if( topo->Faces[index].UV2[0].u<0.0f || topo->Faces[index].UV2[1].u<0.0f || topo->Faces[index].UV2[2].u<0.0f ||
			topo->Faces[index].UV2[0].u>1.0f || topo->Faces[index].UV2[1].u>1.0f || topo->Faces[index].UV2[2].u>1.0f )	topo->Faces[index].clampU2 = false;
		else																											topo->Faces[index].clampU2 = true;

		if( topo->Faces[index].UV2[0].v<0.0f || topo->Faces[index].UV2[1].v<0.0f || topo->Faces[index].UV2[2].v<0.0f || 
			topo->Faces[index].UV2[0].v>1.0f || topo->Faces[index].UV2[1].v>1.0f || topo->Faces[index].UV2[2].v>1.0f )	topo->Faces[index].clampV2 = false;
		else																											topo->Faces[index].clampV2 = true;
	}
	else
	if(numTex==3)
	{
		topo->Faces[index].UV3[0].SetCoord( U.x, V.x);
		topo->Faces[index].UV3[1].SetCoord( U.y, V.y);
		topo->Faces[index].UV3[2].SetCoord( U.z, V.z);

		if( topo->Faces[index].UV3[0].u<0.0f || topo->Faces[index].UV3[1].u<0.0f || topo->Faces[index].UV3[2].u<0.0f ||
			topo->Faces[index].UV3[0].u>1.0f || topo->Faces[index].UV3[1].u>1.0f || topo->Faces[index].UV3[2].u>1.0f )	topo->Faces[index].clampU3 = false;
		else																											topo->Faces[index].clampU3 = true;

		if( topo->Faces[index].UV3[0].v<0.0f || topo->Faces[index].UV3[1].v<0.0f || topo->Faces[index].UV3[2].v<0.0f || 
			topo->Faces[index].UV3[0].v>1.0f || topo->Faces[index].UV3[1].v>1.0f || topo->Faces[index].UV3[2].v>1.0f )	topo->Faces[index].clampV3 = false;
		else																											topo->Faces[index].clampV3 = true;
	}
	if(numTex==4)
	{
		topo->Faces[index].UV4[0].SetCoord( U.x, V.x);
		topo->Faces[index].UV4[1].SetCoord( U.y, V.y);
		topo->Faces[index].UV4[2].SetCoord( U.z, V.z);

		if( topo->Faces[index].UV4[0].u<0.0f || topo->Faces[index].UV4[1].u<0.0f || topo->Faces[index].UV4[2].u<0.0f ||
			topo->Faces[index].UV4[0].u>1.0f || topo->Faces[index].UV4[1].u>1.0f || topo->Faces[index].UV4[2].u>1.0f )	topo->Faces[index].clampU4 = false;
		else																											topo->Faces[index].clampU4 = true;

		if( topo->Faces[index].UV4[0].v<0.0f || topo->Faces[index].UV4[1].v<0.0f || topo->Faces[index].UV4[2].v<0.0f || 
			topo->Faces[index].UV4[0].v>1.0f || topo->Faces[index].UV4[1].v>1.0f || topo->Faces[index].UV4[2].v>1.0f )	topo->Faces[index].clampV4 = false;
		else																											topo->Faces[index].clampV4 = true;
	}

	topo->hasViewChanged = true;

	// Désactive la compilation des displays lists
	topo->displayListCreate = false;

	scene->meshModified		= true;

	MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3setFaceTexCoordF
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d I I [[F F][F F][F F]] ] I
int ZM3setFaceTexCoordF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3setFaceTexCoordF ");
#endif
	int texC = MMpull(m);
	int numT = MMpull(m);
	int face = MMpull(m);
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL)||(face==NIL)||(texC==NIL)||(numT==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=MSH_TYPE_ID))					{	MMset(m,0,NIL);		return 0;	}
    ZMesh	*topo = (ZMesh*) node;

	int numTex = MTOI(numT);
	if((numTex>3)||(numTex<1))			{	MMset(m,0,NIL);		return 0;	}

	int index = MTOI(face);
	if(index >= topo->Faces.size())		{	MMset(m,0,NIL);		return 0;	}

	// Recupère les textures coordinates
	int	coord0 = MTOP(MMfetch(m,MTOP(texC),0));
	int	coord1 = MTOP(MMfetch(m,MTOP(texC),1));
	int	coord2 = MTOP(MMfetch(m,MTOP(texC),2));
	ZVector3	U, V;
	U.SetCoord( MTOF(MMfetch(m,coord0,0)), MTOF(MMfetch(m,coord1,0)), MTOF(MMfetch(m,coord2,0)) );
	V.SetCoord( MTOF(MMfetch(m,coord0,1)), MTOF(MMfetch(m,coord1,1)), MTOF(MMfetch(m,coord2,1)) );

	if(numTex==1)
	{
		topo->Faces[index].UV1[0].SetCoord( U.x, V.x);
		topo->Faces[index].UV1[1].SetCoord( U.y, V.y);
		topo->Faces[index].UV1[2].SetCoord( U.z, V.z);

		if( topo->Faces[index].UV1[0].u<0.0f || topo->Faces[index].UV1[1].u<0.0f || topo->Faces[index].UV1[2].u<0.0f ||
			topo->Faces[index].UV1[0].u>1.0f || topo->Faces[index].UV1[1].u>1.0f || topo->Faces[index].UV1[2].u>1.0f )	topo->Faces[index].clampU1 = false;
		else																											topo->Faces[index].clampU1 = true;

		if( topo->Faces[index].UV1[0].v<0.0f || topo->Faces[index].UV1[1].v<0.0f || topo->Faces[index].UV1[2].v<0.0f || 
			topo->Faces[index].UV1[0].v>1.0f || topo->Faces[index].UV1[1].v>1.0f || topo->Faces[index].UV1[2].v>1.0f )	topo->Faces[index].clampV1 = false;
		else																											topo->Faces[index].clampV1 = true;
	}
	else
	if(numTex==2)
	{
		topo->Faces[index].UV2[0].SetCoord( U.x, V.x);
		topo->Faces[index].UV2[1].SetCoord( U.y, V.y);
		topo->Faces[index].UV2[2].SetCoord( U.z, V.z);

		if( topo->Faces[index].UV2[0].u<0.0f || topo->Faces[index].UV2[1].u<0.0f || topo->Faces[index].UV2[2].u<0.0f ||
			topo->Faces[index].UV2[0].u>1.0f || topo->Faces[index].UV2[1].u>1.0f || topo->Faces[index].UV2[2].u>1.0f )	topo->Faces[index].clampU2 = false;
		else																											topo->Faces[index].clampU2 = true;

		if( topo->Faces[index].UV2[0].v<0.0f || topo->Faces[index].UV2[1].v<0.0f || topo->Faces[index].UV2[2].v<0.0f || 
			topo->Faces[index].UV2[0].v>1.0f || topo->Faces[index].UV2[1].v>1.0f || topo->Faces[index].UV2[2].v>1.0f )	topo->Faces[index].clampV2 = false;
		else																											topo->Faces[index].clampV2 = true;
	}
	else
	if(numTex==3)
	{
		topo->Faces[index].UV3[0].SetCoord( U.x, V.x);
		topo->Faces[index].UV3[1].SetCoord( U.y, V.y);
		topo->Faces[index].UV3[2].SetCoord( U.z, V.z);

		if( topo->Faces[index].UV3[0].u<0.0f || topo->Faces[index].UV3[1].u<0.0f || topo->Faces[index].UV3[2].u<0.0f ||
			topo->Faces[index].UV3[0].u>1.0f || topo->Faces[index].UV3[1].u>1.0f || topo->Faces[index].UV3[2].u>1.0f )	topo->Faces[index].clampU3 = false;
		else																											topo->Faces[index].clampU3 = true;

		if( topo->Faces[index].UV3[0].v<0.0f || topo->Faces[index].UV3[1].v<0.0f || topo->Faces[index].UV3[2].v<0.0f || 
			topo->Faces[index].UV3[0].v>1.0f || topo->Faces[index].UV3[1].v>1.0f || topo->Faces[index].UV3[2].v>1.0f )	topo->Faces[index].clampV3 = false;
		else																											topo->Faces[index].clampV3 = true;
	}
	if(numTex==4)
	{
		topo->Faces[index].UV4[0].SetCoord( U.x, V.x);
		topo->Faces[index].UV4[1].SetCoord( U.y, V.y);
		topo->Faces[index].UV4[2].SetCoord( U.z, V.z);

		if( topo->Faces[index].UV4[0].u<0.0f || topo->Faces[index].UV4[1].u<0.0f || topo->Faces[index].UV4[2].u<0.0f ||
			topo->Faces[index].UV4[0].u>1.0f || topo->Faces[index].UV4[1].u>1.0f || topo->Faces[index].UV4[2].u>1.0f )	topo->Faces[index].clampU4 = false;
		else																											topo->Faces[index].clampU4 = true;

		if( topo->Faces[index].UV4[0].v<0.0f || topo->Faces[index].UV4[1].v<0.0f || topo->Faces[index].UV4[2].v<0.0f || 
			topo->Faces[index].UV4[0].v>1.0f || topo->Faces[index].UV4[1].v>1.0f || topo->Faces[index].UV4[2].v>1.0f )	topo->Faces[index].clampV4 = false;
		else																											topo->Faces[index].clampV4 = true;
	}

	topo->hasViewChanged = true;

	// Désactive la compilation des displays lists
	topo->displayListCreate = false;

	scene->meshModified		= true;

	MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getFaceTexCoord
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d I I] [[I I][I I][I I]]
int ZM3getFaceTexCoord(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getFaceTexCoord ");
#endif
	int numT = MMpull(m);
	int face = MMpull(m);
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL)||(face==NIL)||(numT==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=MSH_TYPE_ID))					{	MMset(m,0,NIL);		return 0;	}
    ZMesh	*topo = (ZMesh*) node;

	int numTex = MTOI(numT);
	if((numTex>3)||(numTex<1))			{	MMset(m,0,NIL);		return 0;	}

	int index = MTOI(face);
	if(index >= topo->Faces.size())		{	MMset(m,0,NIL);		return 0;	}


	// création du tuple de résultat
	int tuple = MMmalloc(m, 3, TYPETAB);
	if(tuple==NIL)						{	MMset(m,0,NIL);		return MERRMEM;	}
	for(int iii=0; iii<3; iii++)	MMstore(m, tuple, iii, NIL);

	MMpush(m, PTOM(tuple));

	int coord0 = MMmalloc(m, 3, TYPETAB);
	if(coord0==NIL)						{	MMset(m,0,NIL);		return MERRMEM;	}
	for(iii=0; iii<3; iii++)	MMstore(m, coord0, iii, NIL);
	MMpush(m, PTOM(coord0));
	
	int coord1 = MMmalloc(m, 3, TYPETAB);
	if(coord1==NIL)						{	MMset(m,0,NIL);		return MERRMEM;	}
	for(iii=0; iii<3; iii++)	MMstore(m, coord1, iii, NIL);
	MMpush(m, PTOM(coord1));
	
	int coord2 = MMmalloc(m, 3, TYPETAB);
	for(iii=0; iii<3; iii++)	MMstore(m, coord2, iii, NIL);
	if(coord2==NIL)						{	MMset(m,0,NIL);		return MERRMEM;	}
	
	coord1 = MTOP( MMpull(m) );
	coord0 = MTOP( MMpull(m) );
	tuple  = MTOP( MMpull(m) );

	if(numTex==1)
	{
		MMstore(m, coord0, 0, ITOM(AROUNDINT(CONST_TEX_COORD*topo->Faces[index].UV1[0].u)));
		MMstore(m, coord0, 1, ITOM(AROUNDINT(CONST_TEX_COORD*topo->Faces[index].UV1[0].v)));

		MMstore(m, coord1, 0, ITOM(AROUNDINT(CONST_TEX_COORD*topo->Faces[index].UV1[1].u)));
		MMstore(m, coord1, 1, ITOM(AROUNDINT(CONST_TEX_COORD*topo->Faces[index].UV1[1].v)));
		
		MMstore(m, coord2, 0, ITOM(AROUNDINT(CONST_TEX_COORD*topo->Faces[index].UV1[2].u)));
		MMstore(m, coord2, 1, ITOM(AROUNDINT(CONST_TEX_COORD*topo->Faces[index].UV1[2].v)));
	}
	else
	if(numTex==2)
	{
		MMstore(m, coord0, 0, ITOM(AROUNDINT(CONST_TEX_COORD*topo->Faces[index].UV2[0].u)));
		MMstore(m, coord0, 1, ITOM(AROUNDINT(CONST_TEX_COORD*topo->Faces[index].UV2[0].v)));

		MMstore(m, coord1, 0, ITOM(AROUNDINT(CONST_TEX_COORD*topo->Faces[index].UV2[1].u)));
		MMstore(m, coord1, 1, ITOM(AROUNDINT(CONST_TEX_COORD*topo->Faces[index].UV2[1].v)));
		
		MMstore(m, coord2, 0, ITOM(AROUNDINT(CONST_TEX_COORD*topo->Faces[index].UV2[2].u)));
		MMstore(m, coord2, 1, ITOM(AROUNDINT(CONST_TEX_COORD*topo->Faces[index].UV2[2].v)));
	}
	else
	if(numTex==3)
	{
		MMstore(m, coord0, 0, ITOM(AROUNDINT(CONST_TEX_COORD*topo->Faces[index].UV3[0].u)));
		MMstore(m, coord0, 1, ITOM(AROUNDINT(CONST_TEX_COORD*topo->Faces[index].UV3[0].v)));

		MMstore(m, coord1, 0, ITOM(AROUNDINT(CONST_TEX_COORD*topo->Faces[index].UV3[1].u)));
		MMstore(m, coord1, 1, ITOM(AROUNDINT(CONST_TEX_COORD*topo->Faces[index].UV3[1].v)));
		
		MMstore(m, coord2, 0, ITOM(AROUNDINT(CONST_TEX_COORD*topo->Faces[index].UV3[2].u)));
		MMstore(m, coord2, 1, ITOM(AROUNDINT(CONST_TEX_COORD*topo->Faces[index].UV3[2].v)));
	}
	else
	if(numTex==4)
	{
		MMstore(m, coord0, 0, ITOM(AROUNDINT(CONST_TEX_COORD*topo->Faces[index].UV4[0].u)));
		MMstore(m, coord0, 1, ITOM(AROUNDINT(CONST_TEX_COORD*topo->Faces[index].UV4[0].v)));

		MMstore(m, coord1, 0, ITOM(AROUNDINT(CONST_TEX_COORD*topo->Faces[index].UV4[1].u)));
		MMstore(m, coord1, 1, ITOM(AROUNDINT(CONST_TEX_COORD*topo->Faces[index].UV4[1].v)));
		
		MMstore(m, coord2, 0, ITOM(AROUNDINT(CONST_TEX_COORD*topo->Faces[index].UV4[2].u)));
		MMstore(m, coord2, 1, ITOM(AROUNDINT(CONST_TEX_COORD*topo->Faces[index].UV4[2].v)));
	}

	MMstore(m, tuple, 0, PTOM(coord0));
	MMstore(m, tuple, 1, PTOM(coord1));
	MMstore(m, tuple, 2, PTOM(coord2));

	MMset(m,0,PTOM(tuple));
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getFaceTexCoordF
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d I I] [[F F][F F][F F]]
int ZM3getFaceTexCoordF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getFaceTexCoordF ");
#endif
	int numT = MMpull(m);
	int face = MMpull(m);
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL)||(face==NIL)||(numT==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=MSH_TYPE_ID))					{	MMset(m,0,NIL);		return 0;	}
    ZMesh	*topo = (ZMesh*) node;

	int numTex = MTOI(numT);
	if((numTex>3)||(numTex<1))			{	MMset(m,0,NIL);		return 0;	}

	int index = MTOI(face);
	if(index >= topo->Faces.size())		{	MMset(m,0,NIL);		return 0;	}


	// création du tuple de résultat
	int tuple = MMmalloc(m, 3, TYPETAB);
	if(tuple==NIL)						{	MMset(m,0,NIL);		return MERRMEM;	}
	for(int iii=0; iii<3; iii++)	MMstore(m, tuple, iii, NIL);

	MMpush(m, PTOM(tuple));

	int coord0 = MMmalloc(m, 3, TYPETAB);
	if(coord0==NIL)						{	MMset(m,0,NIL);		return MERRMEM;	}
	for(iii=0; iii<3; iii++)	MMstore(m, coord0, iii, NIL);
	MMpush(m, PTOM(coord0));
	
	int coord1 = MMmalloc(m, 3, TYPETAB);
	if(coord1==NIL)						{	MMset(m,0,NIL);		return MERRMEM;	}
	for(iii=0; iii<3; iii++)	MMstore(m, coord1, iii, NIL);
	MMpush(m, PTOM(coord1));
	
	int coord2 = MMmalloc(m, 3, TYPETAB);
	if(coord2==NIL)						{	MMset(m,0,NIL);		return MERRMEM;	}
	for(iii=0; iii<3; iii++)	MMstore(m, coord2, iii, NIL);
	
	coord1 = MTOP( MMpull(m) );
	coord0 = MTOP( MMpull(m) );
	tuple  = MTOP( MMpull(m) );

	if(numTex==1)
	{
		MMstore(m, coord0, 0, FTOM(topo->Faces[index].UV1[0].u));
		MMstore(m, coord0, 1, FTOM(topo->Faces[index].UV1[0].v));

		MMstore(m, coord1, 0, FTOM(topo->Faces[index].UV1[1].u));
		MMstore(m, coord1, 1, FTOM(topo->Faces[index].UV1[1].v));

		MMstore(m, coord2, 0, FTOM(topo->Faces[index].UV1[2].u));
		MMstore(m, coord2, 1, FTOM(topo->Faces[index].UV1[2].v));
	}
	else
	if(numTex==2)
	{
		MMstore(m, coord0, 0, FTOM(topo->Faces[index].UV2[0].u));
		MMstore(m, coord0, 1, FTOM(topo->Faces[index].UV2[0].v));

		MMstore(m, coord1, 0, FTOM(topo->Faces[index].UV2[1].u));
		MMstore(m, coord1, 1, FTOM(topo->Faces[index].UV2[1].v));

		MMstore(m, coord2, 0, FTOM(topo->Faces[index].UV2[2].u));
		MMstore(m, coord2, 1, FTOM(topo->Faces[index].UV2[2].v));
	}
	else
	if(numTex==3)
	{
		MMstore(m, coord0, 0, FTOM(topo->Faces[index].UV3[0].u));
		MMstore(m, coord0, 1, FTOM(topo->Faces[index].UV3[0].v));

		MMstore(m, coord1, 0, FTOM(topo->Faces[index].UV3[1].u));
		MMstore(m, coord1, 1, FTOM(topo->Faces[index].UV3[1].v));

		MMstore(m, coord2, 0, FTOM(topo->Faces[index].UV3[2].u));
		MMstore(m, coord2, 1, FTOM(topo->Faces[index].UV3[2].v));
	}
	else
	if(numTex==4)
	{
		MMstore(m, coord0, 0, FTOM(topo->Faces[index].UV4[0].u));
		MMstore(m, coord0, 1, FTOM(topo->Faces[index].UV4[0].v));

		MMstore(m, coord1, 0, FTOM(topo->Faces[index].UV4[1].u));
		MMstore(m, coord1, 1, FTOM(topo->Faces[index].UV4[1].v));

		MMstore(m, coord2, 0, FTOM(topo->Faces[index].UV4[2].u));
		MMstore(m, coord2, 1, FTOM(topo->Faces[index].UV4[2].v));
	}
	MMstore(m, tuple, 0, PTOM(coord0));
	MMstore(m, tuple, 1, PTOM(coord1));
	MMstore(m, tuple, 2, PTOM(coord2));

	MMset(m,0,PTOM(tuple));
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3listOfPolygons
//////////////////////////////////////////////////////////////////////////////////////////////
///	fun [S3d H3d] [[HMat3d [[I I I] r1]] r1]
int ZM3listOfPolygons(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3listOfPolygons ");
#endif
	int h3d  = MMpull(m);
    int s3d  = MMpull(m);

	if((s3d==NIL)||(h3d==NIL))		{	return MMpush(m,NIL);	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	return MMpush(m,NIL);	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL)					{	return MMpush(m,NIL);	}
    
	ZMesh	*topo;

	if(node->type==OBJ_TYPE_ID)
	{
		topo = ((ZObject*)node)->GetMesh();
		if(topo==NULL)					{	return MMpush(m,NIL);	}
	}
	else if(node->type==MSH_TYPE_ID)
	{
		topo = (ZMesh*)node;
	}
	else
		return MMpush(m,NIL);


	vector<ZFace>		*faces;
	ZFace				*F;
	faces = &(topo->Faces);

	// Création de la liste des faces
	if(faces->size()==0)			{	return MMpush(m,NIL);	}

	MMpush(m, s3d);

	int			n=0, mat3d, i, k, tmp_res;
	ZMaterial	*mater;
    for(int j=0; j<faces->size(); j++)
    {
		F = &((*faces)[j]);

		// recupère le materiau
		mater = F->GetMaterial();
		if (mater==NULL)	
		{
			if(MMpush(m,NIL))		return MERRMEM;
		}
		else
		{
			s3d = MMget(m,0);
			mat3d = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),2)), (int)mater);
			if(mat3d!=NIL)	mat3d = PTOM(mat3d);
			if(MMpush(m, mat3d))		return MERRMEM;
		}

		// création des tuples pour les vertices [I I I]
		for(i=0; i<3; i++)
		{
			if(MMpush(m, ITOM(F->VertRef[i])))										return MERRMEM;
			if(MMpush(m, ITOM(AROUNDINT(CONST_TEX_COORD*F->UV1[i].u))))				return MERRMEM;
			if(MMpush(m, ITOM(AROUNDINT(CONST_TEX_COORD*F->UV1[i].v))))				return MERRMEM;
	    	if(MMpush(m, 3*2))														return MERRMEM;
			if(k=MBdeftab(m))		return k;
		}
		if(MMpush(m,NIL)) return MERRMEM;

		// création de la liste des vertices [[I I I] r1]
		for(i=0; i<3; i++)
		{
			if(MMpush(m,2*2))		return MERRMEM;
			if(k=MBdeftab(m))		return k;
		}

		// création d'un element final [HMat3d [[I I I] r1]]
		if(MMpush(m,2*2))		return MERRMEM;
		if(k=MBdeftab(m))		return k;

		INVERT(m,0,1);	// replace le S3d en tête de pile..		
		
		n++;
    }

	MMpull(m);

	if(MMpush(m,NIL))		return MERRMEM;
	for(j=0; j<n; j++)
	{
    	if(MMpush(m,2*2))		return MERRMEM;
		if(k=MBdeftab(m))		return k;
	}

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3listOfPolygonsF
//////////////////////////////////////////////////////////////////////////////////////////////
///	fun [S3d H3d] [[HMat3d [[I F F] r1]] r1]
int ZM3listOfPolygonsF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3listOfPolygonsF ");
#endif
	int h3d  = MMpull(m);
    int s3d  = MMpull(m);

	if((s3d==NIL)||(h3d==NIL))		{	return MMpush(m,NIL);	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	return MMpush(m,NIL);	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL)					{	return MMpush(m,NIL);	}
	
	ZMesh	*topo;

	if(node->type==OBJ_TYPE_ID)
	{
		topo = ((ZObject*)node)->GetMesh();
		if(topo==NULL)					{	return MMpush(m,NIL);	}
	}
	else if(node->type==MSH_TYPE_ID)
	{
		topo = (ZMesh*)node;
	}
	else
		return MMpush(m,NIL);


	vector<ZFace>		*faces;
	ZFace				*F;
	faces = &(topo->Faces);

	// Création de la liste des faces
	if(faces->size()==0)			{	return MMpush(m,NIL);	}

	MMpush(m, s3d);

	int			n=0, mat3d, i, k, tmp_res;
	ZMaterial	*mater;
    for(int j=0; j<faces->size(); j++)
    {
		F = &((*faces)[j]);

		// recupère le materiau
		mater = F->GetMaterial();
		if (mater==NULL)	
		{
			if(MMpush(m,NIL))		return MERRMEM;
		}
		else
		{
			s3d = MMget(m,0);
			mat3d = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),2)), (int)mater);
			if(mat3d!=NIL)	mat3d = PTOM(mat3d);
			if(MMpush(m, mat3d))		return MERRMEM;
		}

		// création des tuples pour les vertices [I I I]
		for(i=0; i<3; i++)
		{
			if(MMpush(m, ITOM(F->VertRef[i])))				return MERRMEM;
			if(MMpush(m, FTOM(F->UV1[i].u)))				return MERRMEM;
			if(MMpush(m, FTOM(F->UV1[i].v)))				return MERRMEM;
	    	if(MMpush(m, 3*2))								return MERRMEM;
			if(k=MBdeftab(m))		return k;
		}
		if(MMpush(m,NIL)) return MERRMEM;

		// création de la liste des vertices [[I I I] r1]
		for(i=0; i<3; i++)
		{
			if(MMpush(m,2*2))		return MERRMEM;
			if(k=MBdeftab(m))		return k;
		}

		// création d'un element final [HMat3d [[I I I] r1]]
		if(MMpush(m,2*2))		return MERRMEM;
		if(k=MBdeftab(m))		return k;

		INVERT(m,0,1);	// replace le S3d en tête de pile..		
		
		n++;
    }

	MMpull(m);

	if(MMpush(m,NIL))		return MERRMEM;
	for(j=0; j<n; j++)
	{
    	if(MMpush(m,2*2))		return MERRMEM;
		if(k=MBdeftab(m))		return k;
	}

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}




//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3setPolygons
//////////////////////////////////////////////////////////////////////////////////////////////
///	fun [S3d H3d [[HMat3d [[I I I] r1]] r1]] I
int ZM3setPolygons(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3setPolygons ");
#endif
	int liste = MTOP(MMpull(m));
	int h3d   = MMpull(m);
    int s3d   = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL)||(liste==NIL))					{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL)					{	MMset(m,0,NIL);		return 0;	}
	
	ZMesh	*topo;

	if(node->type==OBJ_TYPE_ID)
	{
		topo = ((ZObject*)node)->GetMesh();
		if(topo==NULL)					{	MMset(m,0,NIL);		return 0;	}
	}
	else if(node->type==MSH_TYPE_ID)
	{
		topo = (ZMesh*)node;
	}
	else
	{	MMset(m,0,NIL);		return 0;	}

	vector<ZFace>		*faces;
	ZFace				*F;
	faces = &(topo->Faces);

	int		p, q, r, i, j;
	float	u[4], v[4];
	bool	rectangle;									// flag désignant si le polygone est un rectangle ou un triangle

	MMset(m,0,0);

	rectangle = false;

	for(j=0; j<faces->size(); j++)
	{
		F = &((*faces)[j]);

		// CAS où la face précédente était un triangle
		if(!rectangle)
		{
			if(liste==NIL)
			{
				topo->hasTopoChanged = true;
				topo->hasViewChanged = true;
				topo->displayListCreate = false;

				scene->meshModified		= true;

				return 0;
			}

			// récupère le tuple de données de la face
			if((p=MMfetch(m,liste,0)>>1)!=NIL)
			{
				// recupère les données des vertices
				q = MTOP(MMfetch(m,p,1));
				
				for(i=0; i<4; i++)
				{
					u[i] = -100.0f;

					if(q!=NIL)
					{
						r = MTOP(MMfetch(m,q,0));
						if(r!=NIL)
						{
							if(i==3)	rectangle = true;

							u[i] = ((float)MTOI(MMfetch(m,r,1))) / CONST_TEX_COORD;
							v[i] = ((float)MTOI(MMfetch(m,r,2))) / CONST_TEX_COORD;
						}
						q = MTOP(MMfetch(m,q,1));
					}
				}

				// attribue les données à la face courante
				if(u[0] != -100.0f)		{	F->UV1[0].u = u[0];		F->UV1[0].v = v[0];	}
				if(u[1] != -100.0f)		{	F->UV1[1].u = u[1];		F->UV1[1].v = v[1];	}
				if(u[2] != -100.0f)		{	F->UV1[2].u = u[2];		F->UV1[2].v = v[2];	}

				if( F->UV1[0].u<0.0f || F->UV1[1].u<0.0f || F->UV1[2].u<0.0f ||
					F->UV1[0].u>1.0f || F->UV1[1].u>1.0f || F->UV1[2].u>1.0f )	F->clampU1 = false;
				else															F->clampU1 = true;

				if( F->UV1[0].v<0.0f || F->UV1[1].v<0.0f || F->UV1[2].v<0.0f || 
					F->UV1[0].v>1.0f || F->UV1[1].v>1.0f || F->UV1[2].v>1.0f )	F->clampV1 = false;
				else															F->clampV1 = true;
			}
			liste = MTOP(MMfetch(m,liste,1));
		}
		// CAS où la face précédente était un rectangle
		else
		{
			// attribue les données à la face courante
			if(u[0] != -100.0f)		{	F->UV1[0].u = u[0];		F->UV1[0].v = v[0];	}
			if(u[2] != -100.0f)		{	F->UV1[1].u = u[2];		F->UV1[1].v = v[2];	}
			if(u[3] != -100.0f)		{	F->UV1[2].u = u[3];		F->UV1[2].v = v[3];	}

			if( F->UV1[0].u<0.0f || F->UV1[1].u<0.0f || F->UV1[2].u<0.0f ||
				F->UV1[0].u>1.0f || F->UV1[1].u>1.0f || F->UV1[2].u>1.0f )	F->clampU1 = false;
			else															F->clampU1 = true;

			if( F->UV1[0].v<0.0f || F->UV1[1].v<0.0f || F->UV1[2].v<0.0f || 
				F->UV1[0].v>1.0f || F->UV1[1].v>1.0f || F->UV1[2].v>1.0f )	F->clampV1 = false;
			else															F->clampV1 = true;

			rectangle = false;
		}
    }

	topo->hasViewChanged = true;

	// Désactive la compilation des displays lists
//	topo->displayListCreate = false;


//	scene->meshModified		= true;

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3setPolygonsF
//////////////////////////////////////////////////////////////////////////////////////////////
///	fun [S3d H3d [[HMat3d [[I F F] r1]] r1]] I
int ZM3setPolygonsF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3setPolygonsF ");
#endif
	int liste = MTOP(MMpull(m));
	int h3d   = MMpull(m);
    int s3d   = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL)||(liste==NIL))					{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL)					{	MMset(m,0,NIL);		return 0;	}
	
	ZMesh	*topo;

	if(node->type==OBJ_TYPE_ID)
	{
		topo = ((ZObject*)node)->GetMesh();
		if(topo==NULL)					{	MMset(m,0,NIL);		return 0;	}
	}
	else if(node->type==MSH_TYPE_ID)
	{
		topo = (ZMesh*)node;
	}
	else
	{	MMset(m,0,NIL);		return 0;	}

	vector<ZFace>		*faces;
	ZFace				*F;
	faces = &(topo->Faces);

	int		p, q, r, i, j;
	float	u[4], v[4];
	bool	rectangle;									// flag désignant si le polygone est un rectangle ou un triangle

	MMset(m,0,0);

	rectangle = false;

	for(j=0; j<faces->size(); j++)
	{
		F = &((*faces)[j]);

		// CAS où la face précédente était un triangle
		if(!rectangle)
		{
			if(liste==NIL)
			{
				topo->hasTopoChanged = true;
				topo->hasViewChanged = true;
				topo->displayListCreate = false;

				scene->meshModified		= true;

				return 0;
			}

			// récupère le tuple de données de la face
			if((p=MMfetch(m,liste,0)>>1)!=NIL)
			{
				// recupère les données des vertices
				q = MTOP(MMfetch(m,p,1));

				for(i=0; i<4; i++)
				{
					u[i] = -100.0f;

					if(q!=NIL)
					{
						r = MTOP(MMfetch(m,q,0));
						if(r!=NIL)
						{
							if(i==3)	rectangle = true;

							u[i] = MTOF(MMfetch(m,r,1));
							v[i] = MTOF(MMfetch(m,r,2));
						}
						q = MTOP(MMfetch(m,q,1));
					}
				}

				// attribue les données à la face courante
				if(u[0] != -100.0f)		{	F->UV1[0].u = u[0];		F->UV1[0].v = v[0];	}
				if(u[1] != -100.0f)		{	F->UV1[1].u = u[1];		F->UV1[1].v = v[1];	}
				if(u[2] != -100.0f)		{	F->UV1[2].u = u[2];		F->UV1[2].v = v[2];	}

				if( F->UV1[0].u<0.0f || F->UV1[1].u<0.0f || F->UV1[2].u<0.0f ||
					F->UV1[0].u>1.0f || F->UV1[1].u>1.0f || F->UV1[2].u>1.0f )	F->clampU1 = false;
				else															F->clampU1 = true;

				if( F->UV1[0].v<0.0f || F->UV1[1].v<0.0f || F->UV1[2].v<0.0f || 
					F->UV1[0].v>1.0f || F->UV1[1].v>1.0f || F->UV1[2].v>1.0f )	F->clampV1 = false;
				else															F->clampV1 = true;
			}
			liste = MTOP(MMfetch(m,liste,1));
		}
		// CAS où la face précédente était un rectangle
		else
		{
			// attribue les données à la face courante
			if(u[0] != -100.0f)		{	F->UV1[0].u = u[0];		F->UV1[0].v = v[0];	}
			if(u[2] != -100.0f)		{	F->UV1[1].u = u[2];		F->UV1[1].v = v[2];	}
			if(u[3] != -100.0f)		{	F->UV1[2].u = u[3];		F->UV1[2].v = v[3];	}

			if( F->UV1[0].u<0.0f || F->UV1[1].u<0.0f || F->UV1[2].u<0.0f ||
				F->UV1[0].u>1.0f || F->UV1[1].u>1.0f || F->UV1[2].u>1.0f )	F->clampU1 = false;
			else															F->clampU1 = true;

			if( F->UV1[0].v<0.0f || F->UV1[1].v<0.0f || F->UV1[2].v<0.0f || 
				F->UV1[0].v>1.0f || F->UV1[1].v>1.0f || F->UV1[2].v>1.0f )	F->clampV1 = false;
			else															F->clampV1 = true;

			rectangle = false;
		}
    }

	topo->hasViewChanged = true;

	// Désactive la compilation des displays lists
	topo->displayListCreate = false;


	scene->meshModified		= true;

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3deltaPolygons
//////////////////////////////////////////////////////////////////////////////////////////////
///	fun [S3d H3d [[HMat3d [[I I I] r1]] r1]] I
int ZM3deltaPolygons(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3deltaPolygons ");
#endif
	int liste = MTOP(MMpull(m));
	int h3d   = MMpull(m);
    int s3d   = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL)||(liste==NIL))					{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL)					{	MMset(m,0,NIL);		return 0;	}
	
	ZMesh	*topo;

	if(node->type==OBJ_TYPE_ID)
	{
		topo = ((ZObject*)node)->GetMesh();
		if(topo==NULL)					{	MMset(m,0,NIL);		return 0;	}
	}
	else if(node->type==MSH_TYPE_ID)
	{
		topo = (ZMesh*)node;
	}
	else
	{	MMset(m,0,NIL);		return 0;	}

	vector<ZFace>		*faces;
	ZFace				*F;
	faces = &(topo->Faces);

	int		p, q, r, i, j;
	float	u[4], v[4];
	bool	rectangle;												// flag désignant si le polygone est un rectangle ou un triangle

	MMset(m,0,0);

	rectangle = false;

    for(j=0; j<faces->size(); j++)
    {
		F = &((*faces)[j]);

		// CAS où la face précédente était un triangle
		if(!rectangle)
		{
			if(liste==NIL)
			{
				topo->hasTopoChanged = true;
				topo->hasViewChanged = true;
				topo->displayListCreate = false;

				scene->meshModified	 = true;

				return 0;
			}

			// récupère le tuple de données de la face
			if((p=MMfetch(m,liste,0)>>1)!=NIL)
			{
				// recupère les données des vertices
				q = MTOP(MMfetch(m,p,1));
				for(i=0; i<4; i++)
				{
					u[i] = -100.0f;
					
					if(q!=NIL)
					{
						r = MTOP(MMfetch(m,q,0));
						if(r!=NIL)
						{
							if(i==3)	rectangle = true;

							u[i] = ((float)MTOI(MMfetch(m,r,1))) / CONST_TEX_COORD;
							v[i] = ((float)MTOI(MMfetch(m,r,2))) / CONST_TEX_COORD;
						}
						q = MTOP(MMfetch(m,q,1));
					}
				}

				// attribue les données à la face courante
				if(u[0] != -100.0f)		{	F->UV1[0].u += u[0];		F->UV1[0].v += v[0];	}
				if(u[1] != -100.0f)		{	F->UV1[1].u += u[1];		F->UV1[1].v += v[1];	}
				if(u[2] != -100.0f)		{	F->UV1[2].u += u[2];		F->UV1[2].v += v[2];	}

				if( F->UV1[0].u<0.0f || F->UV1[1].u<0.0f || F->UV1[2].u<0.0f ||
					F->UV1[0].u>1.0f || F->UV1[1].u>1.0f || F->UV1[2].u>1.0f )	F->clampU1 = false;
				else															F->clampU1 = true;

				if( F->UV1[0].v<0.0f || F->UV1[1].v<0.0f || F->UV1[2].v<0.0f || 
					F->UV1[0].v>1.0f || F->UV1[1].v>1.0f || F->UV1[2].v>1.0f )	F->clampV1 = false;
				else															F->clampV1 = true;
			}
			liste = MTOP(MMfetch(m,liste,1));
		}
		// CAS où la face précédente était un rectangle
		else
		{
			// attribue les données à la face courante
			if(u[0] != -100.0f)		{	F->UV1[0].u += u[0];		F->UV1[0].v += v[0];	}
			if(u[2] != -100.0f)		{	F->UV1[1].u += u[2];		F->UV1[1].v += v[2];	}
			if(u[3] != -100.0f)		{	F->UV1[2].u += u[3];		F->UV1[2].v += v[3];	}

			if( F->UV1[0].u<0.0f || F->UV1[1].u<0.0f || F->UV1[2].u<0.0f ||
				F->UV1[0].u>1.0f || F->UV1[1].u>1.0f || F->UV1[2].u>1.0f )	F->clampU1 = false;
			else															F->clampU1 = true;

			if( F->UV1[0].v<0.0f || F->UV1[1].v<0.0f || F->UV1[2].v<0.0f || 
				F->UV1[0].v>1.0f || F->UV1[1].v>1.0f || F->UV1[2].v>1.0f )	F->clampV1 = false;
			else															F->clampV1 = true;

			rectangle = false;
		}
    }

	topo->hasViewChanged = true;

	// Désactive la compilation des displays lists
	topo->displayListCreate = false;



	scene->meshModified		= true;

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3deltaPolygonsF
//////////////////////////////////////////////////////////////////////////////////////////////
///	fun [S3d H3d [[HMat3d [[I F F] r1]] r1]] I
int ZM3deltaPolygonsF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3deltaPolygonsF ");
#endif
	int liste = MTOP(MMpull(m));
	int h3d   = MMpull(m);
    int s3d   = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL)||(liste==NIL))					{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL)					{	MMset(m,0,NIL);		return 0;	}
	
	ZMesh	*topo;

	if(node->type==OBJ_TYPE_ID)
	{
		topo = ((ZObject*)node)->GetMesh();
		if(topo==NULL)					{	MMset(m,0,NIL);		return 0;	}
	}
	else if(node->type==MSH_TYPE_ID)
	{
		topo = (ZMesh*)node;
	}
	else
	{	MMset(m,0,NIL);		return 0;	}

	vector<ZFace>		*faces;
	ZFace				*F;
	faces = &(topo->Faces);

	int		p, q, r, i, j;
	float	u[4], v[4];
	bool	rectangle;												// flag désignant si le polygone est un rectangle ou un triangle

	MMset(m,0,0);

	rectangle = false;

    for(j=0; j<faces->size(); j++)
    {
		F = &((*faces)[j]);

		// CAS où la face précédente était un triangle
		if(!rectangle)
		{
			if(liste==NIL)
			{
				topo->hasTopoChanged = true;
				topo->hasViewChanged = true;
				topo->displayListCreate = false;

				scene->meshModified	 = true;

				return 0;
			}

			// récupère le tuple de données de la face
			if((p=MMfetch(m,liste,0)>>1)!=NIL)
			{
				// recupère les données des vertices
				q = MTOP(MMfetch(m,p,1));
				for(i=0; i<4; i++)
				{
					u[i] = -100.0f;
					
					if(q!=NIL)
					{
						r = MTOP(MMfetch(m,q,0));
						if(r!=NIL)
						{
							if(i==3)	rectangle = true;

							u[i] = MTOF(MMfetch(m,r,1));
							v[i] = MTOF(MMfetch(m,r,2));
						}
						q = MTOP(MMfetch(m,q,1));
					}
				}

				// attribue les données à la face courante
				if(u[0] != -100.0f)		{	F->UV1[0].u += u[0];		F->UV1[0].v += v[0];	}
				if(u[1] != -100.0f)		{	F->UV1[1].u += u[1];		F->UV1[1].v += v[1];	}
				if(u[2] != -100.0f)		{	F->UV1[2].u += u[2];		F->UV1[2].v += v[2];	}

				if( F->UV1[0].u<0.0f || F->UV1[1].u<0.0f || F->UV1[2].u<0.0f ||
					F->UV1[0].u>1.0f || F->UV1[1].u>1.0f || F->UV1[2].u>1.0f )	F->clampU1 = false;
				else															F->clampU1 = true;

				if( F->UV1[0].v<0.0f || F->UV1[1].v<0.0f || F->UV1[2].v<0.0f || 
					F->UV1[0].v>1.0f || F->UV1[1].v>1.0f || F->UV1[2].v>1.0f )	F->clampV1 = false;
				else															F->clampV1 = true;
			}
			liste = MTOP(MMfetch(m,liste,1));
		}
		// CAS où la face précédente était un rectangle
		else
		{
			// attribue les données à la face courante
			if(u[0] != -100.0f)		{	F->UV1[0].u += u[0];		F->UV1[0].v += v[0];	}
			if(u[2] != -100.0f)		{	F->UV1[1].u += u[2];		F->UV1[1].v += v[2];	}
			if(u[3] != -100.0f)		{	F->UV1[2].u += u[3];		F->UV1[2].v += v[3];	}

			if( F->UV1[0].u<0.0f || F->UV1[1].u<0.0f || F->UV1[2].u<0.0f ||
				F->UV1[0].u>1.0f || F->UV1[1].u>1.0f || F->UV1[2].u>1.0f )	F->clampU1 = false;
			else															F->clampU1 = true;

			if( F->UV1[0].v<0.0f || F->UV1[1].v<0.0f || F->UV1[2].v<0.0f || 
				F->UV1[0].v>1.0f || F->UV1[1].v>1.0f || F->UV1[2].v>1.0f )	F->clampV1 = false;
			else															F->clampV1 = true;

			rectangle = false;
		}
    }

	topo->hasViewChanged = true;

	// Désactive la compilation des displays lists
	topo->displayListCreate = false;



	scene->meshModified		= true;

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3morphPolygons
//////////////////////////////////////////////////////////////////////////////////////////////
///	fun [S3d H3d [[HMat3d [[I I I] r1]] r1] [[HMat3d [[I I I] r1]] r1] I] I
int ZM3morphPolygons(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3morphPolgons ");
#endif
	int rate  = MTOI(MMpull(m));
	int list1 = MTOP(MMpull(m));
	int list2 = MTOP(MMpull(m));
	int h3d   = MMpull(m);
    int s3d   = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL)||(list1==NIL)||(list2==NIL)||(rate==NIL))			{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL)					{	MMset(m,0,NIL);		return 0;	}
	
	ZMesh	*topo;

	if(node->type==OBJ_TYPE_ID)
	{
		topo = ((ZObject*)node)->GetMesh();
		if(topo==NULL)					{	MMset(m,0,NIL);		return 0;	}
	}
	else if(node->type==MSH_TYPE_ID)
	{
		topo = (ZMesh*)node;
	}
	else
	{	MMset(m,0,NIL);		return 0;	}

	vector<ZFace>		*faces;
	ZFace				*F;
	faces = &(topo->Faces);

	int		p, pp, q, qq, r, rr, i, j;
	float	u[4], v[4];
	bool	rectangle;												// flag désignant si le polygone est un rectangle ou un triangle

	float	t = (float)rate;
	t /= CONST_ANGLE;
	float	ut = 1-t;

	float	val1, val2;

	MMset(m,0,0);

	rectangle = false;

    for(j=0; j<faces->size(); j++)
    {
		F = &((*faces)[j]);

		// CAS où la face précédente était un triangle
		if(!rectangle)
		{
			if((list1==NIL)||(list2==NIL))
			{
				topo->hasTopoChanged = true;
				topo->hasViewChanged = true;
				topo->displayListCreate = false;
				scene->meshModified	 = true;
				return 0;
			}

			// récupère le tuple de données de la face
			if(((p=MMfetch(m,list1,0)>>1)!=NIL)&&((pp=MMfetch(m,list2,0)>>1)!=NIL))		// récupère le tuple de données de la face
			{
				// recupère les données des vertices
				q  = MTOP(MMfetch(m,p,1));													// recupère les données des vertices 1
				qq = MTOP(MMfetch(m,pp,1));													// recupère les données des vertices 2

				for(i=0; i<4; i++)
				{
					u[i] = -100.0f;
					
					if((q!=NIL)&&(qq!=NIL))
					{
						r  = MTOP(MMfetch(m,q,0));
						rr = MTOP(MMfetch(m,qq,0));
	
						if((r!=NIL)&&(rr!=NIL))
						{
							if(i==3)	rectangle = true;

							val1 = ((float)MTOI(MMfetch(m,r,1)))  / CONST_TEX_COORD;
							val2 = ((float)MTOI(MMfetch(m,rr,1))) / CONST_TEX_COORD;
							u[i] = ut*val1 + t*val2;

							val1 = ((float)MTOI(MMfetch(m,r,2)))  / CONST_TEX_COORD;
							val2 = ((float)MTOI(MMfetch(m,rr,2))) / CONST_TEX_COORD;
							v[i] = ut*val1 + t*val2;
						}
						q  = MTOP(MMfetch(m,q,1));
						qq = MTOP(MMfetch(m,qq,1));
					}
				}

				// attribue les données à la face courante
				if(u[0] != -100.0f)		{	F->UV1[0].u = u[0];		F->UV1[0].v = v[0];	}
				if(u[1] != -100.0f)		{	F->UV1[1].u = u[1];		F->UV1[1].v = v[1];	}
				if(u[2] != -100.0f)		{	F->UV1[2].u = u[2];		F->UV1[2].v = v[2];	}

				if( F->UV1[0].u<0.0f || F->UV1[1].u<0.0f || F->UV1[2].u<0.0f ||
					F->UV1[0].u>1.0f || F->UV1[1].u>1.0f || F->UV1[2].u>1.0f )	F->clampU1 = false;
				else															F->clampU1 = true;

				if( F->UV1[0].v<0.0f || F->UV1[1].v<0.0f || F->UV1[2].v<0.0f || 
					F->UV1[0].v>1.0f || F->UV1[1].v>1.0f || F->UV1[2].v>1.0f )	F->clampV1 = false;
				else															F->clampV1 = true;
			}
			list1 = MTOP(MMfetch(m,list1,1));
			list2 = MTOP(MMfetch(m,list2,1));
		}
		// CAS où la face précédente était un rectangle
		else
		{
			// attribue les données à la face courante
			if(u[0] != -100.0f)		{	F->UV1[0].u = u[0];		F->UV1[0].v = v[0];	}
			if(u[2] != -100.0f)		{	F->UV1[1].u = u[2];		F->UV1[1].v = v[2];	}
			if(u[3] != -100.0f)		{	F->UV1[2].u = u[3];		F->UV1[2].v = v[3];	}

			if( F->UV1[0].u<0.0f || F->UV1[1].u<0.0f || F->UV1[2].u<0.0f ||
				F->UV1[0].u>1.0f || F->UV1[1].u>1.0f || F->UV1[2].u>1.0f )	F->clampU1 = false;
			else															F->clampU1 = true;

			if( F->UV1[0].v<0.0f || F->UV1[1].v<0.0f || F->UV1[2].v<0.0f || 
				F->UV1[0].v>1.0f || F->UV1[1].v>1.0f || F->UV1[2].v>1.0f )	F->clampV1 = false;
			else															F->clampV1 = true;

			rectangle = false;
		}
    }

	topo->hasViewChanged = true;

	// Désactive la compilation des displays lists
	topo->displayListCreate = false;


	scene->meshModified		= true;

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3morphPolygonsF
//////////////////////////////////////////////////////////////////////////////////////////////
///	fun [S3d H3d [[HMat3d [[I F F] r1]] r1] [[HMat3d [[I F F] r1]] r1] F] I
int ZM3morphPolygonsF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3morphPolygonsF ");
#endif
	int rate  = MMpull(m);
	int list1 = MTOP(MMpull(m));
	int list2 = MTOP(MMpull(m));
	int h3d   = MMpull(m);
    int s3d   = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL)||(list1==NIL)||(list2==NIL)||(rate==NIL))			{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL)					{	MMset(m,0,NIL);		return 0;	}
	
	ZMesh	*topo;

	if(node->type==OBJ_TYPE_ID)
	{
		topo = ((ZObject*)node)->GetMesh();
		if(topo==NULL)					{	MMset(m,0,NIL);		return 0;	}
	}
	else if(node->type==MSH_TYPE_ID)
	{
		topo = (ZMesh*)node;
	}
	else
	{	MMset(m,0,NIL);		return 0;	}

	vector<ZFace>		*faces;
	ZFace				*F;
	faces = &(topo->Faces);

	int		p, pp, q, qq, r, rr, i, j;
	float	u[4], v[4];
	bool	rectangle;												// flag désignant si le polygone est un rectangle ou un triangle

	float	t = MTOF(rate);
	float	ut = 1-t;

	float	val1, val2;

	MMset(m,0,0);

	rectangle = false;

    for(j=0; j<faces->size(); j++)
    {
		F = &((*faces)[j]);

		// CAS où la face précédente était un triangle
		if(!rectangle)
		{
			if((list1==NIL)||(list2==NIL))
			{
				topo->hasTopoChanged = true;
				topo->hasViewChanged = true;
				topo->displayListCreate = false;

				scene->meshModified	 = true;

				return 0;
			}

			// récupère le tuple de données de la face
			if(((p=MMfetch(m,list1,0)>>1)!=NIL)&&((pp=MMfetch(m,list2,0)>>1)!=NIL))		// récupère le tuple de données de la face
			{
				// recupère les données des vertices
				q  = MTOP(MMfetch(m,p,1));													// recupère les données des vertices 1
				qq = MTOP(MMfetch(m,pp,1));													// recupère les données des vertices 2

				for(i=0; i<4; i++)
				{
					u[i] = -100.0f;
					
					if((q!=NIL)&&(qq!=NIL))
					{
						r  = MTOP(MMfetch(m,q,0));
						rr = MTOP(MMfetch(m,qq,0));

						if((r!=NIL)&&(rr!=NIL))
						{
							if(i==3)	rectangle = true;

							val1 = MTOF(MMfetch(m,r,1));
							val2 = MTOF(MMfetch(m,rr,1));
							u[i] = ut*val1 + t*val2;

							val1 = MTOF(MMfetch(m,r,2));
							val2 = MTOF(MMfetch(m,rr,2));
							v[i] = ut*val1 + t*val2;
						}
						q  = MTOP(MMfetch(m,q,1));
						qq = MTOP(MMfetch(m,qq,1));
					}
				}

				// attribue les données à la face courante
				if(u[0] != -100.0f)		{	F->UV1[0].u = u[0];		F->UV1[0].v = v[0];	}
				if(u[1] != -100.0f)		{	F->UV1[1].u = u[1];		F->UV1[1].v = v[1];	}
				if(u[2] != -100.0f)		{	F->UV1[2].u = u[2];		F->UV1[2].v = v[2];	}

				if( F->UV1[0].u<0.0f || F->UV1[1].u<0.0f || F->UV1[2].u<0.0f ||
					F->UV1[0].u>1.0f || F->UV1[1].u>1.0f || F->UV1[2].u>1.0f )	F->clampU1 = false;
				else															F->clampU1 = true;

				if( F->UV1[0].v<0.0f || F->UV1[1].v<0.0f || F->UV1[2].v<0.0f || 
					F->UV1[0].v>1.0f || F->UV1[1].v>1.0f || F->UV1[2].v>1.0f )	F->clampV1 = false;
				else															F->clampV1 = true;
			}
			list1 = MTOP(MMfetch(m,list1,1));
			list2 = MTOP(MMfetch(m,list2,1));
		}
		// CAS où la face précédente était un rectangle
		else
		{
			// attribue les données à la face courante
			if(u[0] != -100.0f)		{	F->UV1[0].u = u[0];		F->UV1[0].v = v[0];	}
			if(u[2] != -100.0f)		{	F->UV1[1].u = u[2];		F->UV1[1].v = v[2];	}
			if(u[3] != -100.0f)		{	F->UV1[2].u = u[3];		F->UV1[2].v = v[3];	}

			if( F->UV1[0].u<0.0f || F->UV1[1].u<0.0f || F->UV1[2].u<0.0f ||
				F->UV1[0].u>1.0f || F->UV1[1].u>1.0f || F->UV1[2].u>1.0f )	F->clampU1 = false;
			else															F->clampU1 = true;

			if( F->UV1[0].v<0.0f || F->UV1[1].v<0.0f || F->UV1[2].v<0.0f || 
				F->UV1[0].v>1.0f || F->UV1[1].v>1.0f || F->UV1[2].v>1.0f )	F->clampV1 = false;
			else															F->clampV1 = true;

			rectangle = false;
		}
    }

	topo->hasViewChanged = true;

	// Désactive la compilation des displays lists
	topo->displayListCreate = false;


	scene->meshModified		= true;

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}


 
//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3topoAddVertex
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d [I I I]] I
int ZM3topoAddVertex(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3topoAddVertex ");
#endif
	int vtx  = MMpull(m);
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL)||(vtx==NIL))						{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)												{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=MSH_TYPE_ID))					{	MMset(m,0,NIL);		return 0;	}
    ZMesh	*topo = (ZMesh*) node;

	// Recupère les coords du vertex
	float	vertX =  ((float)MTOI(MMfetch(m,MTOP(vtx),0))) / 100.0f;
	float	vertY =  ((float)MTOI(MMfetch(m,MTOP(vtx),1))) / 100.0f;
	float	vertZ = -((float)MTOI(MMfetch(m,MTOP(vtx),2))) / 100.0f;

	ZVert	vert;
	vert.color1.SetCoord(1.0f, 1.0f, 1.0f);
	vert.color2.SetCoord(1.0f, 1.0f, 1.0f);
	
	vert.SetCoord( vertX, vertY, vertZ );
	int numVert = topo->addVert(vert);

	MMset(m,0,ITOM(numVert));
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3topoAddVertexF
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d [F F F]] I
int ZM3topoAddVertexF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3topoAddVertexF ");
#endif
	int vtx  = MMpull(m);
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL)||(vtx==NIL))						{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)												{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=MSH_TYPE_ID))					{	MMset(m,0,NIL);		return 0;	}
    ZMesh	*topo = (ZMesh*) node;

	// Recupère les coords du vertex
	float	vertX =  MTOF(MMfetch(m,MTOP(vtx),0)) / 100.0f;
	float	vertY =  MTOF(MMfetch(m,MTOP(vtx),1)) / 100.0f;
	float	vertZ = -MTOF(MMfetch(m,MTOP(vtx),2)) / 100.0f;

	ZVert	vert;
	vert.color1.SetCoord(1.0f, 1.0f, 1.0f);
	vert.color2.SetCoord(1.0f, 1.0f, 1.0f);

	vert.SetCoord( vertX, vertY, vertZ );
	int numVert = topo->addVert(vert);

	MMset(m,0,ITOM(numVert));
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3topoAddVertices
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d [[I I I] r1]] I
int ZM3topoAddVertices(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3topoAddVertices ");
#endif
	int vtx  = MTOP(MMpull(m));
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL)||(vtx==NIL))						{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)												{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=MSH_TYPE_ID))					{	MMset(m,0,NIL);		return 0;	}
    ZMesh	*topo = (ZMesh*) node;

	// Recupère les coords du vertex
	ZVert	vert;
	vert.color1.SetCoord(1.0f, 1.0f, 1.0f);
	vert.color2.SetCoord(1.0f, 1.0f, 1.0f);

	int coord, numVert=0;
	
	while(vtx!=NIL)
	{
		if((coord=MTOP(MMfetch(m,vtx,0))) != NIL)
		{
			float	vertX =  ((float)MTOI(MMfetch(m,coord,0))) / 100.0f;
			float	vertY =  ((float)MTOI(MMfetch(m,coord,1))) / 100.0f;
			float	vertZ = -((float)MTOI(MMfetch(m,coord,2))) / 100.0f;

			vert.SetCoord( vertX, vertY, vertZ );
			numVert = topo->addVert(vert);
		}
		vtx = MTOP(MMfetch(m,vtx,1));
	}

	MMset(m,0,ITOM(numVert));
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3topoAddVerticesF
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d [[F F F] r1]] I
int ZM3topoAddVerticesF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3topoAddVerticesF ");
#endif
	int vtx  = MTOP(MMpull(m));
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL)||(vtx==NIL))						{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)												{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=MSH_TYPE_ID))					{	MMset(m,0,NIL);		return 0;	}
    ZMesh	*topo = (ZMesh*) node;

	// Recupère les coords du vertex
	ZVert	vert;
	vert.color1.SetCoord(1.0f, 1.0f, 1.0f);
	vert.color2.SetCoord(1.0f, 1.0f, 1.0f);

	int coord, numVert=0;
	
	while(vtx!=NIL)
	{
		if((coord=MTOP(MMfetch(m,vtx,0))) != NIL)
		{
			float	vertX =  MTOF(MMfetch(m,coord,0)) / 100.0f;
			float	vertY =  MTOF(MMfetch(m,coord,1)) / 100.0f;
			float	vertZ = -MTOF(MMfetch(m,coord,2)) / 100.0f;

			vert.SetCoord( vertX, vertY, vertZ );
			numVert = topo->addVert(vert);
		}
		vtx = MTOP(MMfetch(m,vtx,1));
	}

	MMset(m,0,ITOM(numVert));
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3listOfVertices
//////////////////////////////////////////////////////////////////////////////////////////////
///	fun [S3d H3d] [[I I I] r1]
int ZM3listOfVertices(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3listOfVertices ");
#endif
	int h3d  = MMpull(m);
    int s3d  = MMpull(m);

	if((s3d==NIL)||(h3d==NIL))		{	return MMpush(m,NIL);	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	return MMpush(m,NIL);	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL)					{	return MMpush(m,NIL);	}
	
	ZMesh	*topo;

	if(node->type==OBJ_TYPE_ID)
	{
		topo = ((ZObject*)node)->GetMesh();
		if(topo==NULL)					{	return MMpush(m,NIL);	}
	}
	else if(node->type==MSH_TYPE_ID)
	{
		topo = (ZMesh*)node;
	}
	else
		return MMpush(m,NIL);

	
	ZVert	*vert;
	int		n=0, k;
	
	for(int j=0; j<topo->NbVerts; j++)
	{
		vert = &(topo->Verts[j]);
		if(MMpush(m,ITOM(AROUNDINT(100.0f*vert->x))))			return MERRMEM;
		if(MMpush(m,ITOM(AROUNDINT(100.0f*vert->y))))			return MERRMEM;
		if(MMpush(m,ITOM(AROUNDINT(-100.0f*vert->z))))			return MERRMEM;
    	if (MMpush(m,3*2))		return MERRMEM;
		if (k=MBdeftab(m))		return k;
		n++;
	}

	if(MMpush(m,NIL))		return MERRMEM;
	for(j=0; j<n; j++)
	{
    	if(MMpush(m,2*2))		return MERRMEM;
		if(k=MBdeftab(m))		return k;
	}

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3listOfVerticesF
//////////////////////////////////////////////////////////////////////////////////////////////
///	fun [S3d H3d] [[F F F] r1]
int ZM3listOfVerticesF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3listOfVerticesF ");
#endif
	int h3d  = MMpull(m);
    int s3d  = MMpull(m);

	if((s3d==NIL)||(h3d==NIL))		{	return MMpush(m,NIL);	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	return MMpush(m,NIL);	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL)					{	return MMpush(m,NIL);	}
	
	ZMesh	*topo;

	if(node->type==OBJ_TYPE_ID)
	{
		topo = ((ZObject*)node)->GetMesh();
		if(topo==NULL)					{	return MMpush(m,NIL);	}
	}
	else if(node->type==MSH_TYPE_ID)
	{
		topo = (ZMesh*)node;
	}
	else
		return MMpush(m,NIL);

	
	ZVert	*vert;
	int		n=0, k;
	
	for(int j=0; j<topo->NbVerts; j++)
	{
		vert = &(topo->Verts[j]);
		if(MMpush(m,FTOM(100.0f*vert->x)))			return MERRMEM;
		if(MMpush(m,FTOM(100.0f*vert->y)))			return MERRMEM;
		if(MMpush(m,FTOM(-100.0f*vert->z)))			return MERRMEM;
    	if (MMpush(m,3*2))		return MERRMEM;
		if (k=MBdeftab(m))		return k;
		n++;
	}

	if(MMpush(m,NIL))		return MERRMEM;
	for(j=0; j<n; j++)
	{
    	if(MMpush(m,2*2))		return MERRMEM;
		if(k=MBdeftab(m))		return k;
	}

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3topoSetVertex
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d I [I I I]] I
int ZM3topoSetVertex(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3topoSetVertex ");
#endif
	int vtx  = MMpull(m);
	int num  = MMpull(m);
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL)||(vtx==NIL)||(num==NIL))			{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)												{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=MSH_TYPE_ID))					{	MMset(m,0,NIL);		return 0;	}
    ZMesh	*topo = (ZMesh*) node;

	int index = MTOI(num);
	if(index > topo->NbVerts)		{	MMset(m,0,NIL);		return 0;	}

	// Recupère les coords du vertex
	float	vertX =  ((float)MTOI(MMfetch(m,MTOP(vtx),0))) / 100.0f;
	float	vertY =  ((float)MTOI(MMfetch(m,MTOP(vtx),1))) / 100.0f;
	float	vertZ = -((float)MTOI(MMfetch(m,MTOP(vtx),2))) / 100.0f;

	topo->Verts[index].SetCoord( vertX, vertY, vertZ );

	topo->hasTopoChanged = true;
	topo->hasViewChanged = true;
	
	// Désactive la compilation des displays lists
	topo->displayListCreate = false;

	scene->meshModified		= true;

	MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3topoSetVertexF
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d I [F F F]] I
int ZM3topoSetVertexF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3topoSetVertexF ");
#endif
	int vtx  = MMpull(m);
	int num  = MMpull(m);
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);



	if((s3d==NIL)||(h3d==NIL)||(vtx==NIL)||(num==NIL))			{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)												{	MMset(m,0,NIL);		return 0;	}
    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=MSH_TYPE_ID))					{	MMset(m,0,NIL);		return 0;	}
    ZMesh	*topo = (ZMesh*) node;

	int index = MTOI(num);
	if(index > topo->NbVerts)		{	MMset(m,0,NIL);		return 0;	}


	// Recupère les coords du vertex
	float	vertX =  MTOF(MMfetch(m,MTOP(vtx),0)) / 100.0f;
	float	vertY =  MTOF(MMfetch(m,MTOP(vtx),1)) / 100.0f;
    float	vertZ = -MTOF(MMfetch(m,MTOP(vtx),2)) / 100.0f;

	topo->Verts[index].SetCoord( vertX, vertY, vertZ );
	topo->hasTopoChanged = true;
	topo->hasViewChanged = true;
	
	// Désactive la compilation des displays lists
	topo->displayListCreate = false;

	scene->meshModified		= true;


	MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3topoGetVertex
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d I] [I I I]
int ZM3topoGetVertex(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3topoGetVertex ");
#endif
	int num  = MMpull(m);
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL)||(num==NIL))						{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)												{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=MSH_TYPE_ID))					{	MMset(m,0,NIL);		return 0;	}
    ZMesh	*topo = (ZMesh*) node;

	int index = MTOI(num);
	if(index > topo->NbVerts)		{	MMset(m,0,NIL);		return 0;	}

	// crée le tuple final
	int tuple = MMmalloc(m, 3, TYPETAB);
	if(tuple==NIL)					{	MMset(m,0,NIL);		return MERRMEM;	}

	MMstore(m, tuple, 0, ITOM(AROUNDINT(100.0f*topo->Verts[index].x)));
	MMstore(m, tuple, 1, ITOM(AROUNDINT(100.0f*topo->Verts[index].y)));
	MMstore(m, tuple, 2, ITOM(AROUNDINT(-100.0f*topo->Verts[index].z)));

	MMset(m,0,PTOM(tuple));
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3topoGetVertexF
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d I] [F F F]
int ZM3topoGetVertexF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3topoGetVertexF ");
#endif
	int num  = MMpull(m);
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL)||(num==NIL))						{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)												{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=MSH_TYPE_ID))					{	MMset(m,0,NIL);		return 0;	}
    ZMesh	*topo = (ZMesh*) node;

	int index = MTOI(num);
	if(index > topo->NbVerts)		{	MMset(m,0,NIL);		return 0;	}

	// crée le tuple final
	int tuple = MMmalloc(m, 3, TYPETAB);
	if(tuple==NIL)					{	MMset(m,0,NIL);		return MERRMEM;	}

	MMstore(m, tuple, 0, FTOM(100.0f*topo->Verts[index].x)  );
	MMstore(m, tuple, 1, FTOM(100.0f*topo->Verts[index].y)  );
	MMstore(m, tuple, 2, FTOM(-100.0f*topo->Verts[index].z) );

	MMset(m,0,PTOM(tuple));
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3setVertices
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d [[I I I] r1]] I
int ZM3setVertices(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3setVertices ");
#endif
	int liste = MTOP(MMpull(m));
	int h3d   = MMpull(m);
    int s3d   = MMpull(m);

	if((s3d==NIL)||(h3d==NIL)||(liste==NIL))					{	return MMpush(m,NIL);	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)												{	return MMpush(m,NIL);	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL)					{	return MMpush(m,NIL);	}
	
	ZMesh	*topo;

	if(node->type==OBJ_TYPE_ID)
	{
		topo = ((ZObject*)node)->GetMesh();
		if(topo==NULL)					{	return MMpush(m,NIL);	}
	}
	else if(node->type==MSH_TYPE_ID)
	{
		topo = (ZMesh*)node;
	}
	else
		return MMpush(m,NIL);

	ZVert	*vert;
	int		p;


	for(int j=0; j<topo->NbVerts; j++)
	{
		vert = &(topo->Verts[j]);

		if(liste==NIL)
		{
			topo->hasTopoChanged = true;
			topo->hasViewChanged = true;

			scene->meshModified	= true;

			MMpush(m,0);
			return 0;
		}

		if((p=MMfetch(m,liste,0)>>1)!=NIL)
		{
			vert->SetCoord( ((float)MTOI(MMfetch(m,p,0)))/100.0f, ((float)MTOI(MMfetch(m,p,1)))/100.0f, -((float)MTOI(MMfetch(m,p,2)))/100.0f );
		}
		
		liste = MTOP(MMfetch(m,liste,1));
    }

	topo->hasTopoChanged = true;
	topo->hasViewChanged = true;


	// Désactive la compilation des displays lists
	topo->displayListCreate = false;


	scene->meshModified		= true;

	MMpush(m,0);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3setVerticesF
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d [[F F F] r1]] I
int ZM3setVerticesF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3setVerticesF ");
#endif
	int liste = MTOP(MMpull(m));
	int h3d   = MMpull(m);
    int s3d   = MMpull(m);

	if((s3d==NIL)||(h3d==NIL)||(liste==NIL))					{	return MMpush(m,NIL);	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)												{	return MMpush(m,NIL);	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL)					{	return MMpush(m,NIL);	}
	
	ZMesh	*topo;

	if(node->type==OBJ_TYPE_ID)
	{
		topo = ((ZObject*)node)->GetMesh();
		if(topo==NULL)					{	return MMpush(m,NIL);	}
	}
	else if(node->type==MSH_TYPE_ID)
	{
		topo = (ZMesh*)node;
	}
	else
		return MMpush(m,NIL);

	ZVert	*vert;
	int		p;


	for(int j=0; j<topo->NbVerts; j++)
	{
		vert = &(topo->Verts[j]);

		if(liste==NIL)
		{
			topo->hasTopoChanged = true;
			topo->hasViewChanged = true;

			scene->meshModified	= true;

			MMpush(m,0);
			return 0;
		}

		if((p=MMfetch(m,liste,0)>>1)!=NIL)
		{
			vert->SetCoord( MTOF(MMfetch(m,p,0))/100.0f, MTOF(MMfetch(m,p,1))/100.0f, -MTOF(MMfetch(m,p,2))/100.0f );
		}
		
		liste = MTOP(MMfetch(m,liste,1));
    }

	topo->hasTopoChanged = true;
	topo->hasViewChanged = true;


	// Désactive la compilation des displays lists
	topo->displayListCreate = false;


	scene->meshModified		= true;

	MMpush(m,0);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3deltaVertex
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d I [I I I]] I
int ZM3deltaVertex(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3deltaVertex ");
#endif
	int vtx  = MMpull(m);
	int num  = MMpull(m);
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL)||(vtx==NIL)||(num==NIL))			{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)												{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL)					{	MMset(m,0,NIL);		return 0;	}
	
	ZMesh	*topo;

	if(node->type==OBJ_TYPE_ID)
	{
		topo = ((ZObject*)node)->GetMesh();
		if(topo==NULL)					{	MMset(m,0,NIL);		return 0;	}
	}
	else if(node->type==MSH_TYPE_ID)
	{
		topo = (ZMesh*)node;
	}
	else
	{	MMset(m,0,NIL);		return 0;	}

	int index = MTOI(num);
	if(index > topo->NbVerts)									{	MMset(m,0,NIL);		return 0;	}

	// Recupère les coords du vertex
	float	vertX = ((float)MTOI(MMfetch(m,MTOP(vtx),0))) / 100.0f;
	float	vertY = ((float)MTOI(MMfetch(m,MTOP(vtx),1))) / 100.0f;
	float	vertZ = -((float)MTOI(MMfetch(m,MTOP(vtx),2))) / 100.0f;

	topo->Verts[index].x += vertX;
	topo->Verts[index].y += vertY;
	topo->Verts[index].z += vertZ;

	topo->hasTopoChanged = true;
	topo->hasViewChanged = true;
	
	// Désactive la compilation des displays lists
	topo->displayListCreate = false;

	scene->meshModified		= true;

	MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3deltaVertexF
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d I [I I I]] I
int ZM3deltaVertexF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3deltaVertexF ");
#endif
	int vtx  = MMpull(m);
	int num  = MMpull(m);
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL)||(vtx==NIL)||(num==NIL))			{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)												{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL)					{	MMset(m,0,NIL);		return 0;	}
	
	ZMesh	*topo;

	if(node->type==OBJ_TYPE_ID)
	{
		topo = ((ZObject*)node)->GetMesh();
		if(topo==NULL)					{	MMset(m,0,NIL);		return 0;	}
	}
	else if(node->type==MSH_TYPE_ID)
	{
		topo = (ZMesh*)node;
	}
	else
	{	MMset(m,0,NIL);		return 0;	}

	int index = MTOI(num);
	if(index > topo->NbVerts)									{	MMset(m,0,NIL);		return 0;	}

	// Recupère les coords du vertex
	float	vertX = MTOF(MMfetch(m,MTOP(vtx),0)) / 100.0f;
	float	vertY = MTOF(MMfetch(m,MTOP(vtx),1)) / 100.0f;
	float	vertZ = -MTOF(MMfetch(m,MTOP(vtx),2)) / 100.0f;

	topo->Verts[index].x += vertX;
	topo->Verts[index].y += vertY;
	topo->Verts[index].z += vertZ;

	topo->hasTopoChanged = true;
	topo->hasViewChanged = true;
	
	// Désactive la compilation des displays lists
	topo->displayListCreate = false;

	scene->meshModified		= true;

	MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3deltaVertices
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d [[I I I] r1]] I
int ZM3deltaVertices(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3deltaVertices ");
#endif

	int liste = MTOP(MMpull(m));
	int h3d   = MMpull(m);
    int s3d   = MMpull(m);

	if((s3d==NIL)||(h3d==NIL)||(liste==NIL))					{	return MMpush(m,NIL);	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)												{	return MMpush(m,NIL);	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL)					{	return MMpush(m,NIL);	}
	
	ZMesh	*topo;

	if(node->type==OBJ_TYPE_ID)
	{
		topo = ((ZObject*)node)->GetMesh();
		if(topo==NULL)					{	return MMpush(m,NIL);	}
	}
	else if(node->type==MSH_TYPE_ID)
	{
		topo = (ZMesh*)node;
	}
	else
		return MMpush(m,NIL);

	
	ZVert	*vert;
	int		p;
	
    for(int j=0; j<topo->NbVerts; j++)
    {
		vert = &(topo->Verts[j]);

		if(liste==NIL)
		{
			topo->hasTopoChanged = true;
			topo->hasViewChanged = true;

			scene->meshModified		= true;

			MMpush(m,0);
			return 0;
		}

		if((p=MMfetch(m,liste,0)>>1)!=NIL)
		{
			vert->x += ((float)MTOI(MMfetch(m,p,0)))/100.0f;
			vert->y += ((float)MTOI(MMfetch(m,p,1)))/100.0f;
			vert->z += -((float)MTOI(MMfetch(m,p,2)))/100.0f;
		}
		
		liste = MTOP(MMfetch(m,liste,1));
    }
	
	topo->hasTopoChanged = true;
	topo->hasViewChanged = true;

	// Désactive la compilation des displays lists
	topo->displayListCreate = false;


	scene->meshModified		= true;

	MMpush(m,0);
	
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3deltaVerticesF
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d [[F F F] r1]] I
int ZM3deltaVerticesF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3deltaVerticesF ");
#endif

	int liste = MTOP(MMpull(m));
	int h3d   = MMpull(m);
    int s3d   = MMpull(m);

	if((s3d==NIL)||(h3d==NIL)||(liste==NIL))					{	return MMpush(m,NIL);	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)												{	return MMpush(m,NIL);	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL)					{	return MMpush(m,NIL);	}
	
	ZMesh	*topo;

	if(node->type==OBJ_TYPE_ID)
	{
		topo = ((ZObject*)node)->GetMesh();
		if(topo==NULL)					{	return MMpush(m,NIL);	}
	}
	else if(node->type==MSH_TYPE_ID)
	{
		topo = (ZMesh*)node;
	}
	else
		return MMpush(m,NIL);

	
	ZVert	*vert;
	int		p;
	
    for(int j=0; j<topo->NbVerts; j++)
    {
		vert = &(topo->Verts[j]);

		if(liste==NIL)
		{
			topo->hasTopoChanged = true;
			topo->hasViewChanged = true;

			scene->meshModified		= true;

			MMpush(m,0);
			return 0;
		}

		if((p=MMfetch(m,liste,0)>>1)!=NIL)
		{
			vert->x += MTOF(MMfetch(m,p,0))  / 100.0f;
			vert->y += MTOF(MMfetch(m,p,1))  / 100.0f;
			vert->z += -MTOF(MMfetch(m,p,2)) / 100.0f;
		}
		
		liste = MTOP(MMfetch(m,liste,1));
    }
	
	topo->hasTopoChanged = true;
	topo->hasViewChanged = true;

	// Désactive la compilation des displays lists
	topo->displayListCreate = false;


	scene->meshModified		= true;

	MMpush(m,0);
	
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3morphVertex
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d I [I I I] [I I I] I] I
int ZM3morphVertex(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3morphVertex ");
#endif
	int rate = MTOI(MMpull(m));
	int pos2 = MTOP(MMpull(m));
	int pos1 = MTOP(MMpull(m));
	int num  = MMpull(m);
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL)||(num==NIL)||(pos1==NIL)||(pos2==NIL)||(rate==NIL))			{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)																			{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL)					{	MMset(m,0,NIL);		return 0;	}
	
	ZMesh	*topo;

	if(node->type==OBJ_TYPE_ID)
	{
		topo = ((ZObject*)node)->GetMesh();
		if(topo==NULL)					{	MMset(m,0,NIL);		return 0;	}
	}
	else if(node->type==MSH_TYPE_ID)
	{
		topo = (ZMesh*)node;
	}
	else
	{	MMset(m,0,NIL);		return 0;	}

	int index = MTOI(num);
	if(index > topo->NbVerts)		{	MMset(m,0,NIL);		return 0;	}

	float	t = (float)rate;
	t /= CONST_ANGLE;
	float	ut = 1-t;

	// Recupère les coords 1 du vertex
	float	vertX1 = ((float)MTOI(MMfetch(m,pos1,0))) / 100.0f;
	float	vertY1 = ((float)MTOI(MMfetch(m,pos1,1))) / 100.0f;
	float	vertZ1 = -((float)MTOI(MMfetch(m,pos1,2))) / 100.0f;

	// Recupère les coords 2 du vertex
	float	vertX2 = ((float)MTOI(MMfetch(m,pos2,0))) / 100.0f;
	float	vertY2 = ((float)MTOI(MMfetch(m,pos2,1))) / 100.0f;
	float	vertZ2 = -((float)MTOI(MMfetch(m,pos2,2))) / 100.0f;

	topo->Verts[index].x = vertX1*ut + vertX2*t;
	topo->Verts[index].y = vertY1*ut + vertY2*t;
	topo->Verts[index].z = vertZ1*ut + vertZ2*t;

	topo->hasTopoChanged = true;
	topo->hasViewChanged = true;

	// Désactive la compilation des displays lists
	topo->displayListCreate = false;

	scene->meshModified		= true;

	MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3morphVertexF
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d I [F F F] [F F F] F] I
int ZM3morphVertexF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3morphVertexF ");
#endif
	int rate = MMpull(m);
	int pos2 = MTOP(MMpull(m));
	int pos1 = MTOP(MMpull(m));
	int num  = MMpull(m);
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL)||(num==NIL)||(pos1==NIL)||(pos2==NIL)||(rate==NIL))			{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)																			{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL)					{	MMset(m,0,NIL);		return 0;	}
	
	ZMesh	*topo;

	if(node->type==OBJ_TYPE_ID)
	{
		topo = ((ZObject*)node)->GetMesh();
		if(topo==NULL)					{	MMset(m,0,NIL);		return 0;	}
	}
	else if(node->type==MSH_TYPE_ID)
	{
		topo = (ZMesh*)node;
	}
	else
	{	MMset(m,0,NIL);		return 0;	}

	int index = MTOI(num);
	if(index > topo->NbVerts)		{	MMset(m,0,NIL);		return 0;	}

	float	t = MTOF(rate);
	float	ut = 1-t;

	// Recupère les coords 1 du vertex
	float	vertX1 = MTOF(MMfetch(m,pos1,0)) / 100.0f;
	float	vertY1 = MTOF(MMfetch(m,pos1,1)) / 100.0f;
	float	vertZ1 = -MTOF(MMfetch(m,pos1,2)) / 100.0f;

	// Recupère les coords 2 du vertex
	float	vertX2 = MTOF(MMfetch(m,pos2,0)) / 100.0f;
	float	vertY2 = MTOF(MMfetch(m,pos2,1)) / 100.0f;
	float	vertZ2 = -MTOF(MMfetch(m,pos2,2)) / 100.0f;

	topo->Verts[index].x = vertX1*ut + vertX2*t;
	topo->Verts[index].y = vertY1*ut + vertY2*t;
	topo->Verts[index].z = vertZ1*ut + vertZ2*t;

	topo->hasTopoChanged = true;
	topo->hasViewChanged = true;

	// Désactive la compilation des displays lists
	topo->displayListCreate = false;

	scene->meshModified		= true;

	MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3morphVertices
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d [[I I I] r1] [[I I I] r1] I] I
int ZM3morphVertices(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3morphVertices ");
#endif

	int rate  = MTOI(MMpull(m));
	int list2 = MTOP(MMpull(m));
	int list1 = MTOP(MMpull(m));
	int h3d   = MMpull(m);
    int s3d   = MMpull(m);

	if((s3d==NIL)||(h3d==NIL)||(list1==NIL)||(list2==NIL)||(rate==NIL))					{	return MMpush(m,NIL);	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)																		{	return MMpush(m,NIL);	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL)					{	return MMpush(m,NIL);	}
	
	ZMesh	*topo;

	if(node->type==OBJ_TYPE_ID)
	{
		topo = ((ZObject*)node)->GetMesh();
		if(topo==NULL)					{	return MMpush(m,NIL);	}
	}
	else if(node->type==MSH_TYPE_ID)
	{
		topo = (ZMesh*)node;
	}
	else
		return MMpush(m,NIL);

	
	float	t = (float)rate;
	t /= CONST_ANGLE;
	float	ut = 1-t;


	ZVert	*vert;
	int		p, pp;
	
    for(int j=0; j<topo->NbVerts; j++)
    {
		vert = &(topo->Verts[j]);

		if((list1==NIL)||(list2==NIL))
		{
			topo->hasTopoChanged = true;
			topo->hasViewChanged = true;

			scene->meshModified		= true;

			MMpush(m,0);
			return 0;
		}

		if( ((p=MMfetch(m,list1,0)>>1)!=NIL) && ((pp=MMfetch(m,list2,0)>>1)!=NIL) )
		{
			vert->x = ut*((float)MTOI(MMfetch(m,p,0)))/100.0f + t*((float)MTOI(MMfetch(m,pp,0)))/100.0f;
			vert->y = ut*((float)MTOI(MMfetch(m,p,1)))/100.0f + t*((float)MTOI(MMfetch(m,pp,1)))/100.0f;
			vert->z = -(ut*((float)MTOI(MMfetch(m,p,2)))/100.0f + t*((float)MTOI(MMfetch(m,pp,2)))/100.0f);
		}
		
		list1 = MTOP(MMfetch(m,list1,1));
		list2 = MTOP(MMfetch(m,list2,1));
    }

	topo->hasTopoChanged = true;
	topo->hasViewChanged = true;

	// Désactive la compilation des displays lists
	topo->displayListCreate = false;


	scene->meshModified	 = true;

	MMpush(m,0);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3morphVerticesF
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d [[F F F] r1] [[F F F] r1] F] I
int ZM3morphVerticesF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3morphVerticesF ");
#endif
	int rate  = MMpull(m);
	int list2 = MTOP(MMpull(m));
	int list1 = MTOP(MMpull(m));
	int h3d   = MMpull(m);
    int s3d   = MMpull(m);

	if((s3d==NIL)||(h3d==NIL)||(list1==NIL)||(list2==NIL)||(rate==NIL))					{	return MMpush(m,NIL);	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)																		{	return MMpush(m,NIL);	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL)					{	return MMpush(m,NIL);	}
	
	ZMesh	*topo;

	if(node->type==OBJ_TYPE_ID)
	{
		topo = ((ZObject*)node)->GetMesh();
		if(topo==NULL)					{	return MMpush(m,NIL);	}
	}
	else if(node->type==MSH_TYPE_ID)
	{
		topo = (ZMesh*)node;
	}
	else
		return MMpush(m,NIL);

	
	float	t = MTOF(rate);
	float	ut = 1-t;

	ZVert	*vert;
	int		p, pp;
	
    for(int j=0; j<topo->NbVerts; j++)
    {
		vert = &(topo->Verts[j]);

		if((list1==NIL)||(list2==NIL))
		{
			topo->hasTopoChanged = true;
			topo->hasViewChanged = true;

			scene->meshModified		= true;

			MMpush(m,0);
			return 0;
		}

		if( ((p=MMfetch(m,list1,0)>>1)!=NIL) && ((pp=MMfetch(m,list2,0)>>1)!=NIL) )
		{
			vert->x =   ut*(MTOF(MMfetch(m,p,0)))/100.0f + t*(MTOF(MMfetch(m,pp,0)))/100.0f;
			vert->y =   ut*(MTOF(MMfetch(m,p,1)))/100.0f + t*(MTOF(MMfetch(m,pp,1)))/100.0f;
			vert->z = -(ut*(MTOF(MMfetch(m,p,2)))/100.0f + t*(MTOF(MMfetch(m,pp,2)))/100.0f);
		}

		list1 = MTOP(MMfetch(m,list1,1));
		list2 = MTOP(MMfetch(m,list2,1));
    }

	topo->hasTopoChanged = true;
	topo->hasViewChanged = true;

	// Désactive la compilation des displays lists
	topo->displayListCreate = false;


	scene->meshModified	 = true;

	MMpush(m,0);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}


//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3listOfColorVertices
//////////////////////////////////////////////////////////////////////////////////////////////
///	fun [S3d H3d I] [I r1]
int ZM3listOfColorVertices(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3listOfColorVertices ");
#endif
	int numP = MMpull(m);
	int h3d  = MMpull(m);
    int s3d  = MMpull(m);

	if((s3d==NIL)||(h3d==NIL))		{	return MMpush(m,NIL);	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	return MMpush(m,NIL);	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL)					{	return MMpush(m,NIL);	}
	
	ZMesh	*topo;

	if(node->type==OBJ_TYPE_ID)
	{
		topo = ((ZObject*)node)->GetMesh();
		if(topo==NULL)					{	return MMpush(m,NIL);	}
	}
	else if(node->type==MSH_TYPE_ID)
	{
		topo = (ZMesh*)node;
	}
	else
		return MMpush(m,NIL);

	numP = MTOI(numP);
	if((numP>3)||(numP<1))			{	return MMpush(m,NIL);	}

	int			n=0, k;
	ZVector3	*color;
	int			coul;

	for(int j=0; j<topo->NbVerts; j++)
	{
		if(numP==1)		color = &(topo->Verts[j].color1);
		else			color = &(topo->Verts[j].color2);

		coul = AROUNDINT(color->z*CONST_COLOR) + (AROUNDINT(color->y*CONST_COLOR)<<8) + (AROUNDINT(color->x*CONST_COLOR)<<16);
		if(MMpush(m,ITOM(coul)))		return MERRMEM;

		n++;
	}

	if(MMpush(m,NIL))		return MERRMEM;
	for(j=0; j<n; j++)
	{
    	if(MMpush(m,2*2))		return MERRMEM;
		if(k=MBdeftab(m))		return k;
	}

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3topoSetColorVertex
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d I I I] I
int ZM3topoSetColorVertex(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3topoSetColorVertex ");
#endif
	int col  = MMpull(m);
	int numP = MMpull(m);
	int ind  = MMpull(m);
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL)||(ind==NIL)||(col==NIL)||(numP==NIL))			{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)												{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=MSH_TYPE_ID))					{	MMset(m,0,NIL);		return 0;	}
    ZMesh	*topo = (ZMesh*) node;

	int index = MTOI(ind);
	if(index > topo->NbVerts)		{	MMset(m,0,NIL);		return 0;	}

	numP = MTOI(numP);
	if((numP>3)||(numP<1))			{	MMset(m,0,NIL);		return 0;	}

	// Recupère la couleur du vertex
	col = MTOI(col);
	
	ZVector3	*color;
	if(numP==1)		color = &(topo->Verts[index].color1);
	else			color = &(topo->Verts[index].color2);
	
	color->SetCoord( ((float)((col&0x00ff0000)>>16)) / CONST_COLOR,
		 			 ((float)((col&0x0000ff00)>>8) ) / CONST_COLOR,
					 ((float) (col&0x000000ff)	  )  / CONST_COLOR  );

	topo->hasViewChanged = true;

	// Désactive la compilation des displays lists
	topo->displayListCreate = false;

	scene->meshModified	 = true;

	MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3topoGetColorVertex
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d I I] I
int ZM3topoGetColorVertex(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3topoGetColorVertex ");
#endif
	int numP = MMpull(m);
	int ind  = MMpull(m);
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL)||(numP==NIL)||(ind==NIL))			{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)												{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=MSH_TYPE_ID))					{	MMset(m,0,NIL);		return 0;	}
    ZMesh	*topo = (ZMesh*) node;

	int index = MTOI(ind);
	if(index > topo->NbVerts)		{	MMset(m,0,NIL);		return 0;	}

	numP = MTOI(numP);
	if((numP>3)||(numP<1))			{	MMset(m,0,NIL);		return 0;	}

	// crée le tuple final
	ZVector3	*color;
	if(numP==1)		color = &(topo->Verts[index].color1);
	else			color = &(topo->Verts[index].color2);

	int coul = AROUNDINT(color->z*CONST_COLOR) + (AROUNDINT(color->y*CONST_COLOR)<<8) + (AROUNDINT(color->x*CONST_COLOR)<<16);

	MMset(m,0,ITOM(coul));
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3setColorVertices
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d I [I r1]] I
int ZM3setColorVertices(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3setColorVertices ");
#endif
	int liste = MTOP(MMpull(m));
	int numP  = MMpull(m);
	int h3d   = MMpull(m);
    int s3d   = MMpull(m);

	if((s3d==NIL)||(h3d==NIL)||(numP==NIL)||(liste==NIL))		{	return MMpush(m,NIL);	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)												{	return MMpush(m,NIL);	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL)					{	return MMpush(m,NIL);	}
	
	ZMesh	*topo;

	if(node->type==OBJ_TYPE_ID)
	{
		topo = ((ZObject*)node)->GetMesh();
		if(topo==NULL)					{	return MMpush(m,NIL);	}
	}
	else if(node->type==MSH_TYPE_ID)
	{
		topo = (ZMesh*)node;
	}
	else
		return MMpush(m,NIL);

	numP = MTOI(numP);
	if((numP>3)||(numP<1))			{	MMset(m,0,NIL);		return 0;	}
	
	ZVector3	*color;
	int			p;

	for(int j=0; j<topo->NbVerts; j++)
	{
		if(numP==1)		color = &(topo->Verts[j].color1);
		else			color = &(topo->Verts[j].color2);

		if(liste==NIL)
		{
			topo->hasViewChanged = true;

			scene->meshModified	= true;

			MMpush(m,0);
			return 0;
		}

		if((p=MMfetch(m,liste,0)>>1)!=NIL)
		{
			color->SetCoord( ((float)((p&0x00ff0000)>>16)) / CONST_COLOR,
		 					 ((float)((p&0x0000ff00)>>8) ) / CONST_COLOR,
							 ((float) (p&0x000000ff)	 ) / CONST_COLOR );
		}

		liste = MTOP(MMfetch(m,liste,1));
    }

	topo->hasViewChanged = true;

	// Désactive la compilation des displays lists
	topo->displayListCreate = false;

	scene->meshModified		= true;

	MMpush(m,0);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3convVrt
//////////////////////////////////////////////////////////////////////////////////////////////
//	fun [S3d H3d H3d [I I I]] [I I I]
int ZM3convVrt(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3convVrt ");
#endif
	int vect = MTOP(MMpull(m));
	int dst  = MMpull(m);
	int src  = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(src==NIL)||(dst==NIL)||(vect==NIL))				{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)													{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(src),0);
	if(node==NULL)					{	MMset(m,0,NIL);		return 0;	}

	ZVector3	vector;
	vector.SetCoord(MTOI(MMfetch(m,vect,0)), MTOI(MMfetch(m,vect,1)), -MTOI(MMfetch(m,vect,2)));

	vector *= 0.01f;

	// on remonte au World space
	vector *= ComputeWorldMatrix(node);

	// on redescend à la destination
    node = (ZNode*)MMfetch(m,MTOP(dst),0);
	if(node==NULL)					{	MMset(m,0,NIL);		return 0;	}
	ZMatrix		mat = ComputeWorldMatrix(node);
	mat.Inverse();
	vector *= mat;

	// crée le tuple de résultat	
	int tuple = MMmalloc(m, 3, TYPETAB);
	if(tuple==NIL)					{	MMset(m,0,NIL);		return MERRMEM;	}

	vector *= 100.0f;

	MMstore(m, tuple, 0, ITOM(AROUNDINT(vector.x)));
	MMstore(m, tuple, 1, ITOM(AROUNDINT(vector.y)));
	MMstore(m, tuple, 2, ITOM(AROUNDINT(-vector.z)));

	MMset(m,0,PTOM(tuple));
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3convVrtF
//////////////////////////////////////////////////////////////////////////////////////////////
//	fun [S3d H3d H3d [F F F]] [F F F]
int ZM3convVrtF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3convVrtF ");
#endif
	int vect = MTOP(MMpull(m));
	int dst  = MMpull(m);
	int src  = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(src==NIL)||(dst==NIL)||(vect==NIL))				{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)													{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(src),0);
	if(node==NULL)					{	MMset(m,0,NIL);		return 0;	}

	ZVector3	vector;
	vector.SetCoord( MTOF(MMfetch(m,vect,0)), MTOF(MMfetch(m,vect,1)), -MTOF(MMfetch(m,vect,2)));

	vector *= 0.01f;

	// on remonte au World space
	vector *= ComputeWorldMatrix(node);

	// on redescend à la destination
    node = (ZNode*)MMfetch(m,MTOP(dst),0);
	if(node==NULL)					{	MMset(m,0,NIL);		return 0;	}
	ZMatrix		mat = ComputeWorldMatrix(node);
	mat.Inverse();
	vector *= mat;

	// crée le tuple de résultat	
	int tuple = MMmalloc(m, 3, TYPETAB);
	if(tuple==NIL)					{	MMset(m,0,NIL);		return MERRMEM;	}

	vector *= 100.0f;

	MMstore(m, tuple, 0, FTOM(vector.x));
	MMstore(m, tuple, 1, FTOM(vector.y));
	MMstore(m, tuple, 2, FTOM(-vector.z));

	MMset(m,0,PTOM(tuple));
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3convVec
//////////////////////////////////////////////////////////////////////////////////////////////
//	fun [S3d H3d H3d [I I I]] [I I I]
int ZM3convVec(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3convVec ");
#endif
	int vect = MTOP(MMpull(m));
	int dst  = MMpull(m);
	int src  = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(src==NIL)||(dst==NIL)||(vect==NIL))				{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)													{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(src),0);
	if(node==NULL)					{	MMset(m,0,NIL);		return 0;	}

	ZVector4	vector;
	vector.SetCoord(MTOI(MMfetch(m,vect,0)), MTOI(MMfetch(m,vect,1)), -MTOI(MMfetch(m,vect,2)), 0);

	// on remonte au World space
	vector *= ComputeWorldMatrix(node);

	// on redescend à la destination
    node = (ZNode*)MMfetch(m,MTOP(dst),0);
	if(node==NULL)					{	MMset(m,0,NIL);		return 0;	}
	ZMatrix		mat = ComputeWorldMatrix(node);
	mat.Inverse();
	vector *= mat;

	// crée le tuple de résultat	
	int tuple = MMmalloc(m, 3, TYPETAB);
	if(tuple==NIL)					{	MMset(m,0,NIL);		return MERRMEM;	}

	MMstore(m, tuple, 0, ITOM(AROUNDINT(vector.x)));
	MMstore(m, tuple, 1, ITOM(AROUNDINT(vector.y)));
	MMstore(m, tuple, 2, ITOM(AROUNDINT(-vector.z)));

	MMset(m,0,PTOM(tuple));
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3convVecF
//////////////////////////////////////////////////////////////////////////////////////////////
//	fun [S3d H3d H3d [F F F]] [F F F]
int ZM3convVecF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3convVecF ");
#endif
	int vect = MTOP(MMpull(m));
	int dst  = MMpull(m);
	int src  = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(src==NIL)||(dst==NIL)||(vect==NIL))				{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)													{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(src),0);
	if(node==NULL)					{	MMset(m,0,NIL);		return 0;	}

	ZVector4	vector;
	vector.SetCoord(MTOF(MMfetch(m,vect,0)), MTOF(MMfetch(m,vect,1)), -MTOF(MMfetch(m,vect,2)), 0);

	// on remonte au World space
	vector *= ComputeWorldMatrix(node);

	// on redescend à la destination
    node = (ZNode*)MMfetch(m,MTOP(dst),0);
	if(node==NULL)					{	MMset(m,0,NIL);		return 0;	}
	ZMatrix		mat = ComputeWorldMatrix(node);
	mat.Inverse();
	vector *= mat;

	// crée le tuple de résultat	
	int tuple = MMmalloc(m, 3, TYPETAB);
	if(tuple==NIL)					{	MMset(m,0,NIL);		return MERRMEM;	}

	MMstore(m, tuple, 0, FTOM(vector.x));
	MMstore(m, tuple, 1, FTOM(vector.y));
	MMstore(m, tuple, 2, FTOM(-vector.z));

	MMset(m,0,PTOM(tuple));
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}




//$LB (31/10/2004)
typedef struct IntVert
{
  int x;
  int y;
  int z;
} IntVert;


//$LB (31/10/2004)
//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3topoScale
//////////////////////////////////////////////////////////////////////////////////////////////
//	fun [S3d H3d [I I I] I] I
int ZM3topoScale(mmachine m)
{
	#ifdef	_SCOL_DEBUG_
		MMechostr(0,"M3topoScale\n");
	#endif

	int res;
	int flag = MTOI(MMpull(m));
	int tuple = MTOP(MMpull(m));
	int h3d = MMpull (m);
	int s3d  = MMpull (m);
	int	deltaX, XDelta, deltaY, YDelta, deltaZ, ZDelta;


	if((s3d==NIL)||(h3d==NIL)||(tuple==NIL)||(flag==NIL))				
	{
		//$BLG - v5.22: Modif (Uncommented following line - this brought crashes when h3d was NIL, for example after a download error)
		//MMechostr(0, "\nM3topoScale  : one of the argument is nil.\n\n"); MMpush(m,NIL); return 0;
		MMechostr(0, "M3topoScale: one of the argument is nil.\n"); 
		MMpush(m,NIL); 
		return 0;
	}


	//
	// get the process values
	//
	deltaX = MTOI(MMfetch(m,tuple,0));
	deltaY = MTOI(MMfetch(m,tuple,1));
	deltaZ = MTOI(MMfetch(m,tuple,2));
	if ((deltaX == 0) && (deltaY == 0) && (deltaZ == 0)) 
		{
			//$BLG - v5.22: Modif (Uncommented following line - code part, not comment)
			// MMechostr(0, "\nM3topoScale  : all the scale values are zero!\n\n"); MMpush(m,NIL); return 0;
			MMpush(m,NIL); 
			return 0;
		}


	//
	// get the object topology
	//
  ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{MMechostr(0, "\nM3topoScale  : session is NULL!\n\n");	return MMpush(m,NIL);}

  ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL)					{MMechostr(0, "\nM3topoScale  : object is NULL !\n\n");	return MMpush(m,NIL);}
	
	ZMesh	*topo;

	if(node->type==OBJ_TYPE_ID)
	{
		topo = ((ZObject*)node)->GetMesh();
		if(topo==NULL)				{MMechostr(0, "\nM3topoScale  : topology is NULL!\n\n"); return MMpush(m,NIL);}
	}
	else if(node->type==MSH_TYPE_ID)
	{
		topo = (ZMesh*)node;
	}
	else
	{
		MMechostr(0, "\nM3topoScale  : unknown node type!\n\n");
		return MMpush(m,NIL);
	}


	//
	// go through the list of vertices, in order to compute the center of the object
	//
	ZVert	*vert;
	IntVert *tabverts;
	int		n=0, j;
	int		x, y, z;
	int     cx, cx1, cx2, cy, cy1, cy2, cz, cz1, cz2;
	
	cx = cx1 = cx2 = cy = cy1 = cy2 = cz = cz1 = cz2 = 0;

	tabverts = (IntVert*) malloc (topo->NbVerts * sizeof(IntVert));

	for(j=0; j<topo->NbVerts; j++)
	{
		vert = &(topo->Verts[j]);

		x = AROUNDINT(100.0f*vert->x);
		y = AROUNDINT(100.0f*vert->y);
		z = AROUNDINT(-100.0f*vert->z);

		// tempor. store the integers values, we're gonna use them
		tabverts[j].x = x;
		tabverts[j].y = y;
		tabverts[j].z = z;

		// get the min and max coord.
		if (x < cx1) cx1 = x; else if (x > cx2) cx2 = x;
		if (y < cy1) cy1 = y; else if (y > cy2) cy2 = y;
		if (z < cz1) cz1 = z; else if (z > cz2) cz2 = z;
	}

	// compute the center
	cx = cx1 + ((cx2 - cx1)>>1);
	cy = cy1 + ((cy2 - cy1)>>1);
	cz = cz1 + ((cz2 - cz1)>>1);


	//
	// go through the list of vertices again, in order to modify the values
	//
	for (j=0; j < topo->NbVerts; j++)
	{
		if (tabverts[j].x < cx) XDelta = -deltaX; else if (tabverts[j].x > cx) XDelta = deltaX; else XDelta = 0;
		if (tabverts[j].y < cy) YDelta = -deltaY; else if (tabverts[j].y > cy) YDelta = deltaY; else YDelta = 0;
		if (tabverts[j].z < cz) ZDelta = -deltaZ; else if (tabverts[j].z > cz) ZDelta = deltaZ; else ZDelta = 0;

		topo->Verts[j].x += ((float)XDelta) / 100.0f;
		topo->Verts[j].y += ((float)YDelta) / 100.0f;
		topo->Verts[j].z += - ((float)ZDelta) / 100.0f;
	}


	////////////////////////////////////////////////////
	//
	//
	// PROCESS THE MATERIAL REPETITION IF THE USER ASKED TO
	//
	//
	////////////////////////////////////////////////////
	
	if (flag)
	{
		float dx1, dx2, dy1, dy2, dz1, dz2, du1, du2,du3,du4, dv1, dv2,dv3,dv4;
		int first, second, third;
		vector<ZFace>	*faces	= &(topo->Faces);
		ZFace* face;


		// we want the Render Process to repeat the texture over the faces
		topo->texRenderMode = GL_REPEAT;
			


		//
		// on compte sur le fait que les coordoonées mapping des faces sont toujours indexées de la mm manière : 
		//
		//  0 --- 1
		// 0 \    |         
		// |  \ A |      A : faces à index pair, B : faces à index impair
		// |   \  |      
		// | B  \ |
		// |     \2
		// 2 --- 1 
		//


		//
		// X-AXE MODIFICATIONS
		//
		if (deltaX != 0)
		for (int i=0; i < topo->NbFaces; i++)
		{
			face = &(topo->Faces[i]);

			// select only the faces modified on x-axe
			if (( face->Normal.y != 0.0) || (face->Normal.z != 0.0))
			{
				// face B
				if (i & 1)	{ first = 1; second = 2; third = 0;	}
				// face A
				else		{ first = 0; second = 1; third = 2; }

				// distance between vertices, before scale
				dx1 = (float)((float) (tabverts[ face->VertRef[second] ].x - tabverts[ face->VertRef[first] ].x)) / 100.0f;
				// distance between vertices, after scale
				dx2 = topo->Verts[ face->VertRef[second] ].x - topo->Verts[ face->VertRef[first] ].x;



				// compute mapping coordinates difference, according to the distance between the vertices 
				du1 = ( ( face->UV1[second].u - face->UV1[first].u ) * dx2 )  /  dx1;
				du2 = ( ( face->UV2[second].u - face->UV2[first].u ) * dx2 )  /  dx1;
				du3 = ( ( face->UV3[second].u - face->UV3[first].u ) * dx2 )  /  dx1;
				du4 = ( ( face->UV4[second].u - face->UV4[first].u ) * dx2 )  /  dx1;

				if (i & 1)
				{
					face->UV1[first].u += ((float)(deltaX)) / 100.0f;
					face->UV2[first].u += ((float)(deltaX)) / 100.0f;
					face->UV3[first].u += ((float)(deltaX)) / 100.0f;
					face->UV4[first].u += ((float)(deltaX)) / 100.0f;
				}

				// compute new mapping coordinates
				face->UV1[second].u = du1 + face->UV1[first].u;
				face->UV1[third].u = face->UV1[second].u;

				// same thing, for the second texture coordinates
				face->UV2[second].u = du2 + face->UV2[first].u;
				face->UV2[third].u = face->UV2[second].u;

				// same thing, for the second texture coordinates
				face->UV3[second].u = du3 + face->UV3[first].u;
				face->UV3[third].u = face->UV3[second].u;

				// same thing, for the second texture coordinates
				face->UV4[second].u = du4 + face->UV4[first].u;
				face->UV4[third].u = face->UV4[second].u;

			}
		}

		//
		// Y-AXE MODIFICATIONS
		//

		if (deltaY != 0)
		for (int i=0; i < topo->NbFaces; i++)
		{
			face = &(topo->Faces[i]);

			// select only the faces modified on y-axe
			if (( face->Normal.x != 0.0) || (face->Normal.z != 0.0))
			{
	
				if (i & 1)	{ first = 0; second = 2; third = 1;	}
				else		{ first = 2; second = 1; third = 0; }

				dy1 = (float)((float) (tabverts[ face->VertRef[second] ].y - tabverts[ face->VertRef[first] ].y)) / 100.0f;
				dy2 = topo->Verts[ face->VertRef[second] ].y - topo->Verts[ face->VertRef[first] ].y;

				dv1 = ( ( face->UV1[second].v - face->UV1[first].v ) * dy2 )  /  dy1;
				dv2 = ( ( face->UV2[second].v - face->UV2[first].v ) * dy2 )  /  dy1;
				dv3 = ( ( face->UV3[second].v - face->UV3[first].v ) * dy2 )  /  dy1;
				dv4 = ( ( face->UV4[second].v - face->UV4[first].v ) * dy2 )  /  dy1;

				if (i & 1)
				{
					face->UV1[first].v -= ((float)deltaY)/100.0f;
					face->UV2[first].v -= ((float)deltaY)/100.0f;
					face->UV3[first].v -= ((float)deltaY)/100.0f;
					face->UV4[first].v -= ((float)deltaY)/100.0f;
				}

				face->UV1[second].v = dv1 + face->UV1[first].v;
				face->UV1[third].v = face->UV1[second].v;
	

				face->UV2[second].v = dv2 + face->UV2[first].v;
				face->UV2[third].v = face->UV2[second].v;

				face->UV3[second].v = dv3 + face->UV3[first].v;
				face->UV3[third].v = face->UV3[second].v;

				face->UV4[second].v = dv4 + face->UV4[first].v;
				face->UV4[third].v = face->UV4[second].v;
			}
		}
			

		//
		//
		// Z-AXE MODIFICATIONS
		//
		//

		if (deltaZ != 0)
		for (int i=0; i < topo->NbFaces; i++)
		{
			face = &(topo->Faces[i]);

			//
			// ZX-AXE MODIFICATIONS
			//
			if ( face->Normal.x != 0.0)
			{
				if (i & 1)		{ first = 1; second = 2; third = 0;	}
				else			{ first = 0; second = 1; third = 2; }
	
				dz1 = (float)((float) (tabverts[ face->VertRef[second] ].z - tabverts[ face->VertRef[first] ].z)) / 100.0f;
				dz2 = topo->Verts[ face->VertRef[second] ].z - topo->Verts[ face->VertRef[first] ].z;
	
				du1 = ( ( face->UV1[second].u - face->UV1[first].u ) * dz2 )  /  dz1;
				du2 = ( ( face->UV2[second].u - face->UV2[first].u ) * dz2 )  /  dz1;
				du3 = ( ( face->UV3[second].u - face->UV3[first].u ) * dz2 )  /  dz1;
				du4 = ( ( face->UV4[second].u - face->UV4[first].u ) * dz2 )  /  dz1;
	
				if (i & 1)
				{
					face->UV1[first].u -= ((float)deltaZ)/100.0f;
					face->UV2[first].u -= ((float)deltaZ)/100.0f;
					face->UV3[first].u -= ((float)deltaZ)/100.0f;
					face->UV4[first].u -= ((float)deltaZ)/100.0f;
				}
	
				face->UV1[second].u = du1 + face->UV1[first].u;
				face->UV1[third].u = face->UV1[second].u;
	
				face->UV2[second].u = du2 + face->UV2[first].u;
				face->UV2[third].u = face->UV2[second].u;

				face->UV3[second].u = du3 + face->UV3[first].u;
				face->UV3[third].u = face->UV3[second].u;

				face->UV4[second].u = du4 + face->UV4[first].u;
				face->UV4[third].u = face->UV4[second].u;
	
			}
	
			//
			// ZY-AXE MODIFICATIONS
			//
			if (face->Normal.y != 0.0)
			{
				if (i & 1)		{ first = 0; second = 2; third = 1;	}
				else			{ first = 2; second = 1; third = 0; }
	
				dz1 = (float)((float) (tabverts[ face->VertRef[second] ].z - tabverts[ face->VertRef[first] ].z)) / 100.0f;
				dz2 = topo->Verts[ face->VertRef[second] ].z - topo->Verts[ face->VertRef[first] ].z;
	
				dv1 = ( ( face->UV1[second].v - face->UV1[first].v ) * dz2 )  /  dz1;
				dv2 = ( ( face->UV2[second].v - face->UV2[first].v ) * dz2 )  /  dz1;
				dv3 = ( ( face->UV3[second].v - face->UV3[first].v ) * dz2 )  /  dz1;
				dv4 = ( ( face->UV4[second].v - face->UV4[first].v ) * dz2 )  /  dz1;
	
				if (i & 1)
				{
					face->UV1[first].v += ((float)deltaZ)/100.0f;
					face->UV2[first].v += ((float)deltaZ)/100.0f;
					face->UV3[first].v += ((float)deltaZ)/100.0f;
					face->UV4[first].v += ((float)deltaZ)/100.0f;
				}
	
				face->UV1[second].v = dv1 + face->UV1[first].v;
				face->UV1[third].v = face->UV1[second].v;
	
				face->UV2[second].v = dv2 + face->UV2[first].v;
				face->UV2[third].v = face->UV2[second].v;

				face->UV3[second].v = dv3 + face->UV3[first].v;
				face->UV3[third].v = face->UV3[second].v;

				face->UV4[second].v = dv4 + face->UV4[first].v;
				face->UV4[third].v = face->UV4[second].v;
			}
		}
	}



	free (tabverts);
	
	
	scene->materialModified = true;
	topo->hasTopoChanged = true;
	topo->hasViewChanged = true;
	
	
	// Désactive la compilation des displays lists
	topo->displayListCreate = false;

	scene->meshModified		= true;	


	res = MMpush(m, 0);


#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return res;
}


//////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////



//$LBDEBUG fun [S3d H3d] I
int M3test (mmachine m)
{
int h3d = MTOP(MMpull (m));
int s3d  = MTOP(MMpull (m));

MMechostr(0, "\n\nM3TEST ENTRY");


    ZScene	*scene = (ZScene*) MMfetch(m,s3d,0);
	if(scene==NULL)					{MMechostr(0, "\nM3test : session is NULL!");	return MMpush(m,NIL);	}

    ZNode	*node = (ZNode*) MMfetch(m,h3d,0);
	if(node==NULL)					{MMechostr(0, "\nM3test  : object is NULL !");		return MMpush(m,NIL);	}
	
	ZMesh	*topo;

	if(node->type==OBJ_TYPE_ID)
	{
		topo = ((ZObject*)node)->GetMesh();
		if(topo==NULL)					{MMechostr(0, "\nM3test : topology is NULL!");		return MMpush(m,NIL);	}
	}
	else if(node->type==MSH_TYPE_ID)
	{
		topo = (ZMesh*)node;
	}
	else
	{
		MMechostr(0, "\nM3test : unknown node type!");
		return MMpush(m,NIL);
	}


	int first, second, third;
	vector<ZFace>	*faces	= &(topo->Faces);
	//$BLG: v4.6a5 - Removed next line
	//float dx1, dx2, du;
	ZFace* face;
			
	
			for(int i=0; i < topo->NbFaces; i++)
			{
				face = &(topo->Faces[i]);

				// select only the faces modified on x-axe
				if (( face->Normal.y != 0.0) || (face->Normal.z != 0.0))
				{
		
					

					if (i & 1)
					{

						first = 1; second = 2; third = 0;	

						//$LBDEBUG
						MMechostr (0, "\n\nTEST face %d   %f ", i, face->UV1[second].u);

						// compute new mapping coordinates
						face->UV1[first].u += 0.001f;
						face->UV1[second].u += 0.001f;
						face->UV1[third].u += 0.001f;

						//$LBDEBUG
						MMechostr (0, "%f\n", face->UV1[second].u);

						//face->UV1[third].u = face->UV1[second].u;

						// compute new mapping coordinates
						face->UV2[first].u += 0.001f;
						face->UV2[second].u += 0.001f;
						face->UV2[third].u += 0.001f;
					}
				}
 
			}
 
	

	topo->texRenderMode = GL_REPEAT;
	
	scene->materialModified = true;
	topo->hasTopoChanged = true;
	topo->hasViewChanged = true;
	
	
	// Désactive la compilation des displays lists
	topo->displayListCreate = false;

	scene->meshModified		= true;	
	 

	return MMpush(m, 0);
}






//$LBDEBUG fun [S3d H3d] I
int M3test2 (mmachine m)
{
int h3d = MTOP(MMpull (m));
int s3d  = MTOP(MMpull (m));

MMechostr(0, "\n\nM3TEST ENTRY");


    ZScene	*scene = (ZScene*) MMfetch(m,s3d,0);
	if(scene==NULL)					{MMechostr(0, "\nM3test : session is NULL!");	return MMpush(m,NIL);	}

    ZNode	*node = (ZNode*) MMfetch(m,h3d,0);
	if(node==NULL)					{MMechostr(0, "\nM3test  : object is NULL !");		return MMpush(m,NIL);	}
	
	ZMesh	*topo;

	if(node->type==OBJ_TYPE_ID)
	{
		topo = ((ZObject*)node)->GetMesh();
		if(topo==NULL)					{MMechostr(0, "\nM3test : topology is NULL!");		return MMpush(m,NIL);	}
	}
	else if(node->type==MSH_TYPE_ID)
	{
		topo = (ZMesh*)node;
	}
	else
	{
		MMechostr(0, "\nM3test : unknown node type!");
		return MMpush(m,NIL);
	}


	vector<ZFace>	*faces	= &(topo->Faces);
			
	
	for(int i=0; i < topo->NbFaces; i++)
	{

MMechostr(0, "\n\ncoord UV1 0   %f   %f", (*faces)[i].UV1[0].u, (*faces)[i].UV1[0].v );
				MMechostr(0, "\ncoord UV1 1   %f   %f", (*faces)[i].UV1[1].u, (*faces)[i].UV1[1].v );
				MMechostr(0, "\ncoord UV1 2   %f   %f", (*faces)[i].UV1[2].u, (*faces)[i].UV1[2].v );

				MMechostr(0, "\ncoord UV2 0   %f   %f", (*faces)[i].UV2[0].u, (*faces)[i].UV2[0].v );
				MMechostr(0, "\ncoord UV2 1   %f   %f", (*faces)[i].UV2[1].u, (*faces)[i].UV2[1].v );
				MMechostr(0, "\ncoord UV2 2   %f   %f", (*faces)[i].UV2[2].u, (*faces)[i].UV2[2].v );


		for (int j=0; j < 3; j++)
		{
		  if ((*faces)[i].UV1[j].u == 1.0f) (*faces)[i].UV1[j].u = 2.0f;
		  if ((*faces)[i].UV1[j].v == 1.0f) (*faces)[i].UV1[j].v = 1.0f;
		  if ((*faces)[i].UV2[j].u == 1.0f) (*faces)[i].UV2[j].u = 2.0f;
		  if ((*faces)[i].UV2[j].v == 1.0f) (*faces)[i].UV2[j].v = 1.0f;
		} 


MMechostr(0, "\n\ncoord UV1 0   %f   %f", (*faces)[i].UV1[0].u, (*faces)[i].UV1[0].v );
				MMechostr(0, "\ncoord UV1 1   %f   %f", (*faces)[i].UV1[1].u, (*faces)[i].UV1[1].v );
				MMechostr(0, "\ncoord UV1 2   %f   %f", (*faces)[i].UV1[2].u, (*faces)[i].UV1[2].v );

				MMechostr(0, "\ncoord UV2 0   %f   %f", (*faces)[i].UV2[0].u, (*faces)[i].UV2[0].v );
				MMechostr(0, "\ncoord UV2 1   %f   %f", (*faces)[i].UV2[1].u, (*faces)[i].UV2[1].v );
				MMechostr(0, "\ncoord UV2 2   %f   %f", (*faces)[i].UV2[2].u, (*faces)[i].UV2[2].v );

	}

	topo->texRenderMode = GL_REPEAT;
	
	scene->materialModified = true;
	topo->hasTopoChanged = true;
	topo->hasViewChanged = true;
	
	
	// Désactive la compilation des displays lists
	topo->displayListCreate = false;

	scene->meshModified		= true;	
	

	return MMpush(m, 0);
}








///////////////////////////////////////////////////////////////////////////////////////////
////																				   ////
///									GESTION DE MESH										///
////																				   ////
///////////////////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3createMesh
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d] H3d
int ZM3createMesh(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3createMesh ");
#endif
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=MSH_TYPE_ID))					{	MMset(m,0,NIL);		return 0;	}
    ZMesh	*topo = (ZMesh*) node;

	// Creation du Mesh
	ZObject	*newObj;
	newObj = new ZObject((int)scene);
	if(newObj==NULL)				{	MMset(m,0,NIL);		return 0;	}
	newObj->InsertAsChildOf(scene->World);
	newObj->SetName("");

	int hash_tab = MTOP( MMfetch(m,MTOP(s3d),1) );
	int	msh = createH3D(m, (int)newObj, hash_tab);

	ZPRS	*newPRS;
	newPRS = newObj->GetPRS();
	newPRS->coeffM3D = 100.0f;


	newObj->SetMesh(topo);


	scene->updateGraphList = true;

	// Pose le résultat sur la pile
	if(msh!=NIL)	msh = PTOM(msh);
    MMset(m,0,msh);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3meshSetMultiTopo
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d [[H3d I] r1]] I
int ZM3meshSetMultiTopo(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3meshSetMultiTopo ");
#endif
	int list = MTOP(MMpull(m));
	int objt = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(objt==NIL)||(list==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)									{	MMset(m,0,NIL);		return 0;	}

	ZNode* node = (ZNode*) MMfetch(m,MTOP(objt),0);
	if((node==NULL)||(node->type!=OBJ_TYPE_ID))				{	MMset(m,0,NIL);		return 0;	}
    ZObject	*obj = (ZObject*) node;

	if(obj->IsMultiMeshes()==false)							{	MMset(m,0,NIL);		return 0;	}

	obj->CleanMeshList();

	int tuple, curH3D, range;

	while(list!=NIL)
	{
		tuple = MTOP(MMfetch(m,list,0));

		curH3D  = MTOP(MMfetch(m,tuple,0));
		range	= MTOI(MMfetch(m,tuple,1));
		
		node = (ZNode*) MMfetch(m, curH3D, 0);

		if( (curH3D!=NIL) && (node!=NULL) && (node->type==MSH_TYPE_ID))
		{
			if(range >=0 )		obj->AddMeshInList( (ZMesh*)node, (((float)range)/100.0f)*(((float)range)/100.0f) );
			else				obj->AddMeshInList( (ZMesh*)node, FLT_MAX );
		}

		list = MTOP(MMfetch(m,list,1));
	}

	MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3meshSetMultiTopoF
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d [[H3d F] r1]] I
int ZM3meshSetMultiTopoF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3meshSetMultiTopoF ");
#endif
	int list = MTOP(MMpull(m));
	int objt = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(objt==NIL)||(list==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)									{	MMset(m,0,NIL);		return 0;	}

	ZNode* node = (ZNode*) MMfetch(m,MTOP(objt),0);
	if((node==NULL)||(node->type!=OBJ_TYPE_ID))				{	MMset(m,0,NIL);		return 0;	}
    ZObject	*obj = (ZObject*) node;

	if(obj->IsMultiMeshes()==false)							{	MMset(m,0,NIL);		return 0;	}

	obj->CleanMeshList();

	int		tuple, curH3D;
	float	range;

	while(list!=NIL)
	{
		tuple = MTOP(MMfetch(m,list,0));

		curH3D  = MTOP(MMfetch(m,tuple,0));
		range	= MTOF(MMfetch(m,tuple,1));
		
		node = (ZNode*) MMfetch(m, curH3D, 0);

		if( (curH3D!=NIL) && (node!=NULL) && (node->type==MSH_TYPE_ID))
		{
			if(range >=0 )		obj->AddMeshInList( (ZMesh*)node, (((float)range)/100.0f)*(((float)range)/100.0f) );
			else				obj->AddMeshInList( (ZMesh*)node, FLT_MAX );
		}

		list = MTOP(MMfetch(m,list,1));
	}

	MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3meshGetMultiTopo
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d] [[H3d I] r1]
int ZM3meshGetMultiTopo(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3meshGetMultiTopo ");
#endif

	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL))					{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)								{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=OBJ_TYPE_ID))				{	MMset(m,0,NIL);		return 0;	}
    ZObject	*obj = (ZObject*) node;

	if(obj->IsMultiMeshes()==false)							{	MMset(m,0,NIL);		return 0;	}

	ZArray<ZMesh*>		*mshList;
	ZArray<float>		*rangeList;
	
	mshList		= obj->GetMeshList();
	rangeList	= obj->GetRangeSQRList();

	int range, k, n=0, tmp_res;

	for(int i=0; i<mshList->Size(); i++)
	{
		h3d = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)(*mshList)[i]);
		if(h3d!=NIL)	h3d = PTOM(h3d);

		if((*rangeList)[i] != FLT_MAX)		range = ITOM( AROUNDINT(sqrt((float)(*rangeList)[i]) * 100.0f) );
		else								range = ITOM( RANGE_INFINITY );

		if(MMpush(m, h3d))		return MERRMEM;
		if(MMpush(m, range))	return MERRMEM;
    	if(MMpush(m,2*2))		return MERRMEM;
		if(k=MBdeftab(m))		return k;

		INVERT(m,0,1);
		s3d = MMget(m,0);

		n++;
	}

	MMpull(m);

	if(MMpush(m,NIL))		return MERRMEM;
	for(int j=0; j<n; j++)
	{
    	if(MMpush(m,2*2))		return MERRMEM;
		if(k=MBdeftab(m))		return k;
	}

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3meshGetMultiTopoF
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d] [[H3d F] r1]
int ZM3meshGetMultiTopoF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3meshGetMultiTopoF ");
#endif

	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL))					{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)								{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=OBJ_TYPE_ID))				{	MMset(m,0,NIL);		return 0;	}
    ZObject	*obj = (ZObject*) node;

	if(obj->IsMultiMeshes()==false)							{	MMset(m,0,NIL);		return 0;	}

	ZArray<ZMesh*>		*mshList;
	ZArray<float>		*rangeList;
	
	mshList		= obj->GetMeshList();
	rangeList	= obj->GetRangeSQRList();

	int range, k, n=0, tmp_res;

	for(int i=0; i<mshList->Size(); i++)
	{
		h3d = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)(*mshList)[i]);
		if(h3d!=NIL)	h3d = PTOM(h3d);

		if((*rangeList)[i] != FLT_MAX)		range = FTOM( sqrt((float)(*rangeList)[i]) * 100.0f );
		else								range = FTOM( RANGE_INFINITY_F );

		if(MMpush(m, h3d))		return MERRMEM;
		if(MMpush(m, range))	return MERRMEM;
    	if(MMpush(m,2*2))		return MERRMEM;
		if(k=MBdeftab(m))		return k;

		INVERT(m,0,1);
		s3d = MMget(m,0);

		n++;
	}

	MMpull(m);

	if(MMpush(m,NIL))		return MERRMEM;
	for(int j=0; j<n; j++)
	{
    	if(MMpush(m,2*2))		return MERRMEM;
		if(k=MBdeftab(m))		return k;
	}

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}




//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3meshGetActiveTopo
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d] H3d
int ZM3meshGetActiveTopo(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3meshGetActiveTopo ");
#endif
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL))					{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)								{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=OBJ_TYPE_ID))				{	MMset(m,0,NIL);		return 0;	}
    ZObject	*obj = (ZObject*) node;

	if(obj->IsMultiMeshes()==false)							{	MMset(m,0,NIL);		return 0;	}


	h3d = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)obj->GetMesh());
	if(h3d!=NIL)	h3d = PTOM(h3d);

	MMset(m,0,h3d);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3meshSetTopology
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d H3d] I
int ZM3meshSetTopology(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3meshSetTopology ");
#endif
	int top  = MMpull(m);
	int msh  = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(msh==NIL)||(top==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)								{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(top),0);
	if((node==NULL)||(node->type!=MSH_TYPE_ID))					{	MMset(m,0,NIL);		return 0;	}
    ZMesh	*topo = (ZMesh*) node;

    node = (ZNode*) MMfetch(m,MTOP(msh),0);
	if((node==NULL)||(node->type!=OBJ_TYPE_ID))					{	MMset(m,0,NIL);		return 0;	}
    ZObject	*obj = (ZObject*) node;

	if(obj->IsMultiMeshes()==true)								{	MMset(m,0,NIL);		return 0;	}

	obj->SetMesh(topo);

    MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3meshGetTopology
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d] H3d
int ZM3meshGetTopology(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3meshGetTopology ");
#endif
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL))					{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)								{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=OBJ_TYPE_ID))					{	MMset(m,0,NIL);		return 0;	}
    ZObject	*obj = (ZObject*) node;

	if(obj->IsMultiMeshes()==true)								{	MMset(m,0,NIL);		return 0;	}

	ZMesh	*msh = obj->GetMesh();
	if(msh==NULL)								{	MMset(m,0,NIL);		return 0;	}
	
	h3d = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)msh);

	if(h3d!=NIL)	h3d = PTOM(h3d);
    MMset(m,0,h3d);
	
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3meshSetType
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d I] I
int ZM3meshSetType(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3meshSetType ");
#endif

	int typ  = MMpull(m);
	int h3d  = MMpull(m);
  int s3d  = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL)||(typ==NIL))		{	MMset(m,0,NIL);		return 0;	}
  ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)								{	MMset(m,0,NIL);		return 0;	}

  ZNode*	node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=OBJ_TYPE_ID))					{	MMset(m,0,NIL);		return 0;	}
  ZObject	*obj = (ZObject*) node;

	typ = MTOI(typ);

	if(typ & TYP_MESH_MULTI_TOPO)			obj->setFlagMulti(true);
	else									obj->setFlagMulti(false);

	if(typ & TYP_MESH_NOT_CLICKABLE)		obj->clickable = false;
	else									obj->clickable = true;

	if(obj->IsMultiMeshes())
	{
		ZArray<ZMesh*>		*mshList = obj->GetMeshList();
		
		if(typ & TYP_MESH_STATIC)		{	for(int k=0; k<mshList->Size(); k++)	(*mshList)[k]->displayListCreate = true;	}
		else							{	for(int k=0; k<mshList->Size(); k++)	(*mshList)[k]->displayListCreate = false;	}
	}
	else
	if(obj->GetMesh())
	{
		if(typ & TYP_MESH_STATIC)				obj->GetMesh()->displayListCreate = true;
		else									obj->GetMesh()->displayListCreate = false;
	}

    MMset(m,0,0);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3meshGetType
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d] I
int ZM3meshGetType(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3meshGetType ");
#endif

	int h3d  = MMpull(m);
  int s3d  = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL))					{	MMset(m,0,NIL);		return 0;	}
  ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)								{	MMset(m,0,NIL);		return 0;	}

  ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=OBJ_TYPE_ID))					{	MMset(m,0,NIL);		return 0;	}
  ZObject	*obj = (ZObject*) node;

	ZMesh	*msh = obj->GetMesh();
	if(msh==NULL)								{	MMset(m,0,NIL);		return 0;	}

	int mask = 0;

	if(msh->displayListCreate==true)	mask += TYP_MESH_STATIC;
	if(obj->IsMultiMeshes()==true)		mask += TYP_MESH_MULTI_TOPO;
	if(obj->clickable==false)					mask += TYP_MESH_NOT_CLICKABLE;

	MMset(m,0,ITOM(mask));

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3distance
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d H3d] I
int ZM3distance(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3distance ");
#endif
	int nod2 = MMpull(m);
	int nod1 = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(nod2==NIL)||(nod1==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)									{	MMset(m,0,NIL);		return 0;	}


    ZNode	*node = (ZNode*) MMfetch(m,MTOP(nod1),0);
	if((node==NULL)||(node->type<0)||(node->type>MAX_NODE_SCENE))
	{	
		MMset(m,0,NIL);
		return 0;
	}
	ZMatrix		mat = ComputeWorldMatrix(node);
	ZVector3	vect1;
	vect1.SetCoord(mat(0,3), mat(1,3), mat(2,3));


    node = (ZNode*) MMfetch(m,MTOP(nod2),0);
	if((node==NULL)||(node->type<0)||(node->type>MAX_NODE_SCENE))
	{	
		MMset(m,0,NIL);
		return 0;
	}
	mat = ComputeWorldMatrix(node);
	ZVector3	vect2;
	vect2.SetCoord(mat(0,3), mat(1,3), mat(2,3));

	vect2 -= vect1;
	float	length = vect2.Length();

    MMset(m,0, ITOM(AROUNDINT(100.0f*length)));
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}





// Concatène les données..
int ZM3saveconc(char *buf, int *user)
{
	sv3d	s = (sv3d) user;
	int		k, i;

	if(buf)
	{
		if((k = Mpushstrbloc(s->m,buf)))		return k;
		s->n++;
	}

	if((buf==NULL)||(s->n>256))
	{
		if(MMpush(s->m,NIL))	return MERRMEM;

		for(i=0; i<s->n; i++)
		{
			if(MMpush(s->m,2*2))		return MERRMEM;
			if(k=MBdeftab(s->m))		return k;
		}

		if((k=MBstrcatn(s->m)))		return k;

		s->n = 1;
	}

	return 0;
}

//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3save
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d I] S
int ZM3save(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3save ");
#endif
	int flg  = MTOI(MMpull(m));
	int h3d  = MMpull(m);
    int s3d  = MMpull(m);

	if((s3d==NIL)||(h3d==NIL))					{	MMpush(m,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)								{	MMpush(m,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type>MAX_NODE_SCENE))				{	MMpush(m,NIL);		return 0;	}

    struct Save3d	sv;
	struct Sv3d		sm;

	sm.m	= m;						// mmachine
	sm.n	= 0;						// counter of words

	sv.cb	= ZM3saveconc;				// CallBack de sauvegarde
	sv.user	= (int*)&sm;				// structure de sauvegarde

	int		k;
	if((k=ZM3Dsave(scene, &sv, node, true, flg)))		return k;

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return ZM3saveconc(NULL, sv.user);
}





// Cloture de la liste d'éléments
int ZM3listOfMatEnd(mmachine m,int n)
{
	int j, k;
	if(MMpush(m,NIL))		return MERRMEM;
	
	for(j=0;j<n;j++)
	{
    	if(MMpush(m,2*2))		return MERRMEM;
		if(k=MBdeftab(m))		return k;
	}
	
	return 0;
}

// Test de présence dans la pile d'un materiau donné
int ZM3alreadyChecked(mmachine m, int n, int mat3d)
{
	int i;
	for(i=0;i<n;i++)		if(MMget(m,i)==mat3d)	return 1;
	return 0;
}

// Pose les materiaux d'un mesh dans la pile
int ZM3listOfMatOne(mmachine m, ZMesh* mesh, int n)
{
	int	mat3d, tmp_res;
	
	for(int j=0; j<mesh->NbFaces; j++)
    {
		int s3d = MMget(m,0);
		int hash = MTOP(MMfetch(m,MTOP(s3d),2));

		mat3d = NodeTOHandle(m, hash, (int)mesh->Faces[j].GetMaterial());
		if(mat3d!=NIL)		mat3d = PTOM(mat3d);
		
		if(!ZM3alreadyChecked(m, n, mat3d))
		{
			if(MMpush(m,mat3d))			return MERRMEM;
			INVERT(m,0,1);
			n++;
		}
    }
	return n;
}

// Recursion pour la création de la liste des matériaux
int ZM3recListOfMat(mmachine m, ZNode* node, int n, bool first)
{
	if( (node->type==OBJ_TYPE_ID) && (((ZObject*)node)->GetMesh()) )
														n = ZM3listOfMatOne(m, ((ZObject*)node)->GetMesh(), n);

	if(node->son != NULL)
    {
		n = ZM3recListOfMat(m, node->son, n, false);
    }

	if ((!first)&&(node->next!=NULL))
    {
		n = ZM3recListOfMat(m, node->next, n, false);
    }
	
	return n;
}


//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3recListOfMaterials
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d] [HMat3d r1]
int ZM3recListOfMaterials(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3recListOfMaterials ");
#endif
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL))					{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)								{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type>MAX_NODE_SCENE))				{	MMset(m,0,NIL);		return 0;	}

    // attention, le S3d est empilé pour l'usage dans la fonction qui suit..
	int n = ZM3recListOfMat(m, node, 0, true);
	if(n<0)			{	MMset(m,0,NIL);		return 0;	}

	MMpull(m);	// supprime le S3d qui est en tête de pile, avant la création de la liste finale

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return ZM3listOfMatEnd(m, n);
}




















///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////																											   ////
///												GESTION DES MATERIAUX												///
////																											   ////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////





//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3setMaterialTransparencyOrder
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [HMat3d I] I
int ZM3setMaterialTransparencyOrder(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3setMaterialTransparencyOrder");
#endif
	int order = MTOI(MMpull(m));
	int mat = MMget(m,0);

    if((mat==NIL)||(order==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZMaterial	*mater = (ZMaterial*) MMfetch(m,MTOP(mat),0);
	if(mater==NULL)						{	MMset(m,0,NIL);		return 0;	}

	if(order<0)		order = 0;
	mater->transparencyOrder = order;

	MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getMaterialTransparencyOrder
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [HMat3d] I
int ZM3getMaterialTransparencyOrder(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getMaterialTransparencyOrder");
#endif
	int mat = MMget(m,0);

    if((mat==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZMaterial	*mater = (ZMaterial*) MMfetch(m,MTOP(mat),0);
	if(mater==NULL)		{	MMset(m,0,NIL);		return 0;	}

	MMset(m,0, ITOM(mater->transparencyOrder));
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}




//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3listALLMaterials
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d] [HMat3d r1]
int ZM3listALLMaterials(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3listALLMaterials ");
#endif
    int s3d = MMget(m,0);

    if(s3d==NIL)					{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

	int	n=0;
	int tx, tmp_res;
    

	for(int k=0; k<scene->MatList.Size(); k++)
    {
		int s3d = MMget(m,0);
		int hash = MTOP(MMfetch(m,MTOP(s3d),2));

		tx = NodeTOHandle(m, hash, (int)scene->MatList[k]);
		if(tx!=NIL)
		{
			tx = PTOM(tx);
			if(MMpush(m,tx))			return MERRMEM;
			INVERT(m,0,1);
			n++;
		}
    }

	if(n==0)		{	MMset(m,0,NIL);		return n;	}
	MMpull(m);
	if(MMpush(m,NIL))		return MERRMEM;

	for(int j=0;j<n;j++)
	{
    	if(MMpush(m,2*2))		return MERRMEM;
		if(k=MBdeftab(m))		return k;
	}

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}





//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3createMaterial
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d S] HMat3d
int ZM3createMaterial(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3createMaterial ");
#endif
	int name = MMpull(m);
	int s3d  = MMget(m,0);
    
    if((s3d==NIL)||(name==NIL))		{	MMset(m,0,NIL);		return 0;	}

    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}


	// Creation du nouveau materiau
	string	nom = string(MMstartstr(m,MTOP(name)));

	ZMaterial*	curMat = new ZMaterial(scene->accelerated);
	if(!curMat)						{	MMset(m,0,NIL);		return 0;	}
	scene->MatList.Add(curMat);

	curMat->SetName(nom);

	int hash_tab = MTOP( MMfetch(m,MTOP(s3d),2) );
	int mat = createHmatHtx(m, (int)curMat, hash_tab);

	scene->materialModified		= true;

	MMset(m, 0, PTOM(mat));
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}


//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getMat
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d S] HMat3d
int ZM3getMat(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getMat ");
#endif
	int name = MMpull(m);
    int s3d  = MMget(m,0);
    
    if((name==NIL)||(s3d==NIL))		{	MMset(m,0,NIL);		return 0;	}

    ZScene	*scene = (ZScene*)MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

	string	matName = string(MMstartstr(m,MTOP(name)));

	ZMaterial	*curMat = NULL;

	for(int k=0; k<scene->MatList.Size(); k++)
	{
		if( scene->MatList[k]->name==matName && (curMat==NULL || scene->MatList[k]->version>curMat->version) )		curMat = scene->MatList[k];
	}


	if(curMat==NULL)		{	MMset(m,0,NIL);		return 0;	}

	int	mat3d = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),2)), (int)curMat);
	if(mat3d!=NIL)		mat3d = PTOM(mat3d);
	MMset(m,0,mat3d);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3materialName
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d HMat3d] S
int ZM3materialName(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3materialName ");
#endif
   int mat = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(mat==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZMaterial	*mater = (ZMaterial*) MMfetch(m,MTOP(mat),0);
	if(mater==NULL)					{	MMset(m,0,NIL);		return 0;	}

	MMpull(m);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return Mpushstrbloc(m, (char*)mater->name.c_str());
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3renameMat
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d HMat3d S] I
int ZM3renameMat(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3renameMat ");
#endif
    int name = MMpull(m);
    int mat  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(mat==NIL)||(name==NIL))			{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZMaterial	*mater = (ZMaterial*) MMfetch(m,MTOP(mat),0);
	if(mater==NULL)					{	MMset(m,0,NIL);		return 0;	}

	mater->SetName((char*)MMstartstr(m,MTOP(name)));

	MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		fillMaterial
//////////////////////////////////////////////////////////////////////////////////////////////
/// Fill a material with the good texture
///
void fillMaterial(ZMaterial	*mater)
{
	// Texture 1
	ZTexture	*tex = mater->GetTexture1();

	if( (tex!=NULL) && ((tex->activated==false)||(tex->renamed==true)) )
	{
		free(tex->Image);			tex->Image		= NULL;
		free(tex->ImageModif);		tex->ImageModif = NULL;		

		tex->A = tex->C = tex->X = tex->Y = tex->R = tex->S = false;

		int		debName = 0;
		char	*namefile = (char*)tex->name.c_str();
		if(namefile[0]=='%')			debName = M3DloadFilter(namefile, tex);

		bool	test = true;
		char	name[SIZESIGN];
		if(SPfindfile((packdir)SCgetExtra("FirstPack"), &(namefile[debName]), NULL, name)==-1)		test=false;
		if(test)	{ if(tex->LoadTexture(name)==false)		test=false;		}

		if(test)
		{
			if(tex->ImageModif!=NULL)		{	free(tex->ImageModif);		tex->ImageModif = NULL;		}
			tex->CreateModifiedImg();
			tex->SetupTexture();
			mater->EnableMode(RENDER_TEXTURED);
			mater->modified = true;
			tex->modified	= true;
		}
	}
	else if(tex!=NULL && tex->modified /*&& tex->activated==true*/)
	{
		mater->modified = true;
	}

	// Texture 2
	tex = mater->GetTexture2();

	if( (tex!=NULL) && ((tex->activated==false)||(tex->renamed==true)) )
	{
		free(tex->Image);			tex->Image		= NULL;
		free(tex->ImageModif);		tex->ImageModif = NULL;

		tex->A = tex->C = tex->X = tex->Y = tex->R = tex->S = false;

		int		debName = 0;
		char	*namefile = (char*)tex->name.c_str();
		if(namefile[0]=='%')			debName = M3DloadFilter(namefile, tex);

		bool	test = true;
		char	name[SIZESIGN];
		if(SPfindfile((packdir)SCgetExtra("FirstPack"), &(namefile[debName]), NULL, name)==-1)		test=false;
		if(test)	{ if(tex->LoadTexture(name)==false)		test=false;		}

		if(test)
		{
			if(tex->ImageModif!=NULL)		{	free(tex->ImageModif);		tex->ImageModif = NULL;		}
			tex->CreateModifiedImg();
			tex->SetupTexture();
			mater->EnableMode(RENDER_TEXTURED);
			mater->modified = true;
			tex->modified	= true;
		}
	}
	else if(tex!=NULL && tex->modified /*&& tex->activated==true*/)
	{
		mater->modified = true;
	}
	// Texture LightMap
	tex = mater->GetLightMap();

	if( (tex!=NULL) && ((tex->activated==false)||(tex->renamed==true)) )
	{
		free(tex->Image);			tex->Image		= NULL;
		free(tex->ImageModif);		tex->ImageModif = NULL;

		tex->A = tex->C = tex->X = tex->Y = tex->R = tex->S = false;

		int		debName = 0;
		char	*namefile = (char*)tex->name.c_str();
		if(namefile[0]=='%')			debName = M3DloadFilter(namefile, tex);

		bool	test = true;
		char	name[SIZESIGN];
		if(SPfindfile((packdir)SCgetExtra("FirstPack"), &(namefile[debName]), NULL, name)==-1)		test=false;
		if(test)	{ if(tex->LoadTexture(name)==false)		test=false;		}

		if(test)
		{
			if(tex->ImageModif!=NULL)		{	free(tex->ImageModif);		tex->ImageModif = NULL;		}
			tex->CreateModifiedImg();
			tex->SetupTexture();
			//mater->EnableMode(RENDER_TEXTURED);
			mater->EnableMode(RENDER_LIGHTMAP);
			mater->modified = true;
			tex->modified	= true;
		}
	}
	else if(tex!=NULL && tex->modified /*&& tex->activated==true*/)
	{
		mater->modified = true;
	}
}

//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3fillMat
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d HMat3d] I
int ZM3fillMat(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3fillMat ");
#endif

    int mat  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(mat==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene		*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZMaterial	*mater = (ZMaterial*) MMfetch(m,MTOP(mat),0);
	if(mater==NULL)					{	MMset(m,0,NIL);		return 0;	}

	fillMaterial(mater);

	scene->materialModified = true;
	scene->textureModified  = true;

	MMset(m,0,0);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3fillMatObj
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d] I
int ZM3fillMatObj(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3fillMatObj ");
#endif
    int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL))		{	MMset(m,0,NIL);		return 0;	}
	ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=OBJ_TYPE_ID))			{	MMset(m,0,NIL);		return 0;	}

	ZObject	*obj = (ZObject*)node;
	
	if( (obj->IsMultiMeshes()==false) && (obj->GetMesh()) )
	{
		ZMesh	*mesh = obj->GetMesh();

		for(int i=0; i<mesh->FacesMatGour.size(); i++)
		{
			fillMaterial(mesh->FacesMatGour[i].mat);
		}
		for(i=0; i<mesh->FacesMatFlat.size(); i++)
		{
			fillMaterial(mesh->FacesMatFlat[i].mat);
		}
		for(i=0; i<mesh->FacesMatNo.size(); i++)
		{
			fillMaterial(mesh->FacesMatNo[i].mat);
		}
	}
	else if(obj->IsMultiMeshes()==true)
	{
		ZArray<ZMesh*>		*mshList;
		mshList = obj->GetMeshList();

		for(int k=0; k<mshList->Size(); k++)
		{		
			ZMesh	*mesh = (*mshList)[k];

			for(int i=0; i<mesh->FacesMatGour.size(); i++)
			{
				fillMaterial(mesh->FacesMatGour[i].mat);
			}
			for(i=0; i<mesh->FacesMatFlat.size(); i++)
			{
				fillMaterial(mesh->FacesMatFlat[i].mat);
			}
			for(i=0; i<mesh->FacesMatNo.size(); i++)
			{
				fillMaterial(mesh->FacesMatNo[i].mat);
			}
		}
	}
	else
	{	
		MMset(m,0,NIL);		
		return 0;	
	}

	scene->materialModified = true;
	scene->textureModified  = true;

	MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}





void fillObjectRecurs(ZNode	*node)
{
	ZNode		*curNode = node->son;
	ZObject		*obj;

	while(curNode!=NULL)
	{
		if(curNode->type == OBJ_TYPE_ID)
		{
			obj = (ZObject*) curNode;
			
			if( (obj->IsMultiMeshes()==false) && (obj->GetMesh()) )
			{
				ZMesh	*mesh = obj->GetMesh();

				for(int i=0; i<mesh->FacesMatGour.size(); i++)
				{
					fillMaterial(mesh->FacesMatGour[i].mat);
				}
				for(i=0; i<mesh->FacesMatFlat.size(); i++)
				{
					fillMaterial(mesh->FacesMatFlat[i].mat);
				}
				for(i=0; i<mesh->FacesMatNo.size(); i++)
				{
					fillMaterial(mesh->FacesMatNo[i].mat);
				}
			}
			else if(obj->IsMultiMeshes()==true)
			{
				ZArray<ZMesh*>		*mshList;
				mshList = obj->GetMeshList();

				for(int k=0; k<mshList->Size(); k++)
				{		
					ZMesh	*mesh = (*mshList)[k];

					for(int i=0; i<mesh->FacesMatGour.size(); i++)
					{
						fillMaterial(mesh->FacesMatGour[i].mat);
					}
					for(i=0; i<mesh->FacesMatFlat.size(); i++)
					{
						fillMaterial(mesh->FacesMatFlat[i].mat);
					}
					for(i=0; i<mesh->FacesMatNo.size(); i++)
					{
						fillMaterial(mesh->FacesMatNo[i].mat);
					}
				}
			}
		}

		if(curNode->son != NULL)	fillObjectRecurs(curNode);
		curNode = curNode->next;
	}
}

//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3recursFillMatObj
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d] I
int ZM3recursFillMatObj(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3recursFillMatObj ");
#endif
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);


	if((s3d==NIL)||(h3d==NIL))		{	MMset(m,0,NIL);		return 0;	}
	ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL)					{	MMset(m,0,NIL);		return 0;	}



	if(node->type==OBJ_TYPE_ID)
	{
		ZObject	*obj = (ZObject*)node;
		
		if( (obj->IsMultiMeshes()==false) && (obj->GetMesh()) )
		{
			ZMesh	*mesh = obj->GetMesh();

			for(int i=0; i<mesh->FacesMatGour.size(); i++)
			{
				fillMaterial(mesh->FacesMatGour[i].mat);
			}
			for(i=0; i<mesh->FacesMatFlat.size(); i++)
			{
				fillMaterial(mesh->FacesMatFlat[i].mat);
			}
			for(i=0; i<mesh->FacesMatNo.size(); i++)
			{
				fillMaterial(mesh->FacesMatNo[i].mat);
			}
		}
		else if(obj->IsMultiMeshes()==true)
		{
			ZArray<ZMesh*>		*mshList;
			mshList = obj->GetMeshList();

			for(int k=0; k<mshList->Size(); k++)
			{		
				ZMesh	*mesh = (*mshList)[k];

				for(int i=0; i<mesh->FacesMatGour.size(); i++)
				{
					fillMaterial(mesh->FacesMatGour[i].mat);
				}
				for(i=0; i<mesh->FacesMatFlat.size(); i++)
				{
					fillMaterial(mesh->FacesMatFlat[i].mat);
				}
				for(i=0; i<mesh->FacesMatNo.size(); i++)
				{
					fillMaterial(mesh->FacesMatNo[i].mat);
				}
			}
		}
	}

	fillObjectRecurs(node);

	scene->materialModified = true;
	scene->textureModified  = true;

	MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getType
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d HMat3d] I
int ZM3getType(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getType ");
#endif
	int mat = MMpull(m);
	int s3d = MMget(m,0);

	if((s3d==NIL)||(mat==NIL))		{	MMset(m,0,NIL);		return 0;	}

	ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	  if(scene==NULL)		{	MMset(m,0,NIL);		return 0;	}

	ZMaterial	*mater = (ZMaterial*) MMfetch(m,MTOP(mat),0);
	  if(mater==NULL)		{	MMset(m,0,NIL);		return 0;	}

	MMset(m, 0, ITOM(mater->RenderMode));
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getRealType
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d HMat3d] I
int ZM3getRealType(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getRealType ");
#endif
    int mat = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(mat==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZMaterial	*mater = (ZMaterial*) MMfetch(m,MTOP(mat),0);
	if(mater==NULL)					{	MMset(m,0,NIL);		return 0;	}

	int render = mater->RenderMode;

	if (mater->IsOnMode(RENDER_LIGHTMAP) && ((mater->GetLightMap()==NULL)||(mater->GetLightMap()->activated==false)))		
	{	
		render &= (0xffffffff - RENDER_LIGHTMAP);		
	}
	if (mater->IsOnMode(RENDER_TEXTURED) && ((mater->GetTexture1()==NULL)||(mater->GetTexture1()->activated==false)))		
	{	
		render &= (0xffffffff - RENDER_TEXTURED);	
		render &= (0xffffffff - RENDER_TEXTURED_BIS);	
	}
	else if (mater->IsOnMode(RENDER_TEXTURED_BIS) && ((mater->GetTexture2()==NULL)||(mater->GetTexture1()->activated==false)))		
		render &= (0xffffffff - RENDER_TEXTURED_BIS);
	

	MMset(m, 0, ITOM(render));
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3setType
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d HMat3d I] I
int ZM3setType(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3setType ");
#endif

    int mod = MMpull(m);
    int mat = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(mat==NIL)||(mod==NIL))		{	MMset(m,0,NIL);	return 0;	}
    
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	 	if(scene==NULL)		{	MMset(m,0,NIL);	return 0;	}

    ZMaterial	*mater = (ZMaterial*) MMfetch(m,MTOP(mat),0);
		if(mater==NULL)		{	MMset(m,0,NIL);	return 0;	}

		int mode = MTOI(mod);
		if(mode > MAXIMUM_MODE)			return false;
		mater->RenderMode = mode;
		mater->modified   = true;

		scene->materialModified = true;

		MMset(m, 0, 0);
		
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getMaterialFlat
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d HMat3d] I
int ZM3getMaterialFlat(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getMaterialFlat ");
#endif
	int mat = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(mat==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZMaterial	*mater = (ZMaterial*) MMfetch(m,MTOP(mat),0);
	if(mater==NULL)					{	MMset(m,0,NIL);		return 0;	}

	int col = mater->GetDefaultColor();
	int color;
	
	color = ((col&0xff)<<16) + (col&0xff00) + ((col&0xff0000)>>16);
	
	MMset(m, 0, ITOM(color));

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3setMaterialFlat
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d HMat3d I] I
int ZM3setMaterialFlat(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3setMaterialFlat ");
#endif
	int col = MTOI(MMpull(m));
	int mat = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(mat==NIL)||(col==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZMaterial	*mater = (ZMaterial*) MMfetch(m,MTOP(mat),0);
	if(mater==NULL)					{	MMset(m,0,NIL);		return 0;	}

	mater->SetDefaultColor(((col&0xff)<<16)+(col&0xff00)+((col&0xff0000)>>16));
	mater->color.x  = (float) (col&0x000000ff)		/ CONST_COLOR;
	mater->color.y  = (float)((col&0x0000ff00)>>8)	/ CONST_COLOR;
	mater->color.z  = (float)((col&0x00ff0000)>>16)	/ CONST_COLOR;
	mater->modified = true;	

	scene->materialModified = true;

	MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}




//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getMaterialTransparency
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d HMat3d] I
int ZM3getMaterialTransparency(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getMaterialTransparency ");
#endif
    int mat = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(mat==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZMaterial	*mater = (ZMaterial*) MMfetch(m,MTOP(mat),0);
	if(mater==NULL)					{	MMset(m,0,NIL);		return 0;	}

	MMset(m, 0, ITOM(mater->GetCoeffTransp()));
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3setMaterialTransparency
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d HMat3d I] I
int ZM3setMaterialTransparency(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3setMaterialTransparency ");
#endif

	int col = MTOI(MMpull(m));
	int mat = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(mat==NIL)||(col==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZMaterial	*mater = (ZMaterial*) MMfetch(m,MTOP(mat),0);
	if(mater==NULL)					{	MMset(m,0,NIL);		return 0;	}

	if((col<0)||(col>255))			{	MMset(m,0,NIL);		return 0;	}

	mater->SetCoeffTransp(col);
	mater->coeffTransp   = 1.0f-((float)mater->GetCoeffTransp())/CONST_COLOR;

	mater->modified = true;
	scene->materialModified = true;

	MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getMaterialColor
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d HMat3d I] I
int ZM3getMaterialColor (mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getMaterialColor ");
#endif
    int num = MTOI(MMpull(m));
	int mat = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(mat==NIL)||(num==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZMaterial	*mater = (ZMaterial*) MMfetch(m,MTOP(mat),0);
	if(mater==NULL)					{	MMset(m,0,NIL);		return 0;	}

	if(num == 1)	MMset(m, 0, ITOM(mater->color1_24));
	else 
	if(num == 2)	MMset(m, 0, ITOM(mater->color2_24));
	else	
		MMset(m,0,NIL);	
	
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3setMaterialColor
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d HMat3d I I] I
int ZM3setMaterialColor(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3setMaterialColor ");
#endif
    int col = MTOI(MMpull(m));
    int num = MTOI(MMpull(m));
	int mat = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(mat==NIL)||(col==NIL)||(num==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZMaterial	*mater = (ZMaterial*) MMfetch(m,MTOP(mat),0);
	if(mater==NULL)					{	MMset(m,0,NIL);		return 0;	}

	if(num == 1)
	{
		mater->color1_24 = col;
		mater->color1.x = (float) (col&0x000000ff)		/ CONST_COLOR;
		mater->color1.y = (float)((col&0x0000ff00)>>8)	/ CONST_COLOR;
		mater->color1.z = (float)((col&0x00ff0000)>>16)	/ CONST_COLOR;
		mater->modified = true;

		scene->materialModified = true;

		MMset(m,0,0);
	}
	else 
	if(num == 2)
	{
		mater->color2_24 = col;
		mater->color2.x = (float) (col&0x000000ff)		/ CONST_COLOR;
		mater->color2.y = (float)((col&0x0000ff00)>>8)	/ CONST_COLOR;
		mater->color2.z = (float)((col&0x00ff0000)>>16)	/ CONST_COLOR;
		mater->modified = true;

		scene->materialModified = true;

		MMset(m,0,0);
	}
	else	
		MMset(m,0,NIL);	

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3textureFromMaterial
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d HMat3d] HTx3d
int ZM3textureFromMaterial(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3textureFromMaterial ");
#endif
	int mat  = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(mat==NIL))					{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)								{	MMset(m,0,NIL);		return 0;	}

    ZMaterial	*mater = (ZMaterial*) MMfetch(m,MTOP(mat),0);
	if(mater==NULL)					{	MMset(m,0,NIL);		return 0;	}


	if(mater->GetTexture1()==NULL)		{	MMset(m,0,NIL);		return 0;	}
	
	int	tex = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),3)), (int)mater->GetTexture1());
	if(tex!=NIL)		tex = PTOM(tex);
	MMset(m,0,tex);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3textureBISFromMaterial
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d HMat3d] HTx3d
int ZM3textureBISFromMaterial(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3textureBISFromMaterial ");
#endif
	int mat  = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(mat==NIL))					{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)								{	MMset(m,0,NIL);		return 0;	}

    ZMaterial	*mater = (ZMaterial*) MMfetch(m,MTOP(mat),0);
	if(mater==NULL)					{	MMset(m,0,NIL);		return 0;	}


	if(mater->GetTexture2()==NULL)		{	MMset(m,0,NIL);		return 0;	}
	
	int	tex = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),3)), (int)mater->GetTexture2());
	if(tex!=NIL)		tex = PTOM(tex);
	MMset(m,0,tex);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}

//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3lightMapFromMaterial
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d HMat3d] HTx3d
int ZM3lightMapFromMaterial(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3lightMapFromMaterial ");
#endif
	int mat  = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(mat==NIL))					{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)								{	MMset(m,0,NIL);		return 0;	}

    ZMaterial	*mater = (ZMaterial*) MMfetch(m,MTOP(mat),0);
	if(mater==NULL)					{	MMset(m,0,NIL);		return 0;	}


	if(mater->GetLightMap()==NULL)		{	MMset(m,0,NIL);		return 0;	}
	
	int	tex = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),3)), (int)mater->GetLightMap());
	if(tex!=NIL)		tex = PTOM(tex);
	MMset(m,0,tex);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}

//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3chgMaterialTexture
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d HMat3d HTx3d] I
int ZM3chgMaterialTexture(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3chgMaterialTexture ");
#endif
	int tex  = MMpull(m);
	int mat  = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(mat==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZMaterial	*mater = (ZMaterial*) MMfetch(m,MTOP(mat),0);
	if(mater==NULL)					{	MMset(m,0,NIL);		return 0;	}

    if(tex==NIL)
	{
		mater->SetTexture1(NULL);
		mater->modified = true;

		scene->materialModified = true;

		MMset(m,0,0);
		return 0;
	}	
	
	ZTexture	*textu = (ZTexture*) MMfetch(m,MTOP(tex),0);
	if(textu==NULL)					{	MMset(m,0,NIL);		return 0;	}

	mater->SetTexture1(textu);
	mater->modified = true;

	scene->materialModified = true;

	MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3chgMaterialTextureBIS
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d HMat3d HTx3d] I
int ZM3chgMaterialTextureBIS(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3chgMaterialTextureBIS ");
#endif
	int tex  = MMpull(m);
	int mat  = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(mat==NIL))					{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)								{	MMset(m,0,NIL);		return 0;	}

    ZMaterial	*mater = (ZMaterial*) MMfetch(m,MTOP(mat),0);
	if(mater==NULL)					{	MMset(m,0,NIL);		return 0;	}

    if(tex==NIL)
	{
		mater->SetTexture2(NULL);
		mater->modified = true;

		scene->materialModified = true;

		MMset(m,0,0);
		return 0;
	}	

    ZTexture	*textu = (ZTexture*) MMfetch(m,MTOP(tex),0);
	if(textu==NULL)					{	MMset(m,0,NIL);		return 0;	}

	mater->SetTexture2(textu);
	mater->modified = true;

	scene->materialModified = true;

	MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}

//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3chgMaterialLightMap
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d HMat3d HTx3d] I
int ZM3chgMaterialLightMap(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3chgMaterialLightMap ");
#endif
	int tex  = MMpull(m);
	int mat  = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(mat==NIL))					{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)								{	MMset(m,0,NIL);		return 0;	}

    ZMaterial	*mater = (ZMaterial*) MMfetch(m,MTOP(mat),0);
	if(mater==NULL)					{	MMset(m,0,NIL);		return 0;	}

    if(tex==NIL)
	{
		mater->SetLightMap(NULL);
		mater->modified = true;

		scene->materialModified = true;

		MMset(m,0,0);
		return 0;
	}	

    ZTexture	*textu = (ZTexture*) MMfetch(m,MTOP(tex),0);
	if(textu==NULL)					{	MMset(m,0,NIL);		return 0;	}

	mater->SetLightMap(textu);
	mater->modified = true;

	scene->materialModified = true;

	MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}

//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getMaterialMultitex
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d HMat3d] I
int ZM3getMaterialMultitex(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getMaterialMultitex ");
#endif
	int mat = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(mat==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZMaterial	*mater = (ZMaterial*) MMfetch(m,MTOP(mat),0);
	if(mater==NULL)					{	MMset(m,0,NIL);		return 0;	}

	MMset(m,0,ITOM(AROUNDINT(mater->alpha*CONST_ANGLE)));
	
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3setMaterialMultitex
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d HMat3d I] I
int ZM3setMaterialMultitex(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3setMaterialMultitex ");
#endif
    int col = MTOI(MMpull(m));
	int mat = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(mat==NIL)||(col==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZMaterial	*mater = (ZMaterial*) MMfetch(m,MTOP(mat),0);
	if(mater==NULL)					{	MMset(m,0,NIL);		return 0;	}

	mater->alpha = ((float)col) / CONST_ANGLE;
	mater->modified = true;
	
	scene->materialModified = true;

	MMset(m,0,0);	
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3setMaterialAmbient
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d HMat3d I] I
int ZM3setMaterialAmbient(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3setMaterialAmbient ");
#endif
    int col = MTOI(MMpull(m));
	int mat = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(mat==NIL)||(col==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZMaterial	*mater = (ZMaterial*) MMfetch(m,MTOP(mat),0);
	if(mater==NULL)					{	MMset(m,0,NIL);		return 0;	}

	mater->ambient[0] = (float)((col&0x00ff0000)>>16)	/ CONST_COLOR;
	mater->ambient[1] = (float)((col&0x0000ff00)>>8)	/ CONST_COLOR;
	mater->ambient[2] = (float) (col&0x000000ff)		/ CONST_COLOR;
	mater->modified = true;
	
	scene->materialModified = true;

	MMset(m,0,0);	
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getMaterialAmbient
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d HMat3d] [I I I]
int ZM3getMaterialAmbient(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getMaterialAmbient ");
#endif
	int mat = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(mat==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZMaterial	*mater = (ZMaterial*) MMfetch(m,MTOP(mat),0);
	if(mater==NULL)					{	MMset(m,0,NIL);		return 0;	}

	int color = 0;
	color += AROUNDINT(mater->ambient[0]*CONST_COLOR) << 16;
	color += AROUNDINT(mater->ambient[1]*CONST_COLOR) << 8;
	color += AROUNDINT(mater->ambient[2]*CONST_COLOR);
	
	MMset(m,0,ITOM(color));

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3setMaterialDiffuse
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d HMat3d I] I
int ZM3setMaterialDiffuse(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3setMaterialDiffuse ");
#endif
    int col = MTOI(MMpull(m));
	int mat = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(mat==NIL)||(col==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZMaterial	*mater = (ZMaterial*) MMfetch(m,MTOP(mat),0);
	if(mater==NULL)					{	MMset(m,0,NIL);		return 0;	}

	mater->diffuse[0] = (float)((col&0x00ff0000)>>16)	/ CONST_COLOR;
	mater->diffuse[1] = (float)((col&0x0000ff00)>>8)	/ CONST_COLOR;
	mater->diffuse[2] = (float) (col&0x000000ff)		/ CONST_COLOR;
	mater->modified = true;
	
	scene->materialModified = true;

	MMset(m,0,0);	
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}


//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3setMaterialEmissive
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d HMat3d I] I
int ZM3setMaterialEmissive(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3setMaterialEmissive ");
#endif
    int col = MTOI(MMpull(m));
	int mat = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(mat==NIL)||(col==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZMaterial	*mater = (ZMaterial*) MMfetch(m,MTOP(mat),0);
	if(mater==NULL)					{	MMset(m,0,NIL);		return 0;	}

	mater->emission[0] = (float)((col&0x00ff0000)>>16)	/ CONST_COLOR;
	mater->emission[1] = (float)((col&0x0000ff00)>>8)	/ CONST_COLOR;
	mater->emission[2] = (float) (col&0x000000ff)		/ CONST_COLOR;
	mater->modified = true;
	
	scene->materialModified = true;

	MMset(m,0,0);	
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getMaterialDiffuse
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d HMat3d] [I I I]
int ZM3getMaterialDiffuse(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getMaterialDiffuse ");
#endif
	int mat = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(mat==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZMaterial	*mater = (ZMaterial*) MMfetch(m,MTOP(mat),0);
	if(mater==NULL)					{	MMset(m,0,NIL);		return 0;	}

	int color = 0;
	color += AROUNDINT(mater->diffuse[0]*CONST_COLOR) << 16;
	color += AROUNDINT(mater->diffuse[1]*CONST_COLOR) << 8;
	color += AROUNDINT(mater->diffuse[2]*CONST_COLOR);
	
	MMset(m,0,ITOM(color));
	
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}


//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getMaterialEmissive
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d HMat3d] [I I I]
int ZM3getMaterialEmissive(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getMaterialEmissive ");
#endif
	int mat = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(mat==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZMaterial	*mater = (ZMaterial*) MMfetch(m,MTOP(mat),0);
	if(mater==NULL)					{	MMset(m,0,NIL);		return 0;	}

	int color = 0;
	color += AROUNDINT(mater->emission[0]*CONST_COLOR) << 16;
	color += AROUNDINT(mater->emission[1]*CONST_COLOR) << 8;
	color += AROUNDINT(mater->emission[2]*CONST_COLOR);
	
	MMset(m,0,ITOM(color));
	
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3setMaterialSpecular
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d HMat3d I] I
int ZM3setMaterialSpecular(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3setMaterialSpecular ");
#endif
    int col = MTOI(MMpull(m));
	int mat = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(mat==NIL)||(col==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZMaterial	*mater = (ZMaterial*) MMfetch(m,MTOP(mat),0);
	if(mater==NULL)					{	MMset(m,0,NIL);		return 0;	}

	mater->specular[0] = (float)((col&0x00ff0000)>>16)	/ CONST_COLOR;
	mater->specular[1] = (float)((col&0x0000ff00)>>8)	/ CONST_COLOR;
	mater->specular[2] = (float) (col&0x000000ff)		/ CONST_COLOR;
	mater->modified = true;
	
	scene->materialModified = true;

	MMset(m,0,0);	
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getMaterialSpecular
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d HMat3d] [I I I]
int ZM3getMaterialSpecular(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getMaterialSpecular ");
#endif
	int mat = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(mat==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZMaterial	*mater = (ZMaterial*) MMfetch(m,MTOP(mat),0);
	if(mater==NULL)					{	MMset(m,0,NIL);		return 0;	}

	int color = 0;
	color += AROUNDINT(mater->specular[0]*CONST_COLOR) << 16;
	color += AROUNDINT(mater->specular[1]*CONST_COLOR) << 8;
	color += AROUNDINT(mater->specular[2]*CONST_COLOR);

	MMset(m,0,ITOM(color));
	
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///	MS : Ajout 	ZM3setMaterialShininess
///		
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d HMat3d I] I
int ZM3setMaterialShininess(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3setMaterialShininess ");
#endif
    int col = MTOI(MMpull(m));
	int mat = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(mat==NIL)||(col==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZMaterial	*mater = (ZMaterial*) MMfetch(m,MTOP(mat),0);
	if(mater==NULL)					{	MMset(m,0,NIL);		return 0;	}

	mater->shininess = (float) (col&0x000000ff) ;
	mater->modified = true;
	scene->materialModified = true;

	MMset(m,0,0);	
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}


//////////////////////////////////////////////////////////////////////////////////////////////
///	MS : Ajout 	ZM3setMaterialShininessF
///		
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d HMat3d F] I
int ZM3setMaterialShininessF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3setMaterialShininessF ");
#endif
    float col = MTOF(MMpull(m));
	int mat = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(mat==NIL)||(col==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZMaterial	*mater = (ZMaterial*) MMfetch(m,MTOP(mat),0);
	if(mater==NULL)					{	MMset(m,0,NIL);		return 0;	}

	mater->SetShininess((128*col)) ;

	mater->modified = true;
	scene->materialModified = true;

	MMset(m,0,0);	
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}

//////////////////////////////////////////////////////////////////////////////////////////////
///	MS : Ajout	ZM3getMaterialShininess
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d HMat3d] [I]
int ZM3getMaterialShininess(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getMaterialShininess ");
#endif
	int mat = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(mat==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZMaterial	*mater = (ZMaterial*) MMfetch(m,MTOP(mat),0);
	if(mater==NULL)					{	MMset(m,0,NIL);		return 0;	}

	int value = 0;

	value += AROUNDINT(mater->shininess);

	MMset(m,0,ITOM(value));
	
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}

//////////////////////////////////////////////////////////////////////////////////////////////
///	MS : Ajout	ZM3getMaterialShininessF
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d HMat3d] [F]
int ZM3getMaterialShininessF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getMaterialShininessF ");
#endif
	int mat = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(mat==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZMaterial	*mater = (ZMaterial*) MMfetch(m,MTOP(mat),0);
	if(mater==NULL)					{	MMset(m,0,NIL);		return 0;	}

	float value = 0.0;

	value = (mater->shininess)/128.0f ;

	MMset(m,0,FTOM(value));
	
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}

//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3materialCount
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d HMat3d] I
int ZM3materialCount(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3materialCount ");
#endif
	int mat = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(mat==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZMaterial	*mater = (ZMaterial*) MMfetch(m,MTOP(mat),0);
	if(mater==NULL)					{	MMset(m,0,NIL);		return 0;	}

	MMset(m,0,ITOM(mater->nbRef));
	
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3listOfMaterials
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d] [HMat3d r1]
int ZM3listOfMaterials(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3listOfMaterials ");
#endif

	int obj = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(obj==NIL))	{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)				{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(obj),0);
	if(node==NULL)				{	MMset(m,0,NIL);		return 0;	}
	
	if(node->type==OBJ_TYPE_ID)
	{
		ZObject	*curObj = (ZObject*)node;

		int	n=-1;
		// attention, le S3d est empilé pour l'usage dans la fonction qui suit..
		if(curObj->GetMesh())		n = ZM3listOfMatOne(m, curObj->GetMesh(), 0);

		if(n<0)		{	MMset(m,0,NIL);		return 0;	}

		MMpull(m);

#ifdef	_SCOL_DEBUG_
		MMechostr(0,"ok\n");
#endif
		return ZM3listOfMatEnd(m,n);
	}
	else if(node->type==MSH_TYPE_ID)
	{
		ZMesh	*msh = (ZMesh*)node;

		int	n=-1;										// attention, le S3d est empilé pour l'usage dans la fonction qui suit..
		n = ZM3listOfMatOne(m, msh, 0);

		if(n<0)		{	MMset(m,0,NIL);		return 0;	}

		MMpull(m);

#ifdef	_SCOL_DEBUG_
		MMechostr(0,"ok\n");
#endif
		return ZM3listOfMatEnd(m,n);
	}
	else
	{	
#ifdef	_SCOL_DEBUG_
		MMechostr(0,"ERROR !!\n");
#endif
		MMset(m,0,NIL);		
		return 0;	
	}
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3copyObjMaterial
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d HMat3d] HMat3d
int ZM3copyObjMaterial(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3copyObjMaterial ");
#endif

	int mat = MMpull(m);
	int obj = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(obj==NIL)||(mat==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)								{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(obj),0);
	if(node==NULL)								{	MMset(m,0,NIL);		return 0;	}
	
    ZMaterial	*mater = (ZMaterial*) MMfetch(m,MTOP(mat),0);
	if(mater==NULL)								{	MMset(m,0,NIL);		return 0;	}

	int newMat = NIL;

	ZMesh	*msh;

	// Selection du mesh
	if(node->type == OBJ_TYPE_ID)
	{
		ZObject	*curObj = (ZObject*)node;
		msh	= curObj->GetMesh();
		if(msh==NULL)								{	MMset(m,0,NIL);		return 0;	}
	}
	else if(node->type == MSH_TYPE_ID)
	{
		msh = (ZMesh*)node;
	}
	else
	{	
		MMset(m,0,NIL);
		return 0;	
	}

	// Vérification de présence du matériau dans l'objet 3D
	vector<ZFace>	*faces	= &(msh->Faces);
	bool			presence = false;
	
	for(int i=0; (i<msh->NbFaces)&&(!presence); i++)
	{
		if( (*faces)[i].GetMaterial() == mater )		presence = true;
	}

	if(presence == false)				{	MMset(m,0,NIL);		return 0;	}


	// Si le matériau est présent, on procède à l'isolation
	if(mater->nbRef != 1)
	{
		ZMaterial*	curMat = new ZMaterial(scene->accelerated);
		if(!curMat)						{	MMset(m,0,NIL);		return 0;	}
		scene->MatList.Add(curMat);

		curMat->SetName(mater->name);

		// Déclaration dans la hashtable
		int hash_tab = MTOP( MMfetch(m,MTOP(s3d),2) );
		newMat = createHmatHtx(m, (int)curMat, hash_tab);

		// Copie des pptés
		for(i=0; i<4; i++)
		{
			curMat->ambient[i]  = mater->ambient[i];
			curMat->diffuse[i]  = mater->diffuse[i];
			curMat->specular[i] = mater->specular[i];
			curMat->emission[i] = mater->emission[i];
		}

		curMat->shininess = mater->shininess;
		
		curMat->SetTexture1(mater->GetTexture1());
		curMat->SetTexture2(mater->GetTexture2());

		curMat->RenderMode = mater->RenderMode;

		curMat->transparencyOrder = mater->transparencyOrder;

		curMat->color  = mater->color;
		curMat->color1 = mater->color1;
		curMat->color2 = mater->color2;
		curMat->SetDefaultColor(mater->GetDefaultColor());
		curMat->color1_24 = mater->color1_24;
		curMat->color2_24 = mater->color2_24;

		curMat->alpha = mater->alpha;
		curMat->coeffTransp = mater->coeffTransp;
		curMat->SetCoeffTransp(mater->GetCoeffTransp());

		curMat->modified = true;

		scene->materialModified = true;

		// Attribution à l'objet 3D
		for(i=0; i<msh->NbFaces; i++)
		{
			if( (*faces)[i].GetMaterial() == mater )			(*faces)[i].SetMaterial(curMat);
		}
		msh->hasViewChanged = true;

		scene->meshModified		= true;
	}
	else
	{
		newMat = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),2)), (int)mater);
	}

	if(newMat!=NIL)		newMat = PTOM(newMat);

	MMset(m,0,newMat);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3copyMaterial
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d HMat3d S] HMat3d
int ZM3copyMaterial(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3copyMaterial ");
#endif
	int name = MMpull(m);
	int mat  = MMpull(m);
	int s3d  = MMget(m,0);
    
    if((name==NIL)||(s3d==NIL)||(mat==NIL))		{	MMset(m,0,NIL);		return 0;	}

    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZMaterial	*mater = (ZMaterial*) MMfetch(m,MTOP(mat),0);
	if(mater==NULL)					{	MMset(m,0,NIL);		return 0;	}

	
	// Creation du nouveau materiau
	string	nom = string(MMstartstr(m,MTOP(name)));

	ZMaterial*	curMat = new ZMaterial(scene->accelerated);
	if(!curMat)						{	MMset(m,0,NIL);		return 0;	}
	scene->MatList.Add(curMat);

	curMat->SetName(nom);

	int hash_tab = MTOP( MMfetch(m,MTOP(s3d),2) );
	mat = createHmatHtx(m, (int)curMat, hash_tab);

	// Copie des pptés
	for(int i=0; i<4; i++)
	{
		curMat->ambient[i]  = mater->ambient[i];
		curMat->diffuse[i]  = mater->diffuse[i];
		curMat->specular[i] = mater->specular[i];
		curMat->emission[i] = mater->emission[i];
	}

	curMat->shininess = mater->shininess;
	
	curMat->SetTexture1(mater->GetTexture1());
	curMat->SetTexture2(mater->GetTexture2());

	curMat->RenderMode = mater->RenderMode;

	curMat->transparencyOrder = mater->transparencyOrder;

	curMat->color  = mater->color;
	curMat->color1 = mater->color1;
	curMat->color2 = mater->color2;
	curMat->SetDefaultColor(mater->GetDefaultColor());
	curMat->color1_24 = mater->color1_24;
	curMat->color2_24 = mater->color2_24;
	
	curMat->alpha = mater->alpha;
	curMat->coeffTransp = mater->coeffTransp;
	curMat->SetCoeffTransp(mater->GetCoeffTransp());

	curMat->modified = true;	

	scene->materialModified = true;


	MMset(m, 0, PTOM(mat));
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3chgObjMaterial
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d HMat3d HMat3d] I
int ZM3chgObjMaterial(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3chgObjMaterial ");
#endif
	int matNew = MMpull(m);
	int matCur = MMpull(m);
	int obj = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(obj==NIL)||(matNew==NIL)||(matCur==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(obj),0);
	if(node==NULL)					{	MMset(m,0,NIL);		return 0;	}

	ZMaterial	*matN = (ZMaterial*) MMfetch(m,MTOP(matNew),0);
	if(matN==NULL)					{	MMset(m,0,NIL);		return 0;	}

	ZMaterial	*matC = (ZMaterial*) MMfetch(m,MTOP(matCur),0);
	if(matC==NULL)					{	MMset(m,0,NIL);		return 0;	}


	if(node->type==OBJ_TYPE_ID)
	{
		ZObject	*curObj = (ZObject*)node;

		// Change le materiau
		if(curObj->IsMultiMeshes()==false)
		{
			ZMesh	*msh = curObj->GetMesh();
			if(msh==NULL)					{	MMset(m,0,NIL);		return 0;	}

			vector<ZFace>	*faces = &(msh->Faces);
			
			for(int i=0; i<msh->NbFaces; i++)
			{
				if( (*faces)[i].GetMaterial() == matC )			(*faces)[i].SetMaterial(matN);
			}
			
			msh->hasViewChanged = true;
		}
		else
		{
			ZArray<ZMesh*>	*mshList = curObj->GetMeshList();
			ZMesh	*msh;

			for(int ii=0; ii<mshList->Size(); ii++)
			{
				msh = (*mshList)[ii];

				if(msh!=NULL)
				{
					vector<ZFace>	*faces = &(msh->Faces);
					
					for(int i=0; i<msh->NbFaces; i++)
					{
						if( (*faces)[i].GetMaterial() == matC )			(*faces)[i].SetMaterial(matN);
					}

					msh->hasViewChanged = true;
				}
			}
		}
	}
	else if(node->type==MSH_TYPE_ID)
	{
		ZMesh*	msh = (ZMesh*)node;

		vector<ZFace>	*faces = &(msh->Faces);
		
		for(int i=0; i<msh->NbFaces; i++)
		{
			if( (*faces)[i].GetMaterial() == matC )			(*faces)[i].SetMaterial(matN);
		}
		
		msh->hasViewChanged = true;
	}
	else
	{	
		MMset(m,0,NIL);
		return 0;
	}


	scene->meshModified	= true;

	MMset(m,0,0);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3shiftTextureXY
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d HMat3d I I] I
int ZM3shiftTextureXY(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3shiftTextureXY ");
#endif

	int	Y	= MTOI(MMpull(m));
	int	X	= MTOI(MMpull(m));
	int mat = MMpull(m);
	int obj = MMpull(m);
  int s3d = MMget(m,0);

  //$BLG
  //Removed verification of X & Y: NIL is defined as -1, this hindered the use of this value
  //if((s3d==NIL)||(obj==NIL)||(mat==NIL)||(X==NIL)||(Y==NIL))		{	MMset(m,0,NIL);		return 0;	}
  if((s3d==NIL)||(obj==NIL)||(mat==NIL))		{	MMset(m,0,NIL);		return 0;	}
  ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}


    ZNode	*node = (ZNode*) MMfetch(m,MTOP(obj),0);
	if(node==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZMaterial	*mater = (ZMaterial*) MMfetch(m,MTOP(mat),0);
	if(mater==NULL)					{	MMset(m,0,NIL);		return 0;	}

	ZMesh	*msh;

	if(node->type==OBJ_TYPE_ID)	
	{
		msh = ((ZObject*)node)->GetMesh();
		if(msh==NULL)				{	MMset(m,0,NIL);		return 0;	}
	}
	else if(node->type==MSH_TYPE_ID)
	{
		msh = (ZMesh*)node;
	}
	else
	{	
		MMset(m,0,NIL);
		return 0;
	}

	// Change le materiau
	ZFace	*fac;
	float	dX = ((float)X) / CONST_TEX_COORD_SHIFT;
	float	dY = ((float)Y) / CONST_TEX_COORD_SHIFT;

	for(int i=0; i<msh->NbFaces; i++)
	{
		fac = &(msh->Faces[i]);
		
		if(fac->GetMaterial() == mater)
		{
			fac->UV1[0].u += dX;			fac->UV1[0].v += dY;
			fac->UV1[1].u += dX;			fac->UV1[1].v += dY;
			fac->UV1[2].u += dX;			fac->UV1[2].v += dY;

			if( fac->UV1[0].u<0.0f || fac->UV1[1].u<0.0f || fac->UV1[2].u<0.0f ||
				fac->UV1[0].u>1.0f || fac->UV1[1].u>1.0f || fac->UV1[2].u>1.0f )	fac->clampU1 = false;
			else																	fac->clampU1 = true;

			if( fac->UV1[0].v<0.0f || fac->UV1[1].v<0.0f || fac->UV1[2].v<0.0f || 
				fac->UV1[0].v>1.0f || fac->UV1[1].v>1.0f || fac->UV1[2].v>1.0f )	fac->clampV1 = false;
			else																	fac->clampV1 = true;
		}
	}

	//$MS : Modification pour optimisation (appel inutile)
	//msh->hasViewChanged = true;

	mater->modified   = true;

	//	scene->materialModified = true;


	// Désactive la compilation des displays lists
	msh->displayListCreate = false;


	scene->meshModified	= true;

	MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3shiftTextureXYF
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d HMat3d F F] I
int ZM3shiftTextureXYF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3shiftTextureXYF ");
#endif
	int	Y	= MMpull(m);
	int	X	= MMpull(m);
	int mat = MMpull(m);
	int obj = MMpull(m);
    int s3d = MMget(m,0);

  //$BLG
  //Removed verification of X & Y: NIL is defined as -1, this hindered the use of this value  
  //if((s3d==NIL)||(obj==NIL)||(mat==NIL)||(X==NIL)||(Y==NIL))		{	MMset(m,0,NIL);		return 0;	}
  if ((s3d == NIL) || (obj == NIL) || (mat == NIL))		{	MMset(m,0,NIL);		return 0;	}
  ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if (scene == NULL)					{	MMset(m,0,NIL);		return 0;	}

  ZNode	*node = (ZNode*) MMfetch(m,MTOP(obj),0);
	if (node == NULL)					{	MMset(m,0,NIL);		return 0;	}

  ZMaterial	*mater = (ZMaterial*) MMfetch(m,MTOP(mat),0);
	if (mater == NULL)					{	MMset(m,0,NIL);		return 0;	}

	ZMesh	*msh;

	if (node->type == OBJ_TYPE_ID)	
	{
		msh = ((ZObject*)node)->GetMesh();
		if (msh == NULL)				{	MMset(m,0,NIL);		return 0;	}
	}
	else if (node->type == MSH_TYPE_ID)
	{
		msh = (ZMesh*)node;
	}
	else
	{	
		MMset(m,0,NIL);
		return 0;
	}

	// Change le materiau
	ZFace	*fac;
	float	dX = MTOF(X);
	float	dY = MTOF(Y);

	for(int i=0; i<msh->NbFaces; i++)
	{
		fac = &(msh->Faces[i]);
		
		if (fac->GetMaterial() == mater)
		{
			fac->UV1[0].u += dX;			fac->UV1[0].v += dY;
			fac->UV1[1].u += dX;			fac->UV1[1].v += dY;
			fac->UV1[2].u += dX;			fac->UV1[2].v += dY;

			if( fac->UV1[0].u<0.0f || fac->UV1[1].u<0.0f || fac->UV1[2].u<0.0f ||
				fac->UV1[0].u>1.0f || fac->UV1[1].u>1.0f || fac->UV1[2].u>1.0f )	fac->clampU1 = false;
			else																	fac->clampU1 = true;

			if( fac->UV1[0].v<0.0f || fac->UV1[1].v<0.0f || fac->UV1[2].v<0.0f || 
				fac->UV1[0].v>1.0f || fac->UV1[1].v>1.0f || fac->UV1[2].v>1.0f )	fac->clampV1 = false;
			else																	fac->clampV1 = true;
		}
	}

	//msh->hasViewChanged = true;

	mater->modified   = true;

	//scene->materialModified = true;
	
	// Désactive la compilation des displays lists
	msh->displayListCreate = false;

	scene->meshModified	= true;

	MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}


//$BLG: v4.6a5 - New function (Base code from ZM3shiftTextureXY)
//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3shiftTextureBisXY
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d HMat3d I I] I
int ZM3shiftTextureBisXY(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3shiftTextureBisXY ");
#endif

	int	Y	= MTOI(MMpull(m));
	int	X	= MTOI(MMpull(m));
	int mat = MMpull(m);
	int obj = MMpull(m);
  int s3d = MMget(m,0);

  //$BLG
  //Removed verification of X & Y: NIL is defined as -1, this hindered the use of this value
  //if((s3d==NIL)||(obj==NIL)||(mat==NIL)||(X==NIL)||(Y==NIL))		{	MMset(m,0,NIL);		return 0;	}
  if ((s3d == NIL) || (obj == NIL) || (mat == NIL))		{	MMset(m,0,NIL);		return 0;	}
  ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if (scene == NULL)		{	MMset(m,0,NIL);		return 0;	}

  ZNode	*node = (ZNode*) MMfetch(m,MTOP(obj),0);
	if (node == NULL)		{	MMset(m,0,NIL);		return 0;	}

  ZMaterial	*mater = (ZMaterial*) MMfetch(m,MTOP(mat),0);
	if (mater == NULL)		{	MMset(m,0,NIL);		return 0;	}

	ZMesh	*msh;

	if (node->type == OBJ_TYPE_ID)	
	{
		msh = ((ZObject*)node)->GetMesh();
		if (msh== NULL)		{	MMset(m,0,NIL);		return 0;	}
	}
	else if (node->type == MSH_TYPE_ID)
	{
		msh = (ZMesh*)node;
	}
	else
	{	
		MMset(m,0,NIL);
		return 0;
	}

	// Change le materiau
	ZFace	*fac;
	float	dX = ((float)X) / CONST_TEX_COORD_SHIFT;
	float	dY = ((float)Y) / CONST_TEX_COORD_SHIFT;

	for(int i=0; i<msh->NbFaces; i++)
	{
		fac = &(msh->Faces[i]);
		
		if(fac->GetMaterial() == mater)
		{
			fac->UV2[0].u += dX;			fac->UV2[0].v += dY;
			fac->UV2[1].u += dX;			fac->UV2[1].v += dY;
			fac->UV2[2].u += dX;			fac->UV2[2].v += dY;

			if( fac->UV2[0].u<0.0f || fac->UV2[1].u<0.0f || fac->UV2[2].u<0.0f ||
				fac->UV2[0].u>1.0f || fac->UV2[1].u>1.0f || fac->UV2[2].u>1.0f )	fac->clampU2 = false;
			else																	fac->clampU2 = true;

			if( fac->UV2[0].v<0.0f || fac->UV2[1].v<0.0f || fac->UV2[2].v<0.0f || 
				fac->UV2[0].v>1.0f || fac->UV2[1].v>1.0f || fac->UV2[2].v>1.0f )	fac->clampV2 = false;
			else																	fac->clampV2 = true;
		}
	}

	//msh->hasViewChanged = true;

	mater->modified   = true;

	//scene->materialModified = true;
	
	// Désactive la compilation des displays lists
	msh->displayListCreate = false;

	scene->meshModified	= true;

	MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//$BLG: v4.6a5 - New function (Base code from ZM3shiftTextureXYF)
//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3shiftTextureBisXYF
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d HMat3d F F] I
int ZM3shiftTextureBisXYF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3shiftTextureBisXYF ");
#endif
	int	Y	= MMpull(m);
	int	X	= MMpull(m);
	int mat = MMpull(m);
	int obj = MMpull(m);
  int s3d = MMget(m,0);

  //$BLG
  //Removed verification of X & Y: NIL is defined as -1, this hindered the use of this value  
  //if ((s3d == NIL) || (obj == NIL) || (mat == NIL) || (X == NIL) || (Y == NIL))		{	MMset(m,0,NIL);		return 0;	}
  if ((s3d == NIL) || (obj == NIL) || (mat == NIL))		{	MMset(m,0,NIL);		return 0;	}
  ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if (scene == NULL)					{	MMset(m,0,NIL);		return 0;	}

  ZNode	*node = (ZNode*) MMfetch(m,MTOP(obj),0);
	if (node == NULL)					{	MMset(m,0,NIL);		return 0;	}

  ZMaterial	*mater = (ZMaterial*) MMfetch(m,MTOP(mat),0);
	if (mater == NULL)					{	MMset(m,0,NIL);		return 0;	}

	ZMesh	*msh;

	if (node->type == OBJ_TYPE_ID)	
	{
		msh = ((ZObject*)node)->GetMesh();
		if (msh == NULL)				{	MMset(m,0,NIL);		return 0;	}
	}
	else if (node->type == MSH_TYPE_ID)
	{
		msh = (ZMesh*)node;
	}
	else
	{	
		MMset(m,0,NIL);
		return 0;
	}


	// Change le materiau
	ZFace	*fac;
	float	dX = MTOF(X);
	float	dY = MTOF(Y);

	for(int i=0; i<msh->NbFaces; i++)
	{
		fac = &(msh->Faces[i]);
		
		if (fac->GetMaterial() == mater)
		{
			fac->UV2[0].u += dX;			fac->UV2[0].v += dY;
			fac->UV2[1].u += dX;			fac->UV2[1].v += dY;
			fac->UV2[2].u += dX;			fac->UV2[2].v += dY;

			if( fac->UV2[0].u<0.0f || fac->UV2[1].u<0.0f || fac->UV2[2].u<0.0f ||
				fac->UV2[0].u>1.0f || fac->UV2[1].u>1.0f || fac->UV2[2].u>1.0f )	fac->clampU2 = false;
			else																	fac->clampU2 = true;

			if( fac->UV2[0].v<0.0f || fac->UV2[1].v<0.0f || fac->UV2[2].v<0.0f || 
				fac->UV2[0].v>1.0f || fac->UV2[1].v>1.0f || fac->UV2[2].v>1.0f )	fac->clampV2 = false;
			else																	fac->clampV2 = true;
		}
	}

	//msh->hasViewChanged = true;

	mater->modified   = true;

	//scene->materialModified = true;
	
	// Désactive la compilation des displays lists
	msh->displayListCreate = false;

	scene->meshModified	= true;

	MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}


//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3shiftLightMapXY
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d HMat3d I I] I
int ZM3shiftLightMapXY(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3shiftLightMapXY ");
#endif

	int	Y	= MTOI(MMpull(m));
	int	X	= MTOI(MMpull(m));
	int mat = MMpull(m);
	int obj = MMpull(m);
  int s3d = MMget(m,0);

  //$BLG
  //Removed verification of X & Y: NIL is defined as -1, this hindered the use of this value
  //if((s3d==NIL)||(obj==NIL)||(mat==NIL)||(X==NIL)||(Y==NIL))		{	MMset(m,0,NIL);		return 0;	}
  if ((s3d == NIL) || (obj == NIL) || (mat == NIL))		{	MMset(m,0,NIL);		return 0;	}
  ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if (scene == NULL)		{	MMset(m,0,NIL);		return 0;	}

  ZNode	*node = (ZNode*) MMfetch(m,MTOP(obj),0);
	if (node == NULL)		{	MMset(m,0,NIL);		return 0;	}

  ZMaterial	*mater = (ZMaterial*) MMfetch(m,MTOP(mat),0);
	if (mater == NULL)		{	MMset(m,0,NIL);		return 0;	}

	ZMesh	*msh;

	if (node->type == OBJ_TYPE_ID)	
	{
		msh = ((ZObject*)node)->GetMesh();
		if (msh== NULL)		{	MMset(m,0,NIL);		return 0;	}
	}
	else if (node->type == MSH_TYPE_ID)
	{
		msh = (ZMesh*)node;
	}
	else
	{	
		MMset(m,0,NIL);
		return 0;
	}

	// Change le materiau
	ZFace	*fac;
	float	dX = ((float)X) / CONST_TEX_COORD_SHIFT;
	float	dY = ((float)Y) / CONST_TEX_COORD_SHIFT;

		for(int i=0; i<msh->NbFaces; i++)
		{
			fac = &(msh->Faces[i]);
			
			if(fac->GetMaterial() == mater)
			{
				fac->UV3[0].u += dX;			fac->UV3[0].v += dY;
				fac->UV3[1].u += dX;			fac->UV3[1].v += dY;
				fac->UV3[2].u += dX;			fac->UV3[2].v += dY;

				if( fac->UV3[0].u<0.0f || fac->UV3[1].u<0.0f || fac->UV3[2].u<0.0f ||
					fac->UV3[0].u>1.0f || fac->UV3[1].u>1.0f || fac->UV3[2].u>1.0f )	fac->clampU3 = false;
				else																	fac->clampU3 = true;

				if( fac->UV3[0].v<0.0f || fac->UV3[1].v<0.0f || fac->UV3[2].v<0.0f || 
					fac->UV3[0].v>1.0f || fac->UV3[1].v>1.0f || fac->UV3[2].v>1.0f )	fac->clampV3 = false;
				else																	fac->clampV3 = true;
			}
		}
	

	msh->hasViewChanged = true;

	// Désactive la compilation des displays lists
	msh->displayListCreate = false;

	scene->meshModified	= true;

	MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//$BLG: v4.6a5 - New function (Base code from ZM3shiftTextureXYF)
//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3shiftLightMapXYF
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d HMat3d F F] I
int ZM3shiftLightMapXYF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3shiftLightMapXYF ");
#endif
	int	Y	= MMpull(m);
	int	X	= MMpull(m);
	int mat = MMpull(m);
	int obj = MMpull(m);
  int s3d = MMget(m,0);

  //$BLG
  //Removed verification of X & Y: NIL is defined as -1, this hindered the use of this value  
  //if ((s3d == NIL) || (obj == NIL) || (mat == NIL) || (X == NIL) || (Y == NIL))		{	MMset(m,0,NIL);		return 0;	}
  if ((s3d == NIL) || (obj == NIL) || (mat == NIL))		{	MMset(m,0,NIL);		return 0;	}
  ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if (scene == NULL)					{	MMset(m,0,NIL);		return 0;	}

  ZNode	*node = (ZNode*) MMfetch(m,MTOP(obj),0);
	if (node == NULL)					{	MMset(m,0,NIL);		return 0;	}

  ZMaterial	*mater = (ZMaterial*) MMfetch(m,MTOP(mat),0);
	if (mater == NULL)					{	MMset(m,0,NIL);		return 0;	}

	ZMesh	*msh;

	if (node->type == OBJ_TYPE_ID)	
	{
		msh = ((ZObject*)node)->GetMesh();
		if (msh == NULL)				{	MMset(m,0,NIL);		return 0;	}
	}
	else if (node->type == MSH_TYPE_ID)
	{
		msh = (ZMesh*)node;
	}
	else
	{	
		MMset(m,0,NIL);
		return 0;
	}


	// Change le materiau
	ZFace	*fac;
	float	dX = MTOF(X);
	float	dY = MTOF(Y);

	for(int i=0; i<msh->NbFaces; i++)
	{
		fac = &(msh->Faces[i]);
		
		if (fac->GetMaterial() == mater)
		{
			fac->UV3[0].u += dX;			fac->UV3[0].v += dY;
			fac->UV3[1].u += dX;			fac->UV3[1].v += dY;
			fac->UV3[2].u += dX;			fac->UV3[2].v += dY;

			if( fac->UV3[0].u<0.0f || fac->UV3[1].u<0.0f || fac->UV3[2].u<0.0f ||
				fac->UV3[0].u>1.0f || fac->UV3[1].u>1.0f || fac->UV3[2].u>1.0f )	fac->clampU3 = false;
			else																	fac->clampU3 = true;

			if( fac->UV3[0].v<0.0f || fac->UV3[1].v<0.0f || fac->UV3[2].v<0.0f || 
				fac->UV3[0].v>1.0f || fac->UV3[1].v>1.0f || fac->UV3[2].v>1.0f )	fac->clampV3 = false;
			else																	fac->clampV3 = true;
		}
	}

	msh->hasViewChanged = true;
	
	// Désactive la compilation des displays lists
	msh->displayListCreate = false;

	scene->meshModified	= true;

	MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}


//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3saveMat
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d HMat3d] S
int ZM3saveMat(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3saveMat ");
#endif
	int mat  = MMpull(m);
    int s3d  = MMpull(m);

	if((s3d==NIL)||(mat==NIL))					{	MMpush(m,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)								{	MMpush(m,NIL);		return 0;	}

    ZMaterial	*mater = (ZMaterial*) MMfetch(m,MTOP(mat),0);
	if(mater==NULL)					{	MMpush(m,NIL);		return 0;	}


    struct Save3d	sv;
	struct Sv3d		sm;

	sm.m	= m;						// mmachine
	sm.n	= 0;						// counter of words

	sv.cb	= ZM3saveconc;				// CallBack de sauvegarde
	sv.user	= (int*)&sm;				// structure de sauvegarde

	int		k;
	if((k=ZM3DsaveMat(scene, &sv, mater)))		return k;

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return ZM3saveconc(NULL, sv.user);
}

















///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////																											   ////
///												GESTION DES TEXTURES												///
////																											   ////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//$$BLG
//Original code from: http://www.opengl.org/resources/features/OGLextensions/
//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3isExtensionSupported 
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S] I
int ZM3isExtensionSupported(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ZM3isExtensionSupported ");
#endif

  int ret;
  
  int ext = MMget(m,0);
  if (ext == NIL)		{	MMset(m,0,NIL);		return 0;	}
  const char *extension = MMstartstr(m,MTOP(ext));

  const GLubyte *extensions = NULL;
  const GLubyte *start;
  GLubyte *where, *terminator;

  /* Extension names should not have spaces. */
  where = (GLubyte *) strchr(extension, ' ');
  if (where || *extension == '\0')    {	MMset(m,0,NIL);		return 0;	}
  extensions = glGetString(GL_EXTENSIONS);
  /* It takes a bit of care to be fool-proof about parsing the
     OpenGL extensions string. Don't be fooled by sub-strings,
     etc. */
  start = extensions;
  for (;;) 
  {
    where = (GLubyte *) strstr((const char *) start, extension);
    if (!where)  { ret = 0; break; }
    terminator = where + strlen(extension);
    if (where == start || *(where - 1) == ' ')
      if (*terminator == ' ' || *terminator == '\0')  { ret = 1; break; }
    start = terminator;
  }

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

  MMset(m,0,ITOM(ret));
  return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3textureSetGeneralDefaultType 
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d I] I
int ZM3textureSetGeneralDefaultType(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3textureSetGeneralDefaultType ");
#endif

	int flag = MMpull(m);
  int s3d  = MMget(m,0);

  if((flag==NIL)||(s3d==NIL))		{	MMset(m,0,NIL);		return 0;	}
  ZScene	*scene = (ZScene*)MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

	flag = MTOI(flag);

	// TEX_MIPMAP = TF_BILINEAR
  //$BLG
  /*
	if(flag&TF_BILINEAR)	scene->generalTextureFilter = TF_BILINEAR;
	else					scene->generalTextureFilter = TF_LINEAR;
  */
	if (flag == TF_TRILINEAR)	scene->generalTextureFilter = TF_TRILINEAR;
	else if(flag == TF_BILINEAR)	scene->generalTextureFilter = TF_BILINEAR;
	else if (flag == TF_LINEAR)	scene->generalTextureFilter = TF_LINEAR;
	else scene->generalTextureFilter = TF_NONE;

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	/* $MS */
	MMset(m,0,1);
	return 0;
}

//$BLG
//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3textureGetGeneralDefaultType
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d] I
int ZM3textureGetGeneralDefaultType(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3textureGetGeneralDefaultType ");
#endif

  int s3d  = MMget(m,0);
  if (s3d == NIL)		{	MMset(m,0,NIL);		return 0;	}
  ZScene	*scene = (ZScene*)MMfetch(m,MTOP(s3d),0);
 	if(scene==NULL)		{	MMset(m,0,NIL);		return 0;	}

  int flag;
  if (scene->generalTextureFilter == TF_TRILINEAR)		    flag = TF_TRILINEAR;
  else if (scene->generalTextureFilter == TF_BILINEAR)		flag = TF_BILINEAR;
  else if (scene->generalTextureFilter == TF_LINEAR)  		flag = TF_LINEAR;
	else								                                    flag = TF_NONE;

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	MMset(m,0,ITOM(flag));
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3textureSetType
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d HTx3d I] I
int ZM3textureSetType(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3textureSetType ");
#endif


	int flag = MMpull(m);
	int tex  = MMpull(m);
    int s3d  = MMget(m,0);

    if((tex==NIL)||(flag==NIL)||(s3d==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*)MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZTexture	*textu = (ZTexture*) MMfetch(m,MTOP(tex),0);
	if(textu==NULL)					{	MMset(m,0,NIL);		return 0;	}

	flag = MTOI(flag);

	// TEX_MIPMAP == TF_BILINEAR
	//$BLG
	/*
	if(flag&TF_BILINEAR)	textu->SetTextureFilter(TF_BILINEAR);
	else					textu->SetTextureFilter(TF_LINEAR);
	*/
  if (flag == TF_TRILINEAR)	textu->SetTextureFilter(TF_TRILINEAR);
  else if(flag == TF_BILINEAR)	textu->SetTextureFilter(TF_BILINEAR);
	else if (flag == TF_LINEAR)	textu->SetTextureFilter(TF_LINEAR);
	else textu->SetTextureFilter(TF_NONE);
	textu->modified = true;
	scene->textureModified = true;

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	
	MMset(m,0,0);
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3textureGetType
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d HTx3d] I
int ZM3textureGetType(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3textureSetType ");
#endif

	int tex  = MMpull(m);
    int s3d  = MMget(m,0);

    if((tex==NIL)||(s3d==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*)MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZTexture	*textu = (ZTexture*) MMfetch(m,MTOP(tex),0);
	if(textu==NULL)					{	MMset(m,0,NIL);		return 0;	}

	int flag;

	// TEX_MIPMAP == TF_BILINEAR
	//$BLG Start
	//if(textu->filter==TF_BILINEAR)		flag = TF_BILINEAR;
	//else								flag = 0;
  if (textu->filter == TF_TRILINEAR)		    flag = TF_TRILINEAR;
  else if (textu->filter == TF_BILINEAR)		flag = TF_BILINEAR;
  else if (textu->filter == TF_LINEAR)  		flag = TF_LINEAR;
	else								                      flag = TF_NONE;
  //$BLG End

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	MMset(m,0,ITOM(flag));
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3listALLTextures
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d] [HTx3d r1]
int ZM3listALLTextures(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3listALLTextures ");
#endif
	int s3d = MMget(m,0);

    if(s3d==NIL)					{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

	int	n=0;
	int tx, tmp_res;
    
	for(int i=0; i<scene->TexList.Size(); i++)
    {
		
		int s3d = MMget(m,0);
		int hash = MTOP(MMfetch(m,MTOP(s3d),3));

		tx = NodeTOHandle(m, hash, (int)scene->TexList[i]);
		if(tx!=NIL)
		{
			tx = PTOM(tx);
			if(MMpush(m,tx))			return MERRMEM;
			INVERT(m,0,1);
			n++;
		}
    }

	if(n==0)		{	MMset(m,0,NIL);		return n;	}
	MMpull(m);
	if(MMpush(m,NIL))		return MERRMEM;

	int k;
	for(int j=0;j<n;j++)
	{
    	if(MMpush(m,2*2))		return MERRMEM;
		if(k=MBdeftab(m))		return k;
	}

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getTexture
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d S] HTX3d
int ZM3getTexture(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getTexture ");
#endif
	int name = MMpull(m);
    int s3d  = MMget(m,0);

    if((name==NIL)||(s3d==NIL))		{	MMset(m,0,NIL);		return 0;	}

    ZScene	*scene = (ZScene*)MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

	string	nom = string(MMstartstr(m,MTOP(name)));

	for(int i=0; i<scene->TexList.Size() && scene->TexList[i]->name!=nom; i++);

	if(i>=scene->TexList.Size())		{	MMset(m,0,NIL);		return 0;	}

	int	tex = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),3)), (int)scene->TexList[i]);
	if(tex!=NIL)		tex = PTOM(tex);
	MMset(m,0,tex);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3textureName
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d HTx3d] S
int ZM3textureName(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3textureName ");
#endif
    int tex = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(tex==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZTexture	*textu = (ZTexture*) MMfetch(m,MTOP(tex),0);
	if(textu==NULL)					{	MMset(m,0,NIL);		return 0;	}

	MMpull(m);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return Mpushstrbloc(m, (char*)textu->name.c_str());
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3renameTexture
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d HTx3d S] I
int ZM3renameTexture(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3renameTexture ");
#endif
    int name = MMpull(m);
    int tex  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(tex==NIL)||(name==NIL))			{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZTexture	*textu = (ZTexture*) MMfetch(m,MTOP(tex),0);
	if(textu==NULL)					{	MMset(m,0,NIL);		return 0;	}

	textu->SetName((char*)MMstartstr(m,MTOP(name)));
	textu->SetFileName((char*)MMstartstr(m,MTOP(name)));
	textu->renamed = true;

	MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3textureCount
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d HTx3d] I
int ZM3textureCount(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3textureCount ");
#endif
	int tex = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(tex==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZTexture	*textu = (ZTexture*) MMfetch(m,MTOP(tex),0);
	if(textu==NULL)					{	MMset(m,0,NIL);		return 0;	}

	MMset(m,0,ITOM(textu->nbRef));
	
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3copyMaterialTexture
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d HMat3d] HTx3d
int ZM3copyMaterialTexture(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3copyMaterialTexture ");
#endif

	int mat = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(mat==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZMaterial	*mater = (ZMaterial*) MMfetch(m,MTOP(mat),0);
	if(mater==NULL)					{	MMset(m,0,NIL);		return 0;	}

	// Récupération de la texture du matériau
	ZTexture	*tex = mater->GetTexture1();
	if(tex==NULL)					{	MMset(m,0,NIL);		return 0;	}

	int newTex = NIL;

	if(tex->nbRef != 1)
	{
		// Création de la nouvelle texture
		ZTexture	*curTex = new ZTexture(scene->accelerated);
		if(!curTex)					{	MMset(m,0,NIL);		return 0;	}
		scene->TexList.Add(curTex);

		curTex->SetTextureFilter(tex->filter);

		// Copie des données de texture
		curTex->SetFileName(tex->filename);
		curTex->SetName(tex->name);

		curTex->renamed		= true;
		curTex->modified	= true;

		scene->textureModified = true;

		curTex->SetRate(tex->GetRate());
		curTex->value = tex->value;

		curTex->A = tex->A;		curTex->S = tex->S;
		curTex->C = tex->C;		curTex->X = tex->X;
		curTex->R = tex->R;		curTex->Y = tex->Y;

		curTex->filter  = tex->filter;
		curTex->SetTranspR(tex->GetTranspR());
		curTex->SetTranspG(tex->GetTranspG());
		curTex->SetTranspB(tex->GetTranspB());

		curTex->Height = tex->Height;
		curTex->Width  = tex->Width;

		curTex->activated = false;

		if(tex->ID_created==true && tex->activated && tex->accelerated)
		{
			tex->PutGLMultiparams0();
			curTex->ImageModif	= (unsigned char *) malloc(tex->Width * tex->Height * 4);
			glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, curTex->ImageModif);
			curTex->SetupTexture();
			curTex->activated = true;
		}

/*		curTex->SetFileName(tex->filename);
		curTex->SetName(tex->name);

		curTex->renamed = true;
		curTex->modified = true;

		scene->textureModified		= true;

		curTex->SetRate(tex->GetRate());
		curTex->value = tex->value;

		curTex->A = tex->A;		curTex->S = tex->S;
		curTex->C = tex->C;		curTex->X = tex->X;
		curTex->R = tex->R;		curTex->Y = tex->Y;

		curTex->filter  = tex->filter;
		curTex->SetTranspR(tex->GetTranspR());
		curTex->SetTranspG(tex->GetTranspG());
		curTex->SetTranspB(tex->GetTranspB());

		curTex->Height = tex->Height;
		curTex->Width  = tex->Width;

		curTex->activated = tex->activated;

		if(tex->Image != NULL)
		{
			curTex->Image		= (unsigned char *) malloc(tex->Width * tex->Height * 4);
			memcpy(curTex->Image, tex->Image, tex->Height*tex->Width*4);
		}

		if(tex->ImageModif != NULL)
		{
			curTex->ImageModif	= (unsigned char *) malloc(tex->Width * tex->Height * 4);
			memcpy(curTex->ImageModif, tex->ImageModif, tex->Height*tex->Width*4);
		}

		curTex->SetupTexture();
*/

		// Attribution au matériau
		mater->SetTexture1(curTex);
		mater->modified = true;

		scene->materialModified = true;

		// Déclaration dans la hashtable
		int hash_tab = MTOP( MMfetch(m,MTOP(s3d),3) );
		newTex = createHmatHtx(m, (int)curTex, hash_tab);
	}
	else
	{
		newTex = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),3)), (int)tex);
	}

	if(newTex!=NIL)		newTex = PTOM(newTex);

	MMset(m,0,newTex);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3isTextureFilled
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d HTx3d] I
int ZM3isTextureFilled(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3isTextureFilled ");
#endif

	int tex = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(tex==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZTexture	*textu = (ZTexture*) MMfetch(m,MTOP(tex),0);
	if(textu==NULL)					{	MMset(m,0,NIL);		return 0;	}

	
	if(/*(textu->ImageModif==NULL)||*/(textu->activated==false)||(textu->renamed==true))	{	MMset(m,0,0);			return 0;	}
	else																				{	MMset(m,0,ITOM(1));		return 0;	}
	
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3fillTexture
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d HTx3d] I
int ZM3fillTexture(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3fillTexture ");
#endif

	int tex = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(tex==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZTexture	*textu = (ZTexture*) MMfetch(m,MTOP(tex),0);
	if(textu==NULL)					{	MMset(m,0,NIL);		return 0;	}


	// charge la bitmap
	free(textu->Image);		textu->Image = NULL;

	textu->A = textu->C = textu->X = textu->Y = textu->R = textu->S = false;

	int		debName = 0;
	char	*namefile = (char*)textu->name.c_str();
	if(namefile[0]=='%')			debName = M3DloadFilter(namefile, textu); 

	bool	test = true;
	char	name[SIZESIGN];
	if(SPfindfile((packdir)SCgetExtra("FirstPack"), &(namefile[debName]), NULL, name)==-1)		test=false;

	// load du fichier
	if(test)	
	{
		if(textu->LoadTexture(name)==false)
		{
			test = false;
			textu->activated = false;
			textu->modified  = true;
			free(textu->Image);			textu->Image = NULL;	
			free(textu->ImageModif);	textu->ImageModif = NULL;
			MMset(m,0,NIL);
		
			scene->textureModified		= true;
			
			return 0;
		}
	}

	// création de la bitmap finale
	if(test)
	{
		free(textu->ImageModif);		textu->ImageModif = NULL;
		textu->CreateModifiedImg();
		textu->SetupTexture();
		textu->modified  = true;
		textu->activated = true;

		scene->textureModified		= true;
	}


	MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;	
}





//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3freeTexture
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d HTx3d] I
int ZM3freeTexture(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3freeTexture ");
#endif

	int tex = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(tex==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZTexture	*textu = (ZTexture*) MMfetch(m,MTOP(tex),0);
	if(textu==NULL)					{	MMset(m,0,NIL);		return 0;	}

	if(textu->Image!=NULL)				free(textu->Image);
	if(textu->ImageModif!=NULL)			free(textu->ImageModif);

	textu->Image = textu->ImageModif = NULL;

	if(scene->accelerated)
	{
		if(textu->ID_created)
		{
			glDeleteTextures(1, &(textu->texID));
			textu->ID_created = false;
		}
	}
	else
	{
		free(textu->bitmap24);
		textu->bitmap24 = NULL;
	}

	textu->activated = false;
	textu->modified  = true;

	scene->textureModified = true;

	MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}


//$BLG
//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getTextureSize
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d HTx3d] I
int ZM3getTextureSize(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getTextureSize ");
#endif

  //$BLG: v4.6a5 - Removed next line
  //int res;

	int tex = MMpull(m);
  int s3d = MMget(m,0);

  if((s3d==NIL)||(tex==NIL))		{	MMset(m,0,NIL);		return 0;	}
  
  ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

  ZTexture	*textu = (ZTexture*) MMfetch(m,MTOP(tex),0);
	if(textu==NULL)					{	MMset(m,0,NIL);		return 0;	}

	int tuple = MMmalloc(m, 2, TYPETAB);
	if(tuple==NIL)				{	MMset(m,0,NIL);		return MERRMEM; }
	MMstore(m, tuple, 0, ITOM(textu->Width));
	MMstore(m, tuple, 1, ITOM(textu->Height));
  MMset(m,0,PTOM(tuple));

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

  return 0;
}


//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getTransparencyColor
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d HTx3d] I
int ZM3getTransparencyColor(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getTransparencyColor ");
#endif

	int tex = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(tex==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZTexture	*textu = (ZTexture*) MMfetch(m,MTOP(tex),0);
	if(textu==NULL)					{	MMset(m,0,NIL);		return 0;	}

	int couleurTransp = ((textu->GetTranspB())<<16) + ((textu->GetTranspG())<<8) + (textu->GetTranspR());

	MMset(m,0, ITOM(couleurTransp));		// !!!!!!!!!!!! la couleur est au format BGR !!!!!!!!!!!
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;	
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3setTransparencyColor
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d HTx3d I] I
int ZM3setTransparencyColor(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3setTransparencyColor ");
#endif
	int col	= MMpull(m);
	int tex = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(tex==NIL)||(col==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZTexture	*textu = (ZTexture*) MMfetch(m,MTOP(tex),0);
	if(textu==NULL)					{	MMset(m,0,NIL);		return 0;	}

	col = MTOI(col);

	int		debName = 0;
	char	*namefile = (char*)textu->name.c_str();
	if(namefile[0]=='%')			debName = M3DloadFilter(namefile, textu);

	///////--------> EST-CE BIEN RAISONNABLE ???? <---------- /////
	textu->A = true;
	///////////////////////////////////////////////////////////////

	textu->SetTranspR( (col&0x00ff0000)>>16 );
	textu->SetTranspG( (col&0x0000ff00)>>8  );
	textu->SetTranspB( (col&0x000000ff)     );

	if(textu->GetRate()==0)		textu->SetRate(5);
/*
	bool	test = true;
	char	name[SIZESIGN];
	if(SPfindfile((packdir)SCgetExtra("FirstPack"), &(namefile[debName]), NULL, name)==-1)		test=false;


	if(test)
	{
		if(textu->LoadTexture(name)==false)
		{
			test = false;		
			textu->activated = false;
			textu->modified  = true;
			free(textu->Image);			textu->Image = NULL;	
			free(textu->ImageModif);	textu->ImageModif = NULL;
			MMset(m,0,NIL);

			scene->textureModified		= true;
			
			return 0;
		}
	}

	if(test)
	{
		if(textu->ImageModif!=NULL)		{	free(textu->ImageModif);		textu->ImageModif = NULL;		}
		textu->CreateModifiedImg_WithoutLoading_A();
		textu->SetupTexture();
		textu->modified = true;
		textu->activated = true;

		scene->textureModified		= true;
	}
*/
	if(textu->activated==true)
	{
		if(textu->accelerated)
		{
//			if(textu->Width == 63)		_asm{int 3};


			textu->PutGLMultiparams0();
			unsigned char	*bitmap = (unsigned char*) malloc(textu->Width * textu->Height * 4);
			glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, bitmap);

			if(textu->Image!=NULL)			{	free(textu->Image);				textu->Image = NULL;			}
			if(textu->ImageModif!=NULL)		{	free(textu->ImageModif);		textu->ImageModif = NULL;		}

			for(int pipo=0; pipo<textu->Width*textu->Height; pipo++)		bitmap[pipo*4+3] = 255;

			textu->Image = bitmap;

			textu->CreateModifiedImg_WithoutLoading_A();
			textu->SetupTexture();
			textu->modified = true;
			scene->textureModified = true;
		}
		else
		{
			int i, bi;
			OBJBITMAP_BUFFER bitmap = (OBJBITMAP_BUFFER) malloc(textu->Width * textu->Height * 4);
			OBJBITMAP_BUFFER bitm	= (OBJBITMAP_BUFFER)textu->bitmap24;
			for(i=0, bi = 0; i<textu->Width * textu->Height; i++)
			{
				bitmap[i*4+0] = bitm[bi++];	
				bitmap[i*4+1] = bitm[bi++];	
				bitmap[i*4+2] = bitm[bi++];		
				bitmap[i*4+3] = 255;
			}

			textu->Image = bitmap;

			textu->CreateModifiedImg_WithoutLoading_A();
			textu->SetupTexture();
			textu->modified = true;
			scene->textureModified = true;
		}
	}


	MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}




//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3createTexture
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d S] HTx3d
int ZM3createTexture(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3createTexture ");
#endif
	int nam  = MMpull(m);
	int s3d  = MMget(m,0);

    if((s3d==NIL)||(nam==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}


	// Creation de la nouvelle texture
	string	nom = string(MMstartstr(m,MTOP(nam)));

	ZTexture*	curTex = new ZTexture(scene->accelerated);
	if(!curTex)						
	{	
		MMset(m,0,NIL);	
		return 0;	
	}
	scene->TexList.Add(curTex);

	curTex->SetName(nom);
	curTex->SetFileName(nom);
	curTex->renamed = false;		// becoz we load the bitmap in the following lines



	// Chargement de la bitmap
	curTex->SetTextureFilter(scene->generalTextureFilter);

	int		debName  = 0;
	char	*ptrName = (char *) nom.c_str();
	if(nom[0]=='%')			debName = M3DloadFilter(ptrName, curTex);


	bool	test = true;
	char	name[SIZESIGN];

	if(SPfindfile((packdir)SCgetExtra("FirstPack"), (char*)(ptrName+debName), NULL, name)==-1)		{	scene->TexList.DeleteLastEntry();	delete curTex;		MMset(m,0,NIL);		return 0;	}
	if(curTex->LoadTexture(name)==false)
	{
		free(curTex->Image);			curTex->Image = NULL;	
		free(curTex->ImageModif);		curTex->ImageModif = NULL;
		scene->TexList.DeleteLastEntry();
		delete curTex;
		MMset(m,0,NIL);
		return 0;
	}

	// Prépare la texture
	curTex->CreateModifiedImg();
	curTex->SetupTexture();
	curTex->modified = true;

	scene->textureModified		= true;

	int hash_tab = MTOP( MMfetch(m,MTOP(MMget(m,0)),3) );
	int tex = createHmatHtx(m, (int)curTex, hash_tab);

	// Pose le résultat sur la pile
	MMset(m, 0, PTOM(tex));
	
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}































///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////																											   ////
///												GESTION DE RENDU													///
////																											   ////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZMX3hardware
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [] I
int ZMX3hardware(mmachine m)
{
	if(userACCEL)		return MMpush(m,ITOM(1));
	else				return MMpush(m,ITOM(0));
}


/*
//////////////////////////////////////////////////////////////////////////////////////////////
///		MX3getDeviceList
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [] [[S S] r1]
int MX3getDeviceList(mmachine m)
{
	int i,k;
	for(i=0;i<_MX3nb;i++)
	{
		if (k=Mpushstrbloc(m,_MX3clear[i])) return k;
		if (k=Mpushstrbloc(m,_MX3id[i])) return k;
		if (MMpush(m,2*2)) return MERRMEM;
		if (k=MBdeftab(m)) return k;
	}
	if (MMpush(m,NIL)) return MERRMEM;
	for(i=0;i<_MX3nb;i++)
	{
		if (MMpush(m,2*2)) return MERRMEM;
		if (k=MBdeftab(m)) return k;
	}
	return 0;
}
*/





///////////////////////////////////////////////////////////////////////////////////////
///		Macro GLOBAL_RENDER_FILL													///
///////////////////////////////////////////////////////////////////////////////////////
#define GLOBAL_RENDER_FILL(flag_of_wired)																\
	int		fond, y, x, h3d, surf, s3d;																	\
	ZScene	*scene;																						\
	ZNode	*node, *father;																				\
	/*/////////////////////////////////////////////////////////////////									\
	///		RENDU HARD												///									\
	/////////////////////////////////////////////////////////////////*/									\
	if(userACCEL)																						\
	{																									\
		HDC		hdc;																					\
		HGLRC	hglrc;																					\
																										\
		fond = MMpull(m);																				\
		y	 = MMpull(m);																				\
		x	 = MMpull(m);																				\
		h3d	 = MMpull(m);																				\
		surf = MMpull(m);																				\
																										\
		if(surf==NIL) 		{   MMset(m,0,NIL);		return 0;	}										\
																										\
		hdc		= (HDC)	  MMfetch(m,MTOP(surf),1);														\
		hglrc	= (HGLRC) MMfetch(m,MTOP(surf),2);														\
																										\
		if(wglGetCurrentContext()!=hglrc)																\
		{																								\
			wglMakeCurrent(hdc,hglrc);																	\
		}																								\
																										\
		s3d = MMget(m,0);																				\
		if((s3d==NIL)||(h3d==NIL))		{   MMset(m,0,NIL);		return 0;	}							\
																										\
		scene = (ZScene*) MMfetch(m,MTOP(s3d),0);														\
		if(scene==NULL || scene->accelerated==false)	{   MMset(m,0,NIL);		return 0;	}			\
																										\
		/* Couleur de Fond */																			\
		fond = MTOI(fond);																				\
		float	r = 0;																					\
		float	g = 0;																					\
		float	b = 0;																					\
																										\
		if(fond!=NIL)																					\
		{																								\
			r = ((fond)&255)	 / CONST_COLOR;															\
			g = ((fond>>8)&255)	 / CONST_COLOR;															\
			b = ((fond>>16)&255) / CONST_COLOR;															\
		}																								\
																										\
		/* Recupération de la camera */																	\
		node = (ZNode*) MMfetch(m,MTOP(h3d),0);															\
		if((node==NULL)||(node->type!=CAM_TYPE_ID))		{   MMset(m,0,NIL);		return 0;	}			\
		scene->SetActiveCam((ZCamera*)node);															\
																										\
		father = getBigFather(node);																	\
																										\
																										\
		/* Prépare la camera par précaution et aussi pour le calcul des subMatrices */					\
		ZMatrix		matx = ComputeWorldMatrix(node);													\
		((ZCamera*)node)->worldMat = matx;																\
		((ZCamera*)node)->worldPos.SetCoord(matx(0,3), matx(1,3), matx(2,3));							\
																										\
		/* Rendu de la scene */																			\
		if(fond==NIL)		scene->Display(r,g,b, father, flag_of_wired, false, false);					\
		else				scene->Display(r,g,b, father, flag_of_wired, false, true);					\
	}																									\
	/*/////////////////////////////////////////////////////////////////									\
	///		RENDU SOFT												///									\
	/////////////////////////////////////////////////////////////////*/									\
	else																								\
	{																									\
		fond = MMpull(m);																				\
		y	 = MMpull(m);																				\
		x	 = MMpull(m);																				\
		h3d	 = MMpull(m);																				\
		surf = MMpull(m);																				\
		s3d  = MMget(m,0);																				\
																										\
		if((surf==NIL)||(s3d==NIL)||(h3d==NIL)||fullscreenMode)		{   MMset(m,0,NIL);		return 0;	}		\
																										\
		scene = (ZScene*) MMfetch(m,MTOP(s3d),0);														\
		if(scene==NULL)								{   MMset(m,0,NIL);		return 0;	}				\
																										\
		RenderBuffer	buffer;																			\
		if(fillRenderBuffer(m, &buffer, surf))			{   MMset(m,0,NIL);		return 0;	}			\
																										\
		/* Couleur de Fond */																			\
		fond = MTOI(fond);																				\
		float	r = 0;																					\
		float	g = 0;																					\
		float	b = 0;																					\
																										\
		if(fond!=NIL)																					\
		{																								\
			r = ((fond)&255)	 / CONST_COLOR;															\
			g = ((fond>>8)&255)	 / CONST_COLOR;															\
			b = ((fond>>16)&255) / CONST_COLOR;															\
		}																								\
																										\
		/* Recupération de la camera */																	\
		node = (ZNode*) MMfetch(m,MTOP(h3d),0);															\
		if((node==NULL)||(node->type!=CAM_TYPE_ID))		{   MMset(m,0,NIL);		return 0;	}			\
		scene->SetActiveCam((ZCamera*)node);															\
																										\
		father = getBigFather(node);																	\
																										\
		/* Prépare la camera par précaution et aussi pour le calcul des subMatrices */					\
		ZMatrix		matx = ComputeWorldMatrix(node);													\
		((ZCamera*)node)->worldMat = matx;																\
		((ZCamera*)node)->worldPos.SetCoord(matx(0,3), matx(1,3), matx(2,3));							\
																										\
				                                                                                        \
 		/* Rendu de la scene */																			\
		if(fond==NIL)		scene->DisplaySOFT(&buffer, r, g, b, father, flag_of_wired, false, false);	\
		else				scene->DisplaySOFT(&buffer, r, g, b, father, flag_of_wired, false, true);	\
	}



///////////////////////////////////////////////////////////////////////////////////////
///		Macro CLEAN_UNUSED_DATAS													///
///////////////////////////////////////////////////////////////////////////////////////
#define CLEAN_UNUSED_DATAS																				\
																										\
	/* ---> Nettoyage des objets non référencés et déjà utilisés <---	*/								\
	ZMesh	*mesh;																						\
	int		hash_h3d = MTOP(MMfetch(m,MTOP(s3d),1));													\
	int		hash_mat = MTOP(MMfetch(m,MTOP(s3d),2));													\
	int		hash_tex = MTOP(MMfetch(m,MTOP(s3d),3));													\
																										\
	for(int j=0; j < scene->MshList.Size(); j++)														\
	{																									\
		mesh = scene->MshList[j];																		\
		if((mesh->nbRef==0)&&(mesh->referenced))														\
		{																								\
			int	h3ddel = NodeTOHandle(m, hash_h3d, (int)mesh);											\
			DelObj(m, hash_h3d, h3ddel);																\
			delete mesh;																				\
			scene->MshList.DeleteIndex(j);																\
			j--;																						\
		}																								\
	}																									\
	ZMaterial	*material;																				\
	for(j=0; j < scene->MatList.Size(); j++)															\
	{																									\
		material = scene->MatList[j];																	\
		if((material->nbRef==0)&&(material->referenced))												\
		{																								\
			int	h3ddel = NodeTOHandle(m, hash_mat, (int)material);										\
			DelObj(m, hash_mat, h3ddel);																\
			delete material;																			\
			scene->MatList.DeleteIndex(j);																\
			j--;																						\
		}																								\
	}																									\
	ZTexture	*texture;																				\
	for(j=0; j < scene->TexList.Size(); j++)															\
	{																									\
		texture = scene->TexList[j];																	\
		if((texture->nbRef==0)&&(texture->referenced))													\
		{																								\
			int	h3ddel = NodeTOHandle(m, hash_tex, (int)texture);										\
			DelObj(m, hash_tex, h3ddel);																\
			delete texture;																				\
			scene->TexList.DeleteIndex(j);																\
			j--;																						\
		}																								\
	}


#define PROCEED_RENDER_CALLBACK																			\
	/* Traitement des callbacks de rendu */																\
	ZScene	*sce;																						\
	int S3d = MMget(m,5);																				\
	if(S3d!=NIL)																						\
	{																									\
		sce = (ZScene*) MMfetch(m,MTOP(S3d),0);															\
		if(sce!=NULL)																					\
		{																								\
			int cb, nh3d, res;																			\
			ZMesh *curObj;																				\
			for(int i=0;i<sce->cbObj.Size();i++)														\
			{																							\
				curObj	= sce->cbObj[i];																\
				nh3d	= NodeTOHandle(m, MTOP(MMfetch(m,MTOP(S3d),1)), (int)curObj);					\
				cb		= MMfetch(m,nh3d,2);															\
				MMpush(m, PTOM( nh3d ));																\
				MMpush(m, cb);																			\
				if((res = Minterpreter(m)) < 0)															\
					return res;																			\
				UpdateH3d(sce, curObj, m);																\
			}																							\
		}																								\
	}																									\


// fun [S3d H3d fun [H3d] [[[[F F F] I I] r1] [[HMat3d I F F F F I F F F F I F F F F] r1]]] H3d
int M3setRenderCallback(mmachine m)
{
	int cb		=		MMpull(m);
	int h3d		= MTOP( MMpull(m) );
	int s3d		= MTOP( MMget(m,0));

	if((s3d==NIL)||(h3d==NIL))								{   MMset(m,0,NIL);		return 0;	}

	ZNode	*node = (ZNode*) MMfetch(m,h3d,0);
	if((node==NULL)||(node->type!=MSH_TYPE_ID))				{   MMset(m,0,NIL);		return 0;	}

	ZScene	*scene = (ZScene*) MMfetch(m,s3d,0);
	if(scene==NULL)											{	MMset(m,0,NIL);		return 0;	}

	MMstore(m, h3d, 2, cb);

	int pos;

	if(cb==NIL) scene->cbObj.Delete((ZMesh*)node);
	else if(scene->cbObj.Contains((ZMesh*)node, &pos)==false)
	{
		scene->cbObj.Add((ZMesh*)node);
		((ZMesh*)node)->displayListCreate = false;
	}


	MMset(m,0,PTOM(h3d));

	return 0;
}


int UpdateH3d(ZScene *scene, ZMesh *curMesh, mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"Begin -- RenderCallback\n");
#endif
	int data	= MTOP( MMpull(m));

	if(data!=NIL)
	{
		int vertexlist	= MTOP( MMfetch(m,data,0)); 
		int facelist	= MTOP( MMfetch(m,data,1));

		curMesh->Verts.resize(0);
		for(int iii=0; iii<curMesh->NbFaces; iii++)		curMesh->Faces[iii].DeleteFace();
		curMesh->Faces.resize(0);
		curMesh->NbFaces = curMesh->NbVerts = 0;

		ZVert curVert;
		int vertex, tup, vc0, vc1;
		float x,y,z;
		while(vertexlist!=NIL)
		{
			tup		= MTOP( MMfetch(m,vertexlist,0)); 
			vertex	= MTOP( MMfetch(m,tup,0));
			x		= MTOF( MMfetch(m,vertex,0));
			y		= MTOF( MMfetch(m,vertex,1));
			z		= MTOF( MMfetch(m,vertex,2));
			vc0		= MTOI( MMfetch(m,tup,1));
			vc1		= MTOI( MMfetch(m,tup,2));

			curVert.SetCoord(x/100.0f,y/100.0f,-z/100.0f);

			curVert.color1.SetCoord(	((float)((vc0&0x00ff0000)>>16)) / CONST_COLOR,
		 								((float)((vc0&0x0000ff00)>>8) ) / CONST_COLOR,
										((float) (vc0&0x000000ff)	  )  / CONST_COLOR  );
			curVert.color2.SetCoord(	((float)((vc1&0x00ff0000)>>16)) / CONST_COLOR,
		 								((float)((vc1&0x0000ff00)>>8) ) / CONST_COLOR,
										((float) (vc1&0x000000ff)	  )  / CONST_COLOR  );
			curMesh->addVert(curVert);

			vertexlist	= MTOP( MMfetch(m,vertexlist,1));		
		}

		ZNode		*node;
		ZMaterial	*mat;

		ZFace	face;
		while(facelist!=NIL)
		{
			tup				= MTOP( MMfetch(m,facelist,0));
			vertex			= MTOP( MMfetch(m,tup,0));
		
			node			= (ZNode*) MMfetch(m,vertex,0);
			if((node==NULL)||(node->type!=MAT_TYPE_ID))					{	MMset(m,0,NIL);		return 0;	}
			mat		= (ZMaterial*) node;

			face.initFace();
			face.SetMaterial(mat);

			face.VertRef[0]	= MTOI( MMfetch(m,tup,1));
			face.UV1[0].u	= MTOF( MMfetch(m,tup,2));
			face.UV1[0].v	= MTOF( MMfetch(m,tup,3));
			face.UV2[0].u	= MTOF( MMfetch(m,tup,4));
			face.UV2[0].v	= MTOF( MMfetch(m,tup,5));

			face.VertRef[1]	= MTOI( MMfetch(m,tup,6));
			face.UV1[1].u	= MTOF( MMfetch(m,tup,7));
			face.UV1[1].v	= MTOF( MMfetch(m,tup,8));
			face.UV2[1].u	= MTOF( MMfetch(m,tup,9));
			face.UV2[1].v	= MTOF( MMfetch(m,tup,10));

			face.VertRef[2]	= MTOI( MMfetch(m,tup,11));
			face.UV1[2].u	= MTOF( MMfetch(m,tup,12));
			face.UV1[2].v	= MTOF( MMfetch(m,tup,13));
			face.UV2[2].u	= MTOF( MMfetch(m,tup,14));
			face.UV2[2].v	= MTOF( MMfetch(m,tup,15));

		
			curMesh->addFace(face);
			face.SetMaterial(NULL);

			facelist		= MTOP( MMfetch(m,facelist,1));		
		}

		curMesh->hasTopoChanged = curMesh->hasViewChanged = scene->meshModified = true;
	}

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"End -- RenderCallback\n");
#endif
	return 0;
}

//////////////////////////////////////////////////////////////////////////////////////////////
///		ZMX3renderEx
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d ObjSurface H3d I I I] [H3d HMat3d I I I I I]
// -> [objet3D  Materiau  nbFace  U  V  Z  dist]
int ZMX3renderEx(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"MX3renderEx ");
#endif

	/* Traitement des callbacks de rendu */
	PROCEED_RENDER_CALLBACK

	// Macro de rendu GLOBAL
	GLOBAL_RENDER_FILL(false)

	CLEAN_UNUSED_DATAS


	// Détermination de l'objet pointé par (x,y)
	int		width  = ((ZCamera*)node)->width  / 2;
	int		height = ((ZCamera*)node)->height / 2;
	int		result = NIL;
	int		mater  = NIL;
	float	u = 0, v = 0, z = 0, dist = 0;
	int		faceNb;
	//$BLG
	int typ;

	if((x!=NIL)&&(y!=NIL))
	{
		//$BLG
		//ZObject*  obj = scene->Getinfo(MTOI(x)+width, height-MTOI(y), &u, &v, &z, NULL, &faceNb, &dist);
		//if(obj != NULL)
		ZBLG_ObjSpr*  objspr = scene->Getinfo(MTOI(x)+width, height-MTOI(y), &u, &v, &z, NULL, &faceNb, &dist);
		if ((objspr->blg_objspr_obj != NULL) || (objspr->blg_objspr_spr))
		{
			//$BLG
			//result = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)obj);
			//ZMaterial	*mat = obj->GetMesh()->Faces[faceNb].GetMaterial();
			ZMaterial* mat;
			if (objspr->blg_objspr_obj != NULL) 
			{
				typ = OBJ_TYPE_ID;
				result = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)objspr->blg_objspr_obj);
				mat = objspr->blg_objspr_obj->GetMesh()->Faces[faceNb].GetMaterial();
			}
			else if (objspr->blg_objspr_spr != NULL) 
			{
				typ = SPR_TYPE_ID;
				result = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)objspr->blg_objspr_spr);
				mat = objspr->blg_objspr_spr->GetMaterial();
			}
			if ((mat != NULL) && (result != NIL))
			{
				mater = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),2)), (int)mat);
				if (mater != NIL)		mater = PTOM(mater);
			}
			if (result != NIL)		result = PTOM(result);
		}
		//$BLG
		delete objspr;
	}

	// Pose le resultat sur la pile
	MMset(m,0,mater);
	MMpush(m,result);

	int tuple = MMmalloc(m, 7, TYPETAB);
	if (tuple == NIL)	{MMset(m,0,NIL); return MERRMEM;}
	MMstore(m, tuple, 0, MMpull(m));
	MMstore(m, tuple, 1, MMget(m,0));

  //$BLG
	//if(mater!=NIL)
	if ((mater != NIL) && (typ == OBJ_TYPE_ID))
	{
		MMstore(m, tuple, 2, ITOM(faceNb));
		MMstore(m, tuple, 3, ITOM(AROUNDINT(u*CONST_TEX_COORD)));
		MMstore(m, tuple, 4, ITOM(AROUNDINT(v*CONST_TEX_COORD)));
		MMstore(m, tuple, 5, ITOM(AROUNDINT(-z*100.0f)));
		MMstore(m, tuple, 6, ITOM(AROUNDINT(dist*100.0f)));
	}
  //BLG: Added else if
	else if ((mater != NIL) && (typ == SPR_TYPE_ID))
	{
		MMstore(m, tuple, 2, NIL);
		MMstore(m, tuple, 3, NIL);
		MMstore(m, tuple, 4, NIL);
		MMstore(m, tuple, 5, NIL);
		MMstore(m, tuple, 6, ITOM(AROUNDINT(dist*100.0f)));
	}  
	else
	{
		MMstore(m, tuple, 2, NIL);
		MMstore(m, tuple, 3, NIL);
		MMstore(m, tuple, 4, NIL);
		MMstore(m, tuple, 5, NIL);
		MMstore(m, tuple, 6, NIL);
	}
	MMset(m,0,PTOM(tuple));

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZMX3renderExF
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d ObjSurface H3d I I I] [H3d HMat3d I F F F F]
// -> [objet3D  Materiau  nbFace  U  V  Z  dist]
int ZMX3renderExF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"MX3renderEx");
#endif

	/* Traitement des callbacks de rendu */
	PROCEED_RENDER_CALLBACK

	// Macro de rendu GLOBAL
	GLOBAL_RENDER_FILL(false)

	CLEAN_UNUSED_DATAS

	// Détermination de l'objet pointé par (x,y)
	int		width  = ((ZCamera*)node)->width  / 2;
	int		height = ((ZCamera*)node)->height / 2;
	int		result = NIL;
	int		mater  = NIL;
	float	u = 0, v = 0, z = 0, dist = 0;
	int		faceNb;
	//$BLG
	int typ;

	if((x!=NIL)&&(y!=NIL))
	{
		//$BLG
		//ZObject*  obj = scene->Getinfo(MTOI(x)+width, height-MTOI(y), &u, &v, &z, NULL, &faceNb, &dist);
		//if(obj!=NULL)
		ZBLG_ObjSpr* objspr = scene->Getinfo(MTOI(x)+width, height-MTOI(y), &u, &v, &z, NULL, &faceNb, &dist);
		if ((objspr->blg_objspr_obj != NULL) || (objspr->blg_objspr_spr))
		{
			//$BLG
			//result = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)obj);
			//ZMaterial	*mat = obj->GetMesh()->Faces[faceNb].GetMaterial();
			ZMaterial* mat;
			if (objspr->blg_objspr_obj != NULL) 
			{
				typ = OBJ_TYPE_ID;
				result = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)objspr->blg_objspr_obj);
				mat = objspr->blg_objspr_obj->GetMesh()->Faces[faceNb].GetMaterial();
			}
			else if (objspr->blg_objspr_spr != NULL) 
			{
				typ = SPR_TYPE_ID;
				result = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)objspr->blg_objspr_spr);
				mat = objspr->blg_objspr_spr->GetMaterial();
			}			
			if((mat!=NULL)&&(result!=NIL))
			{
				mater = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),2)), (int)mat);
				if(mater!=NIL)		mater = PTOM(mater);
			}
			if(result!=NIL)		result = PTOM(result);
		}
		//$BLG
		delete objspr;
	}

	// Pose le resultat sur la pile
	MMset(m,0,mater);
	MMpush(m,result);

	int tuple = MMmalloc(m, 7, TYPETAB);
	if(tuple==NIL)				{	MMset(m,0,NIL);		return MERRMEM;		}
	MMstore(m, tuple, 0, MMpull(m));
	MMstore(m, tuple, 1, MMget(m,0));

  //$BLG
	//if(mater!=NIL)
	if ((mater != NIL) && (typ == OBJ_TYPE_ID))
	{
		MMstore(m, tuple, 2, ITOM(faceNb));
		MMstore(m, tuple, 3, FTOM(u));
		MMstore(m, tuple, 4, FTOM(v));
		MMstore(m, tuple, 5, FTOM(-z*100.0f));
		MMstore(m, tuple, 6, FTOM(dist*100.0f));
	}
  //BLG: Added else if
	else if ((mater != NIL) && (typ == SPR_TYPE_ID))
	{
		MMstore(m, tuple, 2, NIL);
		MMstore(m, tuple, 3, NIL);
		MMstore(m, tuple, 4, NIL);
		MMstore(m, tuple, 5, NIL);
		MMstore(m, tuple, 6, FTOM(AROUNDINT(dist*100.0f)));
	} 
	else
	{
		MMstore(m, tuple, 2, NIL);
		MMstore(m, tuple, 3, NIL);
		MMstore(m, tuple, 4, NIL);
		MMstore(m, tuple, 5, NIL);
		MMstore(m, tuple, 6, NIL);
	}

    MMset(m,0,PTOM(tuple));

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZMX3Render														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d ObjSurface H3d I I I] H3d
int ZMX3Render(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"MX3render ");
#endif

	/* Traitement des callbacks de rendu */
	PROCEED_RENDER_CALLBACK

   // Macro de rendu GLOBAL
	GLOBAL_RENDER_FILL(false)

	CLEAN_UNUSED_DATAS

	// Détermination de l'objet pointé par (x,y)
	int		width  = ((ZCamera*)node)->width  / 2;
	int		height = ((ZCamera*)node)->height / 2;
	int		result = NIL;
	float	dist = 0;

	if((x!=NIL)&&(y!=NIL))
	{
		int faceNb;
		//$BLG
		//ZObject*  obj = scene->Getinfo(MTOI(x)+width, height-MTOI(y), NULL, NULL, NULL, NULL, &faceNb, &dist);
		//if (obj != NULL)
		ZBLG_ObjSpr* objspr = scene->Getinfo(MTOI(x)+width, height-MTOI(y), NULL, NULL, NULL, NULL, &faceNb, &dist);
		if ((objspr->blg_objspr_obj != NULL) || (objspr->blg_objspr_spr))
		{
			//$BLG
			//result = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)obj);
			if (objspr->blg_objspr_obj != NULL) 
				result = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)objspr->blg_objspr_obj);
			else if (objspr->blg_objspr_spr != NULL) 
				result = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)objspr->blg_objspr_spr);
			if(result!=NIL)		result = PTOM(result);
		}
		//$BLG
		delete objspr;
	}



#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	MMset(m,0,result);

	return 0;
}


//////////////////////////////////////////////////////////////////////////////////////////////
///		ZMX3RenderM													
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d ObjSurface H3d I I I] [H3d HMat3d]
int ZMX3RenderM(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"MX3renderM ");
#endif

	/* Traitement des callbacks de rendu */
	PROCEED_RENDER_CALLBACK

	// Macro de rendu GLOBAL
	GLOBAL_RENDER_FILL(false)

	CLEAN_UNUSED_DATAS



	// Détermination de l'objet pointé par (x,y)
	int		width  = ((ZCamera*)node)->width  / 2;
	int		height = ((ZCamera*)node)->height / 2;
	int		result = NIL;
	int		mater  = NIL;
	float	dist = 0;

	if((x!=NIL)&&(y!=NIL))
	{
		int faceNb;
		//$BLG
		//ZObject*  obj = scene->Getinfo(MTOI(x)+width, height-MTOI(y), NULL, NULL, NULL, NULL, &faceNb, &dist);
		//if(obj!=NULL)
		ZBLG_ObjSpr* objspr = scene->Getinfo(MTOI(x)+width, height-MTOI(y), NULL, NULL, NULL, NULL, &faceNb, &dist);
		if ((objspr->blg_objspr_obj != NULL) || (objspr->blg_objspr_spr))
		{
			//$BLG
			//result = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)obj);
			//ZMaterial	*mat = obj->GetMesh()->Faces[faceNb].GetMaterial();
			ZMaterial* mat;
			if (objspr->blg_objspr_obj != NULL) 
			{
				result = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)objspr->blg_objspr_obj);
				mat = objspr->blg_objspr_obj->GetMesh()->Faces[faceNb].GetMaterial();
			}
			else if (objspr->blg_objspr_spr != NULL) 
			{
				result = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)objspr->blg_objspr_spr);
				mat = objspr->blg_objspr_spr->GetMaterial();
			}						
			if((mat!=NULL)&&(result!=NIL))
			{
				mater = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),2)), (int)mat);
				if(mater!=NIL)		mater = PTOM(mater);
			}
			if(result!=NIL)		result = PTOM(result);
		}
		//$BLG
		delete objspr;
	}

	// Pose le resultat sur la pile
	MMset(m, 0, mater);
	MMpush(m, result);
	int tuple = MMmalloc(m, 2, TYPETAB);
	if(tuple==NIL)				{	MMset(m,0,NIL);		return MERRMEM;		}
	MMstore(m, tuple, 0, MMpull(m) );
	MMstore(m, tuple, 1, MMget(m,0) );

    MMset(m,0,PTOM(tuple));

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZMX3wire
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d ObjSurface H3d I I I] [H3d HMat3d]
int ZMX3wire(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"MX3wire ");
#endif

	/* Traitement des callbacks de rendu */
	PROCEED_RENDER_CALLBACK

	// Macro de rendu GLOBAL
	GLOBAL_RENDER_FILL(true)

	CLEAN_UNUSED_DATAS



	// Détermination de l'objet pointé par (x,y)
	int		width  = ((ZCamera*)node)->width  / 2;
	int		height = ((ZCamera*)node)->height / 2;
	int		result = NIL;
	int		mater  = NIL;
	float	dist = 0;

	if((x!=NIL)&&(y!=NIL))
	{
		int faceNb;
		//$BLG
		//ZObject*  obj = scene->Getinfo(MTOI(x)+width, height-MTOI(y),NULL, NULL, NULL, NULL, &faceNb, &dist);
		//if(obj!=NULL)
		ZBLG_ObjSpr*  objspr = scene->Getinfo(MTOI(x)+width, height-MTOI(y),NULL, NULL, NULL, NULL, &faceNb, &dist);
		if ((objspr->blg_objspr_obj != NULL) || (objspr->blg_objspr_spr))
		{
			//$BLG
			//result = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)obj);
			//ZMaterial	*mat = obj->GetMesh()->Faces[faceNb].GetMaterial();
			ZMaterial* mat;
			if (objspr->blg_objspr_obj != NULL) 
			{
				result = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)objspr->blg_objspr_obj);
				mat = objspr->blg_objspr_obj->GetMesh()->Faces[faceNb].GetMaterial();
			}
			else if (objspr->blg_objspr_spr != NULL) 
			{
				result = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)objspr->blg_objspr_spr);
				mat = objspr->blg_objspr_spr->GetMaterial();
			}
			if((mat!=NULL)&&(result!=NIL))
			{
				mater = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),2)), (int)mat);
				if(mater!=NIL)		mater = PTOM(mater);
			}
			if(result!=NIL)		result = PTOM(result);
		}
		//$BLG
		delete objspr;
	}

	// Pose le resultat sur la pile
	MMset(m, 0, mater);
	MMpush(m, result);
	int tuple = MMmalloc(m, 2, TYPETAB);
	if(tuple==NIL)				{	MMset(m,0,NIL);		return MERRMEM;		}
	MMstore(m, tuple, 0, MMpull(m) );
	MMstore(m, tuple, 1, MMget(m,0) );

    MMset(m,0,PTOM(tuple));

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZMX3wirem
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d ObjSurface H3d I I I] [H3d HMat3d]
int ZMX3wirem(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"MX3wireM ");
#endif

	/* Traitement des callbacks de rendu */
	PROCEED_RENDER_CALLBACK

	// Macro de rendu GLOBAL
	GLOBAL_RENDER_FILL(true)

	CLEAN_UNUSED_DATAS



	// Détermination de l'objet pointé par (x,y)
	int		width  = ((ZCamera*)node)->width  / 2;
	int		height = ((ZCamera*)node)->height / 2;
	int		result = NIL;
	int		mater  = NIL;
	float	dist = 0;

	if((x!=NIL)&&(y!=NIL))
	{
		int faceNb;
		//$BLG
		//ZObject*  obj = scene->Getinfo(MTOI(x)+width, height-MTOI(y), NULL, NULL, NULL, NULL, &faceNb, &dist);
		//if(obj!=NULL)
		ZBLG_ObjSpr*  objspr = scene->Getinfo(MTOI(x)+width, height-MTOI(y), NULL, NULL, NULL, NULL, &faceNb, &dist);
		if ((objspr->blg_objspr_obj != NULL) || (objspr->blg_objspr_spr))
		{
			//$BLG
			//result = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)obj);
			//ZMaterial	*mat = obj->GetMesh()->Faces[faceNb].GetMaterial();
			ZMaterial* mat;
			if (objspr->blg_objspr_obj != NULL) 
			{
				result = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)objspr->blg_objspr_obj);
				mat = objspr->blg_objspr_obj->GetMesh()->Faces[faceNb].GetMaterial();
			}
			else if (objspr->blg_objspr_spr != NULL) 
			{
				result = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)objspr->blg_objspr_spr);
				mat = objspr->blg_objspr_spr->GetMaterial();
			}			
			if((mat!=NULL)&&(result!=NIL))
			{
				mater = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),2)), (int)mat);
				if(mater!=NIL)		mater = PTOM(mater);
			}
			if(result!=NIL)		result = PTOM(result);
		}
		//$BLG
		delete objspr;
	}

	// Pose le resultat sur la pile
	MMset(m, 0, mater);
	MMpush(m, result);
	int tuple = MMmalloc(m, 2, TYPETAB);
	if(tuple==NIL)				{	MMset(m,0,NIL);		return MERRMEM;		}
	MMstore(m, tuple, 0, MMpull(m) );
	MMstore(m, tuple, 1, MMget(m,0) );

    MMset(m,0,PTOM(tuple));

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}


//////////////////////////////////////////////////////////////////////////////////////////////
///		ZMX3wireOrtho
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d ObjSurface H3d I I I] [H3d HMat3d]
int ZMX3wireOrtho(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"MX3wireOrtho ");
#endif


	/* Traitement des callbacks de rendu */
	PROCEED_RENDER_CALLBACK

	int		fond, y, x, h3d, surf, s3d;												
	ZScene	*scene;																	
	ZNode	*node, *father;															

	/*/////////////////////////////////////////////////////////////////									
	///		RENDU HARD												///									
	/////////////////////////////////////////////////////////////////*/									
	if(userACCEL)
	{
		HDC		hdc;
		HGLRC	hglrc;

		fond = MMpull(m);
		y	 = MMpull(m);
		x	 = MMpull(m);
		h3d	 = MMpull(m);
		surf = MMpull(m);

		if(surf==NIL) 		{   MMset(m,0,NIL);		return 0;	}

		hdc		= (HDC)	  MMfetch(m,MTOP(surf),1);
		hglrc	= (HGLRC) MMfetch(m,MTOP(surf),2);

		if(wglGetCurrentContext()!=hglrc)
		{
			wglMakeCurrent(hdc,hglrc);
		}

		s3d = MMget(m,0);
		if((s3d==NIL)||(h3d==NIL))		{   MMset(m,0,NIL);		return 0;	}

		scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
		if(scene==NULL)					{   MMset(m,0,NIL);		return 0;	}

		// Couleur de Fond
		fond = MTOI(fond);
		float	r = 0;
		float	g = 0;
		float	b = 0;

		if(fond!=NIL)
		{
			r = ((fond)&255)	 / CONST_COLOR;
			g = ((fond>>8)&255)	 / CONST_COLOR;
			b = ((fond>>16)&255) / CONST_COLOR;
		}

		// Recupération de la camera
		node = (ZNode*) MMfetch(m,MTOP(h3d),0);
		if((node==NULL)||(node->type!=CAM_TYPE_ID))		{   MMset(m,0,NIL);		return 0;	}
		scene->SetActiveCam((ZCamera*)node);

		father = getBigFather(node);


		// Prépare la camera par précaution..
		ZMatrix		matx = ComputeWorldMatrix(node);
		((ZCamera*)node)->worldMat = matx;
		((ZCamera*)node)->worldPos.SetCoord(matx(0,3), matx(1,3), matx(2,3));
		
		
		// Rendu de la scene
		if(fond==NIL)		scene->Display(r,g,b, father, true, true, false);
		else				scene->Display(r,g,b, father, true, true, true);
	}
	/*/////////////////////////////////////////////////////////////////									
	///		RENDU SOFT												///									
	/////////////////////////////////////////////////////////////////*/									
	else																								
	{																									
		fond = MMpull(m);																			
		y	 = MMpull(m);																			
		x	 = MMpull(m);																			
		h3d	 = MMpull(m);																			
		surf = MMpull(m);																			
		s3d  = MMget(m,0);																			
																										
		if((surf==NIL)||(s3d==NIL)||(h3d==NIL))		{   MMset(m,0,NIL);		return 0;	}				
																										
		scene = (ZScene*) MMfetch(m,MTOP(s3d),0);												
		if(scene==NULL)								{   MMset(m,0,NIL);		return 0;	}				
																										
		RenderBuffer	buffer;																			
		if(fillRenderBuffer(m, &buffer, surf))			{   MMset(m,0,NIL);		return 0;	}			
																										
		/* Couleur de Fond */																			
		fond = MTOI(fond);																				
		float	r = 0;																					
		float	g = 0;																					
		float	b = 0;																					
																										
		if(fond!=NIL)																					
		{																								
			r = ((fond)&255)	 / CONST_COLOR;															
			g = ((fond>>8)&255)	 / CONST_COLOR;															
			b = ((fond>>16)&255) / CONST_COLOR;															
		}																								
																										
		/* Recupération de la camera */																	
		node = (ZNode*) MMfetch(m,MTOP(h3d),0);												
		if((node==NULL)||(node->type!=CAM_TYPE_ID))		{   MMset(m,0,NIL);		return 0;	}			
		scene->SetActiveCam((ZCamera*)node);															
																										
		father = getBigFather(node);															
																										
		/* Prépare la camera par précaution et aussi pour le calcul des subMatrices */					
		ZMatrix		matx = ComputeWorldMatrix(node);													
		((ZCamera*)node)->worldMat = matx;																
		((ZCamera*)node)->worldPos.SetCoord(matx(0,3), matx(1,3), matx(2,3));							

		/* Rendu de la scene */																			
		if(fond==NIL)		scene->DisplaySOFT(&buffer, r, g, b, father, true, true, false);
		else				scene->DisplaySOFT(&buffer, r, g, b, father, true, true, true);
	}


	CLEAN_UNUSED_DATAS


	// Détermination de l'objet pointé par (x,y)
	int		width  = ((ZCamera*)node)->width  / 2;
	int		height = ((ZCamera*)node)->height / 2;

	int		result = NIL;
	int		mater  = NIL;
	float	dist = 0;
	if((x!=NIL)&&(y!=NIL))
	{
		int faceNb;
		//$BLG
		//ZObject*  obj = scene->Getinfo(MTOI(x)+width, height-MTOI(y), NULL, NULL, NULL, NULL, &faceNb, &dist);
		//if(obj!=NULL)
		ZBLG_ObjSpr* objspr = scene->Getinfo(MTOI(x)+width, height-MTOI(y), NULL, NULL, NULL, NULL, &faceNb, &dist);
		if ((objspr->blg_objspr_obj != NULL) || (objspr->blg_objspr_spr))
		{
			//$BLG
			//result = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)obj);
			//ZMaterial	*mat = obj->GetMesh()->Faces[faceNb].GetMaterial();
			ZMaterial* mat;
			if (objspr->blg_objspr_obj != NULL) 
			{
				result = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)objspr->blg_objspr_obj);
				mat = objspr->blg_objspr_obj->GetMesh()->Faces[faceNb].GetMaterial();
			}
			else if (objspr->blg_objspr_spr != NULL) 
			{
				result = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)objspr->blg_objspr_spr);
				mat = objspr->blg_objspr_spr->GetMaterial();
			}			
			if((mat!=NULL)&&(result!=NIL))
			{
				mater = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),2)), (int)mat);
				if(mater!=NIL)		mater = PTOM(mater);
			}
			if(result!=NIL)		result = PTOM(result);
		}
		//$BLG
		delete objspr;
	}

	// Pose le resultat sur la pile
	MMset(m, 0, mater);
	MMpush(m, result);
	int tuple = MMmalloc(m, 2, TYPETAB);
	if(tuple==NIL)				{	MMset(m,0,NIL);		return MERRMEM;		}
	MMstore(m, tuple, 0, MMpull(m) );
	MMstore(m, tuple, 1, MMget(m,0) );

    MMset(m,0,PTOM(tuple));

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}


//////////////////////////////////////////////////////////////////////////////////////////////
///		ZMX3RenderInfo
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d I I] [H3d HMat3d I I I]
int ZMX3RenderInfo(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"MX3renderInfo ");
#endif

	int y	 = MMpull(m);
	int x	 = MMpull(m);
	int h3d	 = MMpull(m);
	int s3d	 = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL)||(x==NIL)||(y==NIL))		{   MMset(m,0,NIL);		return 0;	}
	ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{   MMset(m,0,NIL);		return 0;	}

	// Recupération de la camera
	ZNodeGraph	*node = (ZNodeGraph*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=CAM_TYPE_ID))		{   MMset(m,0,NIL);		return 0;	}
	scene->SetActiveCam((ZCamera*)node);

	// Prépare la camera par précaution..
	ZMatrix		matx = ComputeWorldMatrix(node);
	((ZCamera*)node)->worldMat = matx;
	((ZCamera*)node)->worldPos.SetCoord(matx(0,3), matx(1,3), matx(2,3));
	((ZCamera*)node)->ComputeMatrix();

	// Prépare la scène qui peut avoir changé
	ZNodeGraph	*father = (ZNodeGraph*) getBigFather(node);

	scene->World->createNodeLists(father);

	scene->World->ComputeMatrices(node, father, IdentityMatrix(), 1.0f, true);
	scene->World->TransformVertices();


	// Détermination de l'objet pointé par (x,y)
	int		width  = ((ZCamera*)node)->width / 2;
	int		height = ((ZCamera*)node)->height / 2;
	int		result = NIL;
	int		mater  = NIL;
	float	u = 0, v = 0, z = 0, dist = 0;
	//$BLG
	int typ;

	if((x!=NIL)&&(y!=NIL))
	{
		int faceNb;
		//$BLG
		//ZObject*  obj = scene->Getinfo(MTOI(x)+width, height-MTOI(y), &u, &v, &z, NULL, &faceNb, &dist);
		//if(obj!=NULL)
		ZBLG_ObjSpr*  objspr = scene->Getinfo(MTOI(x)+width, height-MTOI(y), &u, &v, &z, NULL, &faceNb, &dist);
		if ((objspr->blg_objspr_obj != NULL) || (objspr->blg_objspr_spr))
		{
			//$BLG
			//result = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)obj);
			//ZMaterial	*mat = obj->GetMesh()->Faces[faceNb].GetMaterial();
			ZMaterial* mat;
			if (objspr->blg_objspr_obj != NULL) 
			{
				typ = OBJ_TYPE_ID;
				result = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)objspr->blg_objspr_obj);
				mat = objspr->blg_objspr_obj->GetMesh()->Faces[faceNb].GetMaterial();
			}
			else if (objspr->blg_objspr_spr != NULL) 
			{
				typ = SPR_TYPE_ID;
				result = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)objspr->blg_objspr_spr);
				mat = objspr->blg_objspr_spr->GetMaterial();
			}			
			if((mat!=NULL)&&(result!=NIL))
			{
				mater = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),2)), (int)mat);
				if(mater!=NIL)		mater = PTOM(mater);
			}
			if(result!=NIL)		result = PTOM(result);
		}
		//$BLG
		delete objspr;
	}



	// Pose le resultat sur la pile
	MMset(m,0,mater);
	MMpush(m,result);

	int tuple = MMmalloc(m, 5, TYPETAB);
	if(tuple==NIL)				{	MMset(m,0,NIL);		return MERRMEM;		}
	MMstore(m, tuple, 0, MMpull(m));
	MMstore(m, tuple, 1, MMget(m,0));
  //$BLG
	//if(mater!=NIL)
	if ((mater != NIL) && (typ == OBJ_TYPE_ID))
	{
		MMstore(m, tuple, 2, ITOM(AROUNDINT(u*CONST_TEX_COORD)));
		MMstore(m, tuple, 3, ITOM(AROUNDINT(v*CONST_TEX_COORD)));
		MMstore(m, tuple, 4, ITOM(AROUNDINT(-z*100.0f)));
	}
	else
	{
		MMstore(m, tuple, 2, NIL);
		MMstore(m, tuple, 3, NIL);
		MMstore(m, tuple, 4, NIL);
	}

    MMset(m,0,PTOM(tuple));

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}


//////////////////////////////////////////////////////////////////////////////////////////////
///		ZMX3RenderInfoF
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d I I] [H3d HMat3d F F F]
int ZMX3RenderInfoF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"MX3renderInfoF ");
#endif

	int y	 = MMpull(m);
	int x	 = MMpull(m);
	int h3d	 = MMpull(m);
	int s3d	 = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL)||(x==NIL)||(y==NIL))		{   MMset(m,0,NIL);		return 0;	}
	ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{   MMset(m,0,NIL);		return 0;	}

	// Recupération de la camera
	ZNodeGraph	*node = (ZNodeGraph*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=CAM_TYPE_ID))		{   MMset(m,0,NIL);		return 0;	}
	scene->SetActiveCam((ZCamera*)node);

	// Prépare la camera par précaution..
	ZMatrix		matx = ComputeWorldMatrix(node);
	((ZCamera*)node)->worldMat = matx;
	((ZCamera*)node)->worldPos.SetCoord(matx(0,3), matx(1,3), matx(2,3));
	((ZCamera*)node)->ComputeMatrix();

	// Prépare la scène qui peut avoir changé
	ZNodeGraph	*father = (ZNodeGraph*) getBigFather(node);

	scene->World->createNodeLists(father);

	scene->World->ComputeMatrices(node, father, IdentityMatrix(), 1.0f, true);
	scene->World->TransformVertices();


	// Détermination de l'objet pointé par (x,y)
	int		width  = ((ZCamera*)node)->width / 2;
	int		height = ((ZCamera*)node)->height / 2;
	int		result = NIL;
	int		mater  = NIL;
	float	u = 0, v = 0, z = 0, dist = 0;
	//$BLG
	int typ;

	if((x!=NIL)&&(y!=NIL))
	{
		int faceNb;
		//$BLG
		//ZObject*  obj = scene->Getinfo(MTOI(x)+width, height-MTOI(y), &u, &v, &z, NULL, &faceNb, &dist);
		//if(obj!=NULL)
		ZBLG_ObjSpr* objspr = scene->Getinfo(MTOI(x)+width, height-MTOI(y), &u, &v, &z, NULL, &faceNb, &dist);
		if ((objspr->blg_objspr_obj != NULL) || (objspr->blg_objspr_spr))
		{
			//$BLG
			//result = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)obj);
			//ZMaterial	*mat = obj->GetMesh()->Faces[faceNb].GetMaterial();
			ZMaterial* mat;
			if (objspr->blg_objspr_obj != NULL) 
			{
				typ = OBJ_TYPE_ID;
				result = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)objspr->blg_objspr_obj);
				mat = objspr->blg_objspr_obj->GetMesh()->Faces[faceNb].GetMaterial();
			}
			else if (objspr->blg_objspr_spr != NULL) 
			{
				typ = SPR_TYPE_ID;
				result = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)objspr->blg_objspr_spr);
				mat = objspr->blg_objspr_spr->GetMaterial();
			}			
			if((mat!=NULL)&&(result!=NIL))
			{
				mater = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),2)), (int)mat);
				if(mater!=NIL)		mater = PTOM(mater);
			}
			if(result!=NIL)		result = PTOM(result);
		}
		//$BLG
		delete objspr;
	}

	// Pose le resultat sur la pile
	MMset(m,0,mater);
	MMpush(m,result);

	int tuple = MMmalloc(m, 5, TYPETAB);
	if(tuple==NIL)				{	MMset(m,0,NIL);		return MERRMEM;		}
	MMstore(m, tuple, 0, MMpull(m));
	MMstore(m, tuple, 1, MMget(m,0));
	//$BLG
	//if(mater!=NIL)
	if ((mater != NIL) && (typ == OBJ_TYPE_ID))
	{
		MMstore(m, tuple, 2, FTOM(u));
		MMstore(m, tuple, 3, FTOM(v));
		MMstore(m, tuple, 4, FTOM(-z*100.0f));
	}
	else
	{
		MMstore(m, tuple, 2, NIL);
		MMstore(m, tuple, 3, NIL);
		MMstore(m, tuple, 4, NIL);
	}

    MMset(m,0,PTOM(tuple));

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//$BLG
//Check Power Of Two
//Removed 16 and 32 dimensions as OpenGL 1.4 ensures only 64 dimension and above
int Check_POT_from_64_up_to_1024(int n)
{
	if ((n == 64) || (n == 128) || (n == 256) || (n == 512) || (n == 1024))
	  return 1;
	else
	  return 0;
}


//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3blitTexture
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d HTx3d ObjBitmap8] I
int ZM3blitTexture(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3blitTexture ");
#endif

	int bitm = MMpull(m);
	int text = MMpull(m);
	int s3d	 = MMget(m,0);

	if((s3d==NIL)||(text==NIL)||(bitm==NIL))		{   MMset(m,0,NIL);		return 0;	}
	ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)									{   MMset(m,0,NIL);		return 0;	}

    ZTexture	*tex = (ZTexture*) MMfetch(m,MTOP(text),0);
	if(tex==NULL)									{	MMset(m,0,NIL);		return 0;	}


	// Récupère l'ObjBitmap et ses données
	PtrObjVoid		OB;
	PtrObjBitmap	B;

	if(bitm==NIL)								{	MMset(m,0,NIL);		return 0;	}
    OB = (PtrObjVoid) MMstart(m,MTOP(bitm));
    if(OB->Type != OBJ_TYPE_BITMAP<< 1)			{	MMset(m,0,NIL);		return 0;	}
    B = (PtrObjBitmap) MMstart(m,MTOP(OB->Buffer));



	char*		buf = (char*) B->bits;								// BUFFER

	RGBQUAD		Pal[256];												// PALETTE

	HDC			dc = CreateCompatibleDC(NULL);
    HBITMAP		OldBitmap = (HBITMAP) SelectObject(dc, B->DIBhandler);
    GetDIBColorTable(dc, 0, 256, Pal);
    SelectObject(dc, OldBitmap);
    DeleteDC(dc);

	// Couleur de transparence
	tex->C = tex->X = tex->Y = tex->R = tex->S = false;
	tex->A = true;

	tex->SetTranspR( Pal[0].rgbRed   );
	tex->SetTranspG( Pal[0].rgbGreen );
	tex->SetTranspB( Pal[0].rgbBlue  );

	// Prépare la texture
	if( (tex->Width != B->TailleW) || (tex->Height != B->TailleH) )
	{
		tex->Width  = B->TailleW;
		tex->Height = B->TailleH;
		if (tex->ImageModif!=NULL)			free(tex->ImageModif);
		tex->ImageModif	= (unsigned char *) malloc(tex->Width * tex->Height * 4);

		// Copie de la bitmap
		unsigned short	color;
		int				x, y, posii=0;
		for(y=0; y<tex->Height; y++)
		{
			for(x=0; x<tex->Width; x++)
			{
				color = buf[(tex->Height-y-1)*tex->Width + x]&255;
				tex->ImageModif[posii+0] = Pal[color].rgbRed;
				tex->ImageModif[posii+1] = Pal[color].rgbGreen;
				tex->ImageModif[posii+2] = Pal[color].rgbBlue;

				if( color )		tex->ImageModif[posii+3] = 255;
				else			tex->ImageModif[posii+3] = 0;

				posii += 4;
			}
		}

		tex->activated = true;
		tex->renamed   = false;			// becoz we have used the NEW flags of rendering

		if(scene->accelerated)
		{
			if(tex->ID_created==false)		{	glGenTextures(1, &(tex->texID));	tex->ID_created = true;	}
			glBindTexture(GL_TEXTURE_2D, tex->texID);

			if( tex->filter==TF_NONE )
			{
				glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
				glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
			}
			else if(tex->filter == TF_LINEAR)
			{
				glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
				glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
			}
			else if(tex->filter == TF_BILINEAR)
			{
				glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
				glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
			}
			else if(tex->filter == TF_TRILINEAR)
			{
				glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
				glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
			}

			glTexImage2D(GL_TEXTURE_2D, 0, 4, tex->Width, tex->Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, tex->ImageModif );
			if( tex->filter!=TF_NONE )			gluBuild2DMipmaps( GL_TEXTURE_2D, 4, tex->Width, tex->Height, GL_RGBA, GL_UNSIGNED_BYTE, tex->ImageModif );

			free(tex->ImageModif);		tex->ImageModif=NULL;
		}
		else
		{
			tex->StretchImageModif();
			tex->SetupTexture();
		}
	}
	else
	{
		if(tex->ImageModif!=NULL)			free(tex->ImageModif);
		tex->ImageModif	= (unsigned char *) malloc(tex->Width * tex->Height * 4);

		// Copie de la bitmap
		unsigned short	color;
		int				x, y, posii=0;
		for(y=0; y<tex->Height; y++)
		{
			for(x=0; x<tex->Width; x++)
			{
				color = buf[(tex->Height-y-1)*tex->Width + x]&255;
				tex->ImageModif[posii+0] = Pal[color].rgbRed;
				tex->ImageModif[posii+1] = Pal[color].rgbGreen;
				tex->ImageModif[posii+2] = Pal[color].rgbBlue;

				if( color )		tex->ImageModif[posii+3] = 255;
				else			tex->ImageModif[posii+3] = 0;

				posii += 4;
			}
		}

		tex->activated = true;
		tex->renamed   = false;			// becoz we have used the NEW flags of rendering

		if(scene->accelerated)
		{
			//$BLG
			//if( (tex->Width!=16 && tex->Width!=32 && tex->Width!=64 && tex->Width!=128 && tex->Width!=256 && tex->Width!=512 && tex->Width!=1024) ||
		  //(tex->Height!=16 && tex->Height!=32 && tex->Height!=64 && tex->Height!=128 && tex->Height!=256 && tex->Height!=512 && tex->Height!=1024)	)		tex->StretchImageModif();
		  //Note: Dimensions below 64 have been removed to ensure OpenGL 1.4 specifications
		  if (!Check_POT_from_64_up_to_1024(tex->Width) || !Check_POT_from_64_up_to_1024(tex->Height))  tex->StretchImageModif();

			if(tex->ID_created==false)		{	glGenTextures(1, &(tex->texID));	tex->ID_created = true;	}
			glBindTexture(GL_TEXTURE_2D, tex->texID);

			if( tex->filter==TF_NONE )
			{
				glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
				glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
			}
			else if(tex->filter == TF_LINEAR)
			{
				glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
				glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
			}
			else if(tex->filter == TF_BILINEAR)
			{
				glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
				glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
			}
			else if(tex->filter == TF_TRILINEAR)
			{
				glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
				glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
			}

			glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tex->Width, tex->Height, GL_RGBA, GL_UNSIGNED_BYTE, tex->ImageModif);
			if(tex->filter!=TF_NONE)			gluBuild2DMipmaps( GL_TEXTURE_2D, 4, tex->Width, tex->Height, GL_RGBA, GL_UNSIGNED_BYTE, tex->ImageModif );

			free(tex->ImageModif);		tex->ImageModif=NULL;
		}
		else
		{
			tex->StretchImageModif();
			tex->SetupTexture();
		}
		
	}

	scene->textureModified = true;

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	MMset(m,0,0);
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3blitTexture16
//////////////////////////////////////////////////////////////////////////////////////////////
//$BLG
//First code translation was only partial. It was called, in ZM3blitTexture16, by:
//BLG_CopyBGRandA_to_RGBA(buf + offset, tex->ImageModif + posii, colTransp);
//The params were named isrcoffset, idstoffset and itransp
//The code involved is still present in the next code translation. It comprised the most rigth aligned code lines.
void BLG_CopyBGRandA_to_RGBA(unsigned char *src, int i_srcoffset, unsigned char *dst, int i_dstoffset, int i_x, int i_xmax, int i_xinc, int i_y, int i_ymax, int i_transp)
{
	// C code translation - not optimized
	/*
	__asm
	{
		//Saving registries
		push eax
		push ebx
		push ecx
		push edx
		//Initializing Y loop
		mov i_y, 0
		NEWYL:
		  //Initializing X loop
		  mov i_x, 0
		  NEWXL:
		    //Computing 'offset' variable: (ymax-1-y)*xinc + x*3
		    //(ymax-1-y)*xinc
		    mov eax, i_ymax
		    dec eax
		    sub eax, i_y
		    mul i_xinc
		    mov i_srcoffset, eax
		    //x*3
		    mov ebx, 3
		    mov eax, i_x
		    mul ebx
		    //sum
		    add i_srcoffset, eax  //edx:eax
					//Reading BGR color components
					mov eax, src
					add eax, i_srcoffset
					mov cl, [eax]       //B
					and cx, 0x00ff
					inc eax
					mov bh, [eax]       //G
					inc eax
					mov bl, [eax]       //R
					//Writting RGB color components
					mov ax, cx          //B_
					shl eax, 16
					or  ax, bx          //RG
					//Including transparency
					mov ebx, i_transp    //Setting transparency color in RGB_ format
					shl ebx, 8
					cmp eax, ebx       //Is our current color the same as transparency color ?
					jnz NO
					jmp YES
					NO:                //If not, we put the transparency value to 255
					//mov al, 0xff
					or  eax, 0xff000000
					YES:               //if it is, we let this value set to zero as before and don't do nothing except continuing
					//Transfering data src->dst
					mov ebx, dst
					add ebx, i_dstoffset
					mov [ebx], eax
				//Incrementing X & Posii counters and testing end of X loop
				add i_dstoffset, 4
				inc i_x
				mov edx, i_xmax
				cmp edx, i_x
				jz  NXTYL
				jmp NEWXL
		  //Incrementing Y counter and testing end of Y loop
		  NXTYL:
		  inc i_y
		  mov edx, i_ymax
		  cmp edx, i_y
		  jz  RSTOR
		  jmp NEWYL
		//Restoring registries
		RSTOR:
		pop edx
		pop ecx
		pop ebx
		pop eax
	}
	*/
	// C code optimization 1
	/*
	__asm
	{
		//Saving needful registries
		push eax
		push ebx
		//push ecx     // We need only 3 data registries, and eax & edx are necessary
		push edx
		//Initializing Y loop
		mov i_y, 0
		NEWYL:
		  //Computing 'offset' variable: (ymax-1-y)*xinc + x*3          Step 1
		  //(ymax-1-y)*xinc
		  mov eax, i_ymax
		  dec eax
		  sub eax, i_y
		  mul i_xinc
		  mov i_srcoffset, eax
		  //Initializing X loop
		  mov i_x, 0
		  NEWXL:
		    //Computing 'offset' variable: (ymax-1-y)*xinc + x*3         Step 2
		    //x*3
		    mov ebx, 3
		    mov eax, i_x
		    mul ebx              //edx:eax
		    //Computing 'offset' variable: (ymax-1-y)*xinc + x*3         Step 3
		    //sum
		    add eax, i_srcoffset
					//Reading BGR color components
					add eax, src       //eax = src+computed_offset
					mov dl, [eax]      //B
					and dx, 0x00ff
					inc eax
					mov bh, [eax]      //G
					inc eax
					mov bl, [eax]      //R
					//Writting RGB color components
					mov ax, dx         //B_
					shl eax, 16
					or  ax, bx         //RG
					//Including transparency
					mov ebx, i_transp   //Setting transparency color in RGB_ format
					shl ebx, 8
					cmp eax, ebx       //Is our current color the same as transparency color ?
					jnz NO
					jmp YES
					NO:                //If not, we put the transparency value to 255
					//mov al, 0xff
					or  eax, 0xff000000
					YES:               //if it is, we let this value set to zero as before and don't do nothing except continuing
					//Transfering data src->dst
					mov ebx, dst
					mov [ebx], eax
				//Incrementing X & dst ptr, and testing end of X loop
				add dst, 4
				inc i_x
				mov edx, i_xmax
				cmp edx, i_x
				jz  NXTYL
				jmp NEWXL
		  //Incrementing Y counter and testing end of Y loop
		  NXTYL:
		  inc i_y
		  mov edx, i_ymax
		  cmp edx, i_y
		  jz  RSTOR
		  jmp NEWYL
		//Restoring registries
		RSTOR:
		pop edx
		//pop ecx
		pop ebx
		pop eax
	}
	*/
  // C code optimization 2
  /*
	__asm
	{
		//Saving needful registries
		push eax
		push ebx
		push ecx
		push edx
		//Initializing Y loop
		mov i_y, 1      // Initialyzing i_y to 1 instead of 0 allow us to spare a 'dec eax' code line in 'offset' computing
		mov ecx, i_ymax
		NEWYL:
		  //Storing y loop counter to avoid conflict with x loop counter
		  push ecx
		  //Computing 'offset' variable: (ymax-1-y)*xinc + x*3          Step 1
		  //(ymax-1-y)*xinc
		  mov eax, i_ymax
		  //dec eax
		  sub eax, i_y
		  mul i_xinc
		  mov i_srcoffset, eax
		  //Initializing X loop
		  mov i_x, 0
		  mov ecx, i_xmax
		  NEWXL:
		    //Computing 'offset' variable: (ymax-1-y)*xinc + x*3         Step 2
		    //x*3
		    mov ebx, 3
		    mov eax, i_x
		    mul ebx              //edx:eax
		    //Computing 'offset' variable: (ymax-1-y)*xinc + x*3         Step 3
		    //sum
		    add eax, i_srcoffset
					//Reading BGR color components
					add eax, src       //eax = src+computed_offset
					mov dl, [eax]      //B
					and dx, 0x00ff
					inc eax
					mov bh, [eax]      //G
					inc eax
					mov bl, [eax]      //R
					//Writting RGB color components
					mov ax, dx         //B_
					shl eax, 16
					or  ax, bx         //RG
					//Including transparency
					mov ebx, i_transp   //Setting transparency color in RGB_ format
					shl ebx, 8
					cmp eax, ebx       //Is our current color the same as transparency color ?
					jnz NO
					jmp YES
					NO:                //If not, we put the transparency value to 255
					//mov al, 0xff
					or  eax, 0xff000000
					YES:               //Continuing, transparency is now set to 0 (default) or 255
					//Transfering data src->dst
					mov ebx, dst
					mov [ebx], eax
				//Incrementing X & dst ptr, and testing end of X loop
				add dst, 4
				inc i_x
				loop NEWXL
		  //Incrementing Y counter and testing end of Y loop
		  inc i_y
		  pop ecx
		  loop NEWYL
		//Restoring used registries
		pop edx
		pop ecx
		pop ebx
		pop eax
	}	
	*/
  // C code optimization 3
	__asm
	{
		//Saving needful registries
		push eax
		push ebx
		push ecx
		push edx
		//Initializing Y loop
		mov ecx, i_ymax
		NEWYL:
		  //Storing y loop counter to avoid conflict with x loop counter
		  push ecx
		  //Computing 'offset' variable: (ymax-1-y)*xinc + x*3          Step 1
		  //(ymax-1-y)*xinc
		  mov eax, i_ymax
		   dec eax
		   mov i_ymax, eax            // i_ymax is used as a permanent decreasing counter (it is no more useful as a reference value and thus replaces the former i_y variable). Applying dec to the registry is faster than to the variable
		  mul i_xinc
		  mov i_srcoffset, eax
		  //Initializing X loop
		  mov i_x, 0
		  mov ecx, i_xmax
		  NEWXL:
		    //Computing 'offset' variable: (ymax-1-y)*xinc + x*3         Step 2
		    //x*3
		    //This is replaced by increasing i_x by steps of 3
		    mov eax, i_x
		    //Computing 'offset' variable: (ymax-1-y)*xinc + x*3         Step 3
		    //sum
		    add eax, i_srcoffset
					//Reading BGR color components
					add eax, src       //eax = src+computed_offset
					mov dl, [eax]      //B
					and dx, 0x00ff
					inc eax
					mov bh, [eax]      //G
					inc eax
					mov bl, [eax]      //R
					//Writting RGB color components
					mov ax, dx         //B_
					shl eax, 16
					or  ax, bx         //RG
					//Including transparency
					mov ebx, i_transp   //Setting transparency color in RGB_ format
					shl ebx, 8
					cmp eax, ebx       //Is our current color the same as transparency color ?
					jnz NO
					jmp YES
					NO:                //If not, we put the transparency value to 255
					//mov al, 0xff
					or  eax, 0xff000000
					YES:               //Continuing, transparency is now set to 0 (default) or 255
					//Transfering data src->dst
					mov ebx, dst
					mov [ebx], eax
				//Incrementing X & dst ptr, and testing end of X loop
			  add dst, 4
				add i_x, 3
				loop NEWXL
		  //Testing end of Y loop
		  pop ecx
		  loop NEWYL
		//Restoring used registries
		pop edx
		pop ecx
		pop ebx
		pop eax
	}	
}

// fun [S3d HTx3d ObjBitmap] I
int ZM3blitTexture16(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"\nM3blitTexture16 ");
#endif


	//$LB
	int updateNeeded = 0;

	int bitm = MMpull(m);
	int text = MMpull(m);
	int s3d	 = MMget(m,0);

	if((s3d==NIL)||(text==NIL)||(bitm==NIL))		{ MMset(m,0,NIL);	return 0;	}

	ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)									{ MMset(m,0,NIL);	return 0;	}

    ZTexture	*tex = (ZTexture*) MMfetch(m,MTOP(text),0);
	if(tex==NULL)									{	MMset(m,0,NIL);	return 0;	}

	// Récupère l'ObjBitmap et ses données
	PtrObjVoid		OB;
	PtrObjBitmap	B;



  OB = (PtrObjVoid) MMstart(m,MTOP(bitm));
  if(OB->Type != OBJ_TYPE_BITMAP<< 1)			{	MMset(m,0,NIL);	return 0;	}
  B = (PtrObjBitmap) MMstart(m,MTOP(OB->Buffer));

  if(B==NULL) {	MMset(m,0,NIL);	return 0;	}


	OBJBITMAP_BUFFER		buf = (OBJBITMAP_BUFFER) B->bits;								// BUFFER


	//Prépare la texture
	//$LB & $BLG
	if( (tex->Width != B->TailleW) || (tex->Height != B->TailleH) )
	{
		updateNeeded = 1;
		tex->Width  = B->TailleW;
		tex->Height = B->TailleH;
	}

	if(tex->ImageModif!=NULL)	 free(tex->ImageModif);
	tex->ImageModif	= (unsigned char *) malloc(tex->Width * tex->Height * 4);

	int		incremX;

	//$LB (10/12/2003) : windows 24 bits bitmaps are 32 bits aligned 
	//$BLG - Modif - Fix
	/*
	if (tex->Width &0x01) incremX = tex->Width*3 + 3;
	else                  incremX = tex->Width*3;
	if (incremX % 4) incremX += (incremX % 4);
	*/
	if (tex->Width*3 % 4) 
	  incremX = tex->Width*3 + 4 - (tex->Width*3 % 4);
	else
	  incremX = tex->Width*3;

	// Copie de la bitmap
	//$BLG - del - removed for first optimization
	//int	color;
	//$BLG - add - added for second optimization, removed in third one
	//unsigned char alpha;
	//$BLG - del - removed for first optimization, intermediary variables
	//unsigned char cr, cg, cb;
	//$BLG - Modif - third optimization
	//int	x, y, posii=0;
	int	x=0, y=0, posii=0, offset=0;
 
	// -----> on utilise la couleur de transparence d'origine
	int	colTransp = tex->GetTranspB() | (tex->GetTranspG() <<8) | (tex->GetTranspR() <<16);
	//$BLG - del - third optimization
	//int	offset;

  //$BLG - Fourth optimization - Whole next part is replaced by an assembler function
  BLG_CopyBGRandA_to_RGBA(buf, offset, tex->ImageModif, posii, x, tex->Width, incremX, y, tex->Height, colTransp);
  /*
			for(y=0; y<tex->Height; y++)
			{
				for(x=0; x<tex->Width; x++)
				{
					//$LB
					offset = (tex->Height-1-y)*incremX + x*3;					

					//$BLG - del - original code
					//cb = buf[offset+0]; cg = buf[offset+1]; cr = buf[offset+2]; 
					//tex->ImageModif[posii+0] = cr;
					//tex->ImageModif[posii+1] = cg;
					//tex->ImageModif[posii+2] = cb;	
					//color = ((cb<<16) &0xFF0000)  |  ((cg<<8) &0xFF00)  |  (cr &0xFF);
					//$BLG - first optimization
					//tex->ImageModif[posii+0] = buf[offset+2];
					//tex->ImageModif[posii+1] = buf[offset+1];
					//tex->ImageModif[posii+2] = buf[offset+0];
					//$BLG - del - original code
					//color = ((buf[offset+0]<<16) &0xFF0000)  |  ((buf[offset+1]<<8) &0xFF00)  |  (buf[offset+2] &0xFF);
					//if( color == colTransp )
					//{
					//	tex->ImageModif[posii+3] = 0;
					//}
					//else
					//	tex->ImageModif[posii+3] = 255;
          //$BLG - first optimization
          //tex->ImageModif[posii+3] = (((buf[offset+0]<<16) &0xFF0000)  |  ((buf[offset+1]<<8) &0xFF00)  |  (buf[offset+2] &0xFF) == colTransp) * 255;
          //$BLG - second optimization
          //alpha = (((buf[offset+0]<<16) &0xFF0000)  |  ((buf[offset+1]<<8) &0xFF00)  |  (buf[offset+2] &0xFF) == colTransp) * 255;
          BLG_CopyBGRandA_to_RGBA(buf + offset, tex->ImageModif + posii, colTransp);
          //MMechostr(0,"SRC: %d %d %d %d DST: %d %d %d %d \n",buf[offset+0],buf[offset+1],buf[offset+2],colTransp,tex->ImageModif[posii+0],tex->ImageModif[posii+1],tex->ImageModif[posii+2],tex->ImageModif[posii+3]);
          
					posii += 4;
				}
			}
  */

		tex->activated = true;
		tex->renamed = false;			// becoz we have used the NEW flags of rendering

		if(scene->accelerated)
		{
			//$LB
			if (updateNeeded)
			  //$BLG - Removed dimensions below 64. 64 is an OpenGL 1.4 specification
			  //if( (tex->Width!=2 && tex->Width!=4 && tex->Width!=8 && tex->Width!=16 && tex->Width!=32 && tex->Width!=64 && tex->Width!=128 && tex->Width!=256 && tex->Width!=512 && tex->Width!=1024) ||
				  //(tex->Height!=2 && tex->Height!=4 && tex->Height!=8 && tex->Height!=16 && tex->Height!=32 && tex->Height!=64 && tex->Height!=128 && tex->Height!=256 && tex->Height!=512 && tex->Height!=1024)	)		tex->StretchImageModif();
				if ( (tex->Width!=64 && tex->Width!=128 && tex->Width!=256 && tex->Width!=512 && tex->Width!=1024) ||
				     (tex->Height!=64 && tex->Height!=128 && tex->Height!=256 && tex->Height!=512 && tex->Height!=1024)	)		tex->StretchImageModif();

			if(tex->ID_created==false)		{	glGenTextures(1, &(tex->texID));	tex->ID_created = true;	}
			glBindTexture(GL_TEXTURE_2D, tex->texID);

			if( tex->filter==TF_NONE )
			{
				glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
				glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
			}
			else if(tex->filter == TF_LINEAR)
			{
				glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
				glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
			}
			else if(tex->filter == TF_BILINEAR)
			{
				glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
				glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
			}
			else if(tex->filter == TF_TRILINEAR)
			{
				glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
				glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
			}

			//$LB
			/*
			if (updateNeeded)
				glTexImage2D(GL_TEXTURE_2D, 0, 4, tex->Width, tex->Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, tex->ImageModif );
			else 
				glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tex->Width, tex->Height, GL_RGBA, GL_UNSIGNED_BYTE, tex->ImageModif);
			*/
			//$BLG v4.6a4: Not understanding the above difference as we copy the whole picture for both cases.
			glTexImage2D(GL_TEXTURE_2D, 0, 4, tex->Width, tex->Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, tex->ImageModif);

			if(tex->filter != TF_NONE)			gluBuild2DMipmaps( GL_TEXTURE_2D, 4, tex->Width, tex->Height, GL_RGBA, GL_UNSIGNED_BYTE, tex->ImageModif );

			free(tex->ImageModif);		tex->ImageModif=NULL;
		}
		else
		{
			tex->StretchImageModif();
			tex->SetupTexture();			
		}

	scene->textureModified = true;

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif



	MMset(m,0,0);
	return 0;
}




//$BLG
//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3blitSurface2Texture16
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d HTx3d ObjBitmap] I
int ZM3blitSurface2Texture16(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"\nM3blitSurface2Texture16 ");
#endif

  if (userACCEL)
  {
//$BLG: Tracking the reason of the weight of this function.
// Sample scene: 36FPS
// Sample scene with call to this function: 25FPS
// Base code cost:    4 FPS
// glReadPixels cost: 6 FPS
// glTexImage2D cost: 2 FPS
/*
DWORD t0, t1;
MMechostr(0,"DEBUG\n");
t0 = GetTickCount();
*/

	  int updateNeeded = 0;

    unsigned char	*buffer;
    RECT	rect; 
    HWND	hwnd;
    int w,h;

	  int surf = MMpull(m);
	  int text = MMpull(m);
    int s3d	 = MMget(m,0);

	  if((s3d==NIL) || (text==NIL) || (surf==NIL))		{ MMset(m,0,NIL);	return 0;	}
	
	  ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	  if (scene==NULL)									{ MMset(m,0,NIL);	return 0;	}

    ZTexture	*tex = (ZTexture*) MMfetch(m,MTOP(text),0);
	  if (tex==NULL)									{ MMset(m,0,NIL);	return 0;	}
/*
t1 = GetTickCount() - t0;
MMechostr(0,"Params: %d\n", t1);
*/
    SetGL2D(m, MTOP(surf), NULL, &hwnd);
    GetClientRect(hwnd, &rect);
    w = rect.right;
    h = rect.bottom;
    glPixelStorei(GL_PACK_LSB_FIRST,	GL_FALSE);
    glPixelStorei(GL_UNPACK_LSB_FIRST,	GL_FALSE);  
    buffer = (unsigned char*) malloc(sizeof(char)*w*h*4);
    if (!buffer)		return 0;
    glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, buffer);

	  // Prépare la texture
	  if((tex->Width != w) || (tex->Height != h))
	  {
		  updateNeeded = 1;
		  tex->Width  = w;
		  tex->Height = h;
	  }

	  if(tex->ImageModif!=NULL)			free(tex->ImageModif);
	  //tex->ImageModif	= (unsigned char *) malloc(tex->Width * tex->Height * 4);
	  tex->ImageModif	= buffer;

	  //int		incremX;
    //incremX = tex->Width * 4;

	  // Copie de la surface
	  //int	color;
	  //unsigned char cr, cg, cb;
	  //int				x, y, posii=0;
 
	  // -----> on utilise la couleur de transparence d'origine
	  int	colTransp = tex->GetTranspB() | (tex->GetTranspG() <<8) | (tex->GetTranspR() <<16);

/*
	  for(y=0; y<tex->Height; y++)
	  {
		  for(x=0; x<tex->Width; x++)
		  {
		  	//cr = buffer[posii+0]; cg = buffer[posii+1]; cb = buffer[posii+2]; 

		  	//tex->ImageModif[posii+0] = cr;
		  	//tex->ImageModif[posii+1] = cg;
		  	//tex->ImageModif[posii+2] = cb;	

		  	//$BLG: colorTransp en RGB et color en BGR ???
		  	//color = ((cg<<16) &0xFF0000)  |  ((cb<<8) &0xFF00)  |  (cr &0xFF);

		  	//if( color == colTransp )
		  	if( colTransp == (((buffer[posii+2]<<16) &0xFF0000)  |  ((buffer[posii+1]<<8) &0xFF00)  |  (buffer[posii+0] &0xFF)) )
		  	  tex->ImageModif[posii+3] = 0;
		  	else
			  	tex->ImageModif[posii+3] = 255;

			  posii += 4;
		  }
	  }
*/

    int i, imax;
    imax = tex->Width * tex->Height * 4;
    
		for(i=0; i<imax; i+=4)
		{
    	if( colTransp == (((tex->ImageModif[i+2]<<16) &0xFF0000)  |  ((tex->ImageModif[i+1]<<8) &0xFF00)  |  (tex->ImageModif[i+0] &0xFF)) )
	  	  tex->ImageModif[i+3] = 0;
		  else
		 	  tex->ImageModif[i+3] = 255;
		} 

    //$BLG: Buffer is freed through tex->ImageModif
    //free(buffer);

	  tex->activated = true;
	  tex->renamed = false;			// becoz we have used the NEW flags of rendering

	  if(scene->accelerated)
	  {
		  if (updateNeeded)
	  	if( (tex->Width!=2 && tex->Width!=4 && tex->Width!=8 && tex->Width!=16 && tex->Width!=32 && tex->Width!=64 && tex->Width!=128 && tex->Width!=256 && tex->Width!=512 && tex->Width!=1024) ||
	  		(tex->Height!=2 && tex->Height!=4 && tex->Height!=8 && tex->Height!=16 && tex->Height!=32 && tex->Height!=64 && tex->Height!=128 && tex->Height!=256 && tex->Height!=512 && tex->Height!=1024)	)		tex->StretchImageModif();

	  	if(tex->ID_created==false)		{	glGenTextures(1, &(tex->texID));	tex->ID_created = true;	}
	  	glBindTexture(GL_TEXTURE_2D, tex->texID);

	  	if( tex->filter==TF_NONE )
	  	{
		  	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
		  	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
		  }
		  else if(tex->filter == TF_LINEAR)
		  {
		  	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	  		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	  	}
	  	else if(tex->filter == TF_BILINEAR)
	  	{
			  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
			  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
		  }
		  else if(tex->filter == TF_TRILINEAR)
		  {
  			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
			  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
		  }

		  if (updateNeeded)
  			glTexImage2D(GL_TEXTURE_2D, 0, 4, tex->Width, tex->Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, tex->ImageModif );
		  else 
  			glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tex->Width, tex->Height, GL_RGBA, GL_UNSIGNED_BYTE, tex->ImageModif);

	  	if(tex->filter != TF_NONE)			gluBuild2DMipmaps( GL_TEXTURE_2D, 4, tex->Width, tex->Height, GL_RGBA, GL_UNSIGNED_BYTE, tex->ImageModif );

  		free(tex->ImageModif);		tex->ImageModif=NULL;
	  }
	  else
	  {
		  tex->StretchImageModif();
		  tex->SetupTexture();			
	  }

	  scene->textureModified = true;
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	  MMset(m,0,0);
	  return 0;
	}
	else
	{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
    return ZM3blitTexture16(m);
	}
}











//////////////////////////////////////////////////////////////////////////////////////////////
///		Buffer2texture
//////////////////////////////////////////////////////////////////////////////////////////////
int ZBuffer2texture(mmachine m, char *buffer, int width, int height)
{
	int text = MMpull(m);
	int s3d	 = MMget(m,0);

	if((s3d==NIL)||(text==NIL))					{   MMset(m,0,NIL);		return 0;	}
	ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)								{   MMset(m,0,NIL);		return 0;	}

    ZTexture	*tex = (ZTexture*) MMfetch(m,MTOP(text),0);
	if(tex==NULL)								{	MMset(m,0,NIL);		return 0;	}


	// Prépare la texture
	if( (tex->Width != width) || (tex->Height != height) )
	{
		tex->Width  = width;
		tex->Height = height;
		if(tex->ImageModif!=NULL)			free(tex->ImageModif);
		tex->ImageModif	= (unsigned char *) malloc(tex->Width * tex->Height * 4);

		int		srce=0, posii=0;

		for(int y=0; y<tex->Height; y++)
		{
			srce = (tex->Height-1-y) * tex->Width*3;

			for(int x=0; x<tex->Width; x++)
			{
				tex->ImageModif[posii+0] = buffer[srce+0];
				tex->ImageModif[posii+1] = buffer[srce+1];
				tex->ImageModif[posii+2] = buffer[srce+2];
				tex->ImageModif[posii+3] = 255;

				posii	+= 4;
				srce	+= 3;
			}
		}

		tex->activated = true;
		tex->renamed = false;			// becoz we have used the NEW flags of rendering

		if(scene->accelerated)
		{
			if(tex->ID_created==false)		{	glGenTextures(1, &(tex->texID));	tex->ID_created = true;	}
			glBindTexture(GL_TEXTURE_2D, tex->texID);

			glTexImage2D(GL_TEXTURE_2D, 0, 4, tex->Width, tex->Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, tex->ImageModif );
			if(tex->filter != TF_NONE)			gluBuild2DMipmaps( GL_TEXTURE_2D, 4, tex->Width, tex->Height, GL_RGBA, GL_UNSIGNED_BYTE, tex->ImageModif );

			free(tex->ImageModif);		tex->ImageModif=NULL;
		}
		else
		{
			tex->StretchImageModif();
			tex->SetupTexture();
		}
	}
	else
	{
		if(tex->ImageModif!=NULL)			free(tex->ImageModif);
		tex->ImageModif	= (unsigned char *) malloc(tex->Width * tex->Height * 4);

		int		srce=0, posii=0;

		for(int y=0; y<tex->Height; y++)
		{
			srce = (tex->Height-1-y) * tex->Width*3;

			for(int x=0; x<tex->Width; x++)
			{
				tex->ImageModif[posii+0] = buffer[srce+0];
				tex->ImageModif[posii+1] = buffer[srce+1];
				tex->ImageModif[posii+2] = buffer[srce+2];
				tex->ImageModif[posii+3] = 255;

				posii	+= 4;
				srce	+= 3;
			}
		}

		tex->activated = true;
		tex->renamed = false;			// becoz we have used the NEW flags of rendering

		if(scene->accelerated)
		{
			if(tex->ID_created==false)		{	glGenTextures(1, &(tex->texID));	tex->ID_created = true;	}
			glBindTexture(GL_TEXTURE_2D, tex->texID);
			
			glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tex->Width, tex->Height, GL_RGBA, GL_UNSIGNED_BYTE, tex->ImageModif);
			if(tex->filter != TF_NONE)			gluBuild2DMipmaps( GL_TEXTURE_2D, 4, tex->Width, tex->Height, GL_RGBA, GL_UNSIGNED_BYTE, tex->ImageModif );

			free(tex->ImageModif);		tex->ImageModif=NULL;
		}
		else
		{
			tex->StretchImageModif();
			tex->SetupTexture();
		}
	}

	scene->textureModified = true;

	MMset(m,0,text);
	return 0;
}







int Mgethxn(char *c,int l)
{
  int a,k,i,n;
  
  k=0;
  for(i=0;i<l;i++)
  {
	  a=c[i];
      if ((a>='0')&&(a<='9')) n=a-'0';
      else if ((a>='A')&&(a<='F')) n=10+a-'A';
      else if ((a>='a')&&(a<='f')) n=10+a-'a';
      else n=0;
      k=(k<<4)+n;
    }
 
  return k;
}

int myabs(int a,int b)
{
	if (a>b) return a-b;
	return b-a;
}


int hsv2rgb(float h, float s, float v)
{
	int		i;
	int	r,g,b;
	float	f,p,q,t;
		
	v*=255.;
	if (s==0.) r=g=b=v;
	else
	{
		while (h>=360.) h-=360.;
		while (h<0.) h+=360.;
		h/=60.;
		i=floor(h); f=h-(float)i;
		p=v*(1.-s);
		q=v*(1.-s*f);
		t=v*(1.-s*(1.-f));
		switch(i)	{
			case 0:
						r=v; g=t; b=p;
						break;
			case 1:
						r=q; g=v; b=p;
						break;
			case 2:
						r=p; g=v; b=t;
						break;
			case 3:
						r=p; g=q; b=v;
						break;
			case 4:
						r=t; g=p; b=v;
						break;
			case 5:
						r=v; g=p; b=q;
						break;
						}
		}
	//$BLG
	//return ((r<<7)&0x7c00)+((g<<2)&0x3e0)+(b>>3);
	return ((r<<16) &0xff0000) + ((g<<8) &0xff00) + (b &0xff);
}


//$LB
int rgb2hsv(unsigned char r, unsigned char g, unsigned char b, float *rh,float *rs,float *rv)
{
	int max,min;
	float h,s,v,delta;


	if (r>g) max=r; else max=g;
	if (b>max) max=b;
	if (r<g) min=r; else min=g;
	if (b<min) min=b;
	v=max;
	//$LB
	v/=255;
	if (max)
	{
		s=max-min;
		s/=max;
	}
	else s=0;
	if (s==0) h=0;
	else
	{
		delta=max-min;
		if (r==max) h=(g-b)/delta;
		else if (g==max) h=2+(b-r)/delta;
		else h=4+(r-g)/delta;
		h*=60;
		if (h<0) h+=360;
	}
	*rh=h; *rs=s; *rv=v;
	return 0;
}



#define COLORTRANS	1

//$BLG: v4.6a5
//Modified v4.6a1 function version
//New definition for M3Dfilter function to ensure 32bits data alignment in bitmaps
/*
int M3Dfilter(char *s, int l, OBJBITMAP_BUFFER src, int length)
{
	int		i=0;
	int		col24, col, coef, k, x, xr, xg, xb, colr, colg, colb;
	int		ang, sat16;
	float	sat, rh, rs, rv;
	int		transp=0;

	while(i<l)
	{
		if((s[i]=='C')&&(l-i>8))
		{
MMechostr(0,"Mgethxn(C:col24)\n");  
			col24	= Mgethxn(s+i+1,6);
			//$LB	col		= ((col24&0xf80000)>>19)+((col24&0xf800)>>6)+((col24&0xf8)<<7);
			//$BLG: turned color reading from rgb to bgr
			colb = (col24>>16) &0xFF;
			colg = (col24>>8) &0xFF;
			colr = col24      &0xFF;
MMechostr(0,"Mgethxn:OK\n"); 

MMechostr(0,"Mgethxn(C:coef)\n");  
			coef	= Mgethxn(s+i+7,2);

			for(k=0; k<length; k+=3)
			{
				xb = src[k+0]; xg = src[k+1]; xr = src[k+2]; 

				src[k+0] = (((xb*(256-coef)) + (colb*coef) )>>8) &0xFF;
				src[k+1] = (((xg*(256-coef)) + (colg*coef) )>>8) &0xFF;
				src[k+2] = (((xr*(256-coef)) + (colr*coef) )>>8) &0xFF;
			}
			i+=9;
MMechostr(0,"Mgethxn:OK\n"); 
		}
		else if((s[i]=='A')&&(l-i>8))
		{
MMechostr(0,"Mgethxn(A:col24)\n");  
			col24	= Mgethxn(s+i+1,6);
MMechostr(0,"Mgethxn(A:%i)\n",col24);  			
			//$LB col		= ((col24&0xf80000)>>19)+((col24&0xf800)>>6)+((col24&0xf8)<<7);
			//$BLG: turned color reading from rgb to bgr
			colb = (col24>>16) &0xFF;
			colg = (col24>>8) &0xFF;
			colr = col24      &0xFF;

			//transp = col;
			transp	= COLORTRANS;
MMechostr(0,"Mgethxn:OK\n"); 


			//$BLG: Removed >>3 in (Mgethxn(s+i+7,2)>>3)*3;
MMechostr(0,"Mgethxn(A:coef)\n");  
			coef = (Mgethxn(s+i+7,2))*3;
MMechostr(0,"Mgethxn(A:%i)\n",coef);  
			//$LB
			for(k=0; k<length; k+=3)
			{
				xb = src[k+0]; xg = src[k+1]; xr = src[k+2]; 
				x = ((xb<<16) &0xFF0000)  |  ((xg<<8) &0xFF00)  |  (xr &0xFF);

				//$BLG: Changed next lines: Attraction filter should change colors
				//which are next to reference color to reference color.
				//if(x==COLORTRANS)	{src[k+0]=0; src[k+1]=0; src[k+2]=0;}
				//else 
					//if ( (myabs(xb,colr) + myabs(xg,colg) + myabs(xr,colr)) < coef) 
					//{src[k+0]=0; src[k+1]=0; src[k+2]=COLORTRANS;}
  			if ( (myabs(xb,colb) + myabs(xg,colg) + myabs(xr,colr)) < coef) 
					{src[k+0]=colb; src[k+1]=colg; src[k+2]=colr;}			  
			}
			i+=9;
MMechostr(0,"Mgethxn:OK\n"); 
		}
		else if(s[i]=='X')
		{
MMechostr(0,"Mgethxn(Y)\n"); 
			//$LB
			for(k=0; k<length; k+=3)
			{
				xb = src[k+0]; xg = src[k+1]; xr = src[k+2]; 
				//$BLG: Replaced by original Y filter code to ensure proper color cycling
				//Original code however seemed logical but didn't result in proper cycling
				//src[k+0] = xg; src[k+1] = xr; src[k+2] = xb; 
				src[k+0] = xr; src[k+1] = xb; src[k+2] = xg; 
			}
			i++;
MMechostr(0,"Mgethxn:OK\n"); 
		}
		else if(s[i]=='Y')
		{
MMechostr(0,"Mgethxn(Y)\n"); 
			//$LB
			for(k=0; k<length; k+=3)
			{
				xb = src[k+0]; xg = src[k+1]; xr = src[k+2];
				//$BLG: Replaced by original X filter code to ensure proper color cycling
				//Original code however seemed logical but didn't result in proper cycling
				//src[k+0] = xr; src[k+1] = xb; src[k+2] = xg;
				src[k+0] = xg; src[k+1] = xr; src[k+2] = xb; 
			}
			i++;
MMechostr(0,"Mgethxn:OK\n"); 
		}
		else if((s[i]=='R')&&(l-i>4))
		{
MMechostr(0,"Mgethxn(Y:ang)\n");  
			ang = (Mgethxn(s+i+1,4)*360)>>16;

			//$LB
			for(k=0; k<length; k+=3)
			{
				//$BLG
				//rgb2hsv(src[k+0], src[k+1], src[k+2], &rh, &rs, &rv);
				//x = hsv2rgb(rh+ang, rs, rv);
				//src[k+0] = (x>>16) &0xFF; src[k+1] = (x>>8) &0xFF; src[k+2] = x &0xFF; 
				rgb2hsv(src[k+2], src[k+1], src[k+0], &rh, &rs, &rv);
				x = hsv2rgb(rh+ang, rs, rv);
				src[k+0] = x &0xFF; src[k+1] = (x>>8) &0xFF; src[k+2] = (x>>16) &0xFF;
			}
			i+=5;
MMechostr(0,"Mgethxn:OK\n"); 
		}
		else if((s[i]=='S')&&(l-i>6))
		{
MMechostr(0,"Mgethxn(S:sat16)\n");  
			sat16 = Mgethxn(s+i+1,4);
			sat  = sat16;
			sat /= CONST_ANGLE;
MMechostr(0,"Mgethxn:OK\n"); 
MMechostr(0,"Mgethxn(S:coef)\n");  
			coef = Mgethxn(s+i+5,2);
			//$LB
			for(k=0; k<length; k+=3)
			{
				//$BLG
				//rgb2hsv(src[k+0], src[k+1], src[k+2], &rh, &rs, &rv);
				//x = hsv2rgb(rh, (rs*(256-coef)+sat*coef)/256, rv);
				//src[k+0] = (x>>16) &0xFF; src[k+1] = (x>>8) &0xFF; src[k+2] = x &0xFF; 
				rgb2hsv(src[k+2], src[k+1], src[k+0], &rh, &rs, &rv);
				x = hsv2rgb(rh, (rs*(256-coef)+sat*coef)/256, rv);
				src[k+0] = x &0xFF; src[k+1] = (x>>8) &0xFF; src[k+2] = (x>>16) &0xFF; 
			}
			i+=7;
MMechostr(0,"Mgethxn:OK\n"); 
		}
		//$BLG Start
		else if((s[i]=='O')&&(l-i>1))
		{
MMechostr(0,"Mgethxn(O)\n"); 
			i+=2;
MMechostr(0,"Mgethxn:OK\n"); 
		}
		//$BLG End
		else i++;
	}
	return transp;
}
*/
int M3Dfilter(char *s, int l, OBJBITMAP_BUFFER src, int bpl, int w, int h)
{
	int		c=0;		//Char counter
	int 	i, j;		//'For' counters
	int		col24, coef, k, x, xr, xg, xb, colr, colg, colb;
	int		ang, sat16;
	float	sat, rh, rs, rv;
	int		transp=0;

	while(c<l)
	{
		if((s[c]=='C')&&(l-c>8))
		{  
			col24	= Mgethxn(s+c+1,6);
			//$LB	col		= ((col24&0xf80000)>>19)+((col24&0xf800)>>6)+((col24&0xf8)<<7);
			//$BLG: turned color reading from rgb to bgr
			colb = (col24>>16) &0xFF;
			colg = (col24>>8) &0xFF;
			colr = col24      &0xFF;
 
			coef	= Mgethxn(s+c+7,2);

			k = 0;
			for(j=0; j<h; j++)
			{
				for(i=0; i<w; i+=3)
				{
					xb = src[k+i+0]; xg = src[k+i+1]; xr = src[k+i+2]; 
	
					src[k+i+0] = (((xb*(256-coef)) + (colb*coef) )>>8) &0xFF;
					src[k+i+1] = (((xg*(256-coef)) + (colg*coef) )>>8) &0xFF;
					src[k+i+2] = (((xr*(256-coef)) + (colr*coef) )>>8) &0xFF;					
				}
				k+=bpl;
			}
/*
			for(k=0; k<length; k+=3)
			{
				xb = src[k+0]; xg = src[k+1]; xr = src[k+2]; 

				src[k+0] = (((xb*(256-coef)) + (colb*coef) )>>8) &0xFF;
				src[k+1] = (((xg*(256-coef)) + (colg*coef) )>>8) &0xFF;
				src[k+2] = (((xr*(256-coef)) + (colr*coef) )>>8) &0xFF;
			}
*/
			c+=9;
 
		}
		else if((s[c]=='A')&&(l-c>8))
		{
 
			col24	= Mgethxn(s+c+1,6);
			
			//$LB col		= ((col24&0xf80000)>>19)+((col24&0xf800)>>6)+((col24&0xf8)<<7);
			//$BLG: turned color reading from rgb to bgr
			colb = (col24>>16) &0xFF;
			colg = (col24>>8) &0xFF;
			colr = col24      &0xFF;

			//transp = col;
			transp	= COLORTRANS;



			//$BLG: Removed >>3 in (Mgethxn(s+c+7,2)>>3)*3;
 
			coef = (Mgethxn(s+c+7,2))*3; 
			//$LB
			k = 0;
			for(j=0; j<h; j++)
			{
				for(i=0; i<w; i+=3)
				{
					xb = src[k+i+0]; xg = src[k+i+1]; xr = src[k+i+2]; 
					x = ((xb<<16) &0xFF0000)  |  ((xg<<8) &0xFF00)  |  (xr &0xFF);
	  			if ( (myabs(xb,colb) + myabs(xg,colg) + myabs(xr,colr)) < coef) 
						{src[k+i+0]=colb; src[k+i+1]=colg; src[k+i+2]=colr;}										
				}
				k+=bpl;
			}
/*
			for(k=0; k<length; k+=3)
			{
				xb = src[k+0]; xg = src[k+1]; xr = src[k+2]; 
				x = ((xb<<16) &0xFF0000)  |  ((xg<<8) &0xFF00)  |  (xr &0xFF);

				//$BLG: Changed next lines: Attraction filter should change colors
				//which are next to reference color to reference color.
				//if(x==COLORTRANS)	{src[k+0]=0; src[k+1]=0; src[k+2]=0;}
				//else 
					//if ( (myabs(xb,colr) + myabs(xg,colg) + myabs(xr,colr)) < coef) 
					//{src[k+0]=0; src[k+1]=0; src[k+2]=COLORTRANS;}
  			if ( (myabs(xb,colb) + myabs(xg,colg) + myabs(xr,colr)) < coef) 
					{src[k+0]=colb; src[k+1]=colg; src[k+2]=colr;}			  
			}
*/
			c+=9;

		}
		else if(s[c]=='X')
		{
 
			//$LB
			k = 0;
			for(j=0; j<h; j++)
			{
				for(i=0; i<w; i+=3)
				{
					xb = src[k+i+0]; xg = src[k+i+1]; xr = src[k+i+2];
					src[k+i+0] = xr; src[k+i+1] = xb; src[k+i+2] = xg;
				}
				k+=bpl;
			}
/*			
			for(k=0; k<length; k+=3)
			{
				xb = src[k+0]; xg = src[k+1]; xr = src[k+2]; 
				//$BLG: Replaced by original Y filter code to ensure proper color cycling
				//Original code however seemed logical but didn't result in proper cycling
				//src[k+0] = xg; src[k+1] = xr; src[k+2] = xb; 
				src[k+0] = xr; src[k+1] = xb; src[k+2] = xg; 
			}
*/
			c++;

		}
		else if(s[c]=='Y')
		{
 
			//$LB
			k = 0;
			for(j=0; j<h; j++)
			{
				for(i=0; i<w; i+=3)
				{
					xb = src[k+i+0]; xg = src[k+i+1]; xr = src[k+i+2];
					src[k+i+0] = xg; src[k+i+1] = xr; src[k+i+2] = xb; 
				}
				k+=bpl;
			}
/*
			for(k=0; k<length; k+=3)
			{
				xb = src[k+0]; xg = src[k+1]; xr = src[k+2];
				//$BLG: Replaced by original X filter code to ensure proper color cycling
				//Original code however seemed logical but didn't result in proper cycling
				//src[k+0] = xr; src[k+1] = xb; src[k+2] = xg;
				src[k+0] = xg; src[k+1] = xr; src[k+2] = xb; 
			}
*/
			c++;

		}
		else if((s[c]=='R')&&(l-c>4))
		{

			ang = (Mgethxn(s+c+1,4)*360)>>16;

			//$LB
			k=0;
			for(j=0; j<h; j++)
			{
				for(i=0; i<w; i+=3)
				{
					rgb2hsv(src[k+i+2], src[k+i+1], src[k+i+0], &rh, &rs, &rv);
					x = hsv2rgb(rh+ang, rs, rv);
					src[k+i+0] = x &0xFF; src[k+i+1] = (x>>8) &0xFF; src[k+i+2] = (x>>16) &0xFF;					
				}
				k+=bpl;
			}
/*
			for(k=0; k<length; k+=3)
			{
				//$BLG
				//rgb2hsv(src[k+0], src[k+1], src[k+2], &rh, &rs, &rv);
				//x = hsv2rgb(rh+ang, rs, rv);
				//src[k+0] = (x>>16) &0xFF; src[k+1] = (x>>8) &0xFF; src[k+2] = x &0xFF; 
				rgb2hsv(src[k+2], src[k+1], src[k+0], &rh, &rs, &rv);
				x = hsv2rgb(rh+ang, rs, rv);
				src[k+0] = x &0xFF; src[k+1] = (x>>8) &0xFF; src[k+2] = (x>>16) &0xFF;
			}
*/
			c+=5;
 
		}
		else if((s[c]=='S')&&(l-c>6))
		{
 
			sat16 = Mgethxn(s+c+1,4);
			sat  = sat16;
			sat /= CONST_ANGLE;


			coef = Mgethxn(s+c+5,2);
			//$LB
			k = 0;
			for(j=0; j<h; j++)
			{
				for(i=0; i<w; i+=3)
				{
					rgb2hsv(src[k+i+2], src[k+i+1], src[k+i+0], &rh, &rs, &rv);
					x = hsv2rgb(rh, (rs*(256-coef)+sat*coef)/256, rv);
					src[k+i+0] = x &0xFF; src[k+i+1] = (x>>8) &0xFF; src[k+i+2] = (x>>16) &0xFF; 					
				}
				k+=bpl;
			}
/*
			for(k=0; k<length; k+=3)
			{
				//$BLG
				//rgb2hsv(src[k+0], src[k+1], src[k+2], &rh, &rs, &rv);
				//x = hsv2rgb(rh, (rs*(256-coef)+sat*coef)/256, rv);
				//src[k+0] = (x>>16) &0xFF; src[k+1] = (x>>8) &0xFF; src[k+2] = x &0xFF; 
				rgb2hsv(src[k+2], src[k+1], src[k+0], &rh, &rs, &rv);
				x = hsv2rgb(rh, (rs*(256-coef)+sat*coef)/256, rv);
				src[k+0] = x &0xFF; src[k+1] = (x>>8) &0xFF; src[k+2] = (x>>16) &0xFF; 
			}
*/
			c+=7;

		}
		//$BLG Start
		else if((s[c]=='O')&&(l-c>1))
		{

			c+=2;

		}
		//$BLG End
		else c++;
	}
	return transp;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3filter
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [ObjBitmap S] ObjBitmap
int ZM3filter(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3filter ");
#endif

	int flag = MMpull(m);
    int bitm = MMget(m,0);
    
	if((flag==NIL)||(bitm==NIL))		return 0;
	
	char *s = MMstartstr(m,MTOP(flag));

	// recupere les données sur l'ObjBitmap
	PtrObjVoid		OB;
	PtrObjBitmap	B;

	if(bitm==NIL)								{	MMset(m,0,NIL);		return 0;	}
    OB = (PtrObjVoid) MMstart(m,MTOP(bitm));
    if(OB->Type != OBJ_TYPE_BITMAP<< 1)			{	MMset(m,0,NIL);		return 0;	}
    B = (PtrObjBitmap) MMstart(m,MTOP(OB->Buffer));

	//$BLG: Removed >>1 in (B->TailleH*B->BPL)>>1
	//This resulted in filtering only half of the bitmap
	//M3Dfilter(s, strlen(s), (OBJBITMAP_BUFFER)(B->bits), (B->TailleH*B->BPL)>>1);	
  //$BLG: v4.6a5 - New definition for M3Dfilter function to ensure 32bits data alignment in bitmaps
	M3Dfilter(s, strlen(s), (OBJBITMAP_BUFFER)(B->bits), B->BPL, (B->TailleW)*3, B->TailleH);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3nbVisiblePoly
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d] I
int ZM3nbVisiblePoly(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3nbVisiblePoly ");
#endif
	MMset(m,0,NIL);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3nbUsedPolygons
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d] I
int ZM3nbUsedPolygons(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3nbUsedPolygons ");
#endif

	int s3d = MMget(m,0);

	if(s3d==NIL)						{   MMset(m,0,NIL);		return 0;	}
	ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)						{   MMset(m,0,NIL);		return 0;	}


	ZWorld	*world = scene->World;
	int nbPoly = 0;

	for(int i=0; i<world->objList.Size(); i++)
	{
		if(world->objList[i]->GetMesh())		nbPoly += world->objList[i]->GetMesh()->NbFaces;
	}

	MMset(m,0,ITOM(nbPoly));

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;
}






///////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////Mehdi : M3setAntiAliasing//////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d F] I
int ZM3setAntiAliasing(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3setAntiAliasing ");
#endif

	float coef = MMpull(m);
	int s3d  = MMget(m,0);

	if(s3d==NIL || coef ==NIL)						{   MMset(m,0,NIL);		return 0;	}
	ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)						{   MMset(m,0,NIL);		return 0;	}
	
	coef = MTOF(coef) ;

	/*
	scene->World->AntiAliasing = true ;
	scene->World->CoeffAntiAliasing = coef ;
	*/
	MMset(m,0,0);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;
}


/////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////// M3multiSamplingSupported////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//fun [] [I I]
int ZM3multiSamplingSupported(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3multiSamplingSupported ");
#endif

//	int s3d  = MMget(m,0);
	int tuple = MMmalloc(m, 2, TYPETAB);
	int val;
	int val2 ;
	/*
	if(s3d==NIL)						{   MMset(m,0,NIL);		return 0;	}
	ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)						{   MMset(m,0,NIL);		return 0;	}
	//if(tuple==NIL)				{	MMset(m,0,NIL);		return MERRMEM; }
	*/

	// Mehdi : Antialiasing

	ZDetector detect ;
	bool CheckExtension = false ;
	CheckExtension = detect.WGLisExtensionSupported("GL_ARB_multisample") ;
/*	// On récupère les tampons d'accumulations :
	GLint sbuf ;
	glGetIntegerv(WGL_SAMPLE_BUFFERS_EXT, &sbuf) ;
*/
	if (CheckExtension == false)
	{
		arbMultisampleSupported = false ;
		val = 0 ;
		val2 = 0 ;

	}
	if (CheckExtension == true)
	{
		arbMultisampleSupported = true ;
		val = 1 ;
		val2 = Multi_Pass ;
		val2++ ;
	}

	MMstore(m, tuple, 0, ITOM(val));
	MMstore(m, tuple, 1, ITOM(val2));
	//MMset(m,0,PTOM(tuple));
	MMpush(m, PTOM(tuple));


#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////// ZM3maxSampleBuffers////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//fun [] [I]
int ZM3maxSampleBuffers(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ZM3maxSampleBuffers ");
#endif

	//int s3d  = MMget(m,0);
	//int tuple = MMmalloc(m, 2, TYPETAB);
	int val;
/*	if(s3d==NIL)						{   MMset(m,0,NIL);		return 0;	}
	ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)						{   MMset(m,0,NIL);		return 0;	}
	if(tuple==NIL)				{	MMset(m,0,NIL);		return MERRMEM; }
*/
	// Mehdi : Antialiasing

	val = maxSamples ;
/*
	ZDetector detect ;
	bool CheckExtension = false ;
	CheckExtension = detect.WGLisExtensionSupported("GL_ARB_multisample") ;
	if (CheckExtension == false)
	{
		arbMultisampleSupported = false ;
		scene->MultiActivation= false ;
		val = 0 ;

	}
	if (CheckExtension == true)
	{
		arbMultisampleSupported = true ;
		scene->MultiActivation = true ;
		val = 1 ;
	}
	*/
	//MMset(m,0,ITOM(val));
	MMpush(m,ITOM(val)) ;


#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;
}


/////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////// M3EnableMultisampling////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//fun [S3d] [I]
int ZM3EnableMultisampling(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3EnableMultisampling ");
#endif

	int s3d  = MMget(m,0);
	int tuple = MMmalloc(m, 2, TYPETAB);
	int val;
	if(s3d==NIL)						{   MMset(m,0,NIL);		return 0;	}
	ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)						{   MMset(m,0,NIL);		return 0;	}
	//if(tuple==NIL)				{	MMset(m,0,NIL);		return MERRMEM; }

	// Mehdi : Antialiasing

	ZDetector detect ;
	bool CheckExtension = false ;
	CheckExtension = detect.WGLisExtensionSupported("GL_ARB_multisample") ;
	if (CheckExtension == false)
	{
		arbMultisampleSupported = false ;
		scene->MultiActivation= false ;
		val = 0 ;

	}
	if (CheckExtension == true)
	{
		arbMultisampleSupported = true ;
		scene->MultiActivation = true ;
		val = 1 ;
	}
	MMset(m,0,ITOM(val));


#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;
}



/////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////// M3DisableMultisampling////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//fun [S3d] [I]
int ZM3DisableMultisampling(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3DisableMultisampling ");
#endif

	int s3d  = MMget(m,0);
	int tuple = MMmalloc(m, 2, TYPETAB);
	int val;
	if(s3d==NIL)						{   MMset(m,0,NIL);		return 0;	}
	ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)						{   MMset(m,0,NIL);		return 0;	}
	//if(tuple==NIL)				{	MMset(m,0,NIL);		return MERRMEM; }

	// Mehdi : Antialiasing

	ZDetector detect ;
	bool CheckExtension = false ;
	CheckExtension = detect.WGLisExtensionSupported("GL_ARB_multisample") ;
	if (CheckExtension == false)
	{
		arbMultisampleSupported = false ;
		scene->MultiActivation = false ;
		val = 0 ;

	}
	if (CheckExtension == true)
	{
		arbMultisampleSupported = true ;
		scene->MultiActivation = false ;
		val = 1 ;
		

	}
	MMset(m,0,ITOM(val));


#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////// M3getFrameRate////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
/* $MS : FrameRate Function */
//fun [S3d] [F]
int ZM3getFrameRate(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getFrameRate ");
#endif

	int s3d  = MMget(m,0);
	int tuple = MMmalloc(m, 2, TYPETAB);
	float val;
	if(s3d==NIL)						{   MMset(m,0,NIL);		return 0;	}
	ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)						{   MMset(m,0,NIL);		return 0;	}


	val = float(scene->frameRate) ;

	MMset(m,0,FTOM(val));


#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;
}


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////																											   ////
///												GESTION DES COLLISIONS												///
////																											   ////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////




//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3createSphere
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d I] H3d
int ZM3createSphere(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3createSphere ");
#endif

	int ray = MMpull(m);
	int s3d = MMget(m,0);

	if((s3d==NIL)||(ray==NIL))			{   MMset(m,0,NIL);		return 0;	}
	ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)						{   MMset(m,0,NIL);		return 0;	}

    ray = MTOI(ray);

	ZColl	*sph;
	sph = new ZColl((int)scene, 0);
	if(sph==NULL)						{   MMset(m,0,NIL);		return 0;	}
	sph->InsertAsChildOf(scene->World);
	sph->pos.SetNull();		// zéro, car c'est le sommet de l'arbre de collision

	sph->rayon = ((float)ray) / 100.0f;

	int hash_tab = MTOP( MMfetch(m,MTOP(s3d),1) );
	int	h3d = createH3D(m, (int)sph, hash_tab);

	scene->updateGraphList = true;

	// Pose le résultat sur la pile
	if(h3d!=NIL)	h3d = PTOM(h3d);
    MMset(m,0,h3d);
    
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3createSphereF
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d F] H3d
int ZM3createSphereF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3createSphereF ");
#endif

	int ray = MMpull(m);
	int s3d = MMget(m,0);

	if((s3d==NIL)||(ray==NIL))			{   MMset(m,0,NIL);		return 0;	}
	ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)						{   MMset(m,0,NIL);		return 0;	}

	ZColl	*sph;
	sph = new ZColl((int)scene, 0);
	if(sph==NULL)						{   MMset(m,0,NIL);		return 0;	}
	sph->InsertAsChildOf(scene->World);
	sph->pos.SetNull();		// zéro, car c'est le sommet de l'arbre de collision

	sph->rayon = MTOF(ray) / 100.0f;

	int hash_tab = MTOP( MMfetch(m,MTOP(s3d),1) );
	int	h3d = createH3D(m, (int)sph, hash_tab);

	scene->updateGraphList = true;

	// Pose le résultat sur la pile
	if(h3d!=NIL)	h3d = PTOM(h3d);
    MMset(m,0,h3d);
    
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3createObb
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d [I I I]] H3d
int ZM3createObb(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3createObb ");
#endif

	int tupl = MMpull(m);
	int s3d  = MMget(m,0);

	if((s3d==NIL)||(tupl==NIL))			{   MMset(m,0,NIL);		return 0;	}
	ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)						{   MMset(m,0,NIL);		return 0;	}


	float x = (float)(MMfetch(m,MTOP(tupl),0)>>1) / 100.0f;
	float y = (float)(MMfetch(m,MTOP(tupl),1)>>1) / 100.0f;
	float z = (float)(MMfetch(m,MTOP(tupl),2)>>1) / 100.0f;


	// crée la sphère MERE de l'Obb
	ZColl	*sph;
	sph = new ZColl((int)scene, 0);
	if(sph==NULL)						{   MMset(m,0,NIL);		return 0;	}
	sph->InsertAsChildOf(scene->World);
	sph->pos.SetNull();		// zéro, car c'est le sommet de l'arbre de collision

	sph->rayon = sqrt(x*x + y*y + z*z);

	int hash_tab = MTOP( MMfetch(m,MTOP(s3d),1) );
	int	h3d = createH3D(m, (int)sph, hash_tab);


	// crée l'Obb (dans l'arbre de collision)
	ZColl	*obb;
	obb = new ZColl((int)scene, 1);
	if(obb==NULL)						{   MMset(m,0,NIL);		return 0;	}
	obb->pos.SetNull();	
	obb->u.x = x;
	obb->v.y = y;
	obb->w.z = z;


	// insertion comme premier fils
	sph->colA = obb;

	scene->updateGraphList = true;

	// Pose le résultat sur la pile
	if(h3d!=NIL)	h3d = PTOM(h3d);
    MMset(m,0,h3d);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3createObbF
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d [F F F]] H3d
int ZM3createObbF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3createObbF ");
#endif

	int tupl = MMpull(m);
	int s3d  = MMget(m,0);

	if((s3d==NIL)||(tupl==NIL))			{   MMset(m,0,NIL);		return 0;	}
	ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)						{   MMset(m,0,NIL);		return 0;	}


	float x = MTOF(MMfetch(m,MTOP(tupl),0)) / 100.0f;
	float y = MTOF(MMfetch(m,MTOP(tupl),1)) / 100.0f;
	float z = MTOF(MMfetch(m,MTOP(tupl),2)) / 100.0f;


	// crée la sphère MERE de l'Obb
	ZColl	*sph;
	sph = new ZColl((int)scene, 0);
	if(sph==NULL)						{   MMset(m,0,NIL);		return 0;	}
	sph->InsertAsChildOf(scene->World);
	sph->pos.SetNull();		// zéro, car c'est le sommet de l'arbre de collision

	sph->rayon = sqrt(x*x + y*y + z*z);

	int hash_tab = MTOP( MMfetch(m,MTOP(s3d),1) );
	int	h3d = createH3D(m, (int)sph, hash_tab);


	// crée l'Obb (dans l'arbre de collision)
	ZColl	*obb;
	obb = new ZColl((int)scene, 1);
	if(obb==NULL)						{   MMset(m,0,NIL);		return 0;	}
	obb->pos.SetNull();	
	obb->u.x = x;
	obb->v.y = y;
	obb->w.z = z;


	// insertion comme premier fils
	sph->colA = obb;

	scene->updateGraphList = true;

	// Pose le résultat sur la pile
	if(h3d!=NIL)	h3d = PTOM(h3d);
    MMset(m,0,h3d);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3calcObb
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d] [[I I I] [I I I]]
int ZM3calcObb(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3calcObb ");
#endif

	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL)					{	MMset(m,0,NIL);		return 0;	}

	if( (node->type!=OBJ_TYPE_ID) || ( ((ZObject*)node)->GetMesh()==NULL ) )
	{
		MMpull(m);
		int k;

		if (MMpush(m,ITOM(0)))		return MERRMEM;
		if (MMpush(m,ITOM(0)))		return MERRMEM;
		if (MMpush(m,ITOM(0)))		return MERRMEM;
		if (MMpush(m,3*2))			return MERRMEM;
		if (k=MBdeftab(m))			return k;

		if (MMpush(m,ITOM(0)))		return MERRMEM;
		if (MMpush(m,ITOM(0)))		return MERRMEM;
		if (MMpush(m,ITOM(0)))		return MERRMEM;
		if (MMpush(m,3*2))			return MERRMEM;
		if (k=MBdeftab(m))			return k;

		if (MMpush(m,2*2))			return MERRMEM;
		return MBdeftab(m);
	}


	vector<ZVert>	*vertInit;
	vertInit	= &(((ZObject*)node)->GetMesh()->Verts);
	int	nbVerts = ((ZObject*)node)->GetMesh()->NbVerts;

	if(nbVerts==0)					{	MMset(m,0,NIL);		return 0;	}

	float	xmin, xmax, ymin, ymax, zmin, zmax;
	xmin = xmax = (*vertInit)[0].x;
	ymin = ymax = (*vertInit)[0].y;
	zmin = zmax = (*vertInit)[0].z;

	for(int i=1; i<nbVerts; i++)
	{
		if(xmin > (*vertInit)[i].x)		xmin = (*vertInit)[i].x;
		else
		if(xmax < (*vertInit)[i].x)		xmax = (*vertInit)[i].x;

		if(ymin > (*vertInit)[i].y)		ymin = (*vertInit)[i].y;
		else
		if(ymax < (*vertInit)[i].y)		ymax = (*vertInit)[i].y;

		if(zmin > (*vertInit)[i].z)		zmin = (*vertInit)[i].z;
		else
		if(zmax < (*vertInit)[i].z)		zmax = (*vertInit)[i].z;
	}

	ZPRS	*prs = ((ZObject*)node)->GetPRS();
	float	posX = (xmin+xmax) / 2.0f;
	float	posY = (ymin+ymax) / 2.0f;
	float	posZ = (zmin+zmax) / 2.0f;

	float	rx = (xmax-xmin) / 2.0f;
	float	ry = (ymax-ymin) / 2.0f;
	float	rz = (zmax-zmin) / 2.0f;

	MMpull(m);
	int k;
	
	if (MMpush(m,ITOM(AROUNDINT(posX*100.0f))))		return MERRMEM;
    if (MMpush(m,ITOM(AROUNDINT(posY*100.0f))))		return MERRMEM;
    if (MMpush(m,ITOM(AROUNDINT(-posZ*100.0f))))	return MERRMEM;
	if (MMpush(m,3*2))								return MERRMEM;
	if (k=MBdeftab(m))								return k;

	if (MMpush(m,ITOM(AROUNDINT(rx*100.0f))))		return MERRMEM;
    if (MMpush(m,ITOM(AROUNDINT(ry*100.0f))))		return MERRMEM;
    if (MMpush(m,ITOM(AROUNDINT(rz*100.0f))))		return MERRMEM;
	if (MMpush(m,3*2))								return MERRMEM;
	if (k=MBdeftab(m))								return k;

	if (MMpush(m,2*2)) return MERRMEM;
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
    return MBdeftab(m);
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3calcObbF
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d] [[F F F] [F F F]]
int ZM3calcObbF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3CalcObbF ");
#endif

	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL)					{	MMset(m,0,NIL);		return 0;	}

	if( (node->type!=OBJ_TYPE_ID) || ( ((ZObject*)node)->GetMesh()==NULL ) )
	{
		MMpull(m);
		int k;

		if (MMpush(m,FTOM(0)))		return MERRMEM;
		if (MMpush(m,FTOM(0)))		return MERRMEM;
		if (MMpush(m,FTOM(0)))		return MERRMEM;
		if (MMpush(m,3*2))			return MERRMEM;
		if (k=MBdeftab(m))			return k;

		if (MMpush(m,FTOM(0)))		return MERRMEM;
		if (MMpush(m,FTOM(0)))		return MERRMEM;
		if (MMpush(m,FTOM(0)))		return MERRMEM;
		if (MMpush(m,3*2))			return MERRMEM;
		if (k=MBdeftab(m))			return k;

		if (MMpush(m,2*2))			return MERRMEM;
		return MBdeftab(m);
	}


	vector<ZVert>	*vertInit;
	vertInit	= &(((ZObject*)node)->GetMesh()->Verts);
	int	nbVerts = ((ZObject*)node)->GetMesh()->NbVerts;

	if(nbVerts==0)					{	MMset(m,0,NIL);		return 0;	}

	float	xmin, xmax, ymin, ymax, zmin, zmax;
	xmin = xmax = (*vertInit)[0].x;
	ymin = ymax = (*vertInit)[0].y;
	zmin = zmax = (*vertInit)[0].z;

	for(int i=1; i<nbVerts; i++)
	{
		if(xmin > (*vertInit)[i].x)		xmin = (*vertInit)[i].x;
		else
		if(xmax < (*vertInit)[i].x)		xmax = (*vertInit)[i].x;

		if(ymin > (*vertInit)[i].y)		ymin = (*vertInit)[i].y;
		else
		if(ymax < (*vertInit)[i].y)		ymax = (*vertInit)[i].y;

		if(zmin > (*vertInit)[i].z)		zmin = (*vertInit)[i].z;
		else
		if(zmax < (*vertInit)[i].z)		zmax = (*vertInit)[i].z;
	}

	ZPRS	*prs = ((ZObject*)node)->GetPRS();
	float	posX = (xmin+xmax) / 2.0f;
	float	posY = (ymin+ymax) / 2.0f;
	float	posZ = (zmin+zmax) / 2.0f;

	float	rx = (xmax-xmin) / 2.0f;
	float	ry = (ymax-ymin) / 2.0f;
	float	rz = (zmax-zmin) / 2.0f;

	MMpull(m);
	int k;
	
	if (MMpush(m,FTOM(posX*100.0f)))		return MERRMEM;
    if (MMpush(m,FTOM(posY*100.0f)))		return MERRMEM;
    if (MMpush(m,FTOM(-posZ*100.0f)))		return MERRMEM;
	if (MMpush(m,3*2))						return MERRMEM;
	if (k=MBdeftab(m))						return k;

	if (MMpush(m,FTOM(rx*100.0f)))			return MERRMEM;
    if (MMpush(m,FTOM(ry*100.0f)))			return MERRMEM;
    if (MMpush(m,FTOM(rz*100.0f)))			return MERRMEM;
	if (MMpush(m,3*2))						return MERRMEM;
	if (k=MBdeftab(m))						return k;

	if (MMpush(m,2*2)) return MERRMEM;
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
    return MBdeftab(m);
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3firstRadius
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d] I
int ZM3firstRadius(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3firstRadius ");
#endif

	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=COL_TYPE_ID))			{	MMset(m,0,NIL);		return 0;	}

    ZColl	*col = (ZColl*)node;
	if(col->typeColl!=0)								{	MMset(m,0,NIL);		return 0;	}

	MMset(m,0,ITOM(AROUNDINT(col->rayon*100.0f)));

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3firstRadiusF
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d] F
int ZM3firstRadiusF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3firstRadiusF ");
#endif

	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=COL_TYPE_ID))			{	MMset(m,0,NIL);		return 0;	}

    ZColl	*col = (ZColl*)node;
	if(col->typeColl!=0)								{	MMset(m,0,NIL);		return 0;	}

	MMset(m,0,FTOM(col->rayon*100.0f));
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3testInter
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d H3d] [H3d H3d]
int ZM3testInter(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3testInter ");
#endif

	int noB  = MMpull(m);
	int noA  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(noA==NIL)||(noB==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)								{	MMset(m,0,NIL);		return 0;	}

    ZNode	*nodeA = (ZNode*) MMfetch(m,MTOP(noA),0);
	if(nodeA==NULL)								{	MMset(m,0,NIL);		return 0;	}

    ZNode	*nodeB = (ZNode*) MMfetch(m,MTOP(noB),0);
	if(nodeB==NULL)								{	MMset(m,0,NIL);		return 0;	}

    ZNode	*collA, *collB;
    int p = M3DtestInter(scene, nodeA, nodeB, &collA, &collB);

	if(!p)		{	MMset(m,0,NIL);		return 0;	}

	// Traitement des resultats
	noA = noB = NIL;

	if(collA!=NULL)
	{
		noA = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)collA);
		if(noA!=NIL)	noA = PTOM(noA);
	}
	if(MMpush(m,noA))			return MERRMEM;

	int tmp_res=0;
	INVERT(m,0,1);

	if(collB!=NULL)
	{
		noB = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(MMget(m,0)),1)), (int)collB);
		if(noB!=NIL)	noB = PTOM(noB);
	}
	if(MMpush(m,noB))			return MERRMEM;

	INVERT(m,0,1);
	MMpull(m);			// dépile le S3d avant la création du tableau
	
    if(MMpush(m,2*2))			return MERRMEM;
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
    return MBdeftab(m);
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3testColl
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d H3d [I I I] I] [H3d H3d [I I I] [I I I]]
int ZM3testColl(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3testColl ");
#endif

	int gar	 = MMpull(m);
	int vec	 = MMpull(m);
	int noB  = MMpull(m);
	int noA  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(noA==NIL)||(noB==NIL)||(gar==NIL)||(vec==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)								{	MMset(m,0,NIL);		return 0;	}

    ZNode	*nodeA = (ZNode*) MMfetch(m,MTOP(noA),0);
	if(nodeA==NULL)								{	MMset(m,0,NIL);		return 0;	}

    ZNode	*nodeB = (ZNode*) MMfetch(m,MTOP(noB),0);
	if(nodeB==NULL)								{	MMset(m,0,NIL);		return 0;	}

	float garde = (float)( MTOI(gar) ) / 100.0f;
	if(garde<0)		garde = 0.0f;

	ZVector3	transl;
	transl.x = ((float) (MMfetch(m,MTOP(vec),0)>>1)) / 100.0f;
	transl.y = ((float) (MMfetch(m,MTOP(vec),1)>>1)) / 100.0f;
	transl.z = -((float) (MMfetch(m,MTOP(vec),2)>>1)) / 100.0f;

    ZNode		*collA, *collB;
    float		res;
	ZVector3	vcol;
	int k = M3DtestColl(scene, nodeA, nodeB, transl, &res, &vcol, garde, &collA, &collB);

	// Traitement des resultats
	if(!k)		{	MMset(m,0,NIL);		return 0;	}
	
	noA = noB = NIL;
	
	if(collA!=NULL)
	{
		noA = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)collA);
		if(noA!=NIL)	noA = PTOM(noA);
	}
    if(MMpush(m,noA))		return MERRMEM;

	int tmp_res=0;
	INVERT(m,0,1);

	if(collB!=NULL)
	{
		noB = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(MMget(m,0)),1)), (int)collB);
		if(noB!=NIL)	noB = PTOM(noB);
	}
    if(MMpush(m,noB))		return MERRMEM;
    
	INVERT(m,0,1);
	MMpull(m);			// dépile le S3d avant la création du tableau

	if(k<0)		res = 0;
	transl *= (res*100.0f);

    if(MMpush(m,ITOM(AROUNDINT(transl.x))))			return MERRMEM;
    if(MMpush(m,ITOM(AROUNDINT(transl.y))))			return MERRMEM;
    if(MMpush(m,ITOM(AROUNDINT(-transl.z))))		return MERRMEM;
    if(MMpush(m,3*2))		return MERRMEM;

    int r;
	if(r=MBdeftab(m))		return r;
	
	if(k<0)
	{
		if(MMpush(m,NIL))	return MERRMEM;
	}
	else
	{
		vcol *= 100.0f;
		if(MMpush(m,ITOM(AROUNDINT(vcol.x))))			return MERRMEM;
		if(MMpush(m,ITOM(AROUNDINT(vcol.y))))			return MERRMEM;
		if(MMpush(m,ITOM(AROUNDINT(-vcol.z))))			return MERRMEM;
		if(MMpush(m,3*2))		return MERRMEM;
		if(k=MBdeftab(m))		return k;
	}
    
	if(MMpush(m,4*2))		return MERRMEM;
    
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return MBdeftab(m);
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3testCollF
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d H3d [F F F] F] [H3d H3d [F F F] [F F F]]
int ZM3testCollF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3testCollF ");
#endif

	int gar	 = MMpull(m);
	int vec	 = MMpull(m);
	int noB  = MMpull(m);
	int noA  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(noA==NIL)||(noB==NIL)||(gar==NIL)||(vec==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)								{	MMset(m,0,NIL);		return 0;	}

    ZNode	*nodeA = (ZNode*) MMfetch(m,MTOP(noA),0);
	if(nodeA==NULL)								{	MMset(m,0,NIL);		return 0;	}

    ZNode	*nodeB = (ZNode*) MMfetch(m,MTOP(noB),0);
	if(nodeB==NULL)								{	MMset(m,0,NIL);		return 0;	}

	float garde = MTOF(gar) / 100.0f;
	if(garde<0)		garde = 0.0f;

	ZVector3	transl;
	transl.x =  MTOF(MMfetch(m,MTOP(vec),0)) / 100.0f;
	transl.y =  MTOF(MMfetch(m,MTOP(vec),1)) / 100.0f;
	transl.z = -MTOF(MMfetch(m,MTOP(vec),2)) / 100.0f;

    ZNode		*collA, *collB;
    float		res;
	ZVector3	vcol;
	int k = M3DtestColl(scene, nodeA, nodeB, transl, &res, &vcol, garde, &collA, &collB);

	// Traitement des resultats
	if(!k)		{	MMset(m,0,NIL);		return 0;	}
	
	noA = noB = NIL;
	
	if(collA!=NULL)
	{
		noA = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)collA);
		if(noA!=NIL)	noA = PTOM(noA);
	}
    if(MMpush(m,noA))		return MERRMEM;

	int tmp_res=0;
	INVERT(m,0,1);

	if(collB!=NULL)
	{
		noB = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(MMget(m,0)),1)), (int)collB);
		if(noB!=NIL)	noB = PTOM(noB);
	}
    if(MMpush(m,noB))		return MERRMEM;
    
	INVERT(m,0,1);
	MMpull(m);			// dépile le S3d avant la création du tableau

	if(k<0)		res = 0;
	transl *= (res*100.0f);

    if(MMpush(m,FTOM(transl.x)))		return MERRMEM;
    if(MMpush(m,FTOM(transl.y)))		return MERRMEM;
    if(MMpush(m,FTOM(-transl.z)))		return MERRMEM;
    if(MMpush(m,3*2))					return MERRMEM;

    int r;
	if(r=MBdeftab(m))					return r;
	
	if(k<0)
	{
		if(MMpush(m,NIL))	return MERRMEM;
	}
	else
	{
		vcol *= 100.0f;
		if(MMpush(m,FTOM(vcol.x)))			return MERRMEM;
		if(MMpush(m,FTOM(vcol.y)))			return MERRMEM;
		if(MMpush(m,FTOM(-vcol.z)))			return MERRMEM;
		if(MMpush(m,3*2))					return MERRMEM;
		if(k=MBdeftab(m))					return k;
	}
    
	if(MMpush(m,4*2))		return MERRMEM;
    
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return MBdeftab(m);
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3createExactModel
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d] I
int ZM3createExactModel(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3createExactModel ");
#endif

	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL))					{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)								{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL || node->type!=OBJ_TYPE_ID)	{	MMset(m,0,NIL);		return 0;	}

	ZObject	*obj = (ZObject*) node;
	if(obj->IsMultiMeshes())					{	MMset(m,0,NIL);		return 0;	}

	ZMesh	*mesh = obj->GetMesh();
	if(mesh==NULL || mesh->dependency || mesh->displayListCreate==false)		{	MMset(m,0,NIL);		return 0;	}


	if(mesh->CreateRapidModel())		MMset(m,0,0);
	else								MMset(m,0,NIL);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3destroyExactModel 
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d] I
int ZM3destroyExactModel(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3destroyExactModel ");
#endif

	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL))					{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)								{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL || node->type!=OBJ_TYPE_ID)	{	MMset(m,0,NIL);		return 0;	}

	ZObject	*obj = (ZObject*) node;
	if(obj->IsMultiMeshes())					{	MMset(m,0,NIL);		return 0;	}

	ZMesh	*mesh = obj->GetMesh();
	if(mesh==NULL || mesh->dependency || mesh->displayListCreate==false)		{	MMset(m,0,NIL);		return 0;	}

	mesh->DeleteRapidModel();

	MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}




bool	DetectInter(ZObject *obj1, ZObject *obj2)
{
	float		R1[3][3], R2[3][3], T1[3], T2[3], scale1, scale2;

	scale1 = obj1->worldScale;
	scale2 = obj2->worldScale;

	for(int k=0; k<3; k++)
	{
		for(int l=0; l<3; l++)
		{
			R1[l][k] = obj1->worldMat(l,k)/scale1;
			R2[l][k] = obj2->worldMat(l,k)/scale2;
		}
	}

	T1[0] = obj1->worldPos.x;		T1[1] = obj1->worldPos.y;		T1[2] = obj1->worldPos.z;
	T2[0] = obj2->worldPos.x;		T2[1] = obj2->worldPos.y;		T2[2] = obj2->worldPos.z;

	RAPID_Collide(R1, T1, scale1, obj1->GetMesh()->rapid, R2, T2, scale2, obj2->GetMesh()->rapid, RAPID_FIRST_CONTACT);

	if(RAPID_num_contacts)	return true;
	else					return false;
						
}



bool	DetectCollide(ZObject *obj1, ZObject *obj2, ZVector3 &depl)
{
	float		R1[3][3], R2[3][3], T1[3], T2[3], scale1, scale2;
	
	ZVector3	nul, deplCOL;
	deplCOL = depl;
	nul.SetNull();

	scale1 = obj1->worldScale;
	scale2 = obj2->worldScale;

	for(int k=0; k<3; k++)
	{
		for(int l=0; l<3; l++)
		{
			R1[l][k] = obj1->worldMat(l,k)/scale1;
			R2[l][k] = obj2->worldMat(l,k)/scale2;
		}
	}

	T1[0] = obj1->worldPos.x;		T1[1] = obj1->worldPos.y;		T1[2] = obj1->worldPos.z;
	T2[0] = obj2->worldPos.x;		T2[1] = obj2->worldPos.y;		T2[2] = obj2->worldPos.z;

	RAPID_Collide_trans(R1, T1, scale1, depl.vals, obj1->GetMesh()->rapid, R2, T2, scale2, nul.vals, obj2->GetMesh()->rapid, RAPID_ALL_CONTACTS);

	deplCOL *= RAPID_coeff;
	depl = deplCOL;

	if(RAPID_num_contacts)	return true;
	else					return false;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3testExactInter
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d H3d] I
int ZM3testExactInter(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3testExactInter ");
#endif

	int h3d2 = MMpull(m);
 	int h3d1 = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d1==NIL)||(h3d2==NIL))	{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)								{	MMset(m,0,NIL);		return 0;	}

    // Récupère l'obj1
	ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d1),0);
	if(node==NULL || node->type!=OBJ_TYPE_ID)	{	MMset(m,0,NIL);		return 0;	}

	ZObject	*obj1 = (ZObject*) node;
	if(obj1->IsMultiMeshes())					{	MMset(m,0,NIL);		return 0;	}

    // Récupère l'obj2
	node = (ZNode*) MMfetch(m,MTOP(h3d2),0);
	if(node==NULL || node->type!=OBJ_TYPE_ID)	{	MMset(m,0,NIL);		return 0;	}

	ZObject	*obj2 = (ZObject*) node;
	if(obj2->IsMultiMeshes())					{	MMset(m,0,NIL);		return 0;	}

	ZMesh	*mesh1, *mesh2;
	mesh1 = obj1->GetMesh();
	mesh2 = obj2->GetMesh();

	if(		mesh1==NULL || mesh1->rapidCreated==false 
		||	mesh2==NULL || mesh2->rapidCreated==false )		{	MMset(m,0,NIL);		return 0;	}

	if(DetectInter(obj1, obj2))		MMset(m,0,0);
	else							MMset(m,0,NIL);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3testExactColl
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d H3d [F F F]] [F F F]
int ZM3testExactColl(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3testExactColl ");
#endif

	int vec  = MMpull(m);
	int h3d2 = MMpull(m);
 	int h3d1 = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d1==NIL)||(h3d2==NIL)||(vec==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)								{	MMset(m,0,NIL);		return 0;	}

    // Récupère l'obj1
	ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d1),0);
	if(node==NULL || node->type!=OBJ_TYPE_ID)	{	MMset(m,0,NIL);		return 0;	}
	ZObject	*obj1 = (ZObject*) node;
	if(obj1->IsMultiMeshes())					{	MMset(m,0,NIL);		return 0;	}

    // Récupère l'obj2
	node = (ZNode*) MMfetch(m,MTOP(h3d2),0);
	if(node==NULL || node->type!=OBJ_TYPE_ID)	{	MMset(m,0,NIL);		return 0;	}
	ZObject	*obj2 = (ZObject*) node;
	if(obj2->IsMultiMeshes())					{	MMset(m,0,NIL);		return 0;	}

	ZVector3	transl;
	transl.x =  MTOF(MMfetch(m,MTOP(vec),0)) / 100.0f;
	transl.y =  MTOF(MMfetch(m,MTOP(vec),1)) / 100.0f;
	transl.z = -MTOF(MMfetch(m,MTOP(vec),2)) / 100.0f;

	ZMatrix		matx;

	if(scene->activeCam)
	{
		matx = scene->activeCam->cameraMatx;
		matx._14 = matx._24 = matx._34 = 0.0f;
		matx._41 = matx._42 = matx._42 = 0.0f;
		transl *= matx;
	}
	else
	{
		MMset(m,0,NIL);
		return 0;
	}


	ZMesh	*mesh1, *mesh2;
	mesh1 = obj1->GetMesh();
	mesh2 = obj2->GetMesh();

	if(		mesh1==NULL || mesh1->rapidCreated==false 
		||	mesh2==NULL || mesh2->rapidCreated==false )		{	MMset(m,0,NIL);		return 0;	}

	if(DetectCollide(obj1, obj2, transl))
	{
		MMpull(m);

		// Collision en translation
		if(RAPID_is_contact_trans==1)
		{
			transl *= 100.0f;
			matx.Inverse();
			transl *= matx;

			if(MMpush(m,FTOM(transl.x)))		return MERRMEM;
			if(MMpush(m,FTOM(transl.y)))		return MERRMEM;
			if(MMpush(m,FTOM(-transl.z)))		return MERRMEM;
			if(MMpush(m,3*2))					return MERRMEM;

			int r;
			if(r=MBdeftab(m))					return r;
		}
		else
		// Prime intersection
		{
			if(MMpush(m,FTOM(0)))				return MERRMEM;
			if(MMpush(m,FTOM(0)))				return MERRMEM;
			if(MMpush(m,FTOM(0)))				return MERRMEM;
			if(MMpush(m,3*2))					return MERRMEM;

			int r;
			if(r=MBdeftab(m))					return r;
		}
	}
	else
		MMset(m,0,NIL);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;
}














///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////																											   ////
///												GESTION DES ANIMATIONS												///
////																											   ////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

int M3recBoneAnimKey(ZNode *node, ZNode *bone, float key, int flag, int first,ZObject *avatar,ZScene *scene)
{

		if(node==NULL)		return -1;
		if((node->type==ANI_TYPE_ID)&&(bone!=NULL)&&(bone->type == BON_TYPE_ID))
		{
			ZAnim	*anim = (ZAnim*) node;
			ZPRS	*prs = NULL;
			ZBone *curBone = (ZBone*)bone ;
			prs = curBone->GetPRS();

		//	MMechostr(1,"animation courante : % s \n",anim->name.c_str()) ;
			// On applique la key d'animation
			anim->putAnimBoneKey(prs, key, flag,avatar->GetMesh());
				
		}
		if((!first)&&(node->next!=NULL))
		{
			// On réactualise la position du noeud du pere
			
			if(M3recBoneAnimKey(node->next, bone, key, flag, 0,avatar,scene))			return -1;
		}
		if(node->son!=NULL)
		{
			if(M3recBoneAnimKey(node->son, node, key, flag, 0,avatar,scene))		return -1;

		}
		return 0;
} 

//////////////////////////////////////////////////////////////////////////////////////////////
///		FONCTIONS POUR ZM3setAnimKey
//////////////////////////////////////////////////////////////////////////////////////////////
int M3DrecAnimKey(ZNode *node, ZNode *pere, float key, int flag, int first)
{
	if(node==NULL)		return -1;
	if((node->type==ANI_TYPE_ID)&&(pere!=NULL))
	{
		ZAnim	*anim = (ZAnim*) node;
		ZPRS	*prs = NULL;

		prs = ((ZNodeGraph*)pere)->GetPRS();
		
		anim->putAnimKey(prs, key, flag);
	}
	if((!first)&&(node->next!=NULL))
    {
		if(M3DrecAnimKey(node->next, pere, key, flag, 0))			return -1;
    }

	if(node->son!=NULL)
    {
		if(M3DrecAnimKey(node->son, node, key, flag, 0))			return -1;
    }

	return 0;
}

// M3DsetAnimKey
int M3DsetSKLAnimKey(ZNode *node, float key, int flag,ZObject *avatar,ZScene *scene)
{
	return M3recBoneAnimKey(node,NULL, key,flag,1,avatar,scene);
}


// M3DsetAnimKey
int M3DsetAnimKey(ZNode *node, float key, int flag)
{
	return M3DrecAnimKey(node, NULL, key, flag, 1);
}

//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3setAnimKey
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d I] I
int ZM3setAnimKey(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3setAnimKey ");
#endif


	int key  = MMpull(m);
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL)||(key==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)								{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL)								{	MMset(m,0,NIL);		return 0;	}

	int p = M3DsetAnimKey(node, MTOI(key), -1);

	MMset(m,0,ITOM(p));
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}

//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3setSKLAnimKey
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d H3d I] I
int ZM3setSKLAnimKey(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3setAnimKey ");
#endif

	int key  = MMpull(m);
	int mesh = MMpull(m);
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL)||(mesh==NIL)||(key==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)								{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL)								{	MMset(m,0,NIL);		return 0;	}
	if(node->type != BON_TYPE_ID )              {	MMset(m,0,NIL);		return 0;	}

	ZBone		*curBone = (ZBone*) node;

	ZNode	*avatarNode = (ZNode*) MMfetch(m,MTOP(mesh),0);
	if(avatarNode == NULL)					{	MMset(m,0,NIL);		return 0;	}
	if(avatarNode->type != OBJ_TYPE_ID )          {	MMset(m,0,NIL);		return 0;	}

	ZObject	*avatar;
	ZArray <ZMatrix> tempPrev ;
	ZArray <ZMatrix> tempNext ;
	ZArray <ZMatrix> temp ;

	float  mat[16] ;

	if(avatarNode->type==OBJ_TYPE_ID)
	{
		avatar = ((ZObject*)avatarNode);
	}	

	if(curBone->bones.Size() == 0 ) {	MMset(m,0,NIL);		return 0;	}

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	///////////////////////////////////////       Matrice à l'entrée   /////////////////////////////////////////////
	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	for(int k = 0;k<curBone->bones.Size();k++)
	{
		if((key == 2 && curBone->isAnimated == false))
		{
			tempPrev.Add(ComputeWorldMatrix(curBone->bones[k])) ;
			curBone->bones[k]->iniMat = tempPrev[k] ;
		}
		
		else
		{
			tempPrev.Add(curBone->bones[k]->iniMat) ;
		}
		
	}
	
	int p = M3DsetSKLAnimKey(node, MTOI(key), -1,avatar,scene);

    avatar->GetMesh()->Position	= cgGetNamedParameter(avatar->GetMesh()->cgVertexProgram, "IN.Position");
	avatar->GetMesh()->Normal		= cgGetNamedParameter(avatar->GetMesh()->cgVertexProgram, "IN.Normal");
	avatar->GetMesh()->Weights		= cgGetNamedParameter(avatar->GetMesh()->cgVertexProgram, "IN.Weights");
	avatar->GetMesh()->Color	= cgGetNamedParameter(avatar->GetMesh()->cgVertexProgram, "IN.Color");
	avatar->GetMesh()->Indices		= cgGetNamedParameter(avatar->GetMesh()->cgVertexProgram, "IN.Indices");
	avatar->GetMesh()->TexCoord0		= cgGetNamedParameter(avatar->GetMesh()->cgVertexProgram, "IN.TexCoord0");
	avatar->GetMesh()->T		= cgGetNamedParameter(avatar->GetMesh()->cgVertexProgram, "IN.T");
	avatar->GetMesh()->S		= cgGetNamedParameter(avatar->GetMesh()->cgVertexProgram, "IN.S");
	avatar->GetMesh()->SxT		= cgGetNamedParameter(avatar->GetMesh()->cgVertexProgram, "IN.SxT");
	avatar->GetMesh()->WorldViewProj	= cgGetNamedParameter(avatar->GetMesh()->cgVertexProgram, "WorldViewProj");
	avatar->GetMesh()->ModelViewProj	= cgGetNamedParameter(avatar->GetMesh()->cgVertexProgram, "ModelViewProj");
	avatar->GetMesh()->ModelViewInverseProj	= cgGetNamedParameter(avatar->GetMesh()->cgVertexProgram, "ModelViewInverseProj");
	avatar->GetMesh()->AvaViewProj	= cgGetNamedParameter(avatar->GetMesh()->cgVertexProgram, "AvaViewProj");
	avatar->GetMesh()->Bones	= cgGetNamedParameter(avatar->GetMesh()->cgVertexProgram, "Bones");

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	///////////////////////////////////////       Matrice à la sortie    /////////////////////////////////////////////
	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////

		for( k = 0;k<curBone->bones.Size();k++)
		{
			
			tempNext.Add(ComputeWorldMatrix(curBone->bones[k])) ;
			ZMatrix inv = tempPrev[k];
			inv.Inverse() ;

			temp.Add(tempNext[k] * inv);
		
			mat[0] = temp[k]._11 ;mat[1] = temp[k]._12 ;mat[2] = temp[k]._13 ;mat[3] = temp[k]._14 ;
			mat[4] = temp[k]._21 ;mat[5] = temp[k]._22 ;mat[6] = temp[k]._23 ;mat[7] = temp[k]._24 ;
			mat[8] = temp[k]._31 ;mat[9] = temp[k]._32 ;mat[10] = temp[k]._33 ;mat[11] = temp[k]._34 ;
			mat[12] = temp[k]._31 ;mat[13] = temp[k]._32 ;mat[14] = temp[k]._33 ;mat[15] = temp[k]._34 ;

			CGparameter CGparam_currentMatrix = cgGetArrayParameter( avatar->GetMesh()->Bones, k );
			cgGLSetMatrixParameterfr( CGparam_currentMatrix, mat);
		}

		curBone->isAnimated = true ;
		if(curBone->bones[0]->isAnimed == true) {avatar->isAvatar = true ;}
		else { avatar->isAvatar = false  ;}
		scene->skinModified = true ;
	

	MMset(m,0,ITOM(1));


	return 0;
}

//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3setAnimKeyF
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d F] I
int ZM3setAnimKeyF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3setAnimKeyF ");
#endif
	int key  = MMpull(m);
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL)||(key==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)								{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL)								{	MMset(m,0,NIL);		return 0;	}

	int p = M3DsetAnimKey(node, MTOF(key), -1);

	MMset(m,0,ITOM(p));
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		FONCTIONS POUR ZM3setAnimKey2
//////////////////////////////////////////////////////////////////////////////////////////////
int M3DrecAnimKey2(ZNode *node, ZNode *pere, float key1, float key2, float rate, int flag, int first)
{
	if(node==NULL)		return -1;

	if((node->type==ANI_TYPE_ID)&&(pere!=NULL))
	{
		ZAnim	*anim = (ZAnim*) node;
		ZPRS	*prs = NULL;

		prs = ((ZNodeGraph*)pere)->GetPRS();

		anim->putAnimKeyInterp(prs, key1, key2, rate, flag);
	}
	
	if((!first)&&(node->next!=NULL))
    {
		if(M3DrecAnimKey2(node->next, pere, key1, key2, rate, flag, 0))		return -1;
    }

	if(node->son!=NULL)
    {
		if(M3DrecAnimKey2(node->son, node, key1, key2, rate, flag, 0))		return -1;
    }
  
	return 0;
}


int M3DsetAnimKey2(ZNode *node, float key1, float key2, float rate, int flag)
{
	return M3DrecAnimKey2(node, NULL, key1, key2, rate, flag, 1);
}


//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3setAnimKey2
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d I I I] I
int ZM3setAnimKey2(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3setAnimKey2 ");
#endif
	int rate = MMpull(m);
	int key2 = MMpull(m);
	int key1 = MMpull(m);
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL)||(key1==NIL)||(key2==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)												{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL)												{	MMset(m,0,NIL);		return 0;	}

	rate = MTOI(rate) & 255;

	int p = M3DsetAnimKey2(node, MTOI(key1), MTOI(key2), ((float)rate)/CONST_VAL8, -1);

	MMset(m,0,ITOM(p));
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
   return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3setAnimKey2F
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d F F F] I
int ZM3setAnimKey2F(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3setAnimKey2F ");
#endif

	int rate = MMpull(m);
	int key2 = MMpull(m);
	int key1 = MMpull(m);
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL)||(key1==NIL)||(key2==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)												{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL)												{	MMset(m,0,NIL);		return 0;	}

	int p = M3DsetAnimKey2(node, MTOF(key1), MTOF(key2), MTOF(rate), -1);

	MMset(m,0,ITOM(p));

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

    return 0;
}




//////////////////////////////////////////////////////////////////////////////////////////////
///		FONCTIONS POUR ZM3applyAnimKey
//////////////////////////////////////////////////////////////////////////////////////////////
ZNode*	findObj3d(ZNode *node, string name)
{
	while(node!=NULL)
	{
		if(node->name==name)		return node;
		node = node->next;
	}
	return NULL;
}


int M3DrecApplyAnimKey(ZNode *nodeA, ZNode *nodeT, float key, int flag)
{
	if(nodeA==NULL)		return -1;

	ZNode *node;
	if( (node=findObj3d(nodeT,nodeA->name)) != NULL )
	{
		if(nodeA->type==ANI_TYPE_ID)
		{
			ZAnim	*anim = (ZAnim*) nodeA;
			ZPRS	*prs = NULL;

			prs = ((ZNodeGraph*)node)->GetPRS();

			anim->putAnimKey(prs, key, flag);
		}

		if(nodeA->son!=NULL)
		{
			if(M3DrecApplyAnimKey(nodeA->son, node->son, key, flag))	return -1;
		}
	}

	if(nodeA->next!=NULL)
    {
		if(M3DrecApplyAnimKey(nodeA->next, nodeT, key, flag))		return -1;
    }
	return 0;
}


int M3DapplyAnimKey(ZNode *nodeA, ZNode *nodeT, float key, int flag)
{
	if((flag & ANIM_TOP) && (nodeA->type==ANI_TYPE_ID))
	{
		ZAnim	*anim = (ZAnim*) nodeA;
		ZPRS	*prs = NULL;

		prs = ((ZNodeGraph*)nodeT)->GetPRS();
		
		anim->putAnimKey(prs, key, flag);
	}

	return M3DrecApplyAnimKey(nodeA->son, nodeT->son, key, flag);
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3applyAnimKey
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d H3d I I] I
int ZM3applyAnimKey(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3applyAnimKey ");
#endif

	int flag = MMpull(m);
	int key  = MMpull(m);
	int top  = MMpull(m);
	int ani  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(ani==NIL)||(top==NIL)||(key==NIL))					{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)														{	MMset(m,0,NIL);		return 0;	}

    ZNode	*nodeA = (ZNode*) MMfetch(m,MTOP(ani),0);
	if(nodeA==NULL)														{	MMset(m,0,NIL);		return 0;	}

    ZNode	*nodeT = (ZNode*) MMfetch(m,MTOP(top),0);
	if(nodeT==NULL)														{	MMset(m,0,NIL);		return 0;	}

	int p = M3DapplyAnimKey(nodeA, nodeT, MTOI(key), MTOI(flag));
    
	MMset(m,0,ITOM(p));

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

   return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3applyAnimKeyF
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d H3d F I] I
int ZM3applyAnimKeyF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3applyAnimKeyF ");
#endif

	int flag = MMpull(m);
	int key  = MMpull(m);
	int top  = MMpull(m);
	int ani  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(ani==NIL)||(top==NIL)||(key==NIL))					{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)														{	MMset(m,0,NIL);		return 0;	}

    ZNode	*nodeA = (ZNode*) MMfetch(m,MTOP(ani),0);
	if(nodeA==NULL)														{	MMset(m,0,NIL);		return 0;	}

    ZNode	*nodeT = (ZNode*) MMfetch(m,MTOP(top),0);
	if(nodeT==NULL)														{	MMset(m,0,NIL);		return 0;	}

	int p = M3DapplyAnimKey(nodeA, nodeT, MTOF(key), MTOI(flag));
    
	MMset(m,0,ITOM(p));
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
    return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		FONCTIONS POUR ZM3applyAnimKey2
//////////////////////////////////////////////////////////////////////////////////////////////
bool M3DanimKey2(ZAnim *ani0, ZAnim *ani1, ZPRS *prs, float frame0, float frame1, float rate, int flag)
{
	if(prs==NULL)		return false;


	int length0 = ani0->getLength();
	int length1 = ani1->getLength();
	
	if( (frame0<0) || (frame0>length0) || (frame1<0) || (frame1>length1) )		return false;


	///////////////////////////
	// ----> POSITION <----- //
	///////////////////////////

	if(flag & ANIM_POS)
	{
		ZVector3	pos0, pos1;

		//--- Position 0 ---//

		if(ani0->listPos.size())
		{
				 if(frame0 >= ani0->maxKeyPos)			pos0 = ani0->listPos[ani0->listPos.size()-1].pos;
			else if(frame0 <= ani0->minKeyPos)			pos0 = ani0->listPos[0].pos;
			else
			{
				for(int i=0; i<ani0->listPos.size() && frame0>ani0->listPos[i].key; i++);

				if(ani0->listPos[i].key == frame0)		pos0 = ani0->listPos[i].pos;
				else
				{
					float t = ((float)(frame0-ani0->listPos[i-1].key)) / ((float)(ani0->listPos[i].key-ani0->listPos[i-1].key));
					pos0 = t*ani0->listPos[i].pos + (1-t)*ani0->listPos[i-1].pos;
				}
			}
		}
		// dans l'ultime cas où il n'y a pas d'animation..
		else
			pos0 = prs->GetPos();


		//--- Position 1 ---//
		
		if(ani1->listPos.size())
		{
				 if(frame1 >= ani1->maxKeyPos)			pos1 = ani1->listPos[ani1->listPos.size()-1].pos;
			else if(frame1 <= ani1->minKeyPos)			pos1 = ani1->listPos[0].pos;
			else							
			{
				for(int i=0; i<ani1->listPos.size() && frame1>ani1->listPos[i].key; i++);

				if(ani1->listPos[i].key == frame1)		pos1 = ani1->listPos[i].pos;
				else
				{
					float t = ((float)(frame1-ani1->listPos[i-1].key)) / ((float)(ani1->listPos[i].key-ani1->listPos[i-1].key));
					pos1 = t*ani1->listPos[i].pos + (1-t)*ani1->listPos[i-1].pos;
				}
			}
		}
		// dans l'ultime cas où il n'y a pas d'animation..
		else
			pos1 = prs->GetPos();


		// On interpole entre les deux positions au taux de 'rate'
		prs->SetPos( rate*pos1 + (1-rate)*pos0 );	
	}


	///////////////////////////
	// ----> ROTATION <----- //
	///////////////////////////

	if(flag & ANIM_ANG)
	{
		ZQuat	rot0, rot1;
		
		//--- Rotation 0 ---//

		if(ani0->listRot.size())
		{
				 if(frame0 >= ani0->maxKeyRot)			rot0 = ani0->listRot[ani0->listRot.size()-1].rot;
			else if(frame0 <= ani0->minKeyRot)			rot0 = ani0->listRot[0].rot;
			else
			{
				for(int i=0; i<ani0->listRot.size() && frame0>ani0->listRot[i].key; i++);

				if(ani0->listRot[i].key == frame0)		rot0 = ani0->listRot[i].rot;
				else
				{
					float t = ((float)(frame0-ani0->listRot[i-1].key)) / ((float)(ani0->listRot[i].key-ani0->listRot[i-1].key));
					rot0 = quatSlerp(ani0->listRot[i-1].rot, ani0->listRot[i].rot, t);
				}
			}
		}
		// dans l'ultime cas où il n'y a pas d'animation..
		else
		{
			// calcul du quaternion de position de PRS
			ZMatrix	matx;

			matx  = prs->mat;
			matx.SetTrans(0.0f, 0.0f, 0.0f);
			matx *= ScaleMatrix(1.0f / prs->GetScale());
			
			rot0 = matx.GetQuat();
		}

		
		//--- Rotation 1 ---//

		if(ani1->listRot.size())
		{
				 if(frame1 >= ani1->maxKeyRot)			rot1 = ani1->listRot[ani1->listRot.size()-1].rot;
			else if(frame1 <= ani1->minKeyRot)			rot1 = ani1->listRot[0].rot;
			else
			{
				for(int i=0; i<ani1->listRot.size() && frame1>ani1->listRot[i].key; i++);

				if(ani1->listRot[i].key == frame1)		rot1 = ani1->listRot[i].rot;
				else
				{
					float t = ((float)(frame1-ani1->listRot[i-1].key)) / ((float)(ani1->listRot[i].key-ani1->listRot[i-1].key));
					rot1 = quatSlerp(ani1->listRot[i-1].rot, ani1->listRot[i].rot, t);
				}
			}
		}
		// dans l'ultime cas où il n'y a pas d'animation..
		else
		{
			// calcul du quaternion de position de PRS
			ZMatrix	matx;

			matx  = prs->mat;
			matx.SetTrans(0.0f, 0.0f, 0.0f);
			matx *= ScaleMatrix(1.0f / prs->GetScale());
			
			rot1 = matx.GetQuat();
		}

		
		// Interpolation finale entre les deux quaternions
		prs->SetAng( (quatSlerp(rot0, rot1, rate)).GetAnglesYXZ() );
	}
	

	return true;
}


int M3DrecApplyAnimKey2(ZNode *nodeA0, ZNode *nodeA1, ZNode *nodeT, float key0, float key1, float rate, int flag)
{
	if(nodeA0==NULL)		return -1;
	
	ZNode	*nodeC1, *nodeC2;

	if( ((nodeC1=findObj3d(nodeA1,nodeA0->name))!=NULL) && ((nodeC2=findObj3d(nodeT,nodeA0->name))!=NULL) )
	{
		if((nodeA0->type==ANI_TYPE_ID)&&(nodeC1->type==ANI_TYPE_ID))
		{
			ZAnim	*anim0 = (ZAnim*) nodeA0;
			ZAnim	*anim1 = (ZAnim*) nodeC1;
			ZPRS	*prs = NULL;

			prs = ((ZNodeGraph*)nodeC2)->GetPRS();
			
			M3DanimKey2(anim0, anim1, prs, key0, key1, rate, flag);
		}

		if((nodeA0->son!=NULL)&&(nodeC1->son!=NULL))
		{
			if(M3DrecApplyAnimKey2(nodeA0->son, nodeC1->son, nodeC2->son, key0,key1, rate, flag))		return -1;
		}
	}
	
	if(nodeA0->next!=NULL)
    {
		if(M3DrecApplyAnimKey2(nodeA0->next, nodeA1, nodeT, key0, key1, rate, flag))		return -1;
    }

	return 0;
}


int M3DapplyAnimKey2(ZNode *nodeA0, ZNode *nodeA1, ZNode *nodeT, float key0, float key1, float rate, int flag)
{
	if( (flag&ANIM_TOP) && (nodeA0->type==ANI_TYPE_ID)&&(nodeA1->type==ANI_TYPE_ID) )
	{
		ZAnim	*anim0 = (ZAnim*) nodeA0;
		ZAnim	*anim1 = (ZAnim*) nodeA1;
		ZPRS	*prs = NULL;

		prs = ((ZNodeGraph*)nodeT)->GetPRS();

		M3DanimKey2(anim0, anim1, prs, key0, key1, rate, flag);
	}

	return M3DrecApplyAnimKey2(nodeA0->son, nodeA1->son, nodeT->son, key0, key1, rate, flag);
}


//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3applyAnimKey2
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d H3d H3d I I I I] I
int ZM3applyAnimKey2(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3applyAnimKey2 ");
#endif

	int flag = MMpull(m);
	int rate = MMpull(m);
	int key1 = MMpull(m);
	int key0 = MMpull(m);
	int top  = MMpull(m);
	int ani1 = MMpull(m);
	int ani0 = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(ani0==NIL)||(ani1==NIL)||(top==NIL)||(key0==NIL)||(key1==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)														{	MMset(m,0,NIL);		return 0;	}

    ZNode	*nodeA0 = (ZNode*) MMfetch(m,MTOP(ani0),0);
	if(nodeA0==NULL)													{	MMset(m,0,NIL);		return 0;	}

	ZNode	*nodeA1 = (ZNode*) MMfetch(m,MTOP(ani1),0);
	if(nodeA1==NULL)													{	MMset(m,0,NIL);		return 0;	}    

	ZNode	*nodeT = (ZNode*) MMfetch(m,MTOP(top),0);
	if(nodeT==NULL)														{	MMset(m,0,NIL);		return 0;	}


	rate = MTOI(rate) & 255;

	int p = M3DapplyAnimKey2(nodeA0, nodeA1, nodeT, MTOI(key0), MTOI(key1), ((float)rate)/CONST_VAL8, MTOI(flag));

	MMset(m,0,ITOM(p));
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
    return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3applyAnimKey2F
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d H3d H3d F F F I] I
int ZM3applyAnimKey2F(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3applyAnimKey2F ");
#endif

	int flag = MMpull(m);
	int rate = MMpull(m);
	int key1 = MMpull(m);
	int key0 = MMpull(m);
	int top  = MMpull(m);
	int ani1 = MMpull(m);
	int ani0 = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(ani0==NIL)||(ani1==NIL)||(top==NIL)||(key0==NIL)||(key1==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)														{	MMset(m,0,NIL);		return 0;	}

    ZNode	*nodeA0 = (ZNode*) MMfetch(m,MTOP(ani0),0);
	if(nodeA0==NULL)													{	MMset(m,0,NIL);		return 0;	}

	ZNode	*nodeA1 = (ZNode*) MMfetch(m,MTOP(ani1),0);
	if(nodeA1==NULL)													{	MMset(m,0,NIL);		return 0;	}    

	ZNode	*nodeT = (ZNode*) MMfetch(m,MTOP(top),0);
	if(nodeT==NULL)														{	MMset(m,0,NIL);		return 0;	}

	int p = M3DapplyAnimKey2(nodeA0, nodeA1, nodeT, MTOF(key0), MTOF(key1), MTOF(rate), MTOI(flag));

	MMset(m,0,ITOM(p));
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
    return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		FONCTIONS POUR ZM3getAnimLength
//////////////////////////////////////////////////////////////////////////////////////////////
int M3DrecAnimLength(ZNode *node, int max, int first)
{
	if(node==NULL)		return -1;

	if(node->type==ANI_TYPE_ID)
	{
		ZAnim	*anim= (ZAnim*)node;
		if(max < anim->getLength())		max = anim->getLength();
	}

	if((!first)&&(node->next!=NULL))	max = M3DrecAnimLength(node->next, max, 0);

	if(node->son!=NULL)			max = M3DrecAnimLength(node->son, max, 0);

	return max;
}

int M3DgetAnimLength(ZNode *node)
{
	return M3DrecAnimLength(node, 0, 1);
}


//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getAnimLength
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d] I
int ZM3getAnimLength(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getAnimLength ");
#endif

	int ani  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(ani==NIL))					{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)								{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(ani),0);
	if(node==NULL)								{	MMset(m,0,NIL);		return 0;	}

    int p = M3DgetAnimLength(node);
    
	MMset(m,0,ITOM(p));
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
    return 0;
}





///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////    GESTION DES BONES ///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////  ZM3getBone 
///////////////////////////////  ZM3createBone
///////////////////////////////  ZM3setBone
///////////////////////////////  ZM3deleteBone
///////////////////////////////  ZM3ShowSkelet
///////////////////////////////  ZM3getBoneMesh
///////////////////////////////  ZM3getBoneFather
///////////////////////////////  ZM3setBoneFather
///////////////////////////////  ZM3getBoneNumberOfChildren
///////////////////////////////  ZM3getBoneName
///////////////////////////////  ZM3setBoneName
///////////////////////////////  ZM3showBone
///////////////////////////////  ZM3hideBone


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////  Pour la gestion des Skelet //////////////////////////////////////////////////////////////////
///////////////////////////////  ///////////////////////////////  ///////////////////////////////  ////////////////
///////////////////////////////  ZM3getSKL
///////////////////////////////  ZM3setSKL
///////////////////////////////  ZM3showSKL
///////////////////////////////  ZM3getSKLName
///////////////////////////////  ZM3setSKLName
///////////////////////////////  ZM3hideSKL
///////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////   ZM3getBone   //////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d S] H3d
int ZM3getBone(mmachine m)
{


	int name = MMpull(m);
    int s3d  = MMget(m,0);
    
    if((name==NIL)||(s3d==NIL))		{	MMset(m,0,NIL);		return 0;	}

    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

	ZNode	*curNode;
	curNode = NULL;
	GetFirstRecentName(scene->World, &curNode, string(MMstartstr(m,MTOP(name))) );

	if(curNode==NULL)				{	MMset(m,0,NIL);		return 0;	}

	int	h3d = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)curNode);

	if(h3d!=NIL)	h3d = PTOM(h3d);
	MMset(m,0,h3d);
	
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}


//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3renameBone
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d S] I
int ZM3renameBone(mmachine m)
{

    int name = MMpull(m);
    int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL)||(name==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL/*||node->type==MSH_TYPE_ID*/)					{	MMset(m,0,NIL);		return 0;	}

	node->SetName((char*)MMstartstr(m,MTOP(name)));


	MMset(m,0,0);
	return 0;
}
//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getBoneInfo
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d] I
int ZM3getBoneInfo(mmachine m)
{

    int s3d  = MMget(m,0);

    if(s3d==NIL)													{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)													{	MMset(m,0,NIL);		return 0;	}


	int type = 2 ;
	
/////////////// Info sur les skelet  ////////////////////////////////


	for(int i = 0 ;i < scene->World->sklList.Size() ; i++ )
	{
	
	}


	return 0;
}

//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getBoneFather
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d] H3d
int ZM3getBoneFather(mmachine m)
{

    int h3d = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL||node->type==BON_TYPE_ID)				{	MMset(m,0,NIL);		return 0;	}

    node = node->father;

	if((node->type>MAX_NODE_SCENE)||(node==NULL))		{	MMset(m,0,NIL);		return 0;	}

	h3d = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)node);

	if(h3d!=NIL)	h3d = PTOM(h3d);
	MMset(m,0,h3d);
	
	return 0;
}
//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getBoneNumberOfChildren
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d] I
int ZM3getBoneNumberOfChildren(mmachine m)
{

 	int bon = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(bon==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZBone	*bone = (ZBone*) MMfetch(m,MTOP(bon),0);
	if(bone==NULL)					{	MMset(m,0,NIL);		return 0;	}

	int value = 0;

	value = bone->numberOfChild ;

	MMset(m,0,ITOM(value));
	
	return 0;
}



/////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////// ZM3setSKL //////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////  ZM3ShowSkelet  ////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

/// fun [S3d H3d H3d ] I
int ZM3ShowSkelet(mmachine m)
{
   
	int skl = MMpull(m) ;
    int h3d = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL))		{MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}
	ZNode	*curNode = (ZNode*) MMfetch(m, MTOP(h3d), 0);
	if(curNode==NULL)					{	MMset(m,0,NIL);		return 0;	}
	ZSkelet  *curSKL = (ZSkelet*) MMfetch(m, MTOP(skl), 0);
	if(curNode==NULL)					{	MMset(m,0,NIL);		return 0;	}

	int type = 2 ;

if(curSKL->BonesOfSkelet.Size())
{


	// On va associer un mesh au bones afin d'afficher le skelet dans le rendu OpenGL

	if(curNode == NULL)
	{

	}
	else
	{

		if(h3d == NIL)
		{

			ZObject		*curObj = (ZObject*) curNode;
			h3d = createH3D(m, (int)curObj, MTOP(MMfetch(m,MTOP(s3d),1)));


			for (int j=0;j<curSKL->BonesOfSkelet.Size();j++)
			{
			

				/*
				ZObject		*newObj = new ZObject((int)scene);
				if (newObj==NULL)		{MMechostr(1,"NewObj est null!!\n") ;	MMset(m,0,NIL);		return 0;	}
				newObj->InsertAsChildOf(scene->World->boneList[j]->father);
				h3d = createH3D(m, (int)newObj, MTOP(MMfetch(m,MTOP(s3d),1)));

				// Copie du mesh également...
					MMechostr(1,"L'objet n'est pas multimesh\n");
					ZMesh	*msh ;
					ZMesh	*curMsh = NULL;
					if(msh)
					{
						MMechostr(1,"Le mesh de l'objet crée n'est pas nul\n") ;
						curMsh = new ZMesh((int)scene, msh->NbVerts, msh->NbFaces);
						if(curMsh==NULL)		{	MMset(m,0,NIL);		return 0;	}
						MMechostr(1,"Le nouveau mesh de l'objet crée n'est pas nul\n") ;
						scene->MshList.Add(curMsh);


						createH3D(m, (int)curMsh, MTOP(MMfetch(m,MTOP(s3d),1)));

						newObj->SetMesh(curMsh);
						newObj->PRS = scene->World->boneList[j]->PRS ;

						// On set le node du mesh

						newObj->father->son->posX = newObj->PRS.GetPos().x ;
						newObj->father->son->posY = newObj->PRS.GetPos().y ;
						newObj->father->son->posZ = newObj->PRS.GetPos().z ;
					
						// On met l'objet courant associé au bone
			
						scene->World->boneList[j]->BoneObject = newObj ;


					

						// Ajout au liste d'objet
						scene->World->objList.Add(newObj) ;

						// Flag de modifications de la scene

						curMsh->hasTopoChanged		= true;
						curMsh->hasViewChanged		= true;
						newObj->visible				= true;
						scene->updateGraphList		= true;
						scene->textureModified		= true;
						scene->materialModified		= true;
						scene->meshModified			= true;
				
					}*/
				}
			
		}
		else
		{
		
			
			for (int j=0;j<curSKL->BonesOfSkelet.Size();j++)
			{
			
				
				// L'objectif est de rétablir la hierarchie cassée ici par le newObj->InsertAsChild(scene->World) ;
				ZObject		*curObj = (ZObject*) curNode;
				ZObject		*newObj = new ZObject((int)scene);
				if (newObj==NULL)		{	MMset(m,0,NIL);		return 0;	}
				newObj->InsertAsChildOf(curSKL->BonesOfSkelet[j]->father);
				newObj->SetName((curObj->name)+(curSKL->BonesOfSkelet[j]->name));

				h3d = createH3D(m, (int)newObj, MTOP(MMfetch(m,MTOP(s3d),1)));

				
				newObj->rangeMAX = curObj->rangeMAX;
				newObj->rangeMIN = curObj->rangeMIN;
				
				// Copie du mesh également...
				if(curObj->IsMultiMeshes()==false)
				{
					
					ZMesh	*msh = curObj->GetMesh();
					ZMesh	*curMsh = NULL;
					if(msh)
					{
					
						MMechostr(1,"Cas msh existe\n") ;

						curMsh = new ZMesh((int)scene, msh->NbVerts, msh->NbFaces);
						if(curMsh==NULL)		{	MMset(m,0,NIL);		return 0;	}
						scene->MshList.Add(curMsh);
						curMsh->name			  = msh->name+curSKL->BonesOfSkelet[j]->name;

					
						curMsh->dependency		  = msh->dependency;
						curMsh->displayListCreate = msh->displayListCreate;

						createH3D(m, (int)curMsh, MTOP(MMfetch(m,MTOP(s3d),1)));
						
						ZFace	*curFace, *face;
						
						for(int i=0; i<msh->Faces.size(); i++)
						{

							curFace = &(curMsh->Faces[i]);
							face	= &(msh->Faces[i]);

							curFace->initFace();
							curFace->SetMaterial(face->GetMaterial());

							curFace->SetVertsRef(face->VertRef[0], face->VertRef[1], face->VertRef[2]);
							curFace->dependency = face->dependency;

							curFace->UV1[0] = face->UV1[0];
							curFace->UV1[1] = face->UV1[1];
							curFace->UV1[2] = face->UV1[2];
							curFace->UV2[0] = face->UV2[0];
							curFace->UV2[1] = face->UV2[1];
							curFace->UV2[2] = face->UV2[2];

							curFace->clampU1 = face->clampU1;
							curFace->clampV1 = face->clampV1;
							curFace->clampU2 = face->clampU2;
							curFace->clampV2 = face->clampV2;
							curFace->index	= face->index;
						}
						

						ZVert	*curVert, *vert;
						for( i=0; i<msh->Verts.size(); i++)
						{

							curVert = &(curMsh->Verts[i]);
							vert	= &(msh->Verts[i]);

							curVert->color1 = vert->color1;
							curVert->color2 = vert->color2;
							curVert->Normal = vert->Normal;
							curVert->SetCoord(vert->x, vert->y, vert->z);
						}

						newObj->SetMesh(curMsh);
						newObj->PRS = curSKL->BonesOfSkelet[j]->PRS ;

						// On set le node du mesh

						newObj->father->son->posX = newObj->PRS.GetPos().x ;
						newObj->father->son->posY = newObj->PRS.GetPos().y ;
						newObj->father->son->posZ = newObj->PRS.GetPos().z ;
					
						// On met l'objet courant associé au bone
			
						curSKL->BonesOfSkelet[j]->BoneObject = newObj ;

						// Ajout au liste d'objet
						scene->World->objList.Add(newObj) ;

						// Flag de modifications de la scene

						curMsh->hasTopoChanged		= true;
						curMsh->hasViewChanged		= true;
						newObj->visible				= true;
						scene->updateGraphList		= true;
						scene->textureModified		= true;
						scene->materialModified		= true;
						scene->meshModified			= true;

					}
					
				}
				else
				{
					
					ZArray<ZMesh*>		*mshList  = curObj->GetMeshList();
					ZArray<float>		*rangeSQR = curObj->GetRangeSQRList();

					newObj->setFlagMulti(true);

					for(int i=0; i<rangeSQR->Size(); i++)		newObj->AddMeshInList((*mshList)[i], (*rangeSQR)[i]);
					
				}

				
			}
		}
	}
}


	MMset(m,0,ITOM(type));
	return 0;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////  Fonctions pour la récupération de la hierarchie  ////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

int M3recBoneHierarchy(ZNode *node,ZScene *scene,ZSkelet *curSKL)
{


	ZNode*		curNode;
	ZBone *fatherBone = (ZBone*)node ;

	curNode = node ;

	while(curNode != NULL)
	{

		if (curNode->type == BON_TYPE_ID)
		{

			ZPRS	*prs = NULL;
			ZBone *curBone = (ZBone*)curNode ;
			prs = curBone->GetPRS();

			curSKL->BonesOfSkelet.Add(curBone) ;
		}
		// Test of recursion
		if( curNode->next!= NULL )	
		{
			M3recBoneHierarchy(curNode->next, scene, curSKL);
		}
		curNode = curNode->son ;
	}


		return 0;
} 
/* $MS : Add a function to test if a vertex profile shader is valid */
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////       ZM3isShaderVertexProfileEnable   ////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// fun [] I
int ZM3isShaderVertexProfileEnable(mmachine m)
{
	int result = 0;
	CGprofile	cgVertexProfileTest;


	// First determine which vertex shader profile we will use, this will basically be
	// the first one we support.
	cgVertexProfileTest = cgGLGetLatestProfile(CG_GL_VERTEX);
	if (cgVertexProfileTest == CG_PROFILE_UNKNOWN || cgVertexProfileTest == CG_INVALID_ENUMERANT_ERROR)
	{
		result = 0;
		//MMset(m,0,ITOM(result));
		MMpush(m,ITOM(result)) ;
		return 0;
	}
    result = 1 ;
	//MMset(m, 0, ITOM(result));
	MMpush(m,ITOM(result)) ;
	return 0;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////       ZM3isShaderFragmentProfileEnable   ////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// fun [] I
/* $MS : Add a function to test if a fragment profile shader is valid */
int ZM3isShaderFragmentProfileEnable(mmachine m)
{
	int result = 0;
	CGprofile	cgFragmentProfileTest;


	// First determine which fragment shader profile we will use, this will basically be
	// the first one we support.
	cgFragmentProfileTest = cgGLGetLatestProfile(CG_GL_FRAGMENT);

	if (cgFragmentProfileTest == CG_PROFILE_UNKNOWN || cgFragmentProfileTest == CG_INVALID_ENUMERANT_ERROR)
	{
		result = 0;
		//MMset(m,0,ITOM(result));
		MMpush(m,ITOM(result)) ;
		return 0;
	}

    result = 1;
	//MMset(m, 0, ITOM(result));
	MMpush(m,ITOM(result)) ;
	return 0;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////       ZM3isShaderEnable   ////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// fun [] I
int ZM3isShaderEnable(mmachine m)
{
	int result = 0;

	/* $MS : Dyanmic construction of the test's shader */

	string v,f,v1,v2,v3 ;
	std::ostringstream oss;
	int test  = 26;	
	//$BLG - v5.22: Del
	CGcontext	cgContextTest;
	CGprogram	cgVertexProgramTest;
	CGprogram   cgFragmentProgramTest;
	CGprofile	cgVertexProfileTest;
	CGprofile   cgFragmentProfileTest;

	v1 = " struct appdata {float3 Position   : POSITION;    float3 Normal     : NORMAL;    float3 Color      : DIFFUSE;    float2 TexCoord0  : TEXCOORD0;    float3 S          : TEXCOORD1;    float3 T          : TEXCOORD2;    float3 SxT        : TEXCOORD3;    float4 Weights    : TEXCOORD4;    float4 Indices    : TEXCOORD5;};struct vpconn {    float4 HPosition : POSITION;    float4 TexCoord0 : TEXCOORD0;    float4 Color0    : COLOR0;};vpconn main(appdata IN,uniform float4x4 WorldViewProj,uniform float4x4 ModelViewProj,uniform float4x4 ModelViewInverseProj,uniform float4x4 AvaViewProj,uniform float3x4 Bones[";
	oss << test;
    v2 = oss.str();
	v3 = "],uniform float[7] attenuate_const,uniform float3 ambiant[7],uniform float3 diffuse[7],uniform float3 specular[7]){    vpconn OUT;    float4 tempPos = float4( 0.0, 0.0, 0.0, 0.0 );    tempPos.xyz = IN.Position.xyz;      tempPos.w = 1.0;    float i = IN.Indices.x;    float3x3 m;    m[0] = Bones[i][0].xyz;    m[1] = Bones[i][1].xyz;    m[2] = Bones[i][2].xyz;    float3 pos0 = mul(Bones[i], tempPos);    float3 normal0 = mul(m, IN.Normal);    i = IN.Indices.y;    m[0] = Bones[i][0].xyz;    m[1] = Bones[i][1].xyz;    m[2] = Bones[i][2].xyz;    float3 pos1 = mul(Bones[i], tempPos);    float3 normal1 = mul(m, IN.Normal);    float3 finalNormal = normalize(normal0 * IN.Weights.x + normal1 * IN.Weights.y);    float3 finalPos = float3( 0.0, 0.0, 0.0);    finalPos = (pos0 * IN.Weights.x) + (pos1 * IN.Weights.y);    OUT.TexCoord0.x = OUT.TexCoord0.y = 0.0 ;    OUT.TexCoord0.xy = IN.TexCoord0.xy;    float4 tempPos2 = float4( 0.0, 0.0, 0.0, 0.0 );    tempPos2.x = finalPos.x;    tempPos2.y = finalPos.y;    tempPos2.z = finalPos.z;    tempPos2.w = 1.0;    tempPos2 = mul(tempPos2,ModelViewProj) ;    tempPos2 = mul(WorldViewProj, tempPos2);    OUT.HPosition = tempPos2 ;     OUT.Color0.xyz = IN.Color.xyz ;    /*OUT.Color0.xyz = ambiant[0].xyz + ambiant[1].xyz + ambiant[2].xyz + ambiant[3].xyz + ambiant[4].xyz + ambiant[5].xyz + ambiant[6].xyz + 0.3;  */  OUT.Color0.w = 0.0 ;  return OUT;}";
	v = v1 + v2 + v3 ;
	f = "struct FragmentIn{ float4 color      : COLOR;   float2 texCoord   : TEXCOORD0;};struct FragmentOut{   float4 color      : COLOR;};FragmentOut main(FragmentIn In, uniform sampler2D decal){   FragmentOut Out;   Out.color.x = 0.0 ;   Out.color.y = 0.0 ;   Out.color.z = 0.0 ;   Out.color.w = 0.0 ;   Out.color = tex2D(decal, In.texCoord) ;  Out.color *= In.color;   return Out;}";


	// First determine which vertex shader profile we will use, this will basically be
	// the first one we support.
	
	cgVertexProfileTest = cgGLGetLatestProfile(CG_GL_VERTEX);
	cgFragmentProfileTest = cgGLGetLatestProfile(CG_GL_FRAGMENT);

	if (cgVertexProfileTest == CG_PROFILE_UNKNOWN || cgVertexProfileTest == CG_INVALID_ENUMERANT_ERROR)
	{
		result = 0;
		//MMset(m,0,ITOM(result));
		MMpush(m,ITOM(result)) ;
		return 0;
	}

	if (cgFragmentProfileTest == CG_PROFILE_UNKNOWN || cgFragmentProfileTest == CG_INVALID_ENUMERANT_ERROR)
	{
		result = 0;
		//MMset(m,0,ITOM(result));
		MMpush(m,ITOM(result)) ;
		return 0;
  }
  
   

   // Create our context for cg.
   cgContextTest = cgCreateContext();
   // Create the vertex shader.
  // cgVertexProgram = cgCreateProgramFromFile(cgContext, CG_SOURCE, "Cg/Copie de ogl_cg_skinningv28.cg",cgVertexProfile, "main", NULL);
   cgVertexProgramTest = cgCreateProgram(cgContextTest, CG_SOURCE, v.c_str(),cgVertexProfileTest, "main", NULL);
   // Create the fragment shader.
   //cgFragmentProgram = cgCreateProgramFromFile(cgContext, CG_SOURCE, "Cg/CgTextureFS.cg",cgFragmentProfile, "main", NULL);
   cgFragmentProgramTest = cgCreateProgram(cgContextTest, CG_SOURCE, f.c_str(),cgFragmentProfileTest, "main", NULL);

   // Error checking to see if the shaders loaded.
   if(!cgVertexProgramTest)
      {
	   MMechostr(1,"Hardware does not support vertex shaders!");
	   result = 0;
	   //MMset(m,0,ITOM(result));
	   MMpush(m,ITOM(result)) ;
	   return 0 ;
      }

   if(!cgFragmentProgramTest)
      {
		MMechostr(1,"Hardware does not support fragment shaders!");
		result = 0;
		//MMset(m,0,ITOM(result));
		MMpush(m,ITOM(result)) ;
		return 0 ;
		}

   // Load the vertex/fragment shaders into OpenGL.
   cgGLLoadProgram(cgVertexProgramTest);
   cgGLLoadProgram(cgFragmentProgramTest);

  //  cgDestroyProgram(cgVertexProgramTest);
	cgDestroyProgram(cgFragmentProgramTest);
	cgDestroyContext(cgContextTest);

    result = 1;
	//MMset(m, 0, ITOM(result));
	MMpush(m,ITOM(result)) ;
	return 0;
}





////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////   ZM3AttachMeshWithSKL   //////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/// fun [S3d H3d H3d] I
int ZM3AttachMeshWithSKL(mmachine m)
{

    int SKL = MMpull(m);
    int mesh  = MMpull(m);
    int s3d  = MMget(m,0);

	int type = 0 ;

    if((s3d==NIL)||(mesh==NIL))		{MMset(m,0,NIL);		return 0;	}
    
	if(SKL==NIL)					{	MMset(m,0,NIL);	return 0;	}

	ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(mesh),0);
	if(node==NULL||node->type==MSH_TYPE_ID)					{	MMset(m,0,NIL);		return 0;	}
	ZNode	*skelet = (ZNode*) MMfetch(m,MTOP(SKL),0);
	if(skelet==NULL||skelet->type!=BON_TYPE_ID)					{	MMset(m,0,NIL);		return 0;	}
	ZBone *father = (ZBone*)skelet ;
	if(father==NULL||father->type!=BON_TYPE_ID)						{	MMset(m,0,NIL);		return 0;	}

	ZObject		*curObj = (ZObject*) node ;

	ZSkelet		*curSKL ;// = (ZSkelet*) skelet ;

	curSKL = new ZSkelet((int)scene);
	if(curSKL== NULL)			{		MMset(m,0,NIL);	return 0;	}
	curSKL->SkeletExist = true ;
	scene->World->sklList.Add(curSKL) ;
	curSKL->SetName(father->name);

	if(curObj == NULL )				{	MMset(m,0,NIL);		return 0;	}
	if(curSKL == NULL )				{	MMset(m,0,NIL);		return 0;	}

	curSKL->BonesOfSkelet.Clear() ;
	curSKL->BonesOfSkelet.Add(father) ;
	M3recBoneHierarchy(father->son,scene,curSKL) ;
	ZArray<ZBone*> tempArrayBones ;

	if(curSKL->BonesOfSkelet.Size() != 0 )
	{

		for(int i=0;i<curSKL->BonesOfSkelet.Size(); i++)
		{	 
			tempArrayBones.Add(curSKL->BonesOfSkelet[i]) ;
		}
	
		// Replace le tableau de bones dans l'ordre
		if(curSKL->BonesOfSkelet.Size() == tempArrayBones.Size())
		{
			for( i=0;i<curSKL->BonesOfSkelet.Size(); i++)
			{
				curSKL->BonesOfSkelet[tempArrayBones[i]->ID] = tempArrayBones[i] ;
				father->bones[tempArrayBones[i]->ID] = tempArrayBones[i] ;
			}

		}
		else
		{
			MMset(m,0,NIL); return 0 ;
		}
	}
	else 
	{

		MMset(m,0,NIL); return 0 ; 
	}

	scene->updateGraphList = true;

	// On lie le mesh courant au squelette courant
	curSKL->Avatar = curObj ;
	curObj->GetMesh()->numberOfBones = curSKL->BonesOfSkelet.Size() ;
	curObj->GetMesh()->isAvatar = true ;
	curObj->GetMesh()->SetskinningShader() ;
	MMset(m,0,ITOM(type));

	return 0;
}

//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3listSKLFromNode
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d] [H3d r1]
int ZM3listSKLFromNode(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ZM3listSKLFromNode");
#endif

	int		j, k, n, tmp_res;
	n=0;
	int h3d = MMpull(m);
    int s3d = MMget(m,0);

    if(s3d==NIL)					{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

	if(h3d==NIL)			{MMset(m,0,NIL);		return 0;}
    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if(node==NULL)				{MMset(m,0,NIL);		return 0;}



//	scene->World->createNodeLists(node);



	for(int i=0; i<scene->World->sklList.Size(); i++)
    {
		ZNode	*curNode;
		curNode = NULL;
		GetFirstRecentName(scene->World, &curNode, string(scene->World->sklList[i]->name) );


		if(curNode==NULL)				{	MMset(m,0,NIL);		return 0;	}

		int	h3d = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)curNode);
		if (MMpush(m,PTOM(h3d)))		return MERRMEM;

		n++;
		INVERT(m,0,1);
		node = node->next;

	}

	MMpull(m);

	if(MMpush(m,NIL))		return MERRMEM;

	for(j=0;j<n;j++)
	{
    	if (MMpush(m,2*2)) return MERRMEM;

		if (k=MBdeftab(m)) return k;
	}
	
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif


	return 0;
}





///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////																											   ////
///												GESTION DES LUMIERES												///
////																											   ////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3setLightModel
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d I] I
int ZM3setLightModel(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3setLightModel ");
#endif

	int type = MTOI( MMpull(m) );
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(type==NIL))										{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)													{	MMset(m,0,NIL);		return 0;	}

	if(type==0)		scene->generalRealLighting = true;
	else			scene->generalRealLighting = false;

    MMset(m,0,0);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

    return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getLightModel
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d] I
int ZM3getLightModel(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getLightModel ");
#endif

    int s3d  = MMget(m,0);

    if(s3d==NIL)													{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)													{	MMset(m,0,NIL);		return 0;	}

	int type;
	if(scene->generalRealLighting)		type = 0;
	else								type = 1;

    MMset(m,0,ITOM(type));

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

    return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3createLight
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d I I I I I I] H3d
int ZM3createLight(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3createLight ");
#endif

	int p3	 = MMpull(m);
	int p2	 = MMpull(m);
	int p1	 = MMpull(m);
	int beta = MMpull(m);
	int alph = MMpull(m);
	int type = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(type==NIL)||(alph==NIL))						{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)													{	MMset(m,0,NIL);		return 0;	}

	if( (MTOI(type)==LIGHT_PARA) && (beta==NIL) )					{	MMset(m,0,NIL);		return 0;	}
	if( (MTOI(type)==LIGHT_OMNI) && ((beta==NIL)||(p1==NIL)) )		{	MMset(m,0,NIL);		return 0;	}
	if( (MTOI(type)==LIGHT_SPOT) && ((beta==NIL)||(p1==NIL)) )		{	MMset(m,0,NIL);		return 0;	}


	ZLight	*curLgh;
	curLgh = new ZLight((int)scene);
	if(curLgh == NULL)							{	MMset(m,0,NIL);		return 0;	}
	curLgh->InsertAsChildOf(scene->World);
	curLgh->SetName("");
	curLgh->oldStyle = true;


	// Attribution des composantes de la lumière
	curLgh->LightType = MTOI(type);


	float	ambient = ((float)MTOI(alph)) / 64.0f;
	curLgh->SetAmbient(ambient, ambient, ambient, 1.0f);
	curLgh->alpha = MTOI(alph);

	if(beta!=NIL)
	{
		float	diffuse = ((float)MTOI(beta)) / 64.0f;
		curLgh->SetDiffuse(diffuse, diffuse, diffuse, 1.0f);
		curLgh->beta = MTOI(beta);
	}

	if(p1!=NIL)
	{
		float	distance = ((float)MTOI(p1)) / 100.0f;
		curLgh->distance = distance;
		curLgh->dist = MTOI(p1);
	}


	// Declaration en SCOL
	int hash_tab = MTOP( MMfetch(m,MTOP(s3d),1) );
	int	h3d = createH3D(m, (int)curLgh, hash_tab);

	scene->updateGraphList = true;

	// Pose le résultat sur la pile
	if(h3d!=NIL)	h3d = PTOM(h3d);
    MMset(m,0,h3d);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

    return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getLight
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d] [I I I I I I]
int ZM3getLight(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getLight ");
#endif

	int h3d  = MMpull(m);
    int s3d  = MMpull(m);

    if((s3d==NIL)||(h3d==NIL))						{	MMpush(m,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)									{	MMpush(m,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=LGH_TYPE_ID))		{	MMpush(m,NIL);		return 0;	}
	ZLight	*lgh = (ZLight*)node;

	if(lgh->oldStyle == false)						{	MMpush(m,NIL);		return 0;	}

	if(MMpush(m,ITOM(lgh->LightType)))							return MERRMEM;
	if(MMpush(m,ITOM(AROUNDINT(lgh->ambient[0]*64.0f))))		return MERRMEM;
	if(MMpush(m,ITOM(AROUNDINT(lgh->diffuse[0]*64.0f))))		return MERRMEM;
	if(MMpush(m,ITOM(AROUNDINT(lgh->distance*100.0f))))			return MERRMEM;
	if(MMpush(m,NIL))											return MERRMEM;
	if(MMpush(m,NIL))											return MERRMEM;
	if(MMpush(m,6*2))											return MERRMEM;

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return MBdeftab(m);
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3setLight
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d [I I I I I I]] I
int ZM3setLight(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3setLight ");
#endif

	int data = MMpull(m);
	int h3d  = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL)||(data==NIL))			{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)									{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=LGH_TYPE_ID))		{	MMset(m,0,NIL);		return 0;	}
	ZLight	*lgh = (ZLight*) node;

	if(lgh->oldStyle == false)						{	MMset(m,0,NIL);		return 0;	}


	// Attribution des composantes de la lumière
	lgh->LightType = MTOI(MMfetch(m,MTOP(data),0));

	float	ambient = ((float)MTOI(MMfetch(m,MTOP(data),1))) / 64.0f;
	lgh->SetAmbient(ambient, ambient, ambient, 1.0f);
	lgh->alpha = MTOI(MMfetch(m,MTOP(data),1));

	float	diffuse = ((float)MTOI(MMfetch(m,MTOP(data),2))) / 64.0f;
	lgh->SetDiffuse(diffuse, diffuse, diffuse, 1.0f);
	lgh->beta = MTOI(MMfetch(m,MTOP(data),2));

	float	distance = ((float)MTOI(MMfetch(m,MTOP(data),3))) / 100.0f;
	lgh->distance = distance;
	lgh->dist = MTOI(MMfetch(m,MTOP(data),3));

	MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
    return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3createColorLight
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d I I I I I I I] H3d
int ZM3createColorLight(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3createColorLight ");
#endif

	int att_q = MMpull(m);
	int att_c = MMpull(m);
	int angl  = MMpull(m);
	int spec  = MMpull(m);
	int diff  = MMpull(m);
	int amb   = MMpull(m);
	int type  = MMpull(m);
	
    int s3d   = MMget(m,0);

    if((s3d==NIL)||(type==NIL)||(amb==NIL)||(diff==NIL)||(spec==NIL))				{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)													{	MMset(m,0,NIL);		return 0;	}

	ZLight	*curLgh;
	curLgh = new ZLight((int)scene);
	if(curLgh == NULL)							{	MMset(m,0,NIL);		return 0;	}
	curLgh->InsertAsChildOf(scene->World);
	curLgh->SetName("");
	curLgh->oldStyle = false;


	// Attribution des composantes de la lumière
	curLgh->LightType = MTOI( type );

	amb = MTOI(amb);
	curLgh->SetAmbient( ((float)((amb&0x00ff0000)>>16)) / CONST_COLOR,
						((float)((amb&0x0000ff00)>>8) ) / CONST_COLOR,
						((float) (amb&0x000000ff)	  ) / CONST_COLOR, 
						1.0f);
	curLgh->alpha = (int) ((curLgh->ambient[0]+curLgh->ambient[1]+curLgh->ambient[2]) * 64.0f / 3.0f);

	diff = MTOI(diff);
	curLgh->SetDiffuse( ((float)((diff&0x00ff0000)>>16)) / CONST_COLOR,
						((float)((diff&0x0000ff00)>>8) ) / CONST_COLOR,
						((float) (diff&0x000000ff)	   ) / CONST_COLOR, 
						1.0f);
	curLgh->beta = (int) ((curLgh->diffuse[0]+curLgh->diffuse[1]+curLgh->diffuse[2]) * 64.0f / 3.0f);

	spec = MTOI(spec);
	curLgh->SetSpecular( ((float)((spec&0x00ff0000)>>16)) / CONST_COLOR,
						 ((float)((spec&0x0000ff00)>>8) ) / CONST_COLOR,
						 ((float) (spec&0x000000ff)		) / CONST_COLOR, 
						 1.0f);


	// Cut-off et attenuation (const et quadratique)
	if(angl == NIL)		curLgh->spot_cut_off	= 180.0f;
	else				curLgh->spot_cut_off	= MTOI( angl );

	if(att_c == NIL)	curLgh->attenuate_const = 1.0f;
	else				curLgh->attenuate_const = ((float)MTOI(att_c))/100.0f;

	if(att_q == NIL)	curLgh->attenuate_quadr = 0.0f;
	else				curLgh->attenuate_quadr = ((float)MTOI(att_q))/100.0f;


	// Declaration en SCOL
	int hash_tab = MTOP( MMfetch(m,MTOP(s3d),1) );
	int	h3d = createH3D(m, (int)curLgh, hash_tab);

	scene->updateGraphList = true;

	// Pose le résultat sur la pile
	if(h3d!=NIL)	h3d = PTOM(h3d);
    MMset(m,0,h3d);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
    return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getColorLight
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d] [I I I I I I I]
int ZM3getColorLight(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getColorLight ");
#endif

	int h3d  = MMpull(m);
    int s3d  = MMpull(m);

	if((s3d==NIL)||(h3d==NIL))						{	MMpush(m,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)									{	MMpush(m,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=LGH_TYPE_ID))		{	MMpush(m,NIL);		return 0;	}
	ZLight	*lgh = (ZLight*)node;

	if(lgh->oldStyle == true)						{	MMpush(m,NIL);		return 0;	}

	
	
	int coul = 0;
	
	if(MMpush(m,ITOM(lgh->LightType)))							return MERRMEM;

	coul = AROUNDINT(lgh->ambient[2]*CONST_COLOR) + (AROUNDINT(lgh->ambient[1]*CONST_COLOR)<<8) + (AROUNDINT(lgh->ambient[0]*CONST_COLOR)<<16);
	if(MMpush(m,ITOM(coul)))		return MERRMEM;
	
	coul = AROUNDINT(lgh->diffuse[2]*CONST_COLOR) + (AROUNDINT(lgh->diffuse[1]*CONST_COLOR)<<8) + (AROUNDINT(lgh->diffuse[0]*CONST_COLOR)<<16);
	if(MMpush(m,ITOM(coul)))		return MERRMEM;

	coul = AROUNDINT(lgh->specular[2]*CONST_COLOR) + (AROUNDINT(lgh->specular[1]*CONST_COLOR)<<8) + (AROUNDINT(lgh->specular[0]*CONST_COLOR)<<16);
	if(MMpush(m,ITOM(coul)))		return MERRMEM;

	if(MMpush(m,ITOM(lgh->spot_cut_off)))						return MERRMEM;
	if(MMpush(m,ITOM(AROUNDINT(lgh->attenuate_const*100.0f))))	return MERRMEM;
	if(MMpush(m,ITOM(AROUNDINT(lgh->attenuate_quadr*100.0f))))	return MERRMEM;

	if(MMpush(m,7*2))											return MERRMEM;
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return MBdeftab(m);
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3setColorLight
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d I I I I I I I] I
int ZM3setColorLight(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3setColorLight ");
#endif

	int att_q = MMpull(m);
	int att_c = MMpull(m);
	int angl  = MMpull(m);
	int spec  = MMpull(m);
	int diff  = MMpull(m);
	int amb   = MMpull(m);
	int type  = MMpull(m);
	int h3d   = MMpull(m);

    int s3d   = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL)||(type==NIL)||(amb==NIL)||(diff==NIL)||(spec==NIL))				{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)									{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=LGH_TYPE_ID))		{	MMset(m,0,NIL);		return 0;	}
	ZLight	*lgh = (ZLight*) node;

	if(lgh->oldStyle == true)						{	MMset(m,0,NIL);		return 0;	}


	// Attribution des composantes de la lumière
	lgh->LightType = MTOI( type );

	amb = MTOI(amb);
	lgh->SetAmbient( ((float)((amb&0x00ff0000)>>16)) / CONST_COLOR,
					 ((float)((amb&0x0000ff00)>>8) ) / CONST_COLOR,
					 ((float) (amb&0x000000ff)	   ) / CONST_COLOR, 
					 1.0f);
	lgh->alpha = (int) ((lgh->ambient[0]+lgh->ambient[1]+lgh->ambient[2]) * 64.0f / 3.0f);

	diff = MTOI(diff);
	lgh->SetDiffuse( ((float)((diff&0x00ff0000)>>16)) / CONST_COLOR,
					 ((float)((diff&0x0000ff00)>>8) ) / CONST_COLOR,
					 ((float) (diff&0x000000ff)	    ) / CONST_COLOR, 
					 1.0f);
	lgh->beta = (int) ((lgh->diffuse[0]+lgh->diffuse[1]+lgh->diffuse[2]) * 64.0f / 3.0f);

	spec = MTOI(spec);
	lgh->SetSpecular( ((float)((spec&0x00ff0000)>>16)) / CONST_COLOR,
					  ((float)((spec&0x0000ff00)>>8) ) / CONST_COLOR,
					  ((float) (spec&0x000000ff)	 ) / CONST_COLOR, 
					  1.0f);


	// Cut-off et attenuation (const et quadratique)
	if(angl == NIL)		lgh->spot_cut_off	= 180.0f;
	else				lgh->spot_cut_off	= MTOI( angl );

	if(att_c == NIL)	lgh->attenuate_const = 1.0f;
	else				lgh->attenuate_const = ((float)MTOI(att_c))/100.0f;

	if(att_q == NIL)	lgh->attenuate_quadr = 0.0f;
	else				lgh->attenuate_quadr = ((float)MTOI(att_q))/100.0f;

	MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
    return 0;
}













///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////																											   ////
///												GESTION DES SPRITES													///
////																											   ////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


//$BLG
//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3setSpriteClickability
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d I] I
int ZM3setSpriteClickability(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3setSpriteClickability\n");
#endif

	int flg  = MMpull(m);
	int h3d  = MMpull(m);
  int s3d  = MMget(m,0);

	if ((s3d == NIL) || (h3d == NIL) || (flg == NIL) || (MTOI(flg) < 0) || (MTOI(flg) > 1))		
	{
		MMset(m, 0, NIL);
		return 0;
	}
  ZScene *scene = (ZScene*) MMfetch(m, MTOP(s3d), 0);
	if (scene == NULL)								
	{	
		MMset(m, 0, NIL);
		return 0;
	}

  ZNode*	node = (ZNode*) MMfetch(m, MTOP(h3d), 0);
	if ((node == NULL) || (node->type != SPR_TYPE_ID))					
	{
		MMset(m, 0, NIL);
		return 0;
	}
  ZSprite	*spr = (ZSprite*) node;

	flg = MTOI(flg);

	if (flg == 0)	
	  spr->blg_sprClickable = false;
	else
	  spr->blg_sprClickable = true;

  MMset(m,0,0);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;
}


//$BLG
//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getSpriteClickability
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [S3d H3d] I
int ZM3getSpriteClickability(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getSpriteClickability\n");
#endif

	int h3d  = MMpull(m);
  int s3d  = MMget(m,0);

	if ((s3d == NIL) || (h3d == NIL))
	{
		MMset(m, 0, NIL);
		return 0;
	}
  ZScene *scene = (ZScene*) MMfetch(m, MTOP(s3d), 0);
	if (scene == NULL)
	{
		MMset(m, 0, NIL);
		return 0;
	}

  ZNode	*node = (ZNode*) MMfetch(m, MTOP(h3d), 0);
	if ((node == NULL) || (node->type != SPR_TYPE_ID))
	{
		MMset(m, 0, NIL);
		return 0;
	}
  ZSprite	*spr = (ZSprite*) node;

	int ret = 0;
	if (spr->blg_sprClickable == true)  ret++;

	MMset(m, 0, ITOM(ret));

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3createSprite
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d I I HMat3d I]
int ZM3createSprite(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3createSprite ");
#endif

	int flg	 = MMpull(m);
	int mat	 = MMpull(m);
	int H	 = MMpull(m);
	int W	 = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(H==NIL)||(W==NIL)||(mat==NIL))					{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)													{	MMset(m,0,NIL);		return 0;	}

    ZMaterial	*mater = (ZMaterial*) MMfetch(m,MTOP(mat),0);
	if(mater==NULL)													{	MMset(m,0,NIL);		return 0;	}

	// Creation du sprite
	ZSprite		*curSpr;
	curSpr = new ZSprite((int)scene);
	if(curSpr == NULL)												{	MMset(m,0,NIL);		return 0;	}
	curSpr->InsertAsChildOf(scene->World);
	curSpr->SetName("");

	// Attribution des composantes du sprite
	curSpr->halfW = ((float)MTOI(W)) / 200.0f;
	curSpr->halfH = ((float)MTOI(H)) / 200.0f;
	curSpr->SetMaterial(mater);

	if(flg==0)	curSpr->CameraOriented = false;
	else		curSpr->CameraOriented = true;

	// Declaration en SCOL
	int hash_tab = MTOP( MMfetch(m,MTOP(s3d),1) );
	int	h3d = createH3D(m, (int)curSpr, hash_tab);

	scene->updateGraphList = true;

	// Pose le résultat sur la pile
	if(h3d!=NIL)	h3d = PTOM(h3d);
    MMset(m,0,h3d);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

    return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3createSpriteF
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d F F HMat3d I]
int ZM3createSpriteF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3createSpriteF ");
#endif
	int flg	 = MMpull(m);
	int mat	 = MMpull(m);
	int H	 = MMpull(m);
	int W	 = MMpull(m);
    int s3d  = MMget(m,0);

    if((s3d==NIL)||(H==NIL)||(W==NIL)||(mat==NIL))					{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)													{	MMset(m,0,NIL);		return 0;	}

    ZMaterial	*mater = (ZMaterial*) MMfetch(m,MTOP(mat),0);
	if(mater==NULL)													{	MMset(m,0,NIL);		return 0;	}

	// Creation du sprite
	ZSprite		*curSpr;
	curSpr = new ZSprite((int)scene);
	if(curSpr == NULL)												{	MMset(m,0,NIL);		return 0;	}
	curSpr->InsertAsChildOf(scene->World);
	curSpr->SetName("");

	// Attribution des composantes du sprite
	curSpr->halfW = MTOF(W) / 200.0f;
	curSpr->halfH = MTOF(H) / 200.0f;
	curSpr->SetMaterial(mater);

	if(flg==0)	curSpr->CameraOriented = false;
	else		curSpr->CameraOriented = true;

	// Declaration en SCOL
	int hash_tab = MTOP( MMfetch(m,MTOP(s3d),1) );
	int	h3d = createH3D(m, (int)curSpr, hash_tab);

	scene->updateGraphList = true;

	// Pose le résultat sur la pile
	if(h3d!=NIL)	h3d = PTOM(h3d);
    MMset(m,0,h3d);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
    return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3setSprite
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d I I HMat3d I] I
int ZM3setSprite(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3setSprite ");
#endif

	int flg	= MMpull(m);
	int mat	= MMpull(m);
	int H   = MMpull(m);
	int W   = MMpull(m);
	int h3d = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL)||(H==NIL)||(W==NIL)||(mat==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)													{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=SPR_TYPE_ID))						{	MMset(m,0,NIL);		return 0;	}
    ZSprite	*sprite = (ZSprite*)node;

    ZMaterial	*mater = (ZMaterial*) MMfetch(m,MTOP(mat),0);
	if(mater==NULL)													{	MMset(m,0,NIL);		return 0;	}


	// Attribution des composantes du sprite
	sprite->halfW = ((float)MTOI(W)) / 200.0f;
	sprite->halfH = ((float)MTOI(H)) / 200.0f;
	sprite->SetMaterial(mater);

	if(flg==0)	sprite->CameraOriented = false;
	else		sprite->CameraOriented = true;

	MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;	
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3setSpriteF
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d F F HMat3d I] I
int ZM3setSpriteF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3setSpriteF ");
#endif
	int flg	= MMpull(m);
	int mat	= MMpull(m);
	int H   = MMpull(m);
	int W   = MMpull(m);
	int h3d = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL)||(H==NIL)||(W==NIL)||(mat==NIL))		{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)													{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=SPR_TYPE_ID))						{	MMset(m,0,NIL);		return 0;	}
    ZSprite	*sprite = (ZSprite*)node;

    ZMaterial	*mater = (ZMaterial*) MMfetch(m,MTOP(mat),0);
	if(mater==NULL)													{	MMset(m,0,NIL);		return 0;	}


	// Attribution des composantes du sprite
	sprite->halfW = MTOF(W) / 200.0f;
	sprite->halfH = MTOF(H) / 200.0f;
	sprite->SetMaterial(mater);

	if(flg==0)	sprite->CameraOriented = false;
	else		sprite->CameraOriented = true;

	MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;	
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getSprite
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d] [I I HMat3d I]
int ZM3getSprite(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getSprite ");
#endif
	int h3d = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL))										{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)													{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=SPR_TYPE_ID))						{	MMset(m,0,NIL);		return 0;	}
    ZSprite	*sprite = (ZSprite*)node;

	MMpull(m);

	int k;

	// Pose des composants sur la pile
	if(MMpush(m, ITOM(AROUNDINT(200.0f*sprite->halfW))))			return MERRMEM;
	if(MMpush(m, ITOM(AROUNDINT(200.0f*sprite->halfH))))			return MERRMEM;

	int	mat3d = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),2)), (int)sprite->GetMaterial());
	if(mat3d!=NIL)		mat3d = PTOM(mat3d);
	if(MMpush(m, mat3d))											return MERRMEM;

	if(sprite->CameraOriented)		{	if(MMpush(m, 0))		return MERRMEM;	}
	else							{	if(MMpush(m, 2))		return MERRMEM;	}

	// Creation du tuple résultat
	if(MMpush(m, 4*2))												return MERRMEM;
	if(k=MBdeftab(m))												return k;

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;	
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getSpriteF
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d] [F F HMat3d I]
int ZM3getSpriteF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getSpriteF ");
#endif

	int h3d = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL))										{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)													{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=SPR_TYPE_ID))						{	MMset(m,0,NIL);		return 0;	}
    ZSprite	*sprite = (ZSprite*)node;

	MMpull(m);

	int k;

	// Pose des composants sur la pile
	if(MMpush(m, FTOM(200.0f*sprite->halfW)))			return MERRMEM;
	if(MMpush(m, FTOM(200.0f*sprite->halfH)))			return MERRMEM;

	int	mat3d = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),2)), (int)sprite->GetMaterial());
	if(mat3d!=NIL)		mat3d = PTOM(mat3d);
	if(MMpush(m, mat3d))								return MERRMEM;

	if(sprite->CameraOriented)		{	if(MMpush(m, 0))		return MERRMEM;	}
	else							{	if(MMpush(m, 2))		return MERRMEM;	}
	
	// Creation du tuple résultat
	if(MMpush(m, 4*2))					return MERRMEM;
	if(k=MBdeftab(m))					return k;

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;	
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3setSpriteTexCoord
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d [[I I] r1] [[I I] r1]] I
int ZM3setSpriteTexCoord(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3setSpriteTexCoord ");
#endif

	int tex2  = MTOP(MMpull(m));
	int tex1  = MTOP(MMpull(m));
	int h3d   = MMpull(m);
    int s3d   = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL))								{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)											{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=SPR_TYPE_ID))				{	MMset(m,0,NIL);		return 0;	}
    ZSprite	*sprite = (ZSprite*)node;
	

	ZVector3	texCoord[4];
	int			coordPTR;

	if(tex1!=NIL)
	{
		coordPTR = MTOP(MMfetch(m,tex1,0));
		texCoord[0].SetCoord( ((float)MTOI(MMfetch(m,coordPTR,0))) / CONST_TEX_COORD, ((float)MTOI(MMfetch(m,coordPTR,1))) / CONST_TEX_COORD, 1.0f);

		tex1 = MTOP(MMfetch(m,tex1,1));
		if(tex1==NIL)			{	MMset(m,0,NIL);		return 0;	}
		coordPTR = MTOP(MMfetch(m,tex1,0));
		texCoord[1].SetCoord( ((float)MTOI(MMfetch(m,coordPTR,0))) / CONST_TEX_COORD, ((float)MTOI(MMfetch(m,coordPTR,1))) / CONST_TEX_COORD, 1.0f);

		tex1 = MTOP(MMfetch(m,tex1,1));
		if(tex1==NIL)			{	MMset(m,0,NIL);		return 0;	}
		coordPTR = MTOP(MMfetch(m,tex1,0));
		texCoord[2].SetCoord( ((float)MTOI(MMfetch(m,coordPTR,0))) / CONST_TEX_COORD, ((float)MTOI(MMfetch(m,coordPTR,1))) / CONST_TEX_COORD, 1.0f);

		tex1 = MTOP(MMfetch(m,tex1,1));
		if(tex1==NIL)			{	MMset(m,0,NIL);		return 0;	}
		coordPTR = MTOP(MMfetch(m,tex1,0));
		texCoord[3].SetCoord( ((float)MTOI(MMfetch(m,coordPTR,0))) / CONST_TEX_COORD, ((float)MTOI(MMfetch(m,coordPTR,1))) / CONST_TEX_COORD, 1.0f);

		sprite->UV1[0] = texCoord[0];
		sprite->UV1[1] = texCoord[1];
		sprite->UV1[2] = texCoord[2];
		sprite->UV1[3] = texCoord[3];

		if( sprite->UV1[0].u<0.0f || sprite->UV1[1].u<0.0f || sprite->UV1[2].u<0.0f || sprite->UV1[3].u<0.0f ||
			sprite->UV1[0].u>1.0f || sprite->UV1[1].u>1.0f || sprite->UV1[2].u>1.0f || sprite->UV1[3].u>1.0f )	sprite->clampU1 = false;
		else																									sprite->clampU1 = true;

		if( sprite->UV1[0].v<0.0f || sprite->UV1[1].v<0.0f || sprite->UV1[2].v<0.0f || sprite->UV1[3].v<0.0f || 
			sprite->UV1[0].v>1.0f || sprite->UV1[1].v>1.0f || sprite->UV1[2].v>1.0f || sprite->UV1[3].v>1.0f )	sprite->clampV1 = false;
		else																									sprite->clampV1 = true;
	}

	if(tex2!=NIL)
	{
		coordPTR = MTOP(MMfetch(m,tex2,0));
		texCoord[0].SetCoord( ((float)MTOI(MMfetch(m,coordPTR,0))) / CONST_TEX_COORD, ((float)MTOI(MMfetch(m,coordPTR,1))) / CONST_TEX_COORD, 1.0f);

		tex2 = MTOP(MMfetch(m,tex2,1));
		if(tex2==NIL)			{	MMset(m,0,NIL);		return 0;	}
		coordPTR = MTOP(MMfetch(m,tex2,0));
		texCoord[1].SetCoord( ((float)MTOI(MMfetch(m,coordPTR,0))) / CONST_TEX_COORD, ((float)MTOI(MMfetch(m,coordPTR,1))) / CONST_TEX_COORD, 1.0f);

		tex2 = MTOP(MMfetch(m,tex2,1));
		if(tex2==NIL)			{	MMset(m,0,NIL);		return 0;	}
		coordPTR = MTOP(MMfetch(m,tex2,0));
		texCoord[2].SetCoord( ((float)MTOI(MMfetch(m,coordPTR,0))) / CONST_TEX_COORD, ((float)MTOI(MMfetch(m,coordPTR,1))) / CONST_TEX_COORD, 1.0f);

		tex2 = MTOP(MMfetch(m,tex2,1));
		if(tex2==NIL)			{	MMset(m,0,NIL);		return 0;	}
		coordPTR = MTOP(MMfetch(m,tex2,0));
		texCoord[3].SetCoord( ((float)MTOI(MMfetch(m,coordPTR,0))) / CONST_TEX_COORD, ((float)MTOI(MMfetch(m,coordPTR,1))) / CONST_TEX_COORD, 1.0f);

		sprite->UV2[0] = texCoord[0];	
		sprite->UV2[1] = texCoord[1];	
		sprite->UV2[2] = texCoord[2];	
		sprite->UV2[3] = texCoord[3];	

		if( sprite->UV2[0].u<0.0f || sprite->UV2[1].u<0.0f || sprite->UV2[2].u<0.0f || sprite->UV2[3].u<0.0f ||
			sprite->UV2[0].u>1.0f || sprite->UV2[1].u>1.0f || sprite->UV2[2].u>1.0f || sprite->UV2[3].u>1.0f )	sprite->clampU2 = false;
		else																									sprite->clampU2 = true;

		if( sprite->UV2[0].v<0.0f || sprite->UV2[1].v<0.0f || sprite->UV2[2].v<0.0f || sprite->UV2[3].v<0.0f || 
			sprite->UV2[0].v>1.0f || sprite->UV2[1].v>1.0f || sprite->UV2[2].v>1.0f || sprite->UV2[3].v>1.0f )	sprite->clampV2 = false;
		else																									sprite->clampV2 = true;
	}

	MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3setSpriteTexCoordF
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d [[F F] r1] [[F F] r1]] I
int ZM3setSpriteTexCoordF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3setSpriteTexCoordF ");
#endif

	int tex2  = MTOP(MMpull(m));
	int tex1  = MTOP(MMpull(m));
	int h3d   = MMpull(m);
    int s3d   = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL))								{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)											{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=SPR_TYPE_ID))				{	MMset(m,0,NIL);		return 0;	}
    ZSprite	*sprite = (ZSprite*)node;
	

	ZVector3	texCoord[4];
	int			coordPTR;

	if(tex1!=NIL)
	{
		coordPTR = MTOP(MMfetch(m,tex1,0));
		texCoord[0].SetCoord( MTOF(MMfetch(m,coordPTR,0)), MTOF(MMfetch(m,coordPTR,1)), 1.0f);

		tex1 = MTOP(MMfetch(m,tex1,1));
		if(tex1==NIL)			{	MMset(m,0,NIL);		return 0;	}
		coordPTR = MTOP(MMfetch(m,tex1,0));
		texCoord[1].SetCoord( MTOF(MMfetch(m,coordPTR,0)), MTOF(MMfetch(m,coordPTR,1)), 1.0f);

		tex1 = MTOP(MMfetch(m,tex1,1));
		if(tex1==NIL)			{	MMset(m,0,NIL);		return 0;	}
		coordPTR = MTOP(MMfetch(m,tex1,0));
		texCoord[2].SetCoord( MTOF(MMfetch(m,coordPTR,0)), MTOF(MMfetch(m,coordPTR,1)), 1.0f);

		tex1 = MTOP(MMfetch(m,tex1,1));
		if(tex1==NIL)			{	MMset(m,0,NIL);		return 0;	}
		coordPTR = MTOP(MMfetch(m,tex1,0));
		texCoord[3].SetCoord( MTOF(MMfetch(m,coordPTR,0)), MTOF(MMfetch(m,coordPTR,1)), 1.0f);

		sprite->UV1[0] = texCoord[0];	
		sprite->UV1[1] = texCoord[1];	
		sprite->UV1[2] = texCoord[2];	
		sprite->UV1[3] = texCoord[3];	

		if( sprite->UV1[0].u<0.0f || sprite->UV1[1].u<0.0f || sprite->UV1[2].u<0.0f || sprite->UV1[3].u<0.0f ||
			sprite->UV1[0].u>1.0f || sprite->UV1[1].u>1.0f || sprite->UV1[2].u>1.0f || sprite->UV1[3].u>1.0f )	sprite->clampU1 = false;
		else																									sprite->clampU1 = true;

		if( sprite->UV1[0].v<0.0f || sprite->UV1[1].v<0.0f || sprite->UV1[2].v<0.0f || sprite->UV1[3].v<0.0f || 
			sprite->UV1[0].v>1.0f || sprite->UV1[1].v>1.0f || sprite->UV1[2].v>1.0f || sprite->UV1[3].v>1.0f )	sprite->clampV1 = false;
		else																									sprite->clampV1 = true;
	}

	if(tex2!=NIL)
	{
		coordPTR = MTOP(MMfetch(m,tex2,0));
		texCoord[0].SetCoord( MTOF(MMfetch(m,coordPTR,0)), MTOF(MMfetch(m,coordPTR,1)), 1.0f);

		tex2 = MTOP(MMfetch(m,tex2,1));
		if(tex2==NIL)			{	MMset(m,0,NIL);		return 0;	}
		coordPTR = MTOP(MMfetch(m,tex2,0));
		texCoord[1].SetCoord( MTOF(MMfetch(m,coordPTR,0)), MTOF(MMfetch(m,coordPTR,1)), 1.0f);

		tex2 = MTOP(MMfetch(m,tex2,1));
		if(tex2==NIL)			{	MMset(m,0,NIL);		return 0;	}
		coordPTR = MTOP(MMfetch(m,tex2,0));
		texCoord[2].SetCoord( MTOF(MMfetch(m,coordPTR,0)), MTOF(MMfetch(m,coordPTR,1)), 1.0f);

		tex2 = MTOP(MMfetch(m,tex2,1));
		if(tex2==NIL)			{	MMset(m,0,NIL);		return 0;	}
		coordPTR = MTOP(MMfetch(m,tex2,0));
		texCoord[3].SetCoord( MTOF(MMfetch(m,coordPTR,0)), MTOF(MMfetch(m,coordPTR,1)), 1.0f);

		sprite->UV2[0] = texCoord[0];	
		sprite->UV2[1] = texCoord[1];	
		sprite->UV2[2] = texCoord[2];	
		sprite->UV2[3] = texCoord[3];	

		if( sprite->UV2[0].u<0.0f || sprite->UV2[1].u<0.0f || sprite->UV2[2].u<0.0f || sprite->UV2[3].u<0.0f ||
			sprite->UV2[0].u>1.0f || sprite->UV2[1].u>1.0f || sprite->UV2[2].u>1.0f || sprite->UV2[3].u>1.0f )	sprite->clampU2 = false;
		else																									sprite->clampU2 = true;

		if( sprite->UV2[0].v<0.0f || sprite->UV2[1].v<0.0f || sprite->UV2[2].v<0.0f || sprite->UV2[3].v<0.0f || 
			sprite->UV2[0].v>1.0f || sprite->UV2[1].v>1.0f || sprite->UV2[2].v>1.0f || sprite->UV2[3].v>1.0f )	sprite->clampV2 = false;
		else																									sprite->clampV2 = true;
	}

	MMset(m,0,0);
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	return 0;
}


//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getSpriteTexCoord
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d] [[I I] r1] [[I I] r1]]
int ZM3getSpriteTexCoord(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getSpriteTexCoord ");
#endif

	int h3d   = MMpull(m);
    int s3d   = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL))								{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)											{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=SPR_TYPE_ID))				{	MMset(m,0,NIL);		return 0;	}
    ZSprite	*sprite = (ZSprite*)node;
	
	MMpull(m);

	int		j, k;

	// creation de la liste des TexCoord1
	if(MMpush(m, ITOM(AROUNDINT(CONST_TEX_COORD*sprite->UV1[0].u))))			return MERRMEM;
	if(MMpush(m, ITOM(AROUNDINT(CONST_TEX_COORD*sprite->UV1[0].v))))			return MERRMEM;
	if(MMpush(m, 2*2))															return MERRMEM;
	if(k=MBdeftab(m))															return k;
	
	if(MMpush(m, ITOM(AROUNDINT(CONST_TEX_COORD*sprite->UV1[1].u))))			return MERRMEM;
	if(MMpush(m, ITOM(AROUNDINT(CONST_TEX_COORD*sprite->UV1[1].v))))			return MERRMEM;
	if(MMpush(m, 2*2))															return MERRMEM;
	if(k=MBdeftab(m))															return k;

	if(MMpush(m, ITOM(AROUNDINT(CONST_TEX_COORD*sprite->UV1[2].u))))			return MERRMEM;
	if(MMpush(m, ITOM(AROUNDINT(CONST_TEX_COORD*sprite->UV1[2].v))))			return MERRMEM;
	if(MMpush(m, 2*2))															return MERRMEM;
	if(k=MBdeftab(m))															return k;

	if(MMpush(m, ITOM(AROUNDINT(CONST_TEX_COORD*sprite->UV1[3].u))))			return MERRMEM;
	if(MMpush(m, ITOM(AROUNDINT(CONST_TEX_COORD*sprite->UV1[3].v))))			return MERRMEM;
	if(MMpush(m, 2*2))															return MERRMEM;
	if(k=MBdeftab(m))															return k;

	if(MMpush(m, NIL))															return MERRMEM;

	for(j=0; j<4; j++)
	{
    	if(MMpush(m,2*2))		return MERRMEM;
		if(k=MBdeftab(m))		return k;
	}


	// creation de la liste des TexCoord2
	if(MMpush(m, ITOM(AROUNDINT(CONST_TEX_COORD*sprite->UV2[0].u))))			return MERRMEM;
	if(MMpush(m, ITOM(AROUNDINT(CONST_TEX_COORD*sprite->UV2[0].v))))			return MERRMEM;
	if(MMpush(m, 2*2))															return MERRMEM;
	if(k=MBdeftab(m))															return k;
	
	if(MMpush(m, ITOM(AROUNDINT(CONST_TEX_COORD*sprite->UV2[1].u))))			return MERRMEM;
	if(MMpush(m, ITOM(AROUNDINT(CONST_TEX_COORD*sprite->UV2[1].v))))			return MERRMEM;
	if(MMpush(m, 2*2))															return MERRMEM;
	if(k=MBdeftab(m))															return k;

	if(MMpush(m, ITOM(AROUNDINT(CONST_TEX_COORD*sprite->UV2[2].u))))			return MERRMEM;
	if(MMpush(m, ITOM(AROUNDINT(CONST_TEX_COORD*sprite->UV2[2].v))))			return MERRMEM;
	if(MMpush(m, 2*2))															return MERRMEM;
	if(k=MBdeftab(m))															return k;

	if(MMpush(m, ITOM(AROUNDINT(CONST_TEX_COORD*sprite->UV2[3].u))))			return MERRMEM;
	if(MMpush(m, ITOM(AROUNDINT(CONST_TEX_COORD*sprite->UV2[3].v))))			return MERRMEM;
	if(MMpush(m, 2*2))															return MERRMEM;
	if(k=MBdeftab(m))															return k;

	if(MMpush(m, NIL))															return MERRMEM;

	for(j=0; j<4; j++)
	{
    	if(MMpush(m,2*2))		return MERRMEM;
		if(k=MBdeftab(m))		return k;
	}


	// Creation de la liste finale
    if(MMpush(m,2*2))		return MERRMEM;
	if(k=MBdeftab(m))		return k;

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getSpriteTexCoordF
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d] [[F F] r1] [[F F] r1]]
int ZM3getSpriteTexCoordF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getSpriteTexCoordF ");
#endif

	int h3d   = MMpull(m);
    int s3d   = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL))								{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)											{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=SPR_TYPE_ID))				{	MMset(m,0,NIL);		return 0;	}
    ZSprite	*sprite = (ZSprite*)node;

	MMpull(m);

	int		j, k;

	// creation de la liste des TexCoord1
	if(MMpush(m, FTOM(sprite->UV1[0].u)))			return MERRMEM;
	if(MMpush(m, FTOM(sprite->UV1[0].v)))			return MERRMEM;
	if(MMpush(m, 2*2))								return MERRMEM;
	if(k=MBdeftab(m))								return k;
	
	if(MMpush(m, FTOM(sprite->UV1[1].u)))			return MERRMEM;
	if(MMpush(m, FTOM(sprite->UV1[1].v)))			return MERRMEM;
	if(MMpush(m, 2*2))								return MERRMEM;
	if(k=MBdeftab(m))								return k;

	if(MMpush(m, FTOM(sprite->UV1[2].u)))			return MERRMEM;
	if(MMpush(m, FTOM(sprite->UV1[2].v)))			return MERRMEM;
	if(MMpush(m, 2*2))								return MERRMEM;
	if(k=MBdeftab(m))								return k;

	if(MMpush(m, FTOM(sprite->UV1[3].u)))			return MERRMEM;
	if(MMpush(m, FTOM(sprite->UV1[3].v)))			return MERRMEM;
	if(MMpush(m, 2*2))								return MERRMEM;
	if(k=MBdeftab(m))								return k;

	if(MMpush(m, NIL))								return MERRMEM;

	for(j=0; j<4; j++)
	{
    	if(MMpush(m,2*2))		return MERRMEM;
		if(k=MBdeftab(m))		return k;
	}


	// creation de la liste des TexCoord2
	if(MMpush(m, FTOM(sprite->UV2[0].u)))			return MERRMEM;
	if(MMpush(m, FTOM(sprite->UV2[0].v)))			return MERRMEM;
	if(MMpush(m, 2*2))								return MERRMEM;
	if(k=MBdeftab(m))								return k;
	
	if(MMpush(m, FTOM(sprite->UV2[1].u)))			return MERRMEM;
	if(MMpush(m, FTOM(sprite->UV2[1].v)))			return MERRMEM;
	if(MMpush(m, 2*2))								return MERRMEM;
	if(k=MBdeftab(m))								return k;

	if(MMpush(m, FTOM(sprite->UV2[2].u)))			return MERRMEM;
	if(MMpush(m, FTOM(sprite->UV2[2].v)))			return MERRMEM;
	if(MMpush(m, 2*2))								return MERRMEM;
	if(k=MBdeftab(m))								return k;

	if(MMpush(m, FTOM(sprite->UV2[3].u)))			return MERRMEM;
	if(MMpush(m, FTOM(sprite->UV2[3].v)))			return MERRMEM;
	if(MMpush(m, 2*2))								return MERRMEM;
	if(k=MBdeftab(m))								return k;

	if(MMpush(m, NIL))								return MERRMEM;

	for(j=0; j<4; j++)
	{
    	if(MMpush(m,2*2))		return MERRMEM;
		if(k=MBdeftab(m))		return k;
	}


	// Creation de la liste finale
    if(MMpush(m,2*2))		return MERRMEM;
	if(k=MBdeftab(m))		return k;

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;
}


//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3setSpriteVrtColors
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d [I r1] [I r1]] I
int ZM3setSpriteVrtColors(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3setSpriteVrtColors ");
#endif

	int col2  = MTOP(MMpull(m));
	int col1  = MTOP(MMpull(m));
	int h3d   = MMpull(m);
    int s3d   = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL))								{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)											{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=SPR_TYPE_ID))				{	MMset(m,0,NIL);		return 0;	}
    ZSprite	*sprite = (ZSprite*)node;
	

	ZVector3	colors[4];
	int			col;

	if(col1!=NIL)
	{
		col = MTOI(MMfetch(m,col1,0));
		colors[0].SetCoord( ((float)((col&0x00ff0000)>>16)) / CONST_COLOR,
							((float)((col&0x0000ff00)>>8) ) / CONST_COLOR,
							((float) (col&0x000000ff)	  ) / CONST_COLOR  );

		col1 = MTOP(MMfetch(m,col1,1));
		if(col1==NIL)			{	MMset(m,0,NIL);		return 0;	}
		col = MTOI(MMfetch(m,col1,0));
		colors[1].SetCoord( ((float)((col&0x00ff0000)>>16)) / CONST_COLOR,
							((float)((col&0x0000ff00)>>8) ) / CONST_COLOR,
							((float) (col&0x000000ff)	  ) / CONST_COLOR  );

		col1 = MTOP(MMfetch(m,col1,1));
		if(col1==NIL)			{	MMset(m,0,NIL);		return 0;	}
		col = MTOI(MMfetch(m,col1,0));
		colors[2].SetCoord( ((float)((col&0x00ff0000)>>16)) / CONST_COLOR,
							((float)((col&0x0000ff00)>>8) ) / CONST_COLOR,
							((float) (col&0x000000ff)	  ) / CONST_COLOR  );

		col1 = MTOP(MMfetch(m,col1,1));
		if(col1==NIL)			{	MMset(m,0,NIL);		return 0;	}
		col = MTOI(MMfetch(m,col1,0));
		colors[3].SetCoord( ((float)((col&0x00ff0000)>>16)) / CONST_COLOR,
							((float)((col&0x0000ff00)>>8) ) / CONST_COLOR,
							((float) (col&0x000000ff)	  ) / CONST_COLOR  );

		sprite->vertColor1[0] = colors[0];	
		sprite->vertColor1[1] = colors[1];	
		sprite->vertColor1[2] = colors[2];	
		sprite->vertColor1[3] = colors[3];	
	}

	if(col2!=NIL)
	{
		col = MTOI(MMfetch(m,col2,0));
		colors[0].SetCoord( ((float)((col&0x00ff0000)>>16)) / CONST_COLOR,
							((float)((col&0x0000ff00)>>8) ) / CONST_COLOR,
							((float) (col&0x000000ff)	  ) / CONST_COLOR  );

		col2 = MTOP(MMfetch(m,col2,1));
		if(col2==NIL)			{	MMset(m,0,NIL);		return 0;	}
		col = MTOI(MMfetch(m,col2,0));
		colors[1].SetCoord( ((float)((col&0x00ff0000)>>16)) / CONST_COLOR,
							((float)((col&0x0000ff00)>>8) ) / CONST_COLOR,
							((float) (col&0x000000ff)	  ) / CONST_COLOR  );

		col2 = MTOP(MMfetch(m,col2,1));
		if(col2==NIL)			{	MMset(m,0,NIL);		return 0;	}
		col = MTOI(MMfetch(m,col2,0));
		colors[2].SetCoord( ((float)((col&0x00ff0000)>>16)) / CONST_COLOR,
							((float)((col&0x0000ff00)>>8) ) / CONST_COLOR,
							((float) (col&0x000000ff)	  ) / CONST_COLOR  );

		col2 = MTOP(MMfetch(m,col2,1));
		if(col2==NIL)			{	MMset(m,0,NIL);		return 0;	}
		col = MTOI(MMfetch(m,col2,0));
		colors[3].SetCoord( ((float)((col&0x00ff0000)>>16)) / CONST_COLOR,
							((float)((col&0x0000ff00)>>8) ) / CONST_COLOR,
							((float) (col&0x000000ff)	  ) / CONST_COLOR  );

		sprite->vertColor2[0] = colors[0];	
		sprite->vertColor2[1] = colors[1];	
		sprite->vertColor2[2] = colors[2];	
		sprite->vertColor2[3] = colors[3];	
	}

	MMset(m,0,0);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getSpriteVrtColors
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d] [[I r1] [I r1]]
int ZM3getSpriteVrtColors(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getSpriteVrtColors ");
#endif

	int h3d   = MMpull(m);
    int s3d   = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL))								{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)											{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=SPR_TYPE_ID))				{	MMset(m,0,NIL);		return 0;	}
    ZSprite	*sprite = (ZSprite*)node;
	
	MMpull(m);

	int		j, k, coul;


	// creation de la liste des vertColor1
	coul = AROUNDINT(sprite->vertColor1[0].z*CONST_COLOR) + (AROUNDINT(sprite->vertColor1[0].y*CONST_COLOR)<<8) + (AROUNDINT(sprite->vertColor1[0].x*CONST_COLOR)<<16);
	if(MMpush(m,ITOM(coul)))		return MERRMEM;

	coul = AROUNDINT(sprite->vertColor1[1].z*CONST_COLOR) + (AROUNDINT(sprite->vertColor1[1].y*CONST_COLOR)<<8) + (AROUNDINT(sprite->vertColor1[1].x*CONST_COLOR)<<16);
	if(MMpush(m,ITOM(coul)))		return MERRMEM;
	
	coul = AROUNDINT(sprite->vertColor1[2].z*CONST_COLOR) + (AROUNDINT(sprite->vertColor1[2].y*CONST_COLOR)<<8) + (AROUNDINT(sprite->vertColor1[2].x*CONST_COLOR)<<16);
	if(MMpush(m,ITOM(coul)))		return MERRMEM;
	
	coul = AROUNDINT(sprite->vertColor1[3].z*CONST_COLOR) + (AROUNDINT(sprite->vertColor1[3].y*CONST_COLOR)<<8) + (AROUNDINT(sprite->vertColor1[3].x*CONST_COLOR)<<16);
	if(MMpush(m,ITOM(coul)))		return MERRMEM;

	if(MMpush(m, NIL))															return MERRMEM;

	for(j=0; j<4; j++)
	{
    	if(MMpush(m,2*2))		return MERRMEM;
		if(k=MBdeftab(m))		return k;
	}


	// creation de la liste des vertColor2
	coul = AROUNDINT(sprite->vertColor2[0].z*CONST_COLOR) + (AROUNDINT(sprite->vertColor2[0].y*CONST_COLOR)<<8) + (AROUNDINT(sprite->vertColor2[0].x*CONST_COLOR)<<16);
	if(MMpush(m,ITOM(coul)))		return MERRMEM;

	coul = AROUNDINT(sprite->vertColor2[1].z*CONST_COLOR) + (AROUNDINT(sprite->vertColor2[1].y*CONST_COLOR)<<8) + (AROUNDINT(sprite->vertColor2[1].x*CONST_COLOR)<<16);
	if(MMpush(m,ITOM(coul)))		return MERRMEM;
	
	coul = AROUNDINT(sprite->vertColor2[2].z*CONST_COLOR) + (AROUNDINT(sprite->vertColor2[2].y*CONST_COLOR)<<8) + (AROUNDINT(sprite->vertColor2[2].x*CONST_COLOR)<<16);
	if(MMpush(m,ITOM(coul)))		return MERRMEM;
	
	coul = AROUNDINT(sprite->vertColor2[3].z*CONST_COLOR) + (AROUNDINT(sprite->vertColor2[3].y*CONST_COLOR)<<8) + (AROUNDINT(sprite->vertColor2[3].x*CONST_COLOR)<<16);
	if(MMpush(m,ITOM(coul)))		return MERRMEM;

	if(MMpush(m, NIL))															return MERRMEM;

	for(j=0; j<4; j++)
	{
    	if(MMpush(m,2*2))		return MERRMEM;
		if(k=MBdeftab(m))		return k;
	}


	// Creation de la liste finale
    if(MMpush(m,2*2))		return MERRMEM;
	if(k=MBdeftab(m))		return k;

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3setSpriteAngle
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d I] I
int ZM3setSpriteAngle(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3setSpriteAngle ");
#endif

	int rot = MMpull(m);
	int h3d = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL)||(rot==NIL))							{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)													{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=SPR_TYPE_ID))						{	MMset(m,0,NIL);		return 0;	}
    ZSprite	*sprite = (ZSprite*)node;

	// Attribution de la rotation
	sprite->rotationZ = ((float)MTOI(rot)) * 360.0f/CONST_ANGLE;

	MMset(m,0,0);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;	
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3setSpriteAngleF
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d F] I
int ZM3setSpriteAngleF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3setSpriteAngleF ");
#endif

	int rot = MMpull(m);
	int h3d = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL)||(rot==NIL))							{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)													{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=SPR_TYPE_ID))						{	MMset(m,0,NIL);		return 0;	}
    ZSprite	*sprite = (ZSprite*)node;

	// Attribution de la rotation
	sprite->rotationZ = MTOF(rot) * 180.0f/MY_PI;

	MMset(m,0,0);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getSpriteAngle
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d] I
int ZM3getSpriteAngle(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getSpriteAngle ");
#endif

	int h3d = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL))										{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)													{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=SPR_TYPE_ID))						{	MMset(m,0,NIL);		return 0;	}
    ZSprite	*sprite = (ZSprite*)node;

	MMset(m,0,ITOM(AROUNDINT(sprite->rotationZ * CONST_ANGLE / 360.0f)));

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;	
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3getSpriteAngleF
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d] F
int ZM3getSpriteAngleF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3getSpriteAngleF ");
#endif

	int h3d = MMpull(m);
    int s3d = MMget(m,0);

    if((s3d==NIL)||(h3d==NIL))										{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)													{	MMset(m,0,NIL);		return 0;	}

    ZNode	*node = (ZNode*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=SPR_TYPE_ID))						{	MMset(m,0,NIL);		return 0;	}
    ZSprite	*sprite = (ZSprite*)node;

	MMset(m,0, FTOM(sprite->rotationZ * MY_PI/180.0f) );

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;	
}



	



















//////////////////////////////////////////////////////////////////////////////////////////////
///		_SDRAWrectangle														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [ObjSurface I I I I I I I I I] ObjSurface
int ZSDRAWrectangle (mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"_SDRAWrectangle ");
#endif

	if(userACCEL)
	{
		float	r, g, b;
		int		x, y, w, h, mc, tc, cc, mf, cf, surf;

		cf = MTOI(MMpull(m));
		mf = MTOI(MMpull(m));
		cc = MTOI(MMpull(m));
		tc = MTOI(MMpull(m));
		mc = MTOI(MMpull(m));
		h  = MTOI(MMpull(m));
		w  = MTOI(MMpull(m));
		y  = MTOI(MMpull(m));
		x  = MTOI(MMpull(m));

		surf = MTOP(MMget(m,0));
		if(surf==NIL)	return 0;

		SetGL2D(m,surf);

		//$BLG - v5.24: Modif
		//if(mc)
		if(mf == DRAW_SOLID)
		{
			//$BLG - v5.24: Add (uncommented)
			glDisable(GL_CULL_FACE);

			//$BLG - v5.24: Modif
			/*
			b = ((cf>>16)&255)	/ CONST_COLOR;
			g = ((cf>>8)&255)	/ CONST_COLOR;  
			r = ((cf)&255)		/ CONST_COLOR;
			*/
			r = ((cf >> 16) & 255) / CONST_COLOR;
			g = ((cf >> 8)  & 255) / CONST_COLOR;  
			b = ((cf)       & 255) / CONST_COLOR;  
			
			glShadeModel(GL_FLAT);
			glBegin(GL_QUADS);
				glColor4f(r, g, b, 1.0f);
				glVertex2f(x + w, y);
				glVertex2f(x + w, y + h); 	
				glVertex2f(x, y + h); 
				glVertex2f(x, y); 
			glEnd();

			//$BLG - v5.24: Add (uncommented)
			glEnable(GL_CULL_FACE);
		}

		//$BLG - v5.24: Modif
		//if(mf)
		if(mc == DRAW_SOLID)
		{
			//$BLG - v5.24: Modif
			/*
			b = ((cf>>16)&255)	/ CONST_COLOR;  
			g = ((cf>>8)&255)	/ CONST_COLOR;  
			r = ((cf)&255)		/ CONST_COLOR;  
			*/
			r = ((cc >> 16) & 255) / CONST_COLOR;  
			g = ((cc >> 8)	& 255) / CONST_COLOR;  
			b = ((cc)				& 255) / CONST_COLOR; 

			glColor4f(r, g, b, 1.0);
			glLineWidth(tc);
			
			glBegin(GL_LINE_LOOP);
				glVertex2f(x, y);  
				glVertex2f(x + w, y);  
				glVertex2f(x + w, y + h);  
				glVertex2f(x, y + h);
			glEnd();
			
			glLineWidth(1);
		}

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
		return 0;
	}
	else
	{
        int Couleur_Remplissage ;
        int Mode_Remplissage ;
        int Couleur_Contour ;
        int Taille_Contour ;
        int Mode_Contour ;
        int TailleW , TailleH , PosX , PosY , s ;
        PtrObjVoid O ;        
        HPEN Pinceau , OldPen ;
        HWND Item , OldItem ;
        LOGBRUSH Brush ;
        HBRUSH HBrush , OldBrush ;
        HDC Dc ;

        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 :
                Item = (HWND)(( PtrObjBitmap ) MMstart(m, (O->Buffer>>1)) ) ->DIBhandler ;
                Dc = CreateCompatibleDC ( NULL ) ;
                OldItem = (HWND) 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 = (HPEN) SelectObject ( Dc , Pinceau ) ;
        OldBrush = (HBRUSH) 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) ;

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
        return s ;
	}
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		_SDRAWline														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun[ObjSurface I I I I I I I] ObjSurface
int ZSDRAWline (mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"_SDRAWline ");
#endif

	if(userACCEL)
	{
		float	r, g, b;
		int		x, y, xx, yy, mc, tc, cc, surf;

		cc = MMpull(m)>>1;
		tc = MMpull(m)>>1;
		mc = MMpull(m)>>1;
		yy = MMpull(m)>>1;
		xx = MMpull(m)>>1;
		y  = MMpull(m)>>1;
		x  = MMpull(m)>>1;

		surf = MMget(m,0)>>1;
		if(surf == NIL)		return 0;

		SetGL2D(m, surf);

		if (mc == DRAW_SOLID)
		{
			//$BLG - v5.24: Modif
			/*
			b = ((cc>>16)&255) / CONST_COLOR;
			g = ((cc>>8)&255)	/ CONST_COLOR;
			r = ((cc)&255) / CONST_COLOR;
			*/
			r = ((cc>>16)&255) / CONST_COLOR;
			g = ((cc>>8)&255)	/ CONST_COLOR;
			b = ((cc)&255) / CONST_COLOR;
			
			glColor4f(r, g, b, 1.0);
			
			glLineWidth(tc);

			
			glBegin(GL_LINES);
				glVertex2f(x, y);  
				glVertex2f(xx, yy);
			glEnd();

			glLineWidth(1);
		}

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
		return 0;
	}
	else
	{
		int			Taille_Contour, Mode_Contour, Couleur_Contour, X1, Y1, X2, Y2;
		int			surf;
		PtrObjVoid	O;    
		HPEN		Pinceau, OldPen;
		HWND		Item, OldItem;
		POINT		Ligne[2];
		HDC			Dc;

		Couleur_Contour = MTOI( MMpull(m) );
		Taille_Contour	= MTOI( MMpull(m) );
		Mode_Contour	= MTOI( MMpull(m) );
		Y2				= MTOI( MMpull(m) );
		X2				= MTOI( MMpull(m) );
		Y1				= MTOI( MMpull(m) );
		X1				= MTOI( MMpull(m) );
		surf			= MMpull(m);
    
		if(surf == NIL)        return MMpush(m,NIL);

		O = (PtrObjVoid) MMstart(m, (surf>>1) );
    
		switch( MTOI(O->Type) )
		{
			case OBJ_TYPE_BITMAP :          
				Dc	 = CreateCompatibleDC( NULL );
				Item = (HWND) ((PtrObjBitmap)MMstart(m,(O->Buffer>>1)))->DIBhandler;
				OldItem = (HWND) 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 = (HPEN) 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 = (HPEN) SelectObject(Dc, OldPen);
		surf = MMpush(m,surf);
    
		if(O->Type == ITOM(OBJ_TYPE_BITMAP))
		{
			SelectObject(Dc, OldItem);
			DeleteDC( Dc );
		}
		DeleteObject(OldPen);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
		return surf;
	}
}


//////////////////////////////////////////////////////////////////////////////////////////////
///		_SDRAWcircle														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun[ObjSurface I I I I I I I I] ObjSurface
int ZSDRAWcircle (mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"_SDRAWcircle ");
#endif

	if(userACCEL)
	{
		int		x,y,ray,mc,tc,cc,mf,cf,surf,i;
		float	r,g,b /*//$BLG - v5.3.01: Del ,angle*/;

		cf	= MMpull(m)>>1,
		mf	= MMpull(m)>>1,
		cc	= MMpull(m)>>1,
		tc	= MMpull(m)>>1,
		mc	= MMpull(m)>>1,
		ray	= MMpull(m)>>1,
		y	= MMpull(m)>>1,
		x	= MMpull(m)>>1,
		
		surf = MMget(m,0)>>1;
		if(surf==NIL)		return 0;
  
		SetGL2D(m,surf);

		if (mf == DRAW_SOLID)
		{
			glDisable(GL_CULL_FACE);
			
			//$BLG - v5.24: Modif
			/*
			b = ((cf>>16)&255)	/ CONST_COLOR;  
			g = ((cf>>8)&255)	/ CONST_COLOR;  
			r = ((cf)&255)		/ CONST_COLOR; 
			*/
			r = ((cf>>16)&255)	/ CONST_COLOR;  
			g = ((cf>>8)&255)	/ CONST_COLOR;  
			b = ((cf)&255)		/ CONST_COLOR;   

			glColor3f(r,g,b);

			//$BLG - v5.3.01: Modif
			/*
			glBegin(GL_TRIANGLE_FAN);
				//$BLG - v5.24: Modif
				//for (i=0;i<ray*2;i++)
				//{
					//angle=(3.1415926535/((float)ray*2.0f)) * (float)i;
					//glVertex2f(x+sin(angle)*ray, y+cos(angle)*ray); 
				//}
				for (i = 0 ; i < 360; i++)
				{
					angle = (2.0 * 3.1415926535) * ((float)i / 360);
					glVertex2f(x + (ray * cos(angle)), y + (ray * sin(angle)));
				}				
			glEnd();
			*/
			glBegin(GL_TRIANGLE_FAN);
				for (i = 0 ; i < 360; i++)
				{
					glVertex2f(x + (ray * tabCos[i]), y + (ray * tabSin[i]));
				}				
			glEnd();

			glEnable(GL_CULL_FACE);
		}

		if (mc == DRAW_SOLID)
		{
			//$BLG - v5.24: Modif
			/*
			b = ((cf>>16)&255)	/ CONST_COLOR;  
			g = ((cf>>8)&255)	/ CONST_COLOR;  
			r = ((cf)&255)		/ CONST_COLOR;
			*/
			r = ((cc>>16)&255)	/ CONST_COLOR;  
			g = ((cc>>8)&255)	/ CONST_COLOR;  
			b = ((cc)&255)		/ CONST_COLOR;  

			glColor3f(r,g,b);
			glLineWidth(tc);
			
			//$BLG - v5.3.01: Modif
			/*
			glBegin(GL_LINE_LOOP);
				//$BLG - v5.24: Modif
				//for (i=0;i<ray/2;i++)
				//{
					//angle=(4*3.1415926535/(float)ray)*(float)i;
					//glVertex2f(x+sin(angle)*ray,y+cos(angle)*ray);
				//}
				for (i = 0 ; i < 360; i++)
				{
					angle = (2.0 * 3.1415926535) * ((float)i / 360);
					glVertex2f(x + (ray * cos(angle)), y + (ray * sin(angle)));
				}			
			glEnd();
			*/
			glBegin(GL_LINE_LOOP);
				for (i = 0 ; i < 360; i++)
				{
					glVertex2f(x + (ray * tabCos[i]), y + (ray * tabSin[i]));
				}			
			glEnd();
		}
		glLineWidth(1);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
		return 0;
	}
	else
	{
		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 ;

		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) ) ;
				Dc = CreateCompatibleDC ( NULL ) ;
				Item = (HWND)B->DIBhandler ; 
				OldItem = (HWND) 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 = (HBRUSH) SelectObject ( Dc , HBrush ) ;
		OldPen = (HPEN) 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) ;

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
		return s ;
	}
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		Structure GLFont														
//////////////////////////////////////////////////////////////////////////////////////////////
typedef struct GLFont
{
	int list;
	int height;
	int ascend;
} GLFont;





//////////////////////////////////////////////////////////////////////////////////////////////
///		_SDRAWtext														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun[ObjSurface ObjFont I I I I S] ObjSurface
int ZSDRAWtext (mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"_SDRAWtext ");
#endif

	if(userACCEL)
	{
		//MMechostr(0,"_SDRAWtext\n");
		
		glDisable(GL_CULL_FACE);

		PtrObjVoid	OB;
		PtrObjFont	F;
		
		int			font, surf, x, y, flag, col, pstr, listbase;
		char		buf[1025];											// texte à afficher

		HDC			dc;
		HWND		hwnd;
		HGLRC		rc;

		float		r, g, b;
		GLFont	*glfont = NULL;

		buf[1024] = 0;
		
		//$BLG - v5.24: Add
		bool ret;
		int textout;

		pstr =	MMpull(m)>>1;
		col	 =	MMpull(m)>>1;
		flag =	MMpull(m)>>1;		//$BLG Note: Flags are not handled at all before v5.24
		y	   =	MMpull(m)>>1;
		x	   =	MMpull(m)>>1;
		font =	MMpull(m)>>1;
		surf =	MMget(m,0)>>1;

		if ((surf == NIL) || (font == NIL) || (x == NIL) || (y == NIL) || (col == NIL) || (pstr == NIL))
			{/*MMechostr(0,"_SDRAWtext NIL Var\n");*/ return 0;}

		strncpy(buf, MMstartstr(m,pstr), 1024);					// recup le txt

		//$BLG - v5.24: Modif
		//SetGL2D(m, surf, &dc, &hwnd, &rc);						// passe en mode 2D
		ret = SetGL2D(m, surf, &dc, &hwnd, &rc);				// passe en mode 2D
		//MMechostr(0, "SetGL2D: %d\n", ret);

		OB = ( PtrObjVoid ) MMstart(m, font);
		//$BLG: v4.6a6 - Del 
		//Retrieved and used only in next IF
		//F  = ( PtrObjFont ) MMstart(m, OB->Buffer>>1);

		if (OB->Tab == NIL)
		{
			//MMechostr(0,"_SDRAWtext NIL Tab\n");
			// ---------------------> supprimer le OB->tab, car il contient un pointeur SCOL qui ne sera jamais réinitialisé !!!!!!!!!!!
			int f;
			HGDIOBJ oldobj;
			TEXTMETRIC textmetric;
			//$BLG - v5.24: Add
			GLYPHMETRICSFLOAT agmf;

			glfont = (GLFont*) malloc(sizeof(GLFont));
			if (!glfont)		return 0;
			
			MMpush(m, PTOM(font));
			f = MMmalloc(m, 2, TYPEBUF);
			if (f < 0)			return f;
			
			font = MTOP(MMpull(m));
			OB   = (PtrObjVoid) MMstart(m, font);
			F    = (PtrObjFont) MMstart(m, MTOP(OB->Buffer));
			OB->Tab = PTOM(f);
			MMstore(m, f, 0, 0);
			MMstore(m, f, 1, (int)glfont);

			oldobj = SelectObject(dc, F->WHandler);
			//$BLG - v5.24: Add
			/*
			if (oldobj == NULL) MMechostr(0, "SelectObject: NULL\n");
			else if (oldobj == HGDI_ERROR) MMechostr(0, "SelectObject: HGDI_ERROR\n");
			else MMechostr(0, "SelectObject: OK old:%d new:%d\n", oldobj, F->WHandler);
			*/
			
			//$BLG - v5.24: Modif
			//glfont->list = glGenLists(255);
			glfont->list = glGenLists(256);
			//$BLG - v5.24: Add
			/*
			if (glfont->list == GL_INVALID_VALUE) MMechostr(0, "glGenLists: GL_INVALID_VALUE\n");
			else if (glfont->list == GL_INVALID_OPERATION ) MMechostr(0, "glGenLists: GL_INVALID_OPERATION\n");
			else MMechostr(0, "glGenLists: OK\n");
			*/
			
			//$BLG - v5.24: Modif
			//wglUseFontBitmaps(dc, 0, 255, glfont->list);
			//$BLG - v5.24: Modif
			if (F->Flags & FF_HOLLOW)
				textout = WGL_FONT_LINES;
			else
				textout = WGL_FONT_POLYGONS;
			ret = (wglUseFontOutlines(dc, 0, 256, glfont->list, 0, 0, textout, &agmf) != 0);
			//if (ret == FALSE) MMechostr(0, "wglUseFontOutlines: FALSE %d\n", ret); else MMechostr(0, "wglUseFontOutlines: TRUE %d\n", ret);

			GetTextMetrics(dc, &textmetric);
			glfont->height = textmetric.tmHeight;
			glfont->ascend = textmetric.tmAscent;
			//MMechostr(0, "Font h:%d a:%d\n", glfont->height, glfont->ascend);

			SelectObject(dc, oldobj);
			//MMechostr(0, "OK\n");
		}

		glfont = (GLFont*) MMfetch(m, MTOP(OB->Tab), 1);
		//if(!glfont)		{MMechostr(0, "_SDRAWtext !glfont\n"); return 0;}

		glGetIntegerv(GL_LIST_BASE, &listbase);

		r = ((col)&255)		/ CONST_COLOR;  
		g = ((col>>8)&255)  / CONST_COLOR;  
		b = ((col>>16)&255) / CONST_COLOR;  
		glColor3f(r,g,b);

		//$BLG - v5.24: Add
		glPushMatrix();
		glTranslatef(x, y+glfont->ascend, 0);
		glRotatef(180, 1, 0, 0);
		glScalef(glfont->height,glfont->height , 1);

		//$BLG - v5.24: Del
		//glRasterPos2i(x, y+glfont->ascend);
		
		//MMechostr(0, "color: %2.0f %2.0f %2.0f\n", (r*CONST_COLOR), (g*CONST_COLOR), (b*CONST_COLOR));
		//MMechostr(0, "pos: %d %d %d\n", x, y, y+glfont->ascend);

		glListBase(glfont->list);
		
		//$BLG - v5.24: Add
		/*
		GLint frontFace;
		glGetIntegerv(GL_FRONT_FACE, &frontFace);
		*/
		
		glCallLists(strlen(buf), GL_UNSIGNED_BYTE, buf);
		
		//$BLG - v5.24: Add
		/*
		if (frontFace == GL_CCW) {
			glFrontFace(GL_CCW);
		}
		else {
			glFrontFace(GL_CW);
		}
		*/
		
		glListBase(listbase);
		
		//$BLG - v5.24: Add
		glPopMatrix();

		glEnable(GL_CULL_FACE);
		
		//MMechostr(0,"_SDRAWtext OK: %d %s\n", strlen(buf), buf);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
		return 0;
	}
	else
	{
		PtrObjVoid		OB, OF;
		PtrObjFont		F;
		PtrObjBitmap	B;
		int				Flag, PosX, PosY, s, Color, TFlag, s2, oldbk;
		HFONT			OldFont;
		HBITMAP			OldBuffer;
		HDC				Dc;
		HWND			Hw;
		char			Texte[33000];
		

		s = MMpull(m);
		if(s==NIL)		strcpy(Texte, "");
		else			strcpy(Texte, (char*) MMstart(m, (s>>1)+1));

		Color	= MTOI(MMpull(m));
		Flag	= MTOI(MMpull(m));
		PosY	= MTOI(MMpull(m));
		PosX	= MTOI(MMpull(m));
		s2		= MMpull(m);
		s		= MMpull(m);

		if(s2==NIL)			{return MMpush(m,s);}

		OF = (PtrObjVoid) MMstart(m, MTOP(s2));
		F  = (PtrObjFont) MMstart(m, MTOP(OF->Buffer));

		if(s==NIL)			{return MMpush(m,NIL);}

		OB = (PtrObjVoid) MMstart(m, MTOP(s));

		switch(MTOI(OB->Type))
		{
			case OBJ_TYPE_BITMAP :
				B  = (PtrObjBitmap) MMstart(m, MTOP(OB->Buffer));
				Dc = CreateCompatibleDC(NULL);
				OldBuffer = (HBITMAP) SelectObject(Dc, B->DIBhandler);
				break ;

			case OBJ_TYPE_WINDOW :
				Hw = ((PtrObjWindow) MMstart(m,MTOP(OB->Buffer)))->WHandler;
				Dc = GetDC(Hw);
				break ;

			default :
    			MMechostr ( 1 , "TextOut : Parameter Win/Bitmap is type %d\n" , OB->Type >> 1) ;
			return MMpush(m,s);
		}

		TFlag = 0;
		if(Flag & TD_BASELINE )		TFlag |= TA_BASELINE;
		if(Flag & TD_BOTTOM )		TFlag |= TA_BOTTOM;
		if(Flag & TD_TOP )			TFlag |= TA_TOP;
		if(Flag & TD_CENTER )		TFlag |= TA_CENTER;
		if(Flag & TD_LEFT )			TFlag |= TA_LEFT;
		if(Flag & TD_RIGHT )		TFlag |= TA_RIGHT;
    
		OldFont = (HFONT) SelectObject(Dc, F->WHandler);
   
		SetTextColor(Dc, Color);
		oldbk = SetBkMode(Dc, TRANSPARENT);
		SetTextAlign(Dc, TFlag);
    
		if(TextOut(Dc, PosX, PosY, Texte, strlen(Texte)) == FALSE)			MMechostr ( 1 , "Error in Text Out\n" );

		SetBkMode(Dc, oldbk);
		SelectObject(Dc, OldFont);

		if(OB->Type == ITOM(OBJ_TYPE_BITMAP))
		{
			OldBuffer = (HBITMAP) SelectObject(Dc, OldBuffer);
			DeleteDC(Dc);
		}
		
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
		return MMpush(m,s);
	}
}


//$BLG - v5.3.01: Add
//////////////////////////////////////////////////////////////////////////////////////////////
///                     _SDRAWpoint
//////////////////////////////////////////////////////////////////////////////////////////////
// fun[ObjSurface I I I] ObjSurface
int ZSDRAWpoint (mmachine m)
{

#ifdef _SCOL_DEBUG_
  MMechostr(0,"_SDRAWpoint ");
#endif

	if (userACCEL)
	{
    float      r, g, b;
    int                     x, y, c, surf;

    c = MMpull(m)>>1;
    y = MMpull(m)>>1;
    x = MMpull(m)>>1;

    surf = MMget(m, 0)>>1;
    if(surf == NIL)
      return 0;

    SetGL2D(m, surf);

    r = ((c>>16)&255) / CONST_COLOR;
    g = ((c>>8)&255) / CONST_COLOR;
    b = ((c)&255) / CONST_COLOR;
   
    glColor4f(r, g, b, 1.0);
   
    glBegin(GL_POINTS);
      glVertex2f(x, y);
    glEnd();
	
#ifdef     _SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
		
	  return 0;
	}
	else
	{
    int                                 x, y, c;
    int                                 surf;
    PtrObjVoid        O;   
    HPEN               Pen, OldPen;
    HWND              Item, OldItem;
    HDC                             Dc;

    c = MTOI(MMpull(m));
    y = MTOI(MMpull(m));
    x = MTOI(MMpull(m));
    surf = MMpull(m);

    if (surf == NIL)
      return MMpush(m, NIL);

    O = (PtrObjVoid)MMstart(m, (surf>>1));

    switch(MTOI(O->Type))
    {
      case OBJ_TYPE_BITMAP:         
        Dc = CreateCompatibleDC(NULL);
        Item = (HWND)((PtrObjBitmap)MMstart(m, (O->Buffer>>1)))->DIBhandler;
        OldItem = (HWND)SelectObject(Dc, Item);
        break;
      case OBJ_TYPE_WINDOW:
        Item = ((PtrObjWindow)MMstart(m, (O->Buffer>>1)))->WHandler;
        Dc = GetDC(Item);
        break;
    }
	
    Pen = CreatePen(PS_SOLID, 1, c);

    OldPen = (HPEN)SelectObject(Dc, Pen);

    SetPixel(Dc, x, y, c);

    OldPen = (HPEN)SelectObject(Dc, OldPen);
    surf = MMpush(m, surf);

    if(O->Type == ITOM(OBJ_TYPE_BITMAP))
    {
		  SelectObject(Dc, OldItem);
		  DeleteDC(Dc);
    }
    DeleteObject(OldPen);
	
#ifdef     _SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
	  
	  return surf;
	}
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		_SDRAWpoly														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun[ObjSurface I tab[I I] I I I I I] ObjSurface
int ZSDRAWpoly (mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"_SDRAWpoly ");
#endif

	if(userACCEL)
	{
		float	r,g,b;
		int		*ptab;
		
		int	cf	 = MMpull(m)>>1,
				mf	 = MMpull(m)>>1,
				cc	 = MMpull(m)>>1,
				tc	 = MMpull(m)>>1,
				mc	 = MMpull(m)>>1,
				pt	 = MMpull(m)>>1,
				np	 = MMpull(m)>>1,
				surf = MMget(m,0)>>1;

		//MMechostr(0,"_SDRAWpoly\n");

		if (np < 3)			return 0;
		//MMechostr(0,"_SDRAWpoly np\n");
		if (pt == NIL)	return 0;
		//MMechostr(0,"_SDRAWpoly pt\n");
		
		//$BLG - v5.24: Modif
		ptab = (int *)MMstart(m, pt);
		//ptab = (int *)MMstart(m, pt<<1);
  
		if (surf == NIL)	return 0;
		//MMechostr(0,"_SDRAWpoly surf\n");
		SetGL2D(m, surf);

		if (mf == DRAW_SOLID)
		{
			//MMechostr(0,"_SDRAWpoly mf\n");
			glDisable(GL_CULL_FACE);

			//$LB
			r = ((cf>>16) & 0xFF) / CONST_COLOR;  
			g = ((cf>>8)  & 0xFF) / CONST_COLOR;
			b = ((cf)     & 0xFF) / CONST_COLOR;
			glColor3f(r, g ,b);
			
			glBegin(GL_TRIANGLE_FAN);
				//$BLG - v5.24: Modif
				//for(int n = 0; n < np; n += 2)		  glVertex2i(*(ptab+n), *(ptab+n+1));
				//glVertex2i(*(ptab), *(ptab+1));
				for(int n = 0; n < np; n++)		glVertex2i(MTOI(MMfetch(m, (*(ptab+n))>>1, 0)), MTOI(MMfetch(m, (*(ptab+n))>>1, 1)));
				glVertex2i(MTOI(MMfetch(m, (*ptab)>>1, 0)), MTOI(MMfetch(m, (*ptab)>>1, 1)));
			glEnd();
		
			glEnable(GL_CULL_FACE);
		}

		if (mc == DRAW_SOLID)
		{
			//MMechostr(0,"_SDRAWpoly mc\n");
			r = ((cc>>16) & 0xFF) / CONST_COLOR;
			g = ((cc>>8)  & 0xFF) / CONST_COLOR;
			b = ((cc)     & 0xFF) / CONST_COLOR;
			glLineWidth(tc);
			glColor3f(r, g, b);
			
			glBegin (GL_LINE_LOOP);
				//$BLG - v5.24: Modif
				//for(int n = 0; n < np; n += 2)		  glVertex2i(*(ptab+n), *(ptab+n+1));
				//$BLG Note: Debug
				//for (int n = 0; n < np; n++)		  { MMechostr(0,"_SDRAWpoly %d %d - %d %d\n", MMtype(m, pt), *(ptab+n), MTOI(MMfetch(m, (*(ptab+n))>>1, 0)), MTOI(MMfetch(m, (*(ptab+n))>>1, 1))); glVertex2i(*(ptab+n), *(ptab+n+1)); }
				for (int n = 0; n < np; n++)	glVertex2i(MTOI(MMfetch(m, (*(ptab+n))>>1, 0)), MTOI(MMfetch(m, (*(ptab+n))>>1, 1)));
			glEnd();
			
			glLineWidth(1);
		}
		
		//MMechostr(0,"_SDRAWpoly OK\n");

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
		return 0;
	}
	else
	{
		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 ;

		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) ) ;   
   
		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)(( PtrObjBitmap ) MMstart(m, (O->Buffer>>1) ) )->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 = (HPEN)SelectObject ( Dc , Pinceau ) ;
		OldItem = (HWND)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 = (HBRUSH)SelectObject ( Dc , HBrush ) ;

		Polygon ( Dc , p , np2 ) ;
		SetPolyFillMode ( Dc , ALTERNATE ) ;

		SelectObject ( Dc , OldItem ) ;
		OldPen = (HPEN)SelectObject ( Dc , OldPen ) ;
		OldBrush = (HBRUSH)SelectObject ( Dc , OldBrush ) ;
		DeleteDC ( Dc ) ;
		DeleteObject ( OldPen ) ;
		DeleteObject ( OldBrush ) ;
		s = MMpush(m,s) ;

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif
		return s ;
	}
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		M3interpVec														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun[[I I I] [I I I] I] [I I I]
int M3interpVec(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3interpVec ");
#endif

    int			p,q,tx;
    ZVector3	v, w, r;

	tx = MMpull(m)>>1;
    q  = MMpull(m)>>1;
    p  = MMpull(m)>>1;
    if((p==NIL)||(q==NIL))		return MMpush(m,NIL);

	tx &= 255;

    v.x	= MMfetch(m,p,0)>>1;
    v.y	= MMfetch(m,p,1)>>1;
    v.z	= MMfetch(m,p,2)>>1;
    w.x	= MMfetch(m,q,0)>>1;
    w.y	= MMfetch(m,q,1)>>1;
    w.z	= MMfetch(m,q,2)>>1;

	r = v*(1-((float)tx)/CONST_VAL8) + w*(((float)tx)/CONST_VAL8);
	
	if (MMpush(m,ITOM(AROUNDINT(r.x))))		return MERRMEM;
	if (MMpush(m,ITOM(AROUNDINT(r.y))))		return MERRMEM;
	if (MMpush(m,ITOM(AROUNDINT(r.z))))		return MERRMEM;
	if (MMpush(m,3*2))						return MERRMEM;

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return MBdeftab(m);
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		M3interpVecF														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun[[F F F] [F F F] F] [F F F]
int M3interpVecF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3interpVecF ");
#endif

    int			p,q,tx;
    ZVector3	v, w, r;

	tx = MMpull(m);
    q  = MTOP(MMpull(m));
    p  = MTOP(MMpull(m));
    
	if((p==NIL)||(q==NIL))			return MMpush(m,NIL);

	float	rate = MTOF(tx);

    v.x	= MTOF(MMfetch(m,p,0));
    v.y	= MTOF(MMfetch(m,p,1));
    v.z	= MTOF(MMfetch(m,p,2));
    
	w.x	= MTOF(MMfetch(m,q,0));
    w.y	= MTOF(MMfetch(m,q,1));
    w.z	= MTOF(MMfetch(m,q,2));

	r = v*(1-rate) + w*rate;
	
	if (MMpush(m,FTOM(r.x)))		return MERRMEM;
	if (MMpush(m,FTOM(r.y)))		return MERRMEM;
	if (MMpush(m,FTOM(r.z)))		return MERRMEM;
	if (MMpush(m,3*2))				return MERRMEM;

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return MBdeftab(m);
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		M3interpAng													
//////////////////////////////////////////////////////////////////////////////////////////////
// fun[[I I I] [I I I] I] [I I I]
int M3interpAng(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3interpAng ");
#endif

    int			p,q,tx;
    ZVector3	v, w, r;

	tx = MMpull(m)>>1;
    q  = MMpull(m)>>1;
    p  = MMpull(m)>>1;
    if((p==NIL)||(q==NIL))		return MMpush(m,NIL);

	tx &= 255;

	v.x = MMfetch(m,p,0)>>1;
    v.y = MMfetch(m,p,1)>>1;
    v.z = MMfetch(m,p,2)>>1;

    w.x = MMfetch(m,q,0)>>1;
    w.y = MMfetch(m,q,1)>>1;
    w.z = MMfetch(m,q,2)>>1;

	r  = interpAng(v*(360.0f/CONST_ANGLE), w*(360.0f/CONST_ANGLE), ((float)tx)/CONST_VAL8);
	r *= CONST_ANGLE / 360.0f;

	if (MMpush(m,ITOM(AROUNDINT(r.x))))		return MERRMEM;
	if (MMpush(m,ITOM(AROUNDINT(r.y))))		return MERRMEM;
	if (MMpush(m,ITOM(AROUNDINT(r.z))))		return MERRMEM;
	if (MMpush(m,3*2))						return MERRMEM;

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

    return MBdeftab(m);
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		M3interpAngF
//////////////////////////////////////////////////////////////////////////////////////////////
// fun[[F F F] [F F F] F] [F F F]
int M3interpAngF(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3interpAngF ");
#endif

    int			p,q,tx;
    ZVector3	v, w, r;

	tx = MMpull(m);
    q  = MTOP(MMpull(m));
    p  = MTOP(MMpull(m));

    if((p==NIL)||(q==NIL))		return MMpush(m,NIL);

	float	rate = MTOF(tx);

    v.x	= MTOF(MMfetch(m,p,0));
    v.y	= MTOF(MMfetch(m,p,1));
    v.z	= MTOF(MMfetch(m,p,2));
    
	w.x	= MTOF(MMfetch(m,q,0));
    w.y	= MTOF(MMfetch(m,q,1));
    w.z	= MTOF(MMfetch(m,q,2));

	r  = interpAng(v*(180.0f/MY_PI), w*(180.0f/MY_PI), rate);
	r *= MY_PI / 180.0f;

	if (MMpush(m,FTOM(r.x)))		return MERRMEM;
	if (MMpush(m,FTOM(r.y)))		return MERRMEM;
	if (MMpush(m,FTOM(r.z)))		return MERRMEM;
	if (MMpush(m,3*2))				return MERRMEM;

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

    return MBdeftab(m);
}











///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////																											   ////
///												ANCIENNES FONCTIONS													///
////																											   ////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////



	
	
	
int createSceneWITHOUTregister(mmachine m)		// pour le m3initialize
{
    int		i;
	
	// Création de la scene 3D
	ZScene		*scene = NULL;
	scene = new ZScene(false);
	if(scene==NULL)				return MERRMEM;
	scene->InitWorld();
	
	scene->accelerated = false;

	int s3d = MMmalloc(m, 4, TYPETAB);
	if(s3d==NIL)				return MERRMEM;
	for(int iii=0; iii<4; iii++)	MMstore(m, s3d, iii, NIL);

	MMstore(m, s3d, 0, (int)scene);
	MMpush(m,PTOM(s3d));


	// Création de la hash_table des H3D
	int hashH3D = MMmalloc(m, HASH_SIZE, TYPETAB);
	if(hashH3D==NIL)			return MERRMEM;
	for(i=0; i<HASH_SIZE; i++)		MMstore(m, hashH3D, i, NIL);

	s3d = MTOP(MMpull(m));
	MMstore(m, s3d, 1, PTOM(hashH3D));
	MMpush(m,PTOM(s3d));


	// Création de la hash_table des MATERIAUX
	int hashMAT = MMmalloc(m, HASH_SIZE, TYPETAB);
	if(hashMAT==NIL)			return MERRMEM;
	for(i=0; i<HASH_SIZE; i++)		MMstore(m, hashMAT, i, NIL);

	s3d = MTOP(MMpull(m));
	MMstore(m, s3d, 2, PTOM(hashMAT));
	MMpush(m,PTOM(s3d));


	// Création de la hash_table des TEXTURES
	int hashTEX = MMmalloc(m, HASH_SIZE, TYPETAB);
	if(hashTEX==NIL)			return MERRMEM;
	for(i=0; i<HASH_SIZE; i++)		MMstore(m, hashTEX, i, NIL);

	s3d = MTOP(MMpull(m));
	MMstore(m, s3d, 3, PTOM(hashTEX));


	// Pose le résultat sur la pile avant l'appel de 'ObjCreate'
	if(MMpush(m, PTOM(s3d)))	return MERRMEM;

	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3initialize
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [I I I I I I] S3d
int ZM3initialize(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3initialize ");
#endif

	MMpull(m);
    MMpull(m);
    MMpull(m);
    MMpull(m);
    MMpull(m);
    MMpull(m);

	#ifdef	_INFO_SCREEN_
		if(userACCEL && !mainInfoWND)	CreateWinInfoSCREEN(600, 1000);
	#endif

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return createSceneWITHOUTregister(m);			// crée une session et pose le pointeur scol sur la pile
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3desalloc
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d] I
int ZM3desalloc(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3desalloc ");
#endif

	int s3d	 = MMget(m,0);
	if(s3d==NIL)					{	MMset(m,0,NIL);		return 0;	}

	ZooDestroySession(m, 0, s3d);

	MMset(m,0,0);

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;
}





///////////////////////////////////////////////////////////////////////////////////////
///		Macro GLOBAL_RENDER_FILL_SOFT												///
///////////////////////////////////////////////////////////////////////////////////////
#define GLOBAL_RENDER_FILL_SOFT(flag_of_wired)															\
	int		fond, y, x, h3d, surf, s3d;																	\
	ZNode	*node, *father;																				\
																										\
	fond = MMpull(m);																					\
	y	 = MMpull(m);																					\
	x	 = MMpull(m);																					\
	h3d	 = MMpull(m);																					\
	surf = MMpull(m);																					\
	s3d  = MMget(m,0);																					\
																										\
	if((surf==NIL)||(s3d==NIL)||(h3d==NIL)||fullscreenMode)		{   MMset(m,0,NIL);		return 0;	}	\
																										\
	ZScene	*scene;																						\
	scene = (ZScene*) MMfetch(m,MTOP(s3d),0);															\
	if(scene==NULL)								{   MMset(m,0,NIL);		return 0;	}					\
																										\
	/*/////////////////////////////////////////////////////////////////									\
	///		Session en mode HARD -> ne fait rien					///									\
	/////////////////////////////////////////////////////////////////*/									\
	if(scene->accelerated)																				\
	{																									\
		MMset(m,0,NIL);																					\
		return 0;																						\
	}																									\
	/*/////////////////////////////////////////////////////////////////									\
	///		Session en mode SOFT -> affiche le mode soft			///									\
	/////////////////////////////////////////////////////////////////*/									\
	else																								\
	{																									\
		RenderBuffer	buffer;																			\
		if(fillRenderBuffer(m, &buffer, surf))			{   MMset(m,0,NIL);		return 0;	}			\
																										\
		/* Couleur de Fond */																			\
		fond = MTOI(fond);																				\
		float	r = 0;																					\
		float	g = 0;																					\
		float	b = 0;																					\
																										\
		if(fond!=NIL)																					\
		{																								\
			r = ((fond)&255)	 / CONST_COLOR;															\
			g = ((fond>>8)&255)	 / CONST_COLOR;															\
			b = ((fond>>16)&255) / CONST_COLOR;															\
		}																								\
																										\
		/* Recupération de la camera */																	\
		node = (ZNode*) MMfetch(m,MTOP(h3d),0);															\
		if((node==NULL)||(node->type!=CAM_TYPE_ID))		{   MMset(m,0,NIL);		return 0;	}			\
		scene->SetActiveCam((ZCamera*)node);															\
																										\
		father = getBigFather(node);																	\
																										\
		/* Prépare la camera par précaution et aussi pour le calcul des subMatrices */					\
		ZMatrix		matx = ComputeWorldMatrix(node);													\
		((ZCamera*)node)->worldMat = matx;																\
		((ZCamera*)node)->worldPos.SetCoord(matx(0,3), matx(1,3), matx(2,3));							\
																										\
		/* Rendu de la scene */																			\
		if(fond==NIL)		scene->DisplaySOFT(&buffer, r, g, b, father, flag_of_wired, false, false);	\
		else				scene->DisplaySOFT(&buffer, r, g, b, father, flag_of_wired, false, true);	\
	}




//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3scanline
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d ObjBitmap H3d I I I] H3d
int ZM3scanline(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3scanline ");
#endif

	// Macro de rendu GLOBAL
//	GLOBAL_RENDER_FILL_SOFT(false)


////////////////////////////////////////////////////////
////////////////////////////////////////////////////////
////////////////////////////////////////////////////////
////////////////////////////////////////////////////////

	int		fond, y, x, h3d, surf, s3d;																	
	ZNode	*node, *father;	

																										
	fond = MMpull(m);																					
	y	 = MMpull(m);																					
	x	 = MMpull(m);																					
	h3d	 = MMpull(m);																					
	surf = MMpull(m);																					
	s3d  = MMget(m,0);																					
																										
	if((surf==NIL)||(s3d==NIL)||(h3d==NIL)||fullscreenMode)		{   MMset(m,0,NIL);		return 0;	}	
																										
	ZScene	*scene;																						
	scene = (ZScene*) MMfetch(m,MTOP(s3d),0);															
	if(scene==NULL)								{   MMset(m,0,NIL);		return 0;	}					



	///////////////////////////////////////////////////////////////////									
	///		Session en mode HARD -> ne fait rien					///									
	///////////////////////////////////////////////////////////////////
	if(scene->accelerated)																				
	{																									
		MMset(m,0,NIL);																					
		return 0;																						
	}																									
	///////////////////////////////////////////////////////////////////									
	///		Session en mode SOFT -> affiche le mode soft			///									
	///////////////////////////////////////////////////////////////////									
	else																								
	{																									
        PtrObjVoid		O;
        PtrObjBitmap	B;

		int				i;
        OBJBITMAP_BUFFER  Image;

        O = (PtrObjVoid)	MMstart(m, MTOP(surf) );
        B = (PtrObjBitmap)	MMstart(m, MTOP(O->Buffer) );
		
		if(B->bits==NULL)			return -1;

        Image = (OBJBITMAP_BUFFER) B->bits;
		

        i = MTOI(B->BPL * B->TailleH);
		while(i)	Image[--i] = 0;

		////////////////		
		
		RenderBuffer	buffer;																			
		if(fillRenderBuffer(m, &buffer, surf))			{   MMset(m,0,NIL);		return 0;	}			
																										
		// Couleur de Fond
		fond = MTOI(fond);																				
		float	r = 0;																					
		float	g = 0;																					
		float	b = 0;																					
																										
		if(fond!=NIL)																					
		{						
			r = ((fond)&255)	 / CONST_COLOR;															
			g = ((fond>>8)&255)	 / CONST_COLOR;															
			b = ((fond>>16)&255) / CONST_COLOR;															
		}																								
			 																							
		// Recupération de la camera
		node = (ZNode*) MMfetch(m,MTOP(h3d),0);															
		if((node==NULL)||(node->type!=CAM_TYPE_ID))		{   MMset(m,0,NIL);		return 0;	}			
		scene->SetActiveCam((ZCamera*)node);															
																										
		father = getBigFather(node);																	
																										
		// Prépare la camera par précaution et aussi pour le calcul des subMatrices
		ZMatrix		matx = ComputeWorldMatrix(node);													
		((ZCamera*)node)->worldMat = matx;																
		((ZCamera*)node)->worldPos.SetCoord(matx(0,3), matx(1,3), matx(2,3));							

		// Rendu de la scene 						
		if(fond==NIL)		scene->DisplaySOFT(&buffer, r, g, b, father, false, false, false);	
		else				scene->DisplaySOFT(&buffer, r, g, b, father, false, false, true);	
	}


////////////////////////////////////////////////////////
////////////////////////////////////////////////////////
////////////////////////////////////////////////////////
////////////////////////////////////////////////////////


	CLEAN_UNUSED_DATAS

	// Détermination de l'objet pointé par (x,y)
	int		width  = ((ZCamera*)node)->width  / 2;
	int		height = ((ZCamera*)node)->height / 2;

	int		result = NIL;
	float	dist = 0;

	if((x!=NIL)&&(y!=NIL))
	{
		int faceNb;
		//$BLG
		//ZObject*  obj = scene->Getinfo(MTOI(x)+width, height-MTOI(y), NULL, NULL, NULL, NULL, &faceNb, &dist);
		//if(obj!=NULL)
		ZBLG_ObjSpr*  objspr = scene->Getinfo(MTOI(x)+width, height-MTOI(y), NULL, NULL, NULL, NULL, &faceNb, &dist);
		if ((objspr->blg_objspr_obj != NULL) || (objspr->blg_objspr_spr))
		{
			//$BLG
			//result = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)obj);
			if (objspr->blg_objspr_obj != NULL) 
				result = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)objspr->blg_objspr_obj);
			else if (objspr->blg_objspr_spr != NULL) 
				result = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)objspr->blg_objspr_spr);
			if(result!=NIL)		result = PTOM(result);
		}
		//$BLG
		delete objspr;
	}

	MMset(m,0,result);


#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3scanlineM													
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d ObjBitmap H3d I I I] [H3d HMat3d]
int ZM3scanlineM(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3scanlineM ");
#endif

	// Macro de rendu GLOBAL
	GLOBAL_RENDER_FILL_SOFT(false)

	CLEAN_UNUSED_DATAS

	// Détermination de l'objet pointé par (x,y)
	int		width  = ((ZCamera*)node)->width  / 2;
	int		height = ((ZCamera*)node)->height / 2;

	int		result = NIL;
	int		mater  = NIL;
	float	dist = 0;

	if((x!=NIL)&&(y!=NIL))
	{
		int faceNb;
		//$BLG
		//ZObject*  obj = scene->Getinfo(MTOI(x)+width, height-MTOI(y), NULL, NULL, NULL, NULL, &faceNb, &dist);
		//if(obj!=NULL)
		ZBLG_ObjSpr*  objspr = scene->Getinfo(MTOI(x)+width, height-MTOI(y), NULL, NULL, NULL, NULL, &faceNb, &dist);
		if ((objspr->blg_objspr_obj != NULL) || (objspr->blg_objspr_spr))
		{
			//$BLG
			//result = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)obj);
			//ZMaterial	*mat = obj->GetMesh()->Faces[faceNb].GetMaterial();
			ZMaterial* mat;
			if (objspr->blg_objspr_obj != NULL) 
			{
				result = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)objspr->blg_objspr_obj);
				mat = objspr->blg_objspr_obj->GetMesh()->Faces[faceNb].GetMaterial();
			}
			else if (objspr->blg_objspr_spr != NULL) 
			{
				result = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)objspr->blg_objspr_spr);
				mat = objspr->blg_objspr_spr->GetMaterial();
			}
			if((mat!=NULL)&&(result!=NIL))
			{
				mater = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),2)), (int)mat);
				if(mater!=NIL)		mater = PTOM(mater);
			}
			if(result!=NIL)		result = PTOM(result);
		}
		//$BLG
		delete objspr;
	}

	// Pose le resultat sur la pile
	MMset(m, 0, mater);
	MMpush(m, result);
	int tuple = MMmalloc(m, 2, TYPETAB);
	if(tuple==NIL)				{	MMset(m,0,NIL);		return MERRMEM;		}
	MMstore(m, tuple, 0, MMpull(m) );
	MMstore(m, tuple, 1, MMget(m,0) );

    MMset(m,0,PTOM(tuple));

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3scanlineInfo
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d ObjBitmap H3d I I] [H3d HMat3d I I I]
int ZM3scanlineInfo(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3scanlineInfo ");
#endif

	int y	 = MMpull(m);
	int x	 = MMpull(m);
	int h3d	 = MMpull(m);
	MMpull(m);						// on ne se sert pas de l'ObjBitmap
	int s3d	 = MMget(m,0);

	if((s3d==NIL)||(h3d==NIL)||(x==NIL)||(y==NIL))		{   MMset(m,0,NIL);		return 0;	}
	ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{   MMset(m,0,NIL);		return 0;	}

	// Recupération de la camera
	ZNodeGraph	*node = (ZNodeGraph*) MMfetch(m,MTOP(h3d),0);
	if((node==NULL)||(node->type!=CAM_TYPE_ID))		{   MMset(m,0,NIL);		return 0;	}
	scene->SetActiveCam((ZCamera*)node);

	// Prépare la camera par précaution..
	ZMatrix		matx = ComputeWorldMatrix(node);
	((ZCamera*)node)->worldMat = matx;
	((ZCamera*)node)->worldPos.SetCoord(matx(0,3), matx(1,3), matx(2,3));
	((ZCamera*)node)->ComputeMatrix();

	// Prépare la scène qui peut avoir changé
	ZNodeGraph	*father = (ZNodeGraph*) getBigFather(node);

	scene->World->createNodeLists(father);

	scene->World->ComputeMatrices(node, father, IdentityMatrix(), 1.0f, true);
	scene->World->TransformVertices();

	// Détermination de l'objet pointé par (x,y)
	int		width  = ((ZCamera*)node)->width / 2;
	int		height = ((ZCamera*)node)->height / 2;
	int		result = NIL;
	int		mater  = NIL;
	float	u = 0, v = 0, z = 0, dist = 0;

	if((x!=NIL)&&(y!=NIL))
	{
		int faceNb;
		//$BLG
		//ZObject*  obj = scene->Getinfo(MTOI(x)+width, height-MTOI(y), &u, &v, &z, NULL, &faceNb, &dist);
		//if(obj!=NULL)
		ZBLG_ObjSpr*  objspr = scene->Getinfo(MTOI(x)+width, height-MTOI(y), &u, &v, &z, NULL, &faceNb, &dist);
		if ((objspr->blg_objspr_obj != NULL) || (objspr->blg_objspr_spr))
		{
			//$BLG
			//result = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)obj);
			//ZMaterial	*mat = obj->GetMesh()->Faces[faceNb].GetMaterial();
			ZMaterial* mat;
			if (objspr->blg_objspr_obj != NULL) 
			{
				result = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)objspr->blg_objspr_obj);
				mat = objspr->blg_objspr_obj->GetMesh()->Faces[faceNb].GetMaterial();
			}
			else if (objspr->blg_objspr_spr != NULL) 
			{
				result = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),1)), (int)objspr->blg_objspr_spr);
				mat = objspr->blg_objspr_spr->GetMaterial();
			}
			if((mat!=NULL)&&(result!=NIL))
			{
				mater = NodeTOHandle(m, MTOP(MMfetch(m,MTOP(s3d),2)), (int)mat);
				if(mater!=NIL)		mater = PTOM(mater);
			}
			if(result!=NIL)		result = PTOM(result);
		}
		//$BLG
		delete objspr;
	}

	// Pose le resultat sur la pile
	MMset(m,0,mater);
	MMpush(m,result);

	int tuple = MMmalloc(m, 5, TYPETAB);
	if(tuple==NIL)				{	MMset(m,0,NIL);		return MERRMEM;		}
	MMstore(m, tuple, 0, MMpull(m));
	MMstore(m, tuple, 1, MMget(m,0));
	if(mater!=NIL)
	{
		MMstore(m, tuple, 2, ITOM(AROUNDINT(u*CONST_TEX_COORD)));
		MMstore(m, tuple, 3, ITOM(AROUNDINT(v*CONST_TEX_COORD)));
		MMstore(m, tuple, 4, ITOM(AROUNDINT(-z*100.0f)));
	}
	else
	{
		MMstore(m, tuple, 2, NIL);
		MMstore(m, tuple, 3, NIL);
		MMstore(m, tuple, 4, NIL);
	}

    MMset(m,0,PTOM(tuple));

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3textureTotalSize
//////////////////////////////////////////////////////////////////////////////////////////////
///	fun [S3d] I
int ZM3textureTotalSize(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"M3textureTotalSize ");
#endif

    int s3d = MMget(m,0);

    if(s3d==NIL)					{	MMset(m,0,NIL);		return 0;	}
    ZScene	*scene = (ZScene*) MMfetch(m,MTOP(s3d),0);
	if(scene==NULL)					{	MMset(m,0,NIL);		return 0;	}

	ZTexture	*tex;
	
	int		size=0;

	for(int i=0; i<scene->TexList.Size(); i++)
    {
		tex = scene->TexList[i];
		size += tex->Width*tex->Height*4;
    }

	MMset(m,0,ITOM(size));

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3videoInfos														
//////////////////////////////////////////////////////////////////////////////////////////////
/// fun [] [S S S S]
int ZM3videoInfos(mmachine m)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ZM3videoInfos ");
#endif

	ZDetector	detect;
	
	Mpushstrbloc(m, (char*)detect.CheckOpenGLvendor());
	Mpushstrbloc(m, (char*)detect.CheckOpenGLrenderer());
	Mpushstrbloc(m, (char*)detect.CheckOpenGLdriver());
	Mpushstrbloc(m, (char*)detect.CheckOpenGLextensions());

    if(MMpush(m,4*2))			return MERRMEM;
	if(int k=MBdeftab(m))		return k;


#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ok\n");
#endif

	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZMX3TestSurfaceZbuf
//////////////////////////////////////////////////////////////////////////////////////////////
///	fun[ObjSurface] I
int ZMX3TestSurfaceZbuf(mmachine m)
{
	if(MMget(m,0)==NIL)		return 0;
	
	MMset(m,0,ITOM(1));
	
	return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		ZisPentium
//////////////////////////////////////////////////////////////////////////////////////////////
///	fun[] I
int ZisPentium(mmachine m)
{
	if(testP4())	{	MMpush(m,ITOM(4));	return 0;	}
	if(testP3())	{	MMpush(m,ITOM(3));	return 0;	}

	MMpush(m,0);
	return 0;
}





















///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////																											   ////
///										DECLARATION DES FONCTIONS POUR SCOL											///
////																											   ////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////



//$LB (31/10/2004) : added M3topoScale 
//$LBDEBUG : added M3test
#define NbZooPKG	388


//////////////////////////////////////////////////////////////////////////////////////////////
///		Definition des noms de fonction SCOL
//////////////////////////////////////////////////////////////////////////////////////////////
char	*ZooName[NbZooPKG] =
{
	// ----------> Callback de rendu <-----------
	"CB_NOCHANGE",
	"M3setRenderCallback",
	
	"MX3TestSurfaceZbuf",

	"ZTest",
	"M3isValidObj",


	// ----------> Anciennes fonctions <-----------
	"S3d",
	"H3d",
	"M3initialize",
	"M3desalloc",
	"HMat3d",
	"HTx3d",
	"M3scanlineInfo",
	"M3updateTexture",
	"M3importTexture",
	"M3updateTexture16",
	"M3importTexture16",
	"M3scanline",
	"M3scanlinem",
	"M3textureTotalSize",


	// -----------> Gestion de session <-----------
	"SURFACE_FULLSCREEN", "SURFACE_WINDOWED", "SURFACE_NULL",
	"M3create",
	"MX3create",
	"MX3createSession",
	"M3destroy",
	"M3freeMemory",
	"M3reset",
	"ENGINE_HARDWARE", "ENGINE_SOFTWARE",
	"_GETengineState",
	"_CRsurface",
	"_CRforcedSurface",
	"_CRfullscreenSurface",
	"_CRforcedFullscreenSurface",
	"_GETwindowFromFullscreenSurface",
	"_GETsurfaceState",
	"_DSsurface",
	"_FILLsurface",
	"_GETsurfaceSize",
	"_BLTsurface",
	"_BLTsurfaceFullScreen",
	"_Bitmap2Surface",
	"_BlendBitmap2Surface",
	"_Surface2Bitmap",
	"_Surface2Surface",
	"_BlendSurface2Surface",


	// -----------> Gestion des objets <-----------

	// ---> Gestion hierarchique <---
	"M3_MESH","M3_CAM","M3_LIGHT","M3_SHELL","M3_TOPO",
	"M3_COLL","M3_SPRITE","M3_ANIM","M3_COLOR_LIGHT","M3_PARTICLE",
	"M3_LISTENER","M3_SOUND",

	"M3load",
	"M3loadString",
	"M3loadAnimationFileWithSKL",
	"M3createShell",
	"M3delObj",
	"M3copyObj",
	"M3getObj",
	"M3listMeshFromNode",
	"M3getH3dType",
	"M3objName",
	"M3getFather",
	"M3getFirstSon",
	"M3getBrother",
	"M3bigFather",
	"M3isFather",
	"M3unLink",
	"M3link",
	"M3renameObj",
	"M3listOfBigFathers",
	"M3getObjType",
	"M3listALLObj",
	"M3listALLLight",
	"M3listALLCam",
	"M3listALLShl",
	"M3listALLSpr",
	"M3listALLPcl",
	"M3listALLPclEff",
	"M3listALLFont",
	"M3listALLSkl",
	"M3listALLSound",
	"M3listALLBones",

	// ----> Gestion géométrique <----
	"RANGE_INFINITY",
	"RANGE_INFINITY_F",
	"M3setObjRange",
	"M3getObjRange",
	"M3setObjRangeF",
	"M3getObjRangeF",
	"M3setObjVec",
	"M3setObjVecF",
	"M3getObjVec",
	"M3getObjVecF",
	"M3setObjAng",
	"M3setObjAngF",
	"M3getObjAng",
	"M3getObjAngF",
	"M3setObjScale",
	"M3setObjScaleF",
	"M3getObjScale",
	"M3getObjScaleF",
	"M3movObj",
	"M3movObjF",
	"M3rotateObj",
	"M3rotateObjF",
	"M3movObjExt",
	"M3movObjExtF",
	"M3rotateObjExt",
	"M3rotateObjExtF",
	"M3calcMat",
	"M3getObjVecRender",
	"M3getObjVecRenderF",
	"M3getObjMatrixRender",
	"M3getObjMatrixRenderF",
	"M3getCamera",
	"M3setCamera",
	"M3calcPosRef",
	"M3calcPosRefF",
	"M3angularFromMatrix",
	"M3angularFromMatrixF",
	"M3getRadius",
	"M3getRadiusF",
	"M3calcProj",
	"M3calcProjF",
	"M3areMeshesCulled",
	"M3isMeshCulledByOthers",
	"M3angularTarget",
	"M3angularTargetF",
	"M3getGlobalVec",
	"M3getGlobalVecF",

	// ----> Gestion topologique <----
	"M3listALLtopos",
	"M3getTopo",
	"M3createTopo",
	"M3cleanTopo",
	"M3topoCount",
	"M3topoAddFace",
	"M3topoAddFaceF",
	"M3setFaceVertRef",
	"M3getFaceVertRef",
	"M3setFaceMaterial",
	"M3getFaceMaterial",
	"M3setFaceTexCoord",
	"M3setFaceTexCoordF",
	"M3getFaceTexCoord",
	"M3getFaceTexCoordF",
	"M3listOfPolygons",
	"M3listOfPolygonsF",
	"M3setPolygons",
	"M3setPolygonsF",
	"M3deltaPolygons",
	"M3deltaPolygonsF",
	"M3morphPolygons",
	"M3morphPolygonsF",
	"M3topoAddVertex",
	"M3topoAddVertexF",
	"M3topoAddVertices",
	"M3topoAddVerticesF",
	"M3listOfVertices",
	"M3listOfVerticesF",
	"M3topoSetVertex",
	"M3topoSetVertexF",
	"M3topoGetVertex",
	"M3topoGetVertexF",
	"M3setVertices",
	"M3setVerticesF",
	"M3deltaVertex",
	"M3deltaVertexF",
	"M3deltaVertices",
	"M3deltaVerticesF",
	"M3morphVertex",
	"M3morphVertexF",
	"M3morphVertices",
	"M3morphVerticesF",
	"M3listOfColorVertices",
	"M3topoSetColorVertex",
	"M3topoGetColorVertex",
	"M3setColorVertices",
	"M3convVrt",
	"M3convVrtF",
	"M3convVec",
	"M3convVecF",

	//$LB (31/10/2O04)
	"M3topoScale",
	"M3test",

	// ------> Gestion de mesh <------
	"MESH_STATIC",
	"MESH_MULTI_TOPO",
	"MESH_NOT_CLICKABLE",
	"M3createMesh",
	"M3meshSetMultiTopo",
	"M3meshSetMultiTopoF",
	"M3meshGetMultiTopo",
	"M3meshGetMultiTopoF",
	"M3meshGetActiveTopo",
	"M3meshSetTopology",
	"M3meshGetTopology",
	"M3meshSetType",
	"M3meshGetType",
	"M3distance",
	"M3save",
	"M3recListOfMaterials",



	// ---------> Gestion des Materiaux <----------
	"MAT_COLOR1","MAT_COLOR2","MAT_COLOR_VERTEX",
	"MAT_TEXTURED","MAT_TEXTURED_BIS",
	"MAT_LIGHT","MAT_GOURAUD",
	"MAT_TRANSP","MAT_ENV","MAT_LIGHTMAP",

	"M3setMaterialTransparencyOrder",
	"M3getMaterialTransparencyOrder",

	"M3listALLMaterials",
	"M3createMaterial",
	"M3getMat",
	"M3materialName",
	"M3renameMat",
	"M3fillMat",
	"M3fillMatObj",
	"M3recursFillMatObj",
	"M3getType",
	"M3getRealType",
	"M3setType",
	"M3getMaterialFlat",
	"M3setMaterialFlat",
	"M3getMaterialTransparency",
	"M3setMaterialTransparency",
	"M3getMaterialColor",
	"M3setMaterialColor",
	"M3textureFromMaterial",
	"M3textureBISFromMaterial",
	"M3lightMapFromMaterial",
	"M3chgMaterialTexture",
	"M3chgMaterialTextureBIS",
	"M3chgMaterialLightMap",
	"M3getMaterialMultitex",
	"M3setMaterialMultitex",
	"M3setMaterialAmbient",
	"M3getMaterialAmbient",
	"M3setMaterialDiffuse",
	"M3setMaterialEmissive",
	"M3getMaterialDiffuse",
	"M3getMaterialEmissive",
	"M3setMaterialSpecular",
	"M3getMaterialSpecular",
	"M3materialCount",
	"M3listOfMaterials",
	"M3copyObjMaterial",
	"M3copyMaterial",
	"M3chgObjMaterial",
	"M3shiftTextureXY",
	"M3shiftTextureXYF",
	//$BLG: v4.6a5 - Add
	"M3shiftTextureBisXY",
	"M3shiftTextureBisXYF",
	"M3shiftLightMapXY",
	"M3shiftLightMapXYF",
	//$BLG: v4.6a5 - End
	"M3saveMat",
	"M3saveMaterial",

	//$MS 02/04/2007
	"M3setMaterialShininess",
	"M3setMaterialShininessF",
	"M3getMaterialShininess",
	"M3getMaterialShininessF",



	// ---------> Gestion des Textures <----------
	"TEX_MIPMAP",
	"M3isExtensionSupported",
	"M3textureSetGeneralDefaultType",
	"M3textureGetGeneralDefaultType",
	"M3textureSetType",
	"M3textureGetType",
	"M3listALLTextures",
	"M3getTexture",
	"M3textureName",
	"M3renameTexture",
	"M3textureCount",
	"M3copyMaterialTexture",
	"M3isTextureFilled",
	"M3fillTexture",
	"M3freeTexture",
	"M3getTextureSize",
	"M3getTransparencyColor",
	"M3setTransparencyColor",
	"M3createTexture",



	// ------------> Gestion de Rendu <------------
	"MX3hardware",
//	"MX3getDeviceList",
	"MX3renderEx",
	"MX3renderExF",
	"MX3render",
	"MX3renderm",
	"MX3wire",
	"MX3wirem",
	"MX3wireOrtho",
	"MX3renderInfo",
	"MX3renderInfoF",
	"M3blitTexture",
	"M3blitTexture16",
	"M3blitSurface2Texture16",
	"M3filter",
	"M3nbVisiblePoly",
	"M3nbUsedPolygons",
	"M3setAntiAliasing",				// Mehdi : fonction d'AntiAliasing
	"M3multiSamplingSupported",				// Mehdi : fonction qui renvoie si l'extension multisampling est supportée
	"M3maxSampleBuffers",
	"M3EnableMultisampling",
	"M3DisableMultisampling",
	"M3getFrameRate",						// $MS : FrameRateFunction




	// ---------> Gestion des Collisions <---------
	"M3createSphere",
	"M3createObb",
	"M3calcObb",
	"M3firstRadius",
	"M3testInter",
	"M3testColl",
	"M3testCollF",

	"M3createExactModel",
	"M3destroyExactModel",
	"M3testExactInter",
	"M3testExactColl",



	// ---------> Gestion des Animations <---------
	"ANIM_POS","ANIM_ANG","ANIM_TOP",
	"M3setAnimKey",
	"M3setSKLAnimKey",
	"M3setAnimKeyF",
	"M3setAnimKey2",
	"M3setAnimKey2F",
	"M3applyAnimKey",
	"M3applyAnimKeyF",
	"M3applyAnimKey2",
	"M3applyAnimKey2F",
	"M3getAnimLength",

	//------------>Gestion des Bones<-------------------
	"M3getBone",
	"M3renameBone",
	"M3getBoneInfo",
	"M3getBoneFather",
	"M3getNumberOfChildren",
	"M3ShowSkelet",
	"M3isShaderVertexProfileEnable",
	"M3isShaderFragmentProfileEnable",
	"M3isShaderEnable",
	"M3AttachMeshWithSKL",
	"M3listSKLFromNode",




	// ----------> Gestion des Lumières <----------
	"LIGHT_AMBIENT","LIGHT_PARA","LIGHT_OMNI","LIGHT_SPOT","LIGHT_CLASSIC","LIGHT_SATURATED",
	"M3setLightModel",
	"M3getLightModel",
	"M3createLight",
	"M3getLight",
	"M3setLight",
	"M3createColorLight",
	"M3getColorLight",
	"M3setColorLight",



	// ----------> Gestion des Sprites <-----------
	"M3createSprite",
	"M3createSpriteF",
	"M3setSprite",
	"M3setSpriteF",
	"M3getSprite",
	"M3getSpriteF",
	"M3setSpriteTexCoord",
	"M3setSpriteTexCoordF",
	"M3getSpriteTexCoord",
	"M3getSpriteTexCoordF",
	"M3setSpriteVrtColors",
	"M3getSpriteVrtColors",
	"M3setSpriteAngle",
	"M3setSpriteAngleF",
	"M3getSpriteAngle",
	"M3getSpriteAngleF",
  "M3setSpriteClickability",
  "M3getSpriteClickability",


	// ----------> Opérations diverses <-----------
	"_SDRAWrectangle",
	"_SDRAWline",
	"_SDRAWcircle",
	"_SDRAWtext",
	"_SDRAWpoint",
	"_SDRAWpoly",
	"M3interpVec",
	"M3interpVecF",
	"M3interpAng",
	"M3interpAngF",
	"M3videoInfos",
	"_isPentium"
};



//////////////////////////////////////////////////////////////////////////////////////////////
///		Definition des pointeurs sur fonctions
//////////////////////////////////////////////////////////////////////////////////////////////
int (*ZooFunc[NbZooPKG])(mmachine m)=
{
	// ----------> Callback de rendu <-----------
	(int (__cdecl *)(struct Mmachine *))NIL,
	M3setRenderCallback,

	ZMX3TestSurfaceZbuf,									// MX3TestSurfaceZbuf

	ZTest,
	ZM3isValidObj,


	// ----------> Anciennes fonctions <-----------
	NULL,													// S3d
	NULL,													// H3d
	ZM3initialize,											// M3initialize
	ZM3desalloc,											// M3desalloc
	NULL,													// HMat3d
	NULL,													// HTx3d
	ZM3scanlineInfo,										// M3scanlineInfo
	ZM3blitTexture,											// M3updateTexture
	ZM3blitTexture,											// M3importTexture
	ZM3blitTexture16,										// M3updateTexture16
	ZM3blitTexture16,										// M3importTexture16
	ZM3scanline,											// M3scanline
	ZM3scanlineM,											// M3scanlinem
	ZM3textureTotalSize,									// M3textureTotalSize


	// -----------> Gestion de session <-----------
	(int (__cdecl *)(struct Mmachine *))0,(int (__cdecl *)(struct Mmachine *))2,(int (__cdecl *)(struct Mmachine *))4,					// SURFACE_FULLSCREEN	SURFACE_WINDOWED	SURFACE_NULL
	ZM3create,												// M3create
	ZMX3create,												// MX3create
	ZMX3createSession,										// MX3createSession
	ZM3destroy,												// M3destroy
	ZM3freeMemory,											// M3freeMemory
	ZM3reset,												// M3reset
	(int (__cdecl *)(struct Mmachine *))0,(int (__cdecl *)(struct Mmachine *))2,	// ENGINE_HARDWARE     ENGINE_SOFTWARE
	_ZGETengineState,										// _GETengineState
	_ZCRsurface,											// _CRsurface 
	_ZCRforcedSurface,                // _CRforcedSurface
	_ZCRfullscreenSurface,									// _CRfullscreenSurface
	_ZCRforcedFullscreenSurface,            // _CRforcedFullscreenSurface
	_ZGETwindowFromFullscreenSurface,						// _GETwindowFromFullscreenSurface
	_ZGETsurfaceState,										// _GETsurfaceState
	_ZDSsurface,											// _DSsurface
	_ZFILLsurface,											// _FILLsurface
	_ZGETsurfaceSize,										// _GETsurfaceSize
	_ZBLTsurface,											// _BLTsurface
	_ZBLTsurfaceFullScreen,									// _BLTsurfaceFullScreen
	_ZBitmap2Surface,										// _Bitmap2Surface
	_ZBlendBitmap2Surface,										// _BlendBitmap2Surface
	_ZSurface2Bitmap,										// _Surface2Bitmap
	_ZSurface2Surface,										// _Surface2Surface
	_ZBlendSurface2Surface,               // _BlendSurface2Surface


	// -----------> Gestion des objets <-----------

	// ---> Gestion hierarchique <---
	(int (__cdecl *)(struct Mmachine *))0,
	(int (__cdecl *)(struct Mmachine *))2,(int (__cdecl *)(struct Mmachine *))4,(int (__cdecl *)(struct Mmachine *))6,(int (__cdecl *)(struct Mmachine *))20,					// M3_MESH   M3_CAM      M3_LIGHT   M3_SHELL
	(int (__cdecl *)(struct Mmachine *))8,(int (__cdecl *)(struct Mmachine *))10,(int (__cdecl *)(struct Mmachine *))12,				// M3_COLL   M3_SPRITE   M3_ANIM
	(int (__cdecl *)(struct Mmachine *))100,(int (__cdecl *)(struct Mmachine *))14,														// M3_COLOR_LIGHT		M3_PARTICLE
	(int (__cdecl *)(struct Mmachine *))110, (int (__cdecl *)(struct Mmachine *))120,													// M3_LISTENER	M3_SOUND

	ZM3load,												// M3load
	ZM3loadString,											// M3loadString
	ZM3loadAnimationFileWithSKL,							// M3loadAnimationFileWithSKL
	ZM3createShell,											// M3createShell
	ZM3delObj,												// M3delObj
	ZM3copyObj,												// M3copyObj
	ZM3getObj,												// M3getObj
	ZM3listMeshFromNode,		     						// M3listObjFromNode
	ZM3getH3dType,											// M3getObjType
	ZM3objName,												// M3objName
	ZM3getFather,											// M3getFather
	ZM3getFirstSon,											// M3getFirstSon
	ZM3getBrother,											// M3getBrother
	ZM3bigFather,											// M3bigFather
	ZM3isFather,											// M3isFather
	ZM3unLink,												// M3unLink
	ZM3link,												// M3link
	ZM3renameObj,											// M3renameObj
	ZM3listOfBigFathers,									// M3listOfBigFathers
	ZM3getObjType,											// M3getObjType
	ZM3listALLObj,											// M3listALLObj
	ZM3listALLLight,										// M3listALLLight
	ZM3listALLCam,											// M3listALLCam
	ZM3listALLShl,											// M3listALLShl
	ZM3listALLSpr,											// M3listALLSpr
	ZM3listALLPcl,											// M3listALLPcl
	ZM3listALLPclEff,										// M3listALLPclEff
	ZM3listALLFont,		     								// M3listALLFont
	ZM3listALLSkl,		     								// M3listALLSkl
	ZM3listALLSound,		     							// M3listALLSound
	ZM3listALLBones,		     							// M3listALLBones

	// ----> Gestion géométrique <----
	(int (__cdecl *)(struct Mmachine *)) (-20),				// RANGE_INFINITY
	(int (__cdecl *)(struct Mmachine *)) (-20),				// RANGE_INFINITY_F
	ZM3setObjRange,											// M3setObjRange
	ZM3getObjRange,											// M3getObjRange
	ZM3setObjRangeF,										// M3setObjRangeF
	ZM3getObjRangeF,										// M3getObjRangeF
	ZM3setObjVec,											// M3setObjVec
	ZM3setObjVecF,											// M3setObjVecF
	ZM3getObjVec,											// M3getObjVec
	ZM3getObjVecF,											// M3getObjVecF
	ZM3setObjAng,											// M3setObjAng
	ZM3setObjAngF,											// M3setObjAngF
	ZM3getObjAng,											// M3getObjAng
	ZM3getObjAngF,											// M3getObjAngF
	ZM3setObjScale,											// M3setObjScale
	ZM3setObjScaleF,										// M3setObjScaleF
	ZM3getObjScale,											// M3getObjScale
	ZM3getObjScaleF,										// M3getObjScaleF
	ZM3movObj,												// M3movObj
	ZM3movObjF,												// M3movObjF
	ZM3rotateObj,											// M3rotateObj
	ZM3rotateObjF,											// M3rotateObjF
	ZM3movObjExt,											// M3movObjExt
	ZM3movObjExtF,											// M3movObjExtF
	ZM3rotateObjExt,										// M3rotateObjExt
	ZM3rotateObjExtF,										// M3rotateObjExtF
	ZM3calcMat,												// M3calcMat
	ZM3getObjVecRender,										// M3getObjVecRender
	ZM3getObjVecRenderF,									// M3getObjVecRenderF
	ZM3getObjMatrixRender,									// M3getObjMatrixRender
	ZM3getObjMatrixRenderF,									// M3getObjMatrixRenderF
	ZM3getCamera,											// M3getCamera
	ZM3setCamera,											// M3setCamera
	ZM3calcPosRef,											// M3calcPosRef
	ZM3calcPosRefF,											// M3calcPosRefF
	ZM3angularFromMatrix,									// M3angularFromMatrix
	ZM3angularFromMatrixF,									// M3angularFromMatrixF
	ZM3getRadius,											// M3getRadius
	ZM3getRadiusF,											// M3getRadiusF
	ZM3calcProj,											// M3calcProj
	ZM3calcProjF,											// M3calcProjF
	ZM3areMeshesCulled,										// M3areMeshesCulled
	ZM3isMeshCulledByOthers,								// M3isMeshCulledByOthers
	ZM3angularTarget,										// M3angularTarget
	ZM3angularTargetF,										// M3angularTargetF
	ZM3getGlobalVec,										// M3getGlobalVec
	ZM3getGlobalVecF,										// M3getGlobalVecF

	// ----> Gestion topologique <----
	ZM3listALLtopos,										// M3listALLtopos
	ZM3getTopo,												// M3getTopo
	ZM3createTopo,											// M3createTopo
	ZM3cleanTopo,											// M3cleanTopo
	ZM3topoCount,											// M3topoCount
	ZM3topoAddFace,											// M3topoAddFace
	ZM3topoAddFaceF,										// M3topoAddFaceF
	ZM3setFaceVertRef,										// M3setFaceVertRef
	ZM3getFaceVertRef,										// M3getFaceVertRef
	ZM3setFaceMaterial,										// M3setFaceMaterial
	ZM3getFaceMaterial,										// M3getFaceMaterial
	ZM3setFaceTexCoord,										// M3setFaceTexCoord
	ZM3setFaceTexCoordF,									// M3setFaceTexCoordF
	ZM3getFaceTexCoord,										// M3getFaceTexCoord
	ZM3getFaceTexCoordF,									// M3getFaceTexCoordF
	ZM3listOfPolygons,										// M3listOfPolygons
	ZM3listOfPolygonsF,										// M3listOfPolygonsF
	ZM3setPolygons,											// M3setPolygons
	ZM3setPolygonsF,										// M3setPolygonsF
	ZM3deltaPolygons,										// M3deltaPolygons
	ZM3deltaPolygonsF,										// M3deltaPolygonsF
	ZM3morphPolygons,										// M3morphPolygons
	ZM3morphPolygonsF,										// M3morphPolygonsF
	ZM3topoAddVertex,										// M3topoAddVertex
	ZM3topoAddVertexF,										// M3topoAddVertexF
	ZM3topoAddVertices,										// M3topoAddVertices
	ZM3topoAddVerticesF,									// M3topoAddVerticesF
	ZM3listOfVertices,										// M3listOfVertices
	ZM3listOfVerticesF,										// M3listOfVerticesF
	ZM3topoSetVertex,										// M3topoSetVertex
	ZM3topoSetVertexF,										// M3topoSetVertexF
	ZM3topoGetVertex,										// M3topoGetVertex
	ZM3topoGetVertexF,										// M3topoGetVertexF
	ZM3setVertices,											// M3setVertices
	ZM3setVerticesF,										// M3setVerticesF
	ZM3deltaVertex,											// M3deltaVertex
	ZM3deltaVertexF,										// M3deltaVertexF
	ZM3deltaVertices,										// M3deltaVertices
	ZM3deltaVerticesF,										// M3deltaVerticesF
	ZM3morphVertex,											// M3morphVertex
	ZM3morphVertexF,										// M3morphVertexF
	ZM3morphVertices,										// M3morphVertices
	ZM3morphVerticesF,										// M3morphVerticesF
	ZM3listOfColorVertices,									// M3listOfColorVertices
	ZM3topoSetColorVertex,									// M3topoSetColorVertex
	ZM3topoGetColorVertex,									// M3topoGetColorVertex
	ZM3setColorVertices,									// M3setColorVertices
	ZM3convVrt,												// M3convVrt
	ZM3convVrtF,											// M3convVrtF
	ZM3convVec,												// M3convVec
	ZM3convVecF,											// M3convVecF

	//$LB (31/10/2004)
	ZM3topoScale,											// M3topoScale
	M3test,

	// ------> Gestion de mesh <------
	(int (__cdecl *)(struct Mmachine *))2,					// MESH_STATIC
	(int (__cdecl *)(struct Mmachine *))4,					// MESH_MULTI_TOPO
	(int (__cdecl *)(struct Mmachine *))8,					// MESH_NOT_CLICKABLE
	ZM3createMesh,											// M3createMesh
	ZM3meshSetMultiTopo,									// M3meshSetMultiTopo
	ZM3meshSetMultiTopoF,									// M3meshSetMultiTopoF
	ZM3meshGetMultiTopo,									// M3meshGetMultiTopo
	ZM3meshGetMultiTopoF,									// M3meshGetMultiTopoF
	ZM3meshGetActiveTopo,									// M3meshGetActiveTopo
	ZM3meshSetTopology,										// M3meshSetTopology
	ZM3meshGetTopology,										// M3meshGetTopology
	ZM3meshSetType,											// M3meshSetType
	ZM3meshGetType,											// M3meshGetType
	ZM3distance,											// M3distance
	ZM3save,												// M3save
	ZM3recListOfMaterials,									// M3recListOfMaterials



	// ---------> Gestion des Materiaux <----------
	(int (__cdecl *)(struct Mmachine *))512,(int (__cdecl *)(struct Mmachine *))64,(int (__cdecl *)(struct Mmachine *))128,	// MAT_COLOR1     MAT_COLOR2   MAT_COLOR_VERTEX  
	(int (__cdecl *)(struct Mmachine *))2,(int (__cdecl *)(struct Mmachine *))256,											// MAT_TEXTURED   MAT_TEXTURED_BIS  
	(int (__cdecl *)(struct Mmachine *))16,(int (__cdecl *)(struct Mmachine *))4,											// MAT_LIGHT	  MAT_GOURAUD
	(int (__cdecl *)(struct Mmachine *))8,(int (__cdecl *)(struct Mmachine *))32,(int (__cdecl *)(struct Mmachine *))1024,		// MAT_TRANSP	  MAT_ENV     MAT_LIGHTMAP


	ZM3setMaterialTransparencyOrder,
	ZM3getMaterialTransparencyOrder,

	ZM3listALLMaterials,									// M3listALLMaterials
	ZM3createMaterial,										// M3createMaterial
	ZM3getMat,												// M3getMat
	ZM3materialName,										// M3materialName
	ZM3renameMat,											// M3renameMat
	ZM3fillMat,												// M3fillMat
	ZM3fillMatObj,											// M3fillMatObj
	ZM3recursFillMatObj,									// M3recursFillMatObj
	ZM3getType,												// M3getType
	ZM3getRealType,											// M3getRealType
	ZM3setType,												// M3setType
	ZM3getMaterialFlat,										// M3getMaterialFlat
	ZM3setMaterialFlat,										// M3setMaterialFlat
	ZM3getMaterialTransparency,								// M3getMaterialTransparency
	ZM3setMaterialTransparency,								// M3getMaterialTransparency
	ZM3getMaterialColor,									// M3getMaterialColor
	ZM3setMaterialColor,									// M3setMaterialColor
	ZM3textureFromMaterial,									// M3textureFromMaterial
	ZM3textureBISFromMaterial,								// M3textureBISFromMaterial
	ZM3lightMapFromMaterial,								// M3lightMapFromMaterial
	ZM3chgMaterialTexture,									// M3chgMaterialTexture
	ZM3chgMaterialTextureBIS,								// M3chgMaterialTextureBIS
	ZM3chgMaterialLightMap, 								// M3chgMaterialLightMap
	ZM3getMaterialMultitex,									// M3getMaterialMultitex
	ZM3setMaterialMultitex,									// M3setMaterialMultitex
	ZM3setMaterialAmbient,									// M3setMaterialAmbient
	ZM3getMaterialAmbient,									// M3getMaterialAmbient
	ZM3setMaterialDiffuse,									// M3setMaterialDiffuse
	ZM3setMaterialEmissive,									// M3setMaterialEmissive
	ZM3getMaterialDiffuse,									// M3getMaterialDiffuse
	ZM3getMaterialEmissive,									// M3getMaterialEmissive
	ZM3setMaterialSpecular,				 					// M3setMaterialSpecular
	ZM3getMaterialSpecular,									// M3getMaterialSpecular
	ZM3materialCount,										// M3materialCount
	ZM3listOfMaterials,										// M3listOfMaterials
	ZM3copyObjMaterial,										// M3copyObjMaterial
	ZM3copyMaterial,										// M3copyMaterial
	ZM3chgObjMaterial,										// M3chgObjMaterial
	ZM3shiftTextureXY,										// M3shiftTextureXY
	ZM3shiftTextureXYF,										// M3shiftTextureXYF
	//$BLG: v4.6a5 - Add
	ZM3shiftTextureBisXY,										// M3shiftTextureBisXY
	ZM3shiftTextureBisXYF,									// M3shiftTextureBisXYF
	ZM3shiftLightMapXY,										// M3shiftLightMapXY
	ZM3shiftLightMapXYF,									// M3shiftLightMapXYF
	//$BLG: v4.6a5 - End
	ZM3saveMat,												// M3saveMat
	ZM3saveMat,												// M3saveMaterial
	// $MS 02/04/2007
	ZM3setMaterialShininess,				 					// M3setMaterialShininess
	ZM3setMaterialShininessF,				 					// M3setMaterialShininessF
	ZM3getMaterialShininess,				 					// M3getMaterialShininess
	ZM3getMaterialShininessF,				 					// M3getMaterialShininessF




	// ---------> Gestion des Textures <----------
	(int (__cdecl *)(struct Mmachine *))4,					// TEX_MIPMAP
	ZM3isExtensionSupported,              // M3isExtensionSupported
	ZM3textureSetGeneralDefaultType,						// M3textureSetGeneralDefaultType
	ZM3textureGetGeneralDefaultType,						// M3textureGetGeneralDefaultType
	ZM3textureSetType,										// M3textureSetType
	ZM3textureGetType,										// M3textureGetType
	ZM3listALLTextures,										// M3listALLTextures
	ZM3getTexture,											// M3getTexture
	ZM3textureName,											// M3textureName
	ZM3renameTexture,										// M3renameTexture
	ZM3textureCount,										// M3textureCount
	ZM3copyMaterialTexture,									// M3copyMaterialTexture
	ZM3isTextureFilled,										// M3isTextureFilled
	ZM3fillTexture,											// M3fillTexture
	ZM3freeTexture,											// M3freeTexture
	ZM3getTextureSize,                  // M3getTextureSize
	ZM3getTransparencyColor,								// M3getTransparencyColor
	ZM3setTransparencyColor,								// M3setTransparencyColor
	ZM3createTexture,										// M3createTexture




	// ------------> Gestion de Rendu <------------
	ZMX3hardware,											// MX3hardware
//	ZMX3getDeviceList,										// MX3getDeviceList
	ZMX3renderEx,											// MX3renderEx
	ZMX3renderExF,											// MX3renderExF
	ZMX3Render,												// MX3dRender
	ZMX3RenderM,											// MX3RenderM
	ZMX3wire,												// MX3wirem
	ZMX3wirem,												// MX3wirem
	ZMX3wireOrtho,											// MX3wireOrtho
	ZMX3RenderInfo,											// MX3RenderInfo
	ZMX3RenderInfoF,										// MX3RenderInfoF
	ZM3blitTexture,											// M3blitTexture
	ZM3blitTexture16,										// M3blitTexture16
	ZM3blitSurface2Texture16,           // M3blitSurface2Texture16
	ZM3filter,												// M3filter
	ZM3nbVisiblePoly,										// M3nbVisiblePoly
	ZM3nbUsedPolygons,										// M3nbUsedPolygons
		// Mehdi :
	ZM3setAntiAliasing,										// M3setAntiAliasing
	ZM3multiSamplingSupported,								// ZM3multiSamplingSupported
	ZM3maxSampleBuffers,
	ZM3EnableMultisampling,
	ZM3DisableMultisampling,
	ZM3getFrameRate,										// $MS : M3getFrameRate




	// ---------> Gestion des Collisions <---------
	ZM3createSphere,										// M3createSphere
	ZM3createObb,											// M3createObb
	ZM3calcObb,												// M3calcObb
	ZM3firstRadius,											// M3firstRadius
	ZM3testInter,											// M3testInter
	ZM3testColl,											// M3testColl
	ZM3testCollF,											// M3testCollF

	ZM3createExactModel,									// M3createExactModel
	ZM3destroyExactModel,									// M3destroyExactModel
	ZM3testExactInter,										// M3testExactInter
	ZM3testExactColl,										// M3testExactColl



	// ---------> Gestion des Animations <---------
	(int (__cdecl *)(struct Mmachine *))2,(int (__cdecl *)(struct Mmachine *))4,(int (__cdecl *)(struct Mmachine *))8,					// ANIM_POS		ANIM_ANG	ANIM_TOP
	ZM3setAnimKey,											// M3setAnimKey
	ZM3setSKLAnimKey,										// M3setSKLAnimKey
	ZM3setAnimKeyF,											// M3setAnimKeyF
	ZM3setAnimKey2,											// M3setAnimKey2
	ZM3setAnimKey2F,										// M3setAnimKey2F
	ZM3applyAnimKey,										// M3applyAnimKey
	ZM3applyAnimKeyF,										// M3applyAnimKeyF
	ZM3applyAnimKey2,										// M3applyAnimKey2
	ZM3applyAnimKey2F,										// M3applyAnimKey2F
	ZM3getAnimLength,										// M3getAnimLength


	ZM3getBone,												//M3getBone
	ZM3renameBone,											// M3renameBone
	ZM3getBoneInfo,											//M3getBoneInfo
	ZM3getBoneFather,										// M3getBoneFather
	ZM3getBoneNumberOfChildren,								//M3getBoneNumberOfChildren
	ZM3ShowSkelet,											//M3ShowSkelet
	ZM3isShaderVertexProfileEnable,							//M3isShaderVertexProfileEnable
	ZM3isShaderFragmentProfileEnable,						//M3isShaderFragmentProfileEnable
    ZM3isShaderEnable,								     	//M3isSkinningEnable
	ZM3AttachMeshWithSKL,									//M3AttachMeshWithSKL
	ZM3listSKLFromNode,		     							// M3listSKLFromNode



	// ----------> Gestion des Lumières <----------
	(int (__cdecl *)(struct Mmachine *))0,(int (__cdecl *)(struct Mmachine *))2,(int (__cdecl *)(struct Mmachine *))4,(int (__cdecl *)(struct Mmachine *))6,					// LIGHT_AMBIENT	LIGHT_PARA		LIGHT_OMNI		LIGHT_SPOT
	(int (__cdecl *)(struct Mmachine *))0,(int (__cdecl *)(struct Mmachine *))2,		//LIGHT_CLASSIC		LIGHT_SATURATED
	ZM3setLightModel,										// M3setLightModel
	ZM3getLightModel,										// M3getLightModel
	ZM3createLight,											// M3createLight
	ZM3getLight,											// M3getLight
	ZM3setLight,											// M3setLight
	ZM3createColorLight,									// M3createColorLight
	ZM3getColorLight,										// M3getColorLight
	ZM3setColorLight,										// M3setColorLight



	// ----------> Gestion des Sprites <-----------
	ZM3createSprite,										// M3createSprite
	ZM3createSpriteF,										// M3createSpriteF
	ZM3setSprite,											// M3setSprite
	ZM3setSpriteF,											// M3setSpriteF
	ZM3getSprite,											// M3getSprite
	ZM3getSpriteF,											// M3getSpriteF
	ZM3setSpriteTexCoord,									// M3setSpriteTexCoord
	ZM3setSpriteTexCoordF,									// M3setSpriteTexCoordF
	ZM3getSpriteTexCoord,									// M3getSpriteTexCoord
	ZM3getSpriteTexCoordF,									// M3getSpriteTexCoordF
	ZM3setSpriteVrtColors,									// M3setSpriteVrtColors
	ZM3getSpriteVrtColors,									// M3getSpriteVrtColors
	ZM3setSpriteAngle,										// M3setSpriteAngle
	ZM3setSpriteAngleF,										// M3setSpriteAngleF
	ZM3getSpriteAngle,										// M3getSpriteAngle
	ZM3getSpriteAngleF,										// M3getSpriteAngleF
	ZM3setSpriteClickability,           // M3setSpriteClickability
	ZM3getSpriteClickability,           // M3getSpriteClickability


	// ----------> Opérations diverses <-----------
	ZSDRAWrectangle,										// _SDRAWrectangle
	ZSDRAWline,												// _SDRAWline
	ZSDRAWcircle,											// _SDRAWcircle
	ZSDRAWtext,												// _SDRAWtext
	ZSDRAWpoint,											// _SDRAWpoint
	ZSDRAWpoly,												// _SDRAWpoly
	M3interpVec,											// M3interpVec
	M3interpVecF,											// M3interpVecF
	M3interpAng,											// M3interpAng
	M3interpAngF,											// M3interpAngF
	ZM3videoInfos,											// M3videoInfos
	ZisPentium												// _isPentium
};



//////////////////////////////////////////////////////////////////////////////////////////////
///		Definition du nombre de paramètres
//////////////////////////////////////////////////////////////////////////////////////////////
int ZooNArg[NbZooPKG]=
{
	// ----------> Callback de rendu <-----------
	TYPVAR,													// 3D_NOCHANGE
	3,														// M3setRenderCallBack

	1,														// MX3TestSurfaceZbuf

	1,
	2,
	
	// ----------> Anciennes fonctions <-----------
	TYPTYPE,												// S3d
	TYPTYPE,												// H3d
	6,														// M3initialize
	1,														// M3desalloc
	TYPTYPE,												// HMat3d
	TYPTYPE,												// HTx3d
	5,														// M3scanlineInfo
	3,														// M3updateTexture
	3,														// M3importTexture
	3,														// M3updateTexture16
	3,														// M3importTexture16
	6,														// M3scanline
	6,														// M3scanlinem
	1,														// M3textureTotalSize


	// -----------> Gestion de session <-----------
	TYPVAR,TYPVAR,TYPVAR,									// SURFACE_FULLSCREEN	SURFACE_WINDOWED	SURFACE_NULL
	6,														// M3create
	6,														// MX3create
	1,														// MX3createSession
	1,														// M3destroy
	1,														// M3freeMemory
	1,														// M3reset
	TYPVAR,TYPVAR,											// ENGINE_HARDWARE     ENGINE_SOFTWARE
	0,														// _GETengineState
	3,														// _CRsurface
	3,                            // _CRforcedSurface
	3,														// _CRfullscreenSurface
	3,                            // _CRforcedFullscreenSurface
	1,														// _GETwindowFromFullscreenSurface
	0,														// _GETsurfaceState
	1,														// _DSsurface
	2,														// _FILLsurface
	1,														// _GETsurfaceSize
	8,														// _BLTsurface  
	1,														// _BLTsurfaceFullScreen
	9,														// _Bitmap2Surface  
	11,														// _BlendBitmap2Surface  
	9,														// _Surface2Bitmap  
	9,														// _Surface2Surface 
	11,                           // _BlendSurface2Surface

	
	// -----------> Gestion des objets <-----------

	// ---> Gestion hierarchique <---
	TYPVAR,TYPVAR,TYPVAR,TYPVAR,TYPVAR,						// M3_MESH   M3_CAM      M3_LIGHT   M3_SHELL		M3_TOPO
	TYPVAR,TYPVAR,TYPVAR,TYPVAR,TYPVAR,						// M3_COLL   M3_SPRITE   M3_ANIM	M3_COLOR_LIGHT	M3_PARTICLE
	TYPVAR,TYPVAR,											// M3_LISTENER	M3_SOUND

	3,														// M3load
	3,														// M3loadString
	3,														// M3loadAnimationFileWithSKL
	1,														// M3createShell
	2,														// M3delObj
	2,														// M3copyObj
	2,														// M3getObj
	2,														// M3listObjFromNode
	2,														// M3M3getH3dType
	2,														// M3objName
	2,														// M3getFather
	2,														// M3getFirstSon
	2,														// M3getBrother
	2,														// M3bigFather
	3,														// M3isFather
	2,														// M3unLink
	3,														// M3link
	3,														// M3renameObj
	1,														// M3listOfBigFathers
	2,														// M3getObjType
	1,														// M3listALLObj
	1,														// M3listALLLight
	1,														// M3listALLCam
	1,														// M3listALLShl
	1,														// M3listALLSpr
	1,														// M3listALLPcl
	1,														// M3listALLPclEff
	1,														// M3listALLFont
	1,														// M3listALLSkl
	1,														// M3listALLSound
	1,														// M3listALLBones

	// ----> Gestion géométrique <----
	TYPVAR,													// RANGE_INFINITY
	TYPVAR,													// RANGE_INFINITY_F
	3,														// M3setObjRange
	2,														// M3getObjRange
	3,														// M3setObjRangeF
	2,														// M3getObjRangeF
	3,														// M3setObjVec
	3,														// M3setObjVecF
	2,														// M3getObjVec
	2,														// M3getObjVecF
	3,														// M3setObjAng
	3,														// M3setObjAngF
	2,														// M3getObjAng
	2,														// M3getObjAngF
	3,														// M3setObjScale
	3,														// M3setObjScaleF
	2,														// M3getObjScale
	2,														// M3getObjScaleF
	3,														// M3movObj
	3,														// M3movObjF
	3,														// M3rotateObj
	3,														// M3rotateObjF
	3,														// M3movObjExt
	3,														// M3movObjExtF
	3,														// M3rotateObjExt
	3,														// M3rotateObjExtF
	2,														// M3calcMat
	2,														// M3getObjVecRender
	2,														// M3getObjVecRenderF
	2,														// M3getObjMatrixRender
	2,														// M3getObjMatrixRenderF
	2,														// M3getCamera
	3,														// M3setCamera
	3,														// M3calcPosRef
	3,														// M3calcPosRefF
	1,														// M3angularFromMatrix
	1,														// M3angularFromMatrixF
	2,														// M3getRadius
	2,														// M3getRadiusF
	3,														// M3calcProj
	3,														// M3calcProjF
	3,														// M3areMeshesCulled
	3,														// M3isMeshCulledByOthers
	2,														// M3angularTarget
	2,														// M3angularTargetF
	3,														// M3getGlobalVec
	3,														// M3getGlobalVecF



	// ----> Gestion topologique <----
	1,														// M3listALLtopos
	2,														// M3getTopo
	1,														// M3createTopo
	2,														// M3cleanTopo
	2,														// M3topoCount
	6,														// M3topoAddFace
	6,														// M3topoAddFaceF
	4,														// M3setFaceVertRef
	3,														// M3getFaceVertRef
	4,														// M3setFaceMaterial
	3,														// M3getFaceMaterial
	5,														// M3setFaceTexCoord
	5,														// M3setFaceTexCoordF
	4,														// M3getFaceTexCoord
	4,														// M3getFaceTexCoordF
	2,														// M3listOfPolygons
	2,														// M3listOfPolygonsF
	3,														// M3setPolygons
	3,														// M3setPolygonsF
	3,														// M3deltaPolygons
	3,														// M3deltaPolygonsF
	5,														// M3morphPolygons
	5,														// M3morphPolygonsF
	3,														// M3topoAddVertex
	3,														// M3topoAddVertexF
	3,														// M3topoAddVertices
	3,														// M3topoAddVerticesF
	2,														// M3listOfVertices
	2,														// M3listOfVerticesF
	4,														// M3topoSetVertex
	4,														// M3topoSetVertexF
	3,														// M3topoGetVertex
	3,														// M3topoGetVertexF
	3,														// M3setVertices
	3,														// M3setVerticesF
	4,														// M3deltaVertex
	4,														// M3deltaVertexF
	3,														// M3deltaVertices
	3,														// M3deltaVerticesF
	6,														// M3morphVertex
	6,														// M3morphVertexF
	5,														// M3morphVertices
	5,														// M3morphVerticesF
	3,														// M3listOfColorVertices
	5,														// M3topoSetColorVertex
	4,														// M3topoGetColorVertexF
	4,														// M3setColorVertices
	4,														// M3convVrt
	4,														// M3convVrtF
	4,														// M3convVec
	4,														// M3convVecF

	//$LB (31/10/2004)
	4,														// M3topoScale
	2,

	// ------> Gestion de mesh <------
	TYPVAR,													// MESH_STATIC
	TYPVAR,													// MESH_MULTI_TOPO
	TYPVAR,													// MESH_NOT_CLICKABLE
	2,														// M3createMesh
	3,														// M3meshSetMultiTopo
	3,														// M3meshSetMultiTopoF
	2,														// M3meshGetMultiTopo
	2,														// M3meshGetMultiTopoF
	2,														// M3meshGetActiveTopo
	3,														// M3meshSetTopology
	2,														// M3meshGetTopology
	3,														// M3meshSetType
	2,														// M3meshGetType
	3,														// M3distance
	3,														// M3save
	2,														// M3recListOfMaterials



	// ---------> Gestion des Materiaux <----------
	TYPVAR,TYPVAR,TYPVAR,									// MAT_COLOR1     MAT_COLOR2		MAT_COLOR_VERTEX 
	TYPVAR,TYPVAR,											// MAT_TEXTURED   MAT_TEXTURED_BIS  
	TYPVAR,TYPVAR,											// MAT_LIGHT	  MAT_GOURAUD
	TYPVAR,TYPVAR,TYPVAR,								// MAT_TRANSP	  MAT_ENV		 MAT_LIGHTMAP

	2,
	1,


	1,														// M3listALLMaterials
	2,														// M3createMaterial
	2,														// M3getMat
	2,														// M3materialName
	3,														// M3renameMat
	2,														// M3fillMat
	2,														// M3fillMatObj
	2,														// M3recursFillMatObj
	2,														// M3getType
	2,														// M3getRealType
	3,														// M3setType
	2,														// M3getMaterialFlat
	3,														// M3setMaterialFlat
	2,														// M3getMaterialTransparency
	3,														// M3getMaterialTransparency
	3,														// M3getMaterialColor
	4,														// M3setMaterialColor
	2,														// M3textureFromMaterial
	2,														// M3textureBISFromMaterial
	2,														// M3lightMapFromMaterial
	3,														// M3chgMaterialTexture
	3,														// M3chgMaterialTextureBIS
	3,														// M3chgMaterialLightMap
	2,														// M3getMaterialMultitex
	3,														// M3setMaterialMultitex
	3,														// M3setMaterialAmbient
	2,														// M3getMaterialAmbient
	3,														// M3setMaterialDiffuse
	3,														// M3setMaterialEmissive
	2,														// M3getMaterialDiffuse
	2,														// M3getMaterialEmissive
	3,														// M3setMaterialSpecular
	2,														// M3getMaterialSpecular
	2,														// M3materialCount
	2,														// M3listOfMaterials
	3,														// M3copyObjMaterial
	3,														// M3copyMaterial
 	4,														// M3chgObjMaterial
	5,														// M3shiftTextureXY
	5,														// M3shiftTextureXYF
	//$BLG: v4.6a5 - Add
	5,														// M3shiftTextureBisXY
	5,														// M3shiftTextureBisXYF	
	5,														// M3shiftLightMapXY
	5,														// M3shiftLightMapXYF	
	//$BLG: v4.6a5 - End
	2,														// M3saveMat
	2,														// M3saveMaterial
	//$MS 02/04/2007
	3,														// M3setMaterialShininess
	3,														// M3setMaterialShininessF
	2,														// M3getMaterialShininess
	2,														// M3getMaterialShininessF




	// ---------> Gestion des Textures <----------
	TYPVAR,													// TEX_MIPMAP
	1,                            // M3isExtensionSupported
	2,														// M3textureSetGeneralDefaultType
	1,                            // M3textureGetGeneralDefaultType
	3,														// M3textureSetType
	2,														// M3textureGetType
	1,														// M3listALLTextures
	2,														// M3getTexture
	2,														// M3textureName
	3,														// M3renameTexture
	2,														// M3textureCount
	2,														// M3copyMaterialTexture
	2,														// M3isTextureFilled
	2,														// M3fillTexture
	2,														// M3freeTexture
	2,                            // M3getTextureSize
	2,														// M3getTransparencyColor
	3,														// M3setTransparencyColor
	2,														// M3createTexture



	// ------------> Gestion de Rendu <------------
	0,														// MX3hardware
//	0,														// MX3getDeviceList
	6,														// MX3renderEx
	6,														// MX3renderExF
	6,														// MX3dRender
	6,														// MX3RenderM
	6,														// MX3wire
	6,														// MX3wirem
	6,														// MX3wireOrtho
	4,														// MX3RenderInfo
	4,														// MX3RenderInfoF
	3,														// M3blitTexture
	3,														// M3blitTexture16
	3,                            // M3blitSurface2Texture16
	2,														// M3filter
	1,														// M3nbVisiblePoly
	1,														// M3nbUsedPolygons
		// Mehdi :
	2,														// M3setAntiAliasing
	0,														// M3multiSamplingSupported
	0,														// M3maxSampleBuffers
	1,														// M3EnableMultisampling
	1,														// M3DisableMultisampling
	1,														// $MS : M3getFrameRate




	// ---------> Gestion des Collisions <---------
	2,														// M3createSphere
	2,														// M3createObb
	2,														// M3calcObb
	2,														// M3firstRadius
	3,														// M3testInter
	5,														// M3testColl
	5,														// M3testCollF

	2,														// M3createExactModel
	2,														// M3destroyExactModel
	3,														// M3testExactInter
	4,														// M3testExactColl


	// ---------> Gestion des Animations <---------
	TYPVAR,TYPVAR,TYPVAR,									// ANIM_POS		ANIM_ANG	ANIM_TOP
	3,														// M3setAnimKey
	4,														// M3setSKLAnimKey
	3,														// M3setAnimKeyF
	5,														// M3setAnimKey2
	5,														// M3setAnimKey2F
	5,														// M3applyAnimKey
	5,														// M3applyAnimKeyF
	8,														// M3applyAnimKey2
	8,														// M3applyAnimKey2F
	2,														// M3getAnimLength


	// ------------------------> Gestion des bone <----------------------------

	2,														// M3getBone
	3,														// M3renameBone
	1,														// M3getBoneInfo
	2,														// M3getBoneFather
	2,														// M3getBoneNumberOfChildren
	3,														// M3ShowSkelet
	0,														// M3isShaderVertexProfileEnable
	0,														// M3isShaderFragmentProfileEnable
	0,														// M3isShaderEnable
	3,														// M3AttachMeshWithSKL
	2,														// M3listSKLFromNode


	// ----------> Gestion des Lumières <----------
	TYPVAR,TYPVAR,TYPVAR,TYPVAR,							// LIGHT_AMBIENT	LIGHT_PARA		LIGHT_OMNI		LIGHT_SPOT
	TYPVAR,TYPVAR,											//LIGHT_CLASSIC		LIGHT_SATURATED
	2,														// M3setLightModel
	1,														// M3getLightModel
	7,														// M3createLight
	2,														// M3getLight
	3,														// M3setLight
	8,														// M3createColorLight
	2,														// M3getColorLight
	9,														// M3setColorLight



	// ----------> Gestion des Sprites <-----------
	5,														// M3createSprite
	5,														// M3createSpriteF
	6,														// M3setSprite
	6,														// M3setSpriteF
	2,														// M3getSprite
	2,														// M3getSpriteF
	4,														// M3setSpriteTexCoord
	4,														// M3setSpriteTexCoordF
	2,														// M3getSpriteTexCoord
	2,														// M3getSpriteTexCoordF
	4,														// M3setSpriteVrtColors
	2,														// M3getSpriteVrtColors
	3,														// M3setSpriteAngle
	3,														// M3setSpriteAngleF
	2,														// M3getSpriteAngle
	2,														// M3getSpriteAngleF
  3,                            // M3setSpriteClickability
  2,                            // M3getSpriteClickability




	// ----------> Opérations diverses <-----------
	10,														// _SDRAWrectangle
	8,														// _SDRAWline
	9,														// _SDRAWcircle
	7,														// _SDRAWtext
	4,														// _SDRAWpoint
	8,														// _SDRAWpoly
	3,														// M3interpVec
	3,														// M3interpVecF
	3,														// M3interpAng
	3,														// M3interpAngF
	0,														// M3videoInfos
	0														// _isPentium
};



//////////////////////////////////////////////////////////////////////////////////////////////
///		Definition des grammaires fontionnelles
//////////////////////////////////////////////////////////////////////////////////////////////
char* ZooType[NbZooPKG]=
{
	// ----------> Callback de rendu <-----------
	"[[[[F F F] I I] r1] [[HMat3d I F F F F I F F F F I F F F F] r1]]",			// 3D_NOCHANGE
	"fun [S3d H3d fun [H3d] [[[[F F F] I I] r1] [[HMat3d I F F F F I F F F F I F F F F] r1]]] H3d",

	"fun [ObjSurface] I",										// MX3TestSurfaceZbuf

	"fun [I] I",
	"fun [S3d H3d] I",

	// ----------> Anciennes fonctions <-----------
	NULL,														// S3d
	NULL,														// H3d
	"fun [I I I I I I] S3d",									// M3initialize
	"fun [S3d] I",												// M3desalloc
	NULL,														// HMat3d
	NULL,														// HTx3d
	"fun [S3d ObjBitmap H3d I I] [H3d HMat3d I I I]",			// M3scanlineInfo
	"fun [S3d HTx3d ObjBitmap8] I",								// M3updateTexture
	"fun [S3d HTx3d ObjBitmap8] I",								// M3importTexture
	"fun [S3d HTx3d ObjBitmap] I",								// M3updateTexture16
	"fun [S3d HTx3d ObjBitmap] I",								// M3importTexture16
	"fun [S3d ObjBitmap H3d I I I] H3d",						// M3scanline
	"fun [S3d ObjBitmap H3d I I I] [H3d HMat3d]",				// M3scanlinem
	"fun [S3d] I",												// M3textureTotalSize

	
	// -----------> Gestion de session <-----------
	"I","I","I",												// SURFACE_FULLSCREEN	SURFACE_WINDOWED	SURFACE_NULL
	"fun [Chn I I I I I] S3d",									// M3create
	"fun [Chn I I I I I] S3d",									// MX3create
	"fun [Chn] S3d",											// MX3createSession
	"fun [S3d] I",												// M3destroy
	"fun [S3d] I",												// M3freeMemory
	"fun [S3d] I",												// M3reset
	"I","I",													// ENGINE_HARDWARE     ENGINE_SOFTWARE
	"fun [] I",													// _GETengineState
	"fun [Chn I I] ObjSurface",									// _CRsurface
	"fun [Chn I I] ObjSurface",									// _CRforcedSurface
	"fun [Chn I I] ObjSurface",									// _CRfullscreenSurface
	"fun [Chn I I] ObjSurface",									// _CRforcedFullscreenSurface
	"fun [ObjSurface] ObjWin",									// _GETwindowFromFullscreenSurface
	"fun [] I",													// _GETsurfaceState
	"fun [ObjSurface] I",										// _DSsurface
	"fun [ObjSurface I] ObjSurface",							// _FILLsurface
	"fun [ObjSurface] [I I]",									// _GETsurfaceSize
	"fun [ObjWin I I ObjSurface I I I I] ObjWin",				// _BLTsurface    
	"fun [ObjSurface] ObjWin",									// _BLTsurfaceFullScreen
	"fun [ObjSurface I I ObjBitmap I I I I I] ObjSurface",		    // _Bitmap2Surface
	"fun [ObjSurface I I ObjBitmap I I I I I I I] ObjSurface",		// _BlendBitmap2Surface
	"fun [ObjBitmap I I ObjSurface I I I I I] ObjBitmap",		      // _Surface2Bitmap
	"fun [ObjSurface I I ObjSurface I I I I I] ObjSurface",		    // _Surface2Surface
	"fun [ObjSurface I I ObjSurface I I I I I I I] ObjSurface",		// _BlendSurface2Surface


	// -----------> Gestion des objets <-----------

	// ---> Gestion hierarchique <---
	"I","I","I","I","I",										// M3_MESH   M3_CAM      M3_LIGHT   M3_SHELL		M3_TOPO
	"I","I","I","I","I",										// M3_COLL   M3_SPRITE   M3_ANIM	M3_COLOR_LIGHT	M3_PARTICLE
	"I","I",													// M3_LISTENER	M3_SOUND

	"fun [S3d S H3d] I",										// M3load
	"fun [S3d S H3d] I",										// M3loadString
	"fun [S3d S H3d] I",										// M3loadAnimationWithSKL
	"fun [S3d] H3d",											// M3createShell
	"fun [S3d H3d] I",											// M3delObj
	"fun [S3d H3d] H3d",										// M3copyObj
	"fun [S3d S] H3d",											// M3getObj
	"fun [S3d H3d] [H3d r1]",									// M3listMeshFromNode
	"fun [S3d H3d] I",											// M3getH3dType
	"fun [S3d H3d] S",											// M3objName
	"fun [S3d H3d] H3d",										// M3getFather
	"fun [S3d H3d] H3d",										// M3getFirstSon
	"fun [S3d H3d] H3d",										// M3getBrother
	"fun [S3d H3d] H3d",										// M3bigFather
	"fun [S3d H3d H3d] I",										// M3isFather
	"fun [S3d H3d] I",											// M3unLink
	"fun [S3d H3d H3d] I",										// M3link
	"fun [S3d H3d S] I",										// M3renameObj
	"fun [S3d] [H3d r1]",										// M3listOfBigFathers
	"fun [S3d H3d] I",											// M3getObjType
	"fun [S3d] [H3d r1]",										// M3listALLObj
	"fun [S3d] [H3d r1]",										// M3listALLLight
	"fun [S3d] [H3d r1]",										// M3listALLCam
	"fun [S3d] [H3d r1]",										// M3listALLShl
	"fun [S3d] [H3d r1]",										// M3listALLSpr
	"fun [S3d] [H3d r1]",										// M3listALLPcl
	"fun [S3d] [H3d r1]",										// M3listALLPclEff
	"fun [S3d] [H3d r1]",										// M3listALLFont
	"fun [S3d] [H3d r1]",										// M3listALLSkl
	"fun [S3d] [H3d r1]",										// M3listALLSound
	"fun [S3d] [H3d r1]",										// M3listALLBones

	// ----> Gestion géométrique <----
	"I",														// RANGE_INFINITY
	"F",														// RANGE_INFINITY_F
	"fun [S3d H3d [I I]] I",									// M3setObjRange
	"fun [S3d H3d] [I I]",										// M3getObjRange
	"fun [S3d H3d [F F]] I",									// M3setObjRangeF
	"fun [S3d H3d] [F F]",										// M3getObjRangeF
	"fun [S3d H3d [I I I]] I",									// M3setObjVec
	"fun [S3d H3d [F F F]] I",									// M3setObjVecF
	"fun [S3d H3d] [I I I]",									// M3getObjVec
	"fun [S3d H3d] [F F F]",									// M3getObjVecF
	"fun [S3d H3d [I I I]] I",									// M3setObjAng
	"fun [S3d H3d [F F F]] I",									// M3setObjAngF
	"fun [S3d H3d] [I I I]",									// M3getObjAng
	"fun [S3d H3d] [F F F]",									// M3getObjAngF
	"fun [S3d H3d I] I",										// M3setObjScale
	"fun [S3d H3d F] I",										// M3setObjScaleF
	"fun [S3d H3d] I",											// M3getObjScale
	"fun [S3d H3d] F",											// M3getObjScaleF
	"fun [S3d H3d [I I I]] I",									// M3movObj
	"fun [S3d H3d [F F F]] I",									// M3movObjF
	"fun [S3d H3d [I I I]] I",									// M3rotateObj
	"fun [S3d H3d [F F F]] I",									// M3rotateObjF
	"fun [S3d H3d [I I I]] I",									// M3movObjExt
	"fun [S3d H3d [F F F]] I",									// M3movObjExtF
	"fun [S3d H3d [I I I]] I",									// M3rotateObjExt
	"fun [S3d H3d [F F F]] I",									// M3rotateObjExtF
	"fun [S3d H3d] I",											// M3calcMat
	"fun [S3d H3d] [I I I]",									// M3getObjVecRender
	"fun [S3d H3d] [F F F]",									// M3getObjVecRenderF
	"fun [S3d H3d] [[I I I] [I I I] [I I I]]",					// M3getObjMatrixRender
	"fun [S3d H3d] [[F F F] [F F F] [F F F]]",					// M3getObjMatrixRenderF
	"fun [S3d H3d] [[I I] [I I] [I I I]]",						// M3getCamera
	"fun [S3d H3d [[I I] [I I] [I I I]]] I",					// M3setCamera
	"fun [S3d H3d H3d] [[I I I] [[I I I] [I I I] [I I I]]]",	// M3calcPosRef
	"fun [S3d H3d H3d] [[F F F] [[F F F] [F F F] [F F F]]]",	// M3calcPosRefF
	"fun [[[I I I] [I I I] [I I I]]] [I I I]",					// M3angularFromMatrix
	"fun [[[F F F] [F F F] [F F F]]] [F F F]",					// M3angularFromMatrixF
	"fun [S3d H3d] I",											// M3getRadius
	"fun [S3d H3d] F",											// M3getRadiusF
	"fun [S3d H3d H3d] [I I I I]",								// M3calcProj
	"fun [S3d H3d H3d] [I I F F]",								// M3calcProjF
	"fun [S3d H3d [H3d r1]] [I r1]",							// M3areMeshesCulled
	"fun [S3d H3d [H3d r1]] [I r1]",							// M3isMeshCulledByOthers
	"fun [[I I I] [I I I]] [I I I]",							// M3angularTarget
	"fun [[F F F] [F F F]] [F F F]",							// M3angularTargetF
	"fun [S3d H3d [I I I]] [I I I]",							// M3getGlobalVec
	"fun [S3d H3d [F F F]] [F F F]",							// M3getGlobalVecF

	// ----> Gestion topologique <----
	"fun [S3d] [H3d r1]",										// M3listALLtopos
	"fun [S3d S] H3d",											// M3getTopo
	"fun [S3d] H3d",											// M3createTopo
	"fun [S3d H3d] I",											// M3cleanTopo
	"fun [S3d H3d] I",											// M3topoCount
	"fun [S3d H3d [I I I] [[I I] [I I] [I I]] [[I I] [I I] [I I]] HMat3d] I",			// M3topoAddFace
	"fun [S3d H3d [I I I] [[F F] [F F] [F F]] [[F F] [F F] [F F]] HMat3d] I",			// M3topoAddFaceF
	"fun [S3d H3d I [I I I]] I",								// M3setFaceVertRef
	"fun [S3d H3d I] [I I I]",									// M3getFaceVertRef
	"fun [S3d H3d I HMat3d] I",									// M3setFaceMaterial
	"fun [S3d H3d I] HMat3d",									// M3getFaceMaterial
	"fun [S3d H3d I I [[I I] [I I] [I I]]] I",					// M3setFaceTexCoord
	"fun [S3d H3d I I [[F F] [F F] [F F]]] I",					// M3setFaceTexCoordF
	"fun [S3d H3d I I] [[I I] [I I] [I I]]",					// M3getFaceTexCoord
	"fun [S3d H3d I I] [[F F] [F F] [F F]]",					// M3getFaceTexCoordF
	"fun [S3d H3d] [[HMat3d [[I I I] r1]] r1]",					// M3listOfPolygons
	"fun [S3d H3d] [[HMat3d [[I F F] r1]] r1]",					// M3listOfPolygonsF
	"fun [S3d H3d [[HMat3d [[I I I] r1]] r1]] I",				// M3setPolygons
	"fun [S3d H3d [[HMat3d [[I F F] r1]] r1]] I",				// M3setPolygonsF
	"fun [S3d H3d [[HMat3d [[I I I] r1]] r1]] I",				// M3deltaPolygons
	"fun [S3d H3d [[HMat3d [[I F F] r1]] r1]] I",				// M3deltaPolygonsF
	"fun [S3d H3d [[HMat3d [[I I I] r1]] r1] [[HMat3d [[I I I] r1]] r1] I] I",			// M3morphPolygons
	"fun [S3d H3d [[HMat3d [[I F F] r1]] r1] [[HMat3d [[I F F] r1]] r1] F] I",			// M3morphPolygonsF
	"fun [S3d H3d [I I I]] I",									// M3topoAddVertex
	"fun [S3d H3d [F F F]] I",									// M3topoAddVertexF
	"fun [S3d H3d [[I I I] r1]] I",								// M3topoAddVertices
	"fun [S3d H3d [[F F F] r1]] I",								// M3topoAddVerticesF
	"fun [S3d H3d] [[I I I] r1]",								// M3listOfVertices
	"fun [S3d H3d] [[F F F] r1]",								// M3listOfVerticesF
	"fun [S3d H3d I [I I I]] I",								// M3topoSetVertex
	"fun [S3d H3d I [F F F]] I",								// M3topoSetVertexF
	"fun [S3d H3d I] [I I I]",									// M3topoGetVertex
	"fun [S3d H3d I] [F F F]",									// M3topoGetVertexF
	"fun [S3d H3d [[I I I] r1]] I",								// M3setVertices
	"fun [S3d H3d [[F F F] r1]] I",								// M3setVerticesF
	"fun [S3d H3d I [I I I]] I",								// M3deltaVertex
	"fun [S3d H3d I [F F F]] I",								// M3deltaVertexF
	"fun [S3d H3d [[I I I] r1]] I",								// M3deltaVertices
	"fun [S3d H3d [[F F F] r1]] I",								// M3deltaVerticesF
	"fun [S3d H3d I [I I I] [I I I] I] I",						// M3morphVertex
	"fun [S3d H3d I [F F F] [F F F] F] I",						// M3morphVertexF
	"fun [S3d H3d [[I I I] r1] [[I I I] r1] I] I",				// M3morphVertices
	"fun [S3d H3d [[F F F] r1] [[F F F] r1] F] I",				// M3morphVerticesF
	"fun [S3d H3d I] [I r1]",									// M3listOfColorVertices
	"fun [S3d H3d I I I] I",									// M3topoSetColorVertex
	"fun [S3d H3d I I] I",										// M3topoGetColorVertexF
	"fun [S3d H3d I [I r1]] I",									// M3setColorVertices
	"fun [S3d H3d H3d [I I I]] [I I I]",						// M3convVrt
	"fun [S3d H3d H3d [F F F]] [F F F]",						// M3convVrtF
	"fun [S3d H3d H3d [I I I]] [I I I]",						// M3convVec
	"fun [S3d H3d H3d [F F F]] [F F F]",						// M3convVecF

	//$LB (31/10/2004)
	"fun [S3d H3d [I I I] I] I",								// M3topoScale
	"fun [S3d H3d] I",

	// ------> Gestion de mesh <------
	"I",														// MESH_STATIC
	"I",														// MESH_MULTI_TOPO
	"I",														// MESH_NOT_CLICKABLE
	"fun [S3d H3d] H3d",										// M3createMesh
	"fun [S3d H3d [[H3d I] r1]] I",								// M3meshSetMultiTopo
	"fun [S3d H3d [[H3d F] r1]] I",								// M3meshSetMultiTopoF
	"fun [S3d H3d] [[H3d I] r1]",								// M3meshGetMultiTopo
	"fun [S3d H3d] [[H3d F] r1]",								// M3meshGetMultiTopoF
	"fun [S3d H3d] H3d",										// M3meshGetActiveTopo
	"fun [S3d H3d H3d] I",										// M3meshSetTopology
	"fun [S3d H3d] H3d",										// M3meshGetTopology
	"fun [S3d H3d I] I",										// M3meshSetType
	"fun [S3d H3d] I",											// M3meshGetType
	"fun [S3d H3d H3d] I",										// M3distance
	"fun [S3d H3d I] S",										// M3save
	"fun [S3d H3d] [HMat3d r1]",								// M3recListOfMaterials



	// ---------> Gestion des Materiaux <----------
	"I","I","I",												// MAT_COLOR1     MAT_COLOR2		MAT_COLOR_VERTEX 
	"I","I",													// MAT_TEXTURED   MAT_TEXTURED_BIS  
	"I","I",													// MAT_LIGHT	  MAT_GOURAUD
	"I","I","I",											    // MAT_TRANSP	  MAT_ENV

	"fun [HMat3d I] I",											// M3setMaterialTransparencyOrder
	"fun [HMat3d] I",											// M3getMaterialTransparencyOrder

	"fun [S3d] [HMat3d r1]",									// M3listALLMaterials
	"fun [S3d S] HMat3d",										// M3createMaterial
	"fun [S3d S] HMat3d",										// M3getMat
	"fun [S3d HMat3d] S",										// M3materialName
	"fun [S3d HMat3d S] I",										// M3renameMat
	"fun [S3d HMat3d] I",										// M3fillMat
	"fun [S3d H3d] I",											// M3fillMatObj
	"fun [S3d H3d] I",											// M3recursFillMatObj
	"fun [S3d HMat3d] I",										// M3getType
	"fun [S3d HMat3d] I",										// M3getRealType
	"fun [S3d HMat3d I] I",										// M3setType
	"fun [S3d HMat3d] I",										// M3getMaterialFlat
	"fun [S3d HMat3d I] I",										// M3setMaterialFlat
	"fun [S3d HMat3d] I",										// M3getMaterialTransparency
	"fun [S3d HMat3d I] I",										// M3setMaterialTransparency
	"fun [S3d HMat3d I] I",										// M3getMaterialColor
	"fun [S3d HMat3d I I] I",									// M3setMaterialColor
	"fun [S3d HMat3d] HTx3d",									// M3textureFromMaterial
	"fun [S3d HMat3d] HTx3d",									// M3textureBISFromMaterial
	"fun [S3d HMat3d] HTx3d",									// M3lightMapFromMaterial
	"fun [S3d HMat3d HTx3d] I",									// M3chgMaterialTexture
	"fun [S3d HMat3d HTx3d] I",									// M3chgMaterialTextureBIS
	"fun [S3d HMat3d HTx3d] I",									// M3chgMaterialLightMap
	"fun [S3d HMat3d] I",										// M3getMaterialMultitex
	"fun [S3d HMat3d I] I",										// M3setMaterialMultitex
	"fun [S3d HMat3d I] I",										// M3setMaterialAmbient
	"fun [S3d HMat3d] I",										// M3getMaterialAmbient
	"fun [S3d HMat3d I] I",										// M3setMaterialDiffuse
	"fun [S3d HMat3d I] I",										// M3setMaterialEmissive
	"fun [S3d HMat3d] I",										// M3getMaterialDiffuse
	"fun [S3d HMat3d] I",										// M3getMaterialEmissive
	"fun [S3d HMat3d I] I",										// M3setMaterialSpecular
	"fun [S3d HMat3d] I",										// M3getMaterialSpecular
	"fun [S3d HMat3d] I",										// M3materialCount
	"fun [S3d H3d] [HMat3d r1]",								// M3listOfMaterials
	"fun [S3d H3d HMat3d] HMat3d",								// M3copyObjMaterial
	"fun [S3d HMat3d S] HMat3d",								// M3copyMaterial
	"fun [S3d H3d HMat3d HMat3d] I",							// M3chgObjMaterial
	"fun [S3d H3d HMat3d I I] I",								// M3shiftTextureXY
	"fun [S3d H3d HMat3d F F] I",								// M3shiftTextureXYF
	//$BLG: v4.6a5 - Add
	"fun [S3d H3d HMat3d I I] I",								// M3shiftTextureBisXY
	"fun [S3d H3d HMat3d F F] I",								// M3shiftTextureBisXYF
	"fun [S3d H3d HMat3d I I] I",								// M3shiftLightMapXY
	"fun [S3d H3d HMat3d F F] I",								// M3shiftLightMapXYF
	//$BLG: v4.6a5 - End
	"fun [S3d HMat3d] S",										// M3saveMat
	"fun [S3d HMat3d] S",										// M3saveMaterial
	//$MS Ajout
	"fun [S3d HMat3d I] I",										// M3setMaterialShininess
	"fun [S3d HMat3d F] I",										// M3setMaterialShininessF
	"fun [S3d HMat3d] I",										// M3getMaterialShininess
	"fun [S3d HMat3d] F",										// M3getMaterialShininessF


	// ---------> Gestion des Textures <----------
	"I",														// TEX_MIPMAP
	"fun [S] I",                    // M3isExtensionSupported
	"fun [S3d I] I",											// M3textureSetGeneralDefaultType
	"fun [S3d] I",											  // M3textureGetGeneralDefaultType
	"fun [S3d HTx3d I] I",								  // M3textureSetType
	"fun [S3d HTx3d] I",										// M3textureGetType
	"fun [S3d] [HTx3d r1]",										// M3listALLTextures
	"fun [S3d S] HTx3d",										// M3getTexture
	"fun [S3d HTx3d] S",										// M3textureName
	"fun [S3d HTx3d S] I",										// M3renameTexture
	"fun [S3d HTx3d] I",										// M3textureCount
	"fun [S3d HMat3d] HTx3d",									// M3copyMaterialTexture
	"fun [S3d HTx3d] I",										// M3isTextureFilled
	"fun [S3d HTx3d] I",										// M3fillTexture
	"fun [S3d HTx3d] I",										// M3freeTexture
	"fun [S3d HTx3d] [I I]",                // M3getTextureSize
	"fun [S3d HTx3d] I",										// M3getTransparencyColor
	"fun [S3d HTx3d I] I",										// M3setTransparencyColor
	"fun [S3d S] HTx3d",										// M3createTexture



	// ------------> Gestion de Rendu <------------
	"fun [] I",													// MX3hardware
//	"fun [] [[S S] r1]",										// MX3getDeviceList
	"fun [S3d ObjSurface H3d I I I] [H3d HMat3d I I I I I]",	// MX3renderEx
	"fun [S3d ObjSurface H3d I I I] [H3d HMat3d I F F F F]",	// MX3renderExF
	"fun [S3d ObjSurface H3d I I I] H3d",						// MX3dRender
	"fun [S3d ObjSurface H3d I I I] [H3d HMat3d]",				// MX3RenderM
	"fun [S3d ObjSurface H3d I I I] [H3d HMat3d]",				// MX3wire
	"fun [S3d ObjSurface H3d I I I] [H3d HMat3d]",				// MX3wirem
	"fun [S3d ObjSurface H3d I I I] [H3d HMat3d]",				// MX3wireOrtho
	"fun [S3d H3d I I] [H3d HMat3d I I I]",						// MX3RenderInfo
	"fun [S3d H3d I I] [H3d HMat3d F F F]",						// MX3RenderInfoF
	"fun [S3d HTx3d ObjBitmap8] I",								// M3blitTexture
	"fun [S3d HTx3d ObjBitmap] I",								// M3blitTexture16
	"fun [S3d HTx3d ObjSurface] I",           // M3blitSurface2Texture16
	"fun [ObjBitmap S] ObjBitmap",								// M3filter
	"fun [S3d] I",												// M3nbVisiblePoly
	"fun [S3d] I",												// M3nbUsedPolygons
		// Mehdi :
	"fun [S3d F] I",											// M3setAntiAliasing
	"fun [] [I I]",											// M3multiSamplingSupported
	"fun [] I",												    // M3maxSampleBuffers
	"fun [S3d] I",												// M3EnableMultisampling
	"fun [S3d] I",												// M3DisableMultisampling
	"fun [S3d] F",												// M3getFrameRate




	// ---------> Gestion des Collisions <---------
	"fun [S3d I] H3d",											// M3createSphere
	"fun [S3d [I I I]] H3d",									// M3createObb
	"fun [S3d H3d] [[I I I] [I I I]]",							// M3calcObb
	"fun [S3d H3d] I",											// M3firstRadius
	"fun [S3d H3d H3d] [H3d H3d]",								// M3testInter
	"fun [S3d H3d H3d [I I I] I] [H3d H3d [I I I] [I I I]]",	// M3testColl
	"fun [S3d H3d H3d [F F F] F] [H3d H3d [F F F] [F F F]]",	// M3testCollF

	"fun [S3d H3d] I",											// M3createExactModel
	"fun [S3d H3d] I",											// M3destroyExactModel
	"fun [S3d H3d H3d] I",										// M3testExactInter
	"fun [S3d H3d H3d [F F F]] [F F F]",						// M3testExactColl



	// ---------> Gestion des Animations <---------
	"I","I","I",												// ANIM_POS		ANIM_ANG	ANIM_TOP
	"fun [S3d H3d I] I",										// M3setAnimKey
	"fun [S3d H3d H3d I] I",									// M3setSKLAnimKey
	"fun [S3d H3d F] I",										// M3setAnimKeyF
	"fun [S3d H3d I I I] I",									// M3setAnimKey2
	"fun [S3d H3d F F F] I",									// M3setAnimKey2F
	"fun [S3d H3d H3d I I] I",									// M3applyAnimKey
	"fun [S3d H3d H3d F I] I",									// M3applyAnimKeyF
	"fun [S3d H3d H3d H3d I I I I] I",							// M3applyAnimKey2
	"fun [S3d H3d H3d H3d F F F I] I",							// M3applyAnimKey2F
	"fun [S3d H3d] I",											// M3getAnimLength

	///////////////////////////////////////////////////////////////////////////////////////////////////////////
	/////////////////////////////  Gestion des Bones//////////////////////////////////////////////////////////
	//////////////////////////////////////////////////////////////////////////////////////////////////////////



	"fun [S3d S] H3d",											// M3getBone
	"fun [S3d H3d S] I",										// M3renameBone
	"fun [S3d] I",												// M3getBoneInfo
	"fun [S3d H3d] H3d",										// M3getBoneFather
	"fun [S3d H3d] I",											// M3getBoneNumberOfChildren
	"fun [S3d H3d H3d] I",										// M3ShowSkelet
	"fun [] I",													// M3isShaderVertexProfileEnable
	"fun [] I",									        		// M3isShaderFragmentProfileEnable
	"fun [] I",									        	    // M3isShaderEnable
	"fun [S3d H3d H3d] I",										// M3AttachMeshWithSKL
	"fun [S3d H3d] [H3d r1]",									// M3listSKLFromNode


	// ----------> Gestion des Lumières <----------
	"I","I","I","I",											// LIGHT_AMBIENT	LIGHT_PARA		LIGHT_OMNI		LIGHT_SPOT
	"I","I",													//LIGHT_CLASSIC		LIGHT_SATURATED
	"fun [S3d I] I",											// M3setLightModel
	"fun [S3d] I",												// M3getLightModel
	"fun [S3d I I I I I I] H3d",								// M3createLight
	"fun [S3d H3d] [I I I I I I]",								// M3getLight
	"fun [S3d H3d [I I I I I I]] I",							// M3setLight
	"fun [S3d I I I I I I I] H3d",								// M3createColorLight
	"fun [S3d H3d] [I I I I I I I]",							// M3getColorLight
	"fun [S3d H3d I I I I I I I] I",							// M3setColorLight



	// ----------> Gestion des Sprites <-----------
	"fun [S3d I I HMat3d I] H3d",								// M3createSprite
	"fun [S3d F F HMat3d I] H3d",								// M3createSpriteF
	"fun [S3d H3d I I HMat3d I] I",								// M3setSprite
	"fun [S3d H3d F F HMat3d I] I",								// M3setSpriteF
	"fun [S3d H3d] [I I HMat3d I]",								// M3getSprite
	"fun [S3d H3d] [F F HMat3d I]",								// M3getSpriteF
	"fun [S3d H3d [[I I] r1] [[I I] r1]] I",					// M3setSpriteTexCoord
	"fun [S3d H3d [[F F] r1] [[F F] r1]] I",					// M3setSpriteTexCoordF
	"fun [S3d H3d] [[[I I] r1] [[I I] r1]]",					// M3getSpriteTexCoord
	"fun [S3d H3d] [[[F F] r1] [[F F] r1]]",					// M3getSpriteTexCoordF
	"fun [S3d H3d [I r1] [I r1]] I",							// M3setSpriteVrtColors
	"fun [S3d H3d] [[I r1] [I r1]]",							// M3getSpriteVrtColors
	"fun [S3d H3d I] I",										// M3setSpriteAngle
	"fun [S3d H3d F] I",										// M3setSpriteAngleF
	"fun [S3d H3d] I",											// M3getSpriteAngle
	"fun [S3d H3d] F",											// M3getSpriteAngleF
  "fun [S3d H3d I] I",                    // M3setSpriteClickability
  "fun [S3d H3d] I",                      // M3getSpriteClickability


	// ----------> Opérations diverses <-----------
	"fun [ObjSurface I I I I I I I I I] ObjSurface",			// _SDRAWrectangle
	"fun [ObjSurface I I I I I I I] ObjSurface",				// _SDRAWline
	"fun [ObjSurface I I I I I I I I] ObjSurface",				// _SDRAWcircle
	"fun [ObjSurface ObjFont I I I I S] ObjSurface",			// _SDRAWtext
	"fun [ObjSurface I I I] ObjSurface",						// _SDRAWpoint
	"fun [ObjSurface I tab[I I] I I I I I] ObjSurface",			// _SDRAWpoly
	"fun [[I I I] [I I I] I] [I I I]",							// M3interpVec
	"fun [[F F F] [F F F] F] [F F F]",							// M3interpVecF
	"fun [[I I I] [I I I] I] [I I I]",							// M3interpAng
	"fun [[F F F] [F F F] F] [F F F]",							// M3interpAngF
	"fun [] [S S S S]",											// M3videoInfos
	"fun [] I"													// _isPentium
};



#define GET_X_LPARAM(lp)			((int)(short)LOWORD(lp))
#define GET_Y_LPARAM(lp)			((int)(short)HIWORD(lp))

 

LRESULT CALLBACK GLWndProc (HWND thisWindow, UINT msgType, WPARAM wParam, LPARAM lParam)     
{
	LPARAM	newparam;
	POINT	point;
	HWND	parent;


	if( (parent=GetParent(thisWindow)) == NULL)		return DefWindowProc(thisWindow,msgType,wParam,lParam);

	// Traitement pour chaque type d'évènement
	switch ( msgType )
	{
		//case WM_MOUSEWHEEL:
		case WM_LBUTTONDOWN:
		case WM_RBUTTONDOWN: 
		case WM_MBUTTONDOWN:
		case WM_LBUTTONUP:
		case WM_RBUTTONUP:
		case WM_MBUTTONUP:
		case WM_LBUTTONDBLCLK:
		case WM_RBUTTONDBLCLK:
		case WM_MBUTTONDBLCLK:
		case WM_MOUSEMOVE:
#ifdef _INFO_SCREEN_
			mainMouseX = GET_X_LPARAM(lParam);
			mainMouseY = GET_Y_LPARAM(lParam);
#endif 
			point.x = GET_X_LPARAM(lParam);
			point.y = GET_Y_LPARAM(lParam);
			ClientToScreen(thisWindow, &point);
			ScreenToClient(parent, &point);
			newparam = MAKELONG(point.x, point.y);
			PostMessage(GetParent(thisWindow), msgType, wParam, newparam);
			break;

		case WM_KEYUP: 
//			monClavier[wParam] = false;

		case WM_KEYDOWN:
//			monClavier[wParam] = true;

		case WM_CHAR:
		case WM_CAPTURECHANGED:
		case WM_SETFOCUS:
		case WM_KILLFOCUS:
		case WM_PAINT:
			PostMessage(GetParent(thisWindow),msgType,wParam,lParam);
			break;

		case WM_CREATE:
			SetWindowLong(thisWindow,GWL_USERDATA,lParam);
			return 0;
			break;

		case WM_DESTROY:
			{
				OBJdelTH(mm, typeSurface, (int)thisWindow);
			}
			return 0;
			break;

	}

	return DefWindowProc(thisWindow,msgType,wParam,lParam);
}











///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////																											   ////
///											FONCTIONS D'APPEL DE LA DLL												///
////																											   ////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////



int LoadEngine(mmachine m)
{
	int			k;

	//$BLG - v5.22: Del
	//MMechostr(0,"\n" );
	MMechostr(0,"> Loading Zoo Engine\n" );

	k = PKhardpak(m, "ZooEngine", NbZooPKG, ZooName, ZooFunc, ZooNArg, ZooType);

	// Declaration des types de donnée
	typeSurface = OBJregister(0, 0, ZooDestroySurface, "OBJTYPESURFACE");			// type 'ObjSurface'
    typeSession	= OBJregister(0, 0, ZooDestroySession, "OBJTYPE3D");				// type 'S3d'



	//==== Init des classes de fenêtre OGL ====
	HScol = NULL;
	HScol = (HWND)SCgetExtra("hscol");

	WNDCLASS	glwnd;
	hInstance   = GetModuleHandle(NULL);    // Grab An Instance For Our Window
	glwnd.style			= CS_DBLCLKS;
	glwnd.cbClsExtra	= 0;
	glwnd.cbWndExtra	= 0;
	glwnd.hbrBackground	= 0;
	glwnd.hCursor		= LoadCursor(NULL,IDC_ARROW);
	glwnd.hIcon			= NULL;
	glwnd.hInstance		= hInstance;
	glwnd.lpfnWndProc	= GLWndProc;
	glwnd.lpszClassName	= "scolGL";
	glwnd.lpszMenuName	= NULL;

	RegisterClass(&glwnd);

	//==== Software inits ====
	Zbuffer = (CELL*) malloc( 1600 * sizeof(CELL));


	InitPaletteSOFT();



#ifdef	__OPTI_P3__

	if(testP3())		{	infoP3 = true;		MMechostr(0,"> --> SSE1 supported\n" ); }
	else						{	infoP3 = false;		MMechostr(0,"> --> SSE1 not supported\n" ); }

	if(testP4())		{	infoP4 = true;		MMechostr(0,"> --> SSE2 supported\n" ); }
	else						{	infoP4 = false;		MMechostr(0,"> --> SSE2 not supported\n" ); }

#else

	infoP4 = infoP3 = false;

#endif

	MMechostr(0,"> Zoo Engine successfully loaded\n" );
	//$BLG - v5.22: Del
	//MMechostr(0,"\n" );

	return k;
}



///////////////////////////////////////////////
///		FUNCTIONS for Engine declaring		///
///////////////////////////////////////////////
int		(*MX3registerDevice)(char *clearname,char *id);


///////////////////////////////////////////////
///		FUNCTIONS for Sound Loading			///
///////////////////////////////////////////////
int		SCOLloadSound(mmachine m,cbmachine w);				// Declaration in Sound.cpp
int		SCOLfreeSound();									// Declaration in Sound.cpp


///////////////////////////////////////////////
///		FUNCTION for Particle Loading		///
///////////////////////////////////////////////
int		SCOLloadParticle(mmachine m,cbmachine w);			// Declaration in Particle4.cpp


///////////////////////////////////////////////
///		FUNCTION for Callback3D Loading		///
///////////////////////////////////////////////
int		SCOLloadCB3D(mmachine m,cbmachine w);				// Declaration in Particle4.cpp


///////////////////////////////////////////////
///		FUNCTION for BOX loading			///
///////////////////////////////////////////////
int		SCOLloadBOX(mmachine m);							// Declaration in Particle4.cpp





//
//$LBDEBUG //$LB (24/11/2004)
// this is a hack in order to fix a bug about the process of particles
// <=> choose an algo in fonction of the 3d card vendor
//
int LBDEBUG_VENDOR_ATI = (-1);



///////////////////////////////////////////////////////////////
///		Starting point of the DLL							///
///////////////////////////////////////////////////////////////
extern "C" __declspec (dllexport) int ScolLoadPlugin(mmachine m, cbmachine w)
{
	int		k = 0;
	char	*hwid = NULL;

	for(int ii=0; ii<255; ii++)		monClavier[ii] = false;

	//$BLG - v5.3.01: Add
	int i;
	float angle;
	for (i = 0 ; i < 360; i++)
	{
		angle = (2.0f * 3.1415926535f) * ((float)i / 360.0f);
		tabCos[i] = cos(angle);
		tabSin[i] = sin(angle);
	}				

	ww = w;
	mm = m;

	ww->Buffer2texture = ZBuffer2texture;

	//$BLG - v5.22: Del
	//MMechostr(MSKDEBUG,"SCOLloadZooGL trying loading OpenGL DLL ...\n");

	MX3registerDevice = (int(*)(char *clearname,char *id))SCgetExtra("MX3registerDevice");

	LoadEngine(m);

	userACCEL	= false;

	//$BLG - v5.22: Modif
	//MMechostr(1,"----Création du contexte test------\n") ;
	MMechostr(1,"> Test context creation\n") ;
	CreateWinInfoTest(600, 1000);
	//$BLG - v5.22: Add
	MMechostr(1, "> End of test context destruction\n" );
	
	//$BLG - v5.22: Modif
	//MMechostr(1,"----Initialisation de la 3D------\n") ;
	MMechostr(1,"> 3D initialization\n") ;
	Init3DConfig() ;
	
	//$BLG - v5.22: Modif
	//MMechostr(1,"----Create main context !!!!!------\n") ;
	MMechostr(1,"> Main context creation\n") ;
	mainglrc	= CreateMainContext();
	//$BLG - v5.22: Modif
	//MMechostr(1,"----Create main context !!!!!------\n") ;
	MMechostr(1,"> Main context successfuly created\n");

	//$BLG - v5.22: Del
	//MMechostr (1,"*****************************************************\n*****************************************\n**********Contexte Crée***************************") ;
	
	//$BLG - v5.22: Modif
	//MMechostr(1,"Le format de pixel choisit est : %i \n",mainPIXELFORMAT) ;
	MMechostr(1,"> Chosen pixel format is : %i \n",mainPIXELFORMAT) ;

	
	if(mainglrc && MX3registerDevice)
	{
		MX3registerDevice("OpenGL", "OpenGL");
		// UserACCEL : temporairement mis à true, à cause du fichier 'vgh'
		userACCEL = true;
	}


	hwid = (char*) SCgetExtra("3dhardware");


	// Passe dans le mode sélectionné par le user
	if(hwid!=NULL)
	{
		// mode SOFT
		if(!strcmp(hwid,"Scol Software 3D Engine"))
		{
			userACCEL = false;
			//$BLG - v5.22: Modif
			//MMechostr(MSKDEBUG,"... DLL loaded in SOFTWARE mode\n");
			MMechostr(MSKDEBUG,"> DLL loaded in SOFTWARE mode\n");
			SCOLloadSound(m, w);
			SCOLloadParticle(m, w);
			SCOLloadCB3D(m, w);
			SCOLloadBOX(m);
		}
		// mode OpenGL
		else if(!strcmp(hwid,"OpenGL") && userACCEL)
		{
			userACCEL = true;
			//$BLG - v5.22: Modif
			//MMechostr(MSKDEBUG,"... DLL loaded in HARDWARE mode\n");
			MMechostr(MSKDEBUG,"> DLL loaded in HARDWARE mode\n");
			SCOLloadSound(m, w);
			SCOLloadParticle(m, w);
			SCOLloadCB3D(m, w);
			SCOLloadBOX(m);
		}
		// ID non vide et non reconnu : on passe en SOFT
		else if(strlen(hwid) != 0)
		{
			userACCEL = false;
			//$BLG - v5.22: Modif
			//MMechostr(MSKDEBUG,"... Mode unknown\n");
			MMechostr(MSKDEBUG,"> DLL loaded in UNKNOWN mode\n");
			SCOLloadSound(m, w);
			SCOLloadParticle(m, w);
			SCOLloadCB3D(m, w);
			SCOLloadBOX(m);
		}
		// Pas d'ID du tout (c'est le dernier cas)
		else
		{
			//$BLG - v5.22: Modif
			/*
			if(userACCEL)		MMechostr(MSKDEBUG,"... Automatic ACCELERATED mode\n");
			else				MMechostr(MSKDEBUG,"... Automatic SOFTWARE mode\n");
			*/
			if(userACCEL)		MMechostr(MSKDEBUG, "> DLL loaded in Automatic HARDWARE mode\n");
			else						MMechostr(MSKDEBUG, "> DLL loaded in Automatic SOFTWARE mode\n");
			SCOLloadSound(m, w);
			SCOLloadParticle(m, w);
			SCOLloadCB3D(m, w);
			SCOLloadBOX(m);
		}
	}
	else
	{
		//$BLG - v5.22: Modif
		/*
		if(userACCEL)		MMechostr(MSKDEBUG,"... Automatic ACCELERATED mode\n");
		else				MMechostr(MSKDEBUG,"... Automatic SOFTWARE mode\n");
		*/
		if(userACCEL)		MMechostr(MSKDEBUG, "> DLL loaded in Automatic HARDWARE mode\n");
		else						MMechostr(MSKDEBUG, "> DLL loaded in Automatic SOFTWARE mode\n");
		SCOLloadSound(m, w);
		SCOLloadParticle(m, w);
		SCOLloadCB3D(m, w);
		SCOLloadBOX(m);
	}
 

	//$LBDEBUG //$LB (24/11/2004)
	if (LBDEBUG_VENDOR_ATI < 0)
	{
		int i;
		ZDetector	detect;
		char vendor[256];
		
	  sprintf (&vendor[0], "%s", detect.CheckOpenGLvendor());
	
	  //$BLG - v5.22: Modif
	  //MMechostr(0, "\nVENDOR %s\n", vendor);
	  MMechostr(0, "> 3D Harware Vendor: %s\n", vendor);
	
	  for (i=0; i < strlen (vendor); i++)
		  if ((vendor[i] >= 97) && (vendor[i] <= 122))
			  vendor[i] -= 32;
	
		//$BLG - v5.22: Del
		//MMechostr(0, "\nVENDOR %s\n", vendor);
	
		if (strstr (vendor, "ATI ") != NULL)
		{
			//$BLG - v5.22: Del
			//MMechostr(0, "\n3d Hardware Vendor : ATI\n");
			LBDEBUG_VENDOR_ATI = 1;
		}
		else 
		{
			//$BLG - v5.22: Del
			//MMechostr(0, "\n3d Hardware Vendor : not ATI\n");
			LBDEBUG_VENDOR_ATI = 0;
		}
	}
	///////////////////


	return k;
}





///////////////////////////////////////////////////////////////
///		Ending point of the DLL								///
///////////////////////////////////////////////////////////////
extern "C" __declspec (dllexport) int ScolUnloadPlugin()
{
	MMechostr(MSKDEBUG,"Release OpenGL DLL\n");


#ifdef _INFO_SCREEN_

	if(userACCEL)
	{
		if(mainInfoRC)
		{
			if(wglMakeCurrent(NULL,NULL)==FALSE)		MMechostr(1, "------ Can't set the current rendering context to NULL ! ------\n" );
			if(wglDeleteContext(mainInfoRC)==FALSE)		MMechostr(1, "------ Can't delete the MAIN rendering context ! ------\n" );
		}

		if(mainInfoDC)
		{
			if(ReleaseDC(mainInfoWND, mainInfoDC)==0)	MMechostr(1, "------ Can't release the MAIN device context ! ------\n" );;
		}

		if(mainInfoWND)
		{
			if(DestroyWindow(mainInfoWND)==0)			MMechostr(1, "------ Can't destroy the MAIN window ! ------\n" );;
		}

		if(!UnregisterClass("InfoGL", hInstance))
		{
			MMechostr(1,"----> Could Not Unregister InfoSCREEN Class !\n");
		}
	}

#endif


	MMechostr(1, "\n------ CLOSING ZOOGL DLL..\n" );

	if(mainglrc)
	{
		if(wglMakeCurrent(NULL,NULL)==FALSE)		MMechostr(1, "------ Can't set the current rendering context to NULL ! ------\n" );
		
		if(wglDeleteContext(mainglrc)==FALSE)		MMechostr(1, "------ Can't delete the MAIN rendering context ! ------\n" );
		else										MMechostr(1, "--> mainglrc released : OK\n" );
	}

	if(mainhdc) 
	{
		if(ReleaseDC(mainhwnd, mainhdc)==0)			MMechostr(1, "------ Can't release the MAIN device context ! ------\n" );
		else										MMechostr(1, "--> mainhdc released : OK\n" );
	}

	if(mainhwnd)
	{
		if(DestroyWindow(mainhwnd)==0)				MMechostr(1, "------ Can't destroy the MAIN window ! ------\n" );
		else										MMechostr(1, "--> mainhwnd released : OK\n" );
	}

	mainglrc  = NULL;
	mainhdc   = NULL;
	mainhwnd  = NULL;

	if(!UnregisterClass("scolGL", hInstance))
	{
		MMechostr(1, "----> Could Not Unregister Class !\n");
		hInstance=NULL;         // Set hInstance To NULL
	}
	else
		MMechostr(1, "--> class scolGL unregistred : OK\n" );

	MMechostr(1, "------ ..ZOOGL DLL CLOSED\n\n" );


	SCOLfreeSound();

	return 0;
}


/*
extern "C" __declspec (dllexport) BOOL WINAPI DllMain(HANDLE hinstDLL, DWORD dwReason, LPVOID lpvReserved)
{
	_asm{int 3};
	return TRUE;
}
*/


