#define STRICT

// Includes standard Windows
#include <windows.h>
#include <windowsx.h>
#include <time.h>
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <stdio.h>

#include	<stdarg.h>

// Includes D3D
#define  D3D_OVERLOADS
#include <ddraw.h>
#include <d3d.h>
#include <d3dx.h>

// Includes utilitaires D3D
#include "d3dmath.h"
#include "d3dutil.h"
#include "D3DEnum.h"

// Ids Resources
#include "resource.h"

// Constantes
#include "const.h"

// Types
#include "types.h"

// Variables globales projet
#include "vars.h"

// Prototypes fonctions autres modules
#include "proto.h"

// Macros
#include "macros.h"

// Spécifiques module
#include "libraries/gadtools.h"

// Variables statiques au module
static SCROLLINFO Si;

// Définitions des orientations possibles pour 4 triangles dans 1 carré (A, B, C, D)
typedef int *tridef[3];

static int  A[] = { 0, 0 },
            B[] = { 0, 1 },
            C[] = { 1, 1 },
            D[] = { 1, 0 };

static tridef   iSW[] = { {A, B, C}, {A, C, B} , {B, C, A}, {B, A, C}, {C, A, B}, {C, B, A} },
                iNE[] = { {A, D, C}, {A, C, D} , {D, C, A}, {D, A, C}, {C, A, D}, {C, D, A} },
                iSE[] = { {C, B, D}, {C, D, B} , {B, D, C}, {B, C, D}, {D, C, B}, {D, B, C} },
                iNW[] = { {A, B, D}, {A, D, B} , {B, D, A}, {B, A, D}, {D, A, B}, {D, B, A} };

//////////////////// E C L A I R A G E  G L O B A L //////////////////////////////
BOOL CALLBACK bGlobLightDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	int wmId, nPos;
    static D3DCOLOR cbAmbient, cbBack;
	Si.cbSize = sizeof(Si);

    switch( uMsg )
    {
	case WM_COMMAND :
         wmId    = LOWORD(wParam);

         switch (wmId)
		 {
			case IDRESET:	// Restaurer les valeurs initiales
				// Restaurer les valeurs
				cAmbient = cbAmbient;
				cBack = cbBack;

				// Repositionner les états du pipe D3D
				vSetD3DState();

				// Repositionner les curseurs des sliders
				Si.fMask = SIF_POS;
				Si.nPos = (cAmbient & 0xff0000) >> 16;  SetScrollInfo(GetDlgItem(hWnd, IDC_BA), SB_CTL, &Si, TRUE);
				Si.nPos = (cAmbient & 0x00ff00) >> 8;   SetScrollInfo(GetDlgItem(hWnd, IDC_GA), SB_CTL, &Si, TRUE);
				Si.nPos =  cAmbient & 0x0000ff;         SetScrollInfo(GetDlgItem(hWnd, IDC_RA), SB_CTL, &Si, TRUE);
				Si.nPos = (cBack & 0xff0000) >> 16;     SetScrollInfo(GetDlgItem(hWnd, IDC_BF), SB_CTL, &Si, TRUE);
				Si.nPos = (cBack & 0x00ff00) >> 8;      SetScrollInfo(GetDlgItem(hWnd, IDC_GF), SB_CTL, &Si, TRUE);
				Si.nPos =  cBack & 0x0000ff;            SetScrollInfo(GetDlgItem(hWnd, IDC_RF), SB_CTL, &Si, TRUE);

				vForce3DRefresh(XDC_MODE_COMPLET);
				break;

			case IDCANCEL:	// Restaurer les valeurs initiales et quitter
				// Restaurer les valeurs
				cAmbient = cbAmbient;
				cBack = cbBack;

				vForce3DRefresh(XDC_MODE_COMPLET);

				// ATTENTION pas de break, on continue...

            case IDOK:	// Fin dialogue
				EndDialog(hWnd, 0);
				break;
		 }
		 return TRUE;
		 break;

	 case WM_HSCROLL :	// Scroll slider
		 // Récupérer les valeurs de scroll
		 nPos = wParam;   // scroll box position

		 switch(lParam)
		 {
			 case IDC_BA :
				 cAmbient &= 0xff00ffff;
				 cAmbient |= nPos << 16;
				 // Mettre à jour les variables d'état du pipe D3D
				 vSetD3DState();
				 break;
			 case IDC_GA :
				 cAmbient &= 0xffff00ff;
				 cAmbient |= nPos << 8;
				 // Mettre à jour les variables d'état du pipe D3D
				 vSetD3DState();
				 break;
			 case IDC_RA :
				 cAmbient &= 0xffffff00;
				 cAmbient |= nPos;
				 // Mettre à jour les variables d'état du pipe D3D
				 vSetD3DState();
				 break;
			 case IDC_BF :
				 cBack &= 0xff00ffff;
				 cBack |= nPos << 16;
				 break;
			 case IDC_GF :
				 cBack &= 0xffff00ff;
				 cBack |= nPos << 8;
				 break;
			 case IDC_RF :
				 cBack &= 0xffffff00;
				 cBack |= nPos;
				 break;
		 }

	 	 // Redessiner la 3D
	 	 vSetD3DState();
	 	 vForce3DRefresh(XDC_MODE_COMPLET);

		 return TRUE;
		 break;

	 case WM_INITDIALOG :
		 // Positionner les sliders
		 Si.fMask = SIF_POS | SIF_RANGE;
		 Si.nMin = 0;
		 Si.nMax = 255;

		 Si.nPos = (cAmbient & 0xff0000) >> 16;     SetScrollInfo(GetDlgItem(hWnd, IDC_BA), SB_CTL, &Si, TRUE);
		 Si.nPos = (cAmbient & 0x00ff00) >> 8;      SetScrollInfo(GetDlgItem(hWnd, IDC_GA), SB_CTL, &Si, TRUE);
		 Si.nPos =  cAmbient & 0x0000ff;            SetScrollInfo(GetDlgItem(hWnd, IDC_RA), SB_CTL, &Si, TRUE);
		 Si.nPos = (cBack & 0xff0000) >> 16;        SetScrollInfo(GetDlgItem(hWnd, IDC_BF), SB_CTL, &Si, TRUE);
		 Si.nPos = (cBack & 0x00ff00) >> 8;         SetScrollInfo(GetDlgItem(hWnd, IDC_GF), SB_CTL, &Si, TRUE);
		 Si.nPos =  cBack & 0x0000ff;               SetScrollInfo(GetDlgItem(hWnd, IDC_RF), SB_CTL, &Si, TRUE);

		 // Mémoriser les valeurs initiales
		 cbAmbient = cAmbient;
		 cbBack = cBack;
		 return TRUE;
		 break;
	}

	return FALSE;
}

///////////////////////// S P H E R E /////////////////////////////////////////
BOOL CALLBACK bSphereDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
 	int wmId;
    static int iH = 8, iV = 8, iDlgId;	   // Subdivisions horizontales & verticales
 	char cBuf[12];
    static BOOL b2Params;

 	switch( uMsg )
    {
 	case WM_COMMAND :
        wmId    = LOWORD(wParam);

        switch (wmId)
	    {
 		    case IDCANCEL:
 			    EndDialog(hWnd, -1);
 			    break;

            case IDOK:  // Fin dialogue
 			    SendDlgItemMessage(hWnd, IDC_SH, WM_GETTEXT, sizeof(cBuf) - 1, (LPARAM) cBuf); iH = atoi(cBuf);
 			    if (b2Params) { SendDlgItemMessage(hWnd, IDC_SV, WM_GETTEXT, sizeof(cBuf) - 1, (LPARAM) cBuf); iV = atoi(cBuf); }
 			    if ((iH > 0) && (iV > 0)) // Ajouter la sphère ou l'hémisphère ou le tore
                {
                    switch(iDlgId)
                    {
                        case ID_EDITION_AJOUTER_SPHRE:
                        case ID_EDITION_AJOUTER_HMISPHRE:
                            vAddSphere(Cursor1, (fXmax - fXmin) / 4., iH, iV, (iDlgId == ID_EDITION_AJOUTER_HMISPHRE));
                            break;

                        case ID_EDITION_AJOUTER_TORE:
                            vAddTorus(Cursor1, (fXmax - fXmin) / 4., (fXmax - fXmin) / 6., iH, iV);
                            break;

                        case ID_EDITION_AJOUTER_DISQUE:
                            vAddDisk(Cursor1, (fXmax - fXmin) / 4., iH);
                            break;

                        case ID_EDITION_AJOUTER_CERCLE:
                            vAddCircle(Cursor1, (fXmax - fXmin) / 4., iH);
                            break;

                        case ID_EDITION_AJOUTER_CYLINDRE:
                            vAddCyl(Cursor1, (fXmax - fXmin) / 4., iH);
                            break;

                        case ID_EDITION_AJOUTER_TUBE:
                            vAddTube(Cursor1, (fXmax - fXmin) / 4., iH);
                            break;

                        case ID_EDITION_AJOUTER_CNE:
                            vAddCone(Cursor1, (fXmax - fXmin) / 4., iH);
                            break;

                        case ID_EDITION_GRIDSTEP:
                            fGridSize = iH / 100.f;
                            break;
                    }

    			    // Redessiner la 2D
    			    vForce2DRefresh(XDC_MODE_COMPLET);
    			    // Redessiner la 3D
        		    if (lParam != ID_EDITION_AJOUTER_CERCLE && lParam != ID_EDITION_GRIDSTEP) vForce3DRefresh(XDC_MODE_COMPLET);

 			        EndDialog(hWnd, 0);
                }
 			    else
 			    {
 				    vTrace(GetCatalogStr(hCat, MSG_0336, "*** E0008 : définition impossible (SH : %d, sV : %d)"), iH, iV);
 				    EndDialog(hWnd, -1);
 			    }
 			    break;
	    }
	    return TRUE;
	    break;

	case WM_INITDIALOG :
        iDlgId = lParam;

    	sprintf(cBuf, "%d", iDlgId == ID_EDITION_GRIDSTEP ? (int) (100. * fGridSize) : iH);  SendDlgItemMessage(hWnd, IDC_SH, WM_SETTEXT, 0, (LPARAM) cBuf);
	
        b2Params = (ID_EDITION_AJOUTER_SPHRE
                 || iDlgId == ID_EDITION_AJOUTER_HMISPHRE
                 || iDlgId == ID_EDITION_AJOUTER_TORE);
    	if (b2Params) { sprintf(cBuf, "%d", iV);  SendDlgItemMessage(hWnd, IDC_SV, WM_SETTEXT, 0, (LPARAM) cBuf); }

		return TRUE;
	}

	return FALSE;
}

extern BOOL GetScrollInfo(int iGad, int iDummy, SCROLLINFO *hSi, BOOL bDummy);

////////////////////// M A T E R I A L S ////////////////////////////////////
BOOL CALLBACK bMtrlDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    static int iMtrl;
    int iCnt;
    static gMtrl gMtrlBak;
	char cVal[255];
	float fValue;
    D3DMATERIAL7 *pMtrl;
    char cBuf[80];

	Si.cbSize = sizeof(Si);

	switch( uMsg )
    {
    	case WM_COMMAND :
             switch (LOWORD(wParam))
    		 {
    			// Bouton texturé
    			case IDC_MTEXTURED:
                    if (Materials[iMtrl].bTextured = SendDlgItemMessage(hWnd, IDC_MTEXTURED, BM_GETCHECK, (WPARAM) 0, 0L))
                    {
                        GetScrollInfo(IDC_TEXNUM, 0, &Si, TRUE);
                        strncpy(Materials[iMtrl].sTexName, Textures[Si.nPos].sName, sizeof(Materials[iMtrl].sTexName));
                        vXRefMaterials2Textures();
                    }
            		
                    // Redessiner la 3D
    		        vForce3DRefresh(XDC_MODE_COMPLET);

                    goto __Mtrl_SetSliders;

                case IDS_NOM:
                    SendDlgItemMessage(hWnd, IDS_NOM, WM_GETTEXT, sizeof(cBuf) - 1, (LPARAM) cBuf);
                    strncpy(Materials[iMtrl].sName, cBuf, sizeof(Materials[iMtrl].sName));
                    break;

                case IDC_NEW:
                    iCnt = iMakeMaterial(&(Materials[iMtrl].mtrl), Materials[iMtrl].sName, XDC_FORCENEW);
                    if (iCnt != -1)
                    {
                        if (strlen(Materials[iCnt].sName) < sizeof(Materials[iCnt].sName) - 9) strcat(Materials[iCnt].sName, GetCatalogStr(hCat, MSG_0339, "[copie]"));
                        Materials[iCnt].bTextured = Materials[iMtrl].bTextured;
                        strncpy(Materials[iCnt].sTexName, Materials[iMtrl].sTexName, sizeof(Materials[iCnt].sTexName));

                        vXRefMaterials2Textures();

                        iMtrl = iCnt;
                        goto __Mtrl_SetAll;
                    }
                    else
                        vTrace(GetCatalogStr(hCat, MSG_0340, "*** E0118 : plus de slot Material libre"));
                    break;

                case IDRESET:
                    Materials[iMtrl] = gMtrlBak;
    				vForce3DRefresh(XDC_MODE_COMPLET);
                    goto __Mtrl_SetSliders;

                case IDC_DEL:
                    if (iMtrl < 5) // cf. objects-base, deleteobjects()
                    {
                        vTrace(GetCatalogStr(hCat, MSG_0341, "*** E0119 : suppression d'un des 5 matériaux de base impossible"));
                        break;
                    }

                    // Vérifier si on a des triangles qui utilisent ce lmaterial avant de le détruire
                    for (iCnt = 0 ; iCnt <= iTriaLastUsed && !(Triangles[iCnt].bEnabled && Triangles[iCnt].iMtrl == iMtrl) ; iCnt++) ;
                    if (iCnt <= iTriaLastUsed)
                    {
                        vTrace(GetCatalogStr(hCat, MSG_0342, "*** E0120 : il y a des facettes attachées à ce material"));
                        break;
                    }

                    bDeleteMaterial(iMtrl--);
                    vCollect();
                    goto __Mtrl_SetAll;

    			case IDCANCEL:
                    Materials[iMtrl] = gMtrlBak;
    				vForce3DRefresh(XDC_MODE_COMPLET);
                case IDOK:	// Fin dialogue
    				EndDialog(hWnd, -1);
    				break;
    		 }
    		 return TRUE;
    		 break;

    	 case WM_HSCROLL :	// Scroll slider
    		fValue = (float) wParam / 100.f;
    		pMtrl = &(Materials[iMtrl].mtrl);

    		switch(lParam)
    		{
    			case IDC_D_A:	pMtrl -> diffuse.a = fValue;  sprintf(cVal, "A %03d %%", wParam); SendDlgItemMessage(hWnd, IDV_D_A, WM_SETTEXT, 0, (long)&cVal[0]); break;
    			case IDC_D_R:	pMtrl -> diffuse.r = fValue;  sprintf(cVal, "R %03d %%", wParam); SendDlgItemMessage(hWnd, IDV_D_R, WM_SETTEXT, 0, (long)&cVal[0]); break;
    			case IDC_D_G:	pMtrl -> diffuse.g = fValue;  sprintf(cVal, "G %03d %%", wParam); SendDlgItemMessage(hWnd, IDV_D_G, WM_SETTEXT, 0, (long)&cVal[0]); break;
    			case IDC_D_B:	pMtrl -> diffuse.b = fValue;  sprintf(cVal, "B %03d %%", wParam); SendDlgItemMessage(hWnd, IDV_D_B, WM_SETTEXT, 0, (long)&cVal[0]); break;

    			case IDC_A_A:	pMtrl -> ambient.a = fValue;  sprintf(cVal, "A %03d %%", wParam); SendDlgItemMessage(hWnd, IDV_A_A, WM_SETTEXT, 0, (long)&cVal[0]); break;
    			case IDC_A_R:	pMtrl -> ambient.r = fValue;  sprintf(cVal, "R %03d %%", wParam); SendDlgItemMessage(hWnd, IDV_A_R, WM_SETTEXT, 0, (long)&cVal[0]); break;
    			case IDC_A_G:	pMtrl -> ambient.g = fValue;  sprintf(cVal, "G %03d %%", wParam); SendDlgItemMessage(hWnd, IDV_A_G, WM_SETTEXT, 0, (long)&cVal[0]); break;
    			case IDC_A_B:	pMtrl -> ambient.b = fValue;  sprintf(cVal, "B %03d %%", wParam); SendDlgItemMessage(hWnd, IDV_A_B, WM_SETTEXT, 0, (long)&cVal[0]); break;

    			case IDC_S_A:	pMtrl -> specular.a = fValue; sprintf(cVal, "A %03d %%", wParam); SendDlgItemMessage(hWnd, IDV_S_A, WM_SETTEXT, 0, (long)&cVal[0]); break;
    			case IDC_S_R:	pMtrl -> specular.r = fValue; sprintf(cVal, "R %03d %%", wParam); SendDlgItemMessage(hWnd, IDV_S_R, WM_SETTEXT, 0, (long)&cVal[0]); break;
    			case IDC_S_G:	pMtrl -> specular.g = fValue; sprintf(cVal, "G %03d %%", wParam); SendDlgItemMessage(hWnd, IDV_S_G, WM_SETTEXT, 0, (long)&cVal[0]); break;
    			case IDC_S_B:	pMtrl -> specular.b = fValue; sprintf(cVal, "B %03d %%", wParam); SendDlgItemMessage(hWnd, IDV_S_B, WM_SETTEXT, 0, (long)&cVal[0]); break;
    			case IDC_S_P:	pMtrl -> power = fValue;      sprintf(cVal, "P %03d %%", wParam); SendDlgItemMessage(hWnd, IDV_S_P, WM_SETTEXT, 0, (long)&cVal[0]); break;

    			case IDC_E_A:	pMtrl -> emissive.a = fValue; sprintf(cVal, "A %03d %%", wParam); SendDlgItemMessage(hWnd, IDV_E_A, WM_SETTEXT, 0, (long)&cVal[0]); break;
    			case IDC_E_R:	pMtrl -> emissive.r = fValue; sprintf(cVal, "R %03d %%", wParam); SendDlgItemMessage(hWnd, IDV_E_R, WM_SETTEXT, 0, (long)&cVal[0]); break;
    			case IDC_E_G:	pMtrl -> emissive.g = fValue; sprintf(cVal, "G %03d %%", wParam); SendDlgItemMessage(hWnd, IDV_E_G, WM_SETTEXT, 0, (long)&cVal[0]); break;
    			case IDC_E_B:	pMtrl -> emissive.b = fValue; sprintf(cVal, "B %03d %%", wParam); SendDlgItemMessage(hWnd, IDV_E_B, WM_SETTEXT, 0, (long)&cVal[0]); break;

                case IDC_MATNUM : iMtrl = wParam; goto __Mtrl_SetAll;
                case IDC_TEXNUM :
                    strncpy(Materials[iMtrl].sTexName, Textures[wParam].sName, sizeof(Materials[iMtrl].sTexName));
                    vXRefMaterials2Textures();
            		vForce3DRefresh(XDC_MODE_COMPLET);
                    goto __Mtrl_SetSliders;
   	       }

    		// Redessiner la 3D
    		vForce3DRefresh(XDC_MODE_COMPLET);
    		return TRUE;

    	case WM_INITDIALOG :
__Mtrl_SetAll:
            gMtrlBak = Materials[iMtrl];
            // Positionner le slider n° matériau
    		Si.fMask = SIF_POS | SIF_RANGE;
    		Si.nMin = 0;	          // Mini
    		Si.nMax = iMtrlLastUsed;  // Maxi
    		Si.nPos = iMtrl;
            SetScrollInfo(GetDlgItem(hWnd, IDC_MATNUM), SB_CTL, &Si, TRUE);

__Mtrl_SetSliders:
            sprintf(cVal, "%04d", iMtrl); SendDlgItemMessage(hWnd, IDV_MATNUM, WM_SETTEXT, 0, (LPARAM)&cVal[0]);
    		SendDlgItemMessage(hWnd, IDC_MTEXTURED, BM_SETCHECK, (WPARAM) Materials[iMtrl].bTextured, 0L);
            SendDlgItemMessage(hWnd, IDS_NOM, WM_SETTEXT, 0, (LPARAM) &Materials[iMtrl].sName[0]);
            SendDlgItemMessage(hWnd, IDV_TEXNAME, WM_SETTEXT, 0, (LPARAM) (Materials[iMtrl].bTextured ? &Textures[Materials[iMtrl].iTexture].sName[0] : "--------.---"));

    		// Positionner les sliders couleurs
    		Si.fMask = SIF_POS | SIF_RANGE;
    		Si.nMin = 0;	// Mini
            Si.nMax = iTextLastUsed;
            Si.nPos = Materials[iMtrl].iTexture;
            SetScrollInfo(GetDlgItem(hWnd, IDC_TEXNUM), SB_CTL, &Si, TRUE);
            SendDlgItemMessage(hWnd, IDC_TEXNUM, GA_Disabled, Materials[iMtrl].bTextured, 0);
            SendDlgItemMessage(hWnd, IDV_TEXNAME, GA_Disabled, Materials[iMtrl].bTextured, 0);

            Si.nMax = 100;	// Maxi
    		pMtrl = &(Materials[iMtrl].mtrl);

    		Si.nPos = (int) (100.f * pMtrl -> diffuse.a);  sprintf(cVal, "A %03d %%", Si.nPos); SetScrollInfo(GetDlgItem(hWnd, IDC_D_A), SB_CTL, &Si, TRUE); SendDlgItemMessage(hWnd, IDV_D_A, WM_SETTEXT, 0, (long)&cVal[0]);
    		Si.nPos = (int) (100.f * pMtrl -> diffuse.r);  sprintf(cVal, "R %03d %%", Si.nPos); SetScrollInfo(GetDlgItem(hWnd, IDC_D_R), SB_CTL, &Si, TRUE); SendDlgItemMessage(hWnd, IDV_D_R, WM_SETTEXT, 0, (long)&cVal[0]);
    		Si.nPos = (int) (100.f * pMtrl -> diffuse.g);  sprintf(cVal, "G %03d %%", Si.nPos); SetScrollInfo(GetDlgItem(hWnd, IDC_D_G), SB_CTL, &Si, TRUE); SendDlgItemMessage(hWnd, IDV_D_G, WM_SETTEXT, 0, (long)&cVal[0]);
    		Si.nPos = (int) (100.f * pMtrl -> diffuse.b);  sprintf(cVal, "B %03d %%", Si.nPos); SetScrollInfo(GetDlgItem(hWnd, IDC_D_B), SB_CTL, &Si, TRUE); SendDlgItemMessage(hWnd, IDV_D_B, WM_SETTEXT, 0, (long)&cVal[0]);

    		Si.nPos = (int) (100.f * pMtrl -> ambient.a);  sprintf(cVal, "A %03d %%", Si.nPos); SetScrollInfo(GetDlgItem(hWnd, IDC_A_A), SB_CTL, &Si, TRUE); SendDlgItemMessage(hWnd, IDV_A_A, WM_SETTEXT, 0, (long)&cVal[0]);
    		Si.nPos = (int) (100.f * pMtrl -> ambient.r);  sprintf(cVal, "R %03d %%", Si.nPos); SetScrollInfo(GetDlgItem(hWnd, IDC_A_R), SB_CTL, &Si, TRUE); SendDlgItemMessage(hWnd, IDV_A_R, WM_SETTEXT, 0, (long)&cVal[0]);
    		Si.nPos = (int) (100.f * pMtrl -> ambient.g);  sprintf(cVal, "G %03d %%", Si.nPos); SetScrollInfo(GetDlgItem(hWnd, IDC_A_G), SB_CTL, &Si, TRUE); SendDlgItemMessage(hWnd, IDV_A_G, WM_SETTEXT, 0, (long)&cVal[0]);
    		Si.nPos = (int) (100.f * pMtrl -> ambient.b);  sprintf(cVal, "B %03d %%", Si.nPos); SetScrollInfo(GetDlgItem(hWnd, IDC_A_B), SB_CTL, &Si, TRUE); SendDlgItemMessage(hWnd, IDV_A_B, WM_SETTEXT, 0, (long)&cVal[0]);

    		Si.nPos = (int) (100.f * pMtrl -> specular.a); sprintf(cVal, "A %03d %%", Si.nPos); SetScrollInfo(GetDlgItem(hWnd, IDC_S_A), SB_CTL, &Si, TRUE); SendDlgItemMessage(hWnd, IDV_S_A, WM_SETTEXT, 0, (long)&cVal[0]);
    		Si.nPos = (int) (100.f * pMtrl -> specular.r); sprintf(cVal, "R %03d %%", Si.nPos); SetScrollInfo(GetDlgItem(hWnd, IDC_S_R), SB_CTL, &Si, TRUE); SendDlgItemMessage(hWnd, IDV_S_R, WM_SETTEXT, 0, (long)&cVal[0]);
    		Si.nPos = (int) (100.f * pMtrl -> specular.g); sprintf(cVal, "G %03d %%", Si.nPos); SetScrollInfo(GetDlgItem(hWnd, IDC_S_G), SB_CTL, &Si, TRUE); SendDlgItemMessage(hWnd, IDV_S_G, WM_SETTEXT, 0, (long)&cVal[0]);
    		Si.nPos = (int) (100.f * pMtrl -> specular.b); sprintf(cVal, "B %03d %%", Si.nPos); SetScrollInfo(GetDlgItem(hWnd, IDC_S_B), SB_CTL, &Si, TRUE); SendDlgItemMessage(hWnd, IDV_S_B, WM_SETTEXT, 0, (long)&cVal[0]);
    		Si.nPos = (int) (100.f * pMtrl -> power);      sprintf(cVal, "P %03d %%", Si.nPos); SetScrollInfo(GetDlgItem(hWnd, IDC_S_P), SB_CTL, &Si, TRUE); SendDlgItemMessage(hWnd, IDV_S_P, WM_SETTEXT, 0, (long)&cVal[0]);

    		Si.nPos = (int) (100.f * pMtrl -> emissive.a); sprintf(cVal, "A %03d %%", Si.nPos); SetScrollInfo(GetDlgItem(hWnd, IDC_E_A), SB_CTL, &Si, TRUE); SendDlgItemMessage(hWnd, IDV_E_A, WM_SETTEXT, 0, (long)&cVal[0]);
    		Si.nPos = (int) (100.f * pMtrl -> emissive.r); sprintf(cVal, "R %03d %%", Si.nPos); SetScrollInfo(GetDlgItem(hWnd, IDC_E_R), SB_CTL, &Si, TRUE); SendDlgItemMessage(hWnd, IDV_E_R, WM_SETTEXT, 0, (long)&cVal[0]);
    		Si.nPos = (int) (100.f * pMtrl -> emissive.g); sprintf(cVal, "G %03d %%", Si.nPos); SetScrollInfo(GetDlgItem(hWnd, IDC_E_G), SB_CTL, &Si, TRUE); SendDlgItemMessage(hWnd, IDV_E_G, WM_SETTEXT, 0, (long)&cVal[0]);
    		Si.nPos = (int) (100.f * pMtrl -> emissive.b); sprintf(cVal, "B %03d %%", Si.nPos); SetScrollInfo(GetDlgItem(hWnd, IDC_E_B), SB_CTL, &Si, TRUE); SendDlgItemMessage(hWnd, IDV_E_B, WM_SETTEXT, 0, (long)&cVal[0]);

    		return TRUE;
	}
	return FALSE;
}

////////////////////// L A M P E S ////////////////////////////////////
BOOL CALLBACK bLampDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    static int iLamp;
    static gLamp gLampBak;
    static D3DLIGHT7 *pLamp;
    char cBuf[80];

	Si.cbSize = sizeof(Si);

	switch( uMsg )
    {
    	case WM_COMMAND :
             switch (LOWORD(wParam))
    		 {
                case IDC_LIT:
                    Lampes[iLamp].bLit = SendDlgItemMessage(hWnd, IDC_LIT, BM_GETCHECK,   (WPARAM) 0, 0L);;
                    goto __Lamp_Done;

                case IDC_POINT:
                    pLamp -> dltType = D3DLIGHT_POINT;
                    goto __Lamp_Done;

                case IDC_DIRECT:
                    pLamp -> dltType = D3DLIGHT_DIRECTIONAL;
                    goto __Lamp_Done;

                case IDC_SPOT:
                    pLamp -> dltType = D3DLIGHT_SPOT;
                    goto __Lamp_Done;

                case IDV_D_A:
                    SendDlgItemMessage(hWnd, IDV_D_A, WM_GETTEXT, sizeof(cBuf) - 1, (LPARAM) cBuf); pLamp -> dcvDiffuse.a = atof(cBuf)/255.;
                    goto __Lamp_Done;

                case IDV_D_R:
                    SendDlgItemMessage(hWnd, IDV_D_R, WM_GETTEXT, sizeof(cBuf) - 1, (LPARAM) cBuf); pLamp -> dcvDiffuse.r = atof(cBuf)/255.;
                    goto __Lamp_Done;

                case IDV_D_V:
                    SendDlgItemMessage(hWnd, IDV_D_V, WM_GETTEXT, sizeof(cBuf) - 1, (LPARAM) cBuf); pLamp -> dcvDiffuse.g = atof(cBuf)/255.;
                    goto __Lamp_Done;

                case IDV_D_B:
                    SendDlgItemMessage(hWnd, IDV_D_B, WM_GETTEXT, sizeof(cBuf) - 1, (LPARAM) cBuf); pLamp -> dcvDiffuse.b = atof(cBuf)/255.;
                    goto __Lamp_Done;

                case IDC_A_A:
                    SendDlgItemMessage(hWnd, IDV_A_A, WM_GETTEXT, sizeof(cBuf) - 1, (LPARAM) cBuf); pLamp -> dcvAmbient.a = atof(cBuf)/255.;
                    goto __Lamp_Done;

                case IDV_A_R:
                    SendDlgItemMessage(hWnd, IDV_A_R, WM_GETTEXT, sizeof(cBuf) - 1, (LPARAM) cBuf); pLamp -> dcvAmbient.r = atof(cBuf)/255.;
                    goto __Lamp_Done;

                case IDV_A_V:
                    SendDlgItemMessage(hWnd, IDV_A_V, WM_GETTEXT, sizeof(cBuf) - 1, (LPARAM) cBuf); pLamp -> dcvAmbient.g = atof(cBuf)/255.;
                    goto __Lamp_Done;

                case IDV_A_B:
                    SendDlgItemMessage(hWnd, IDV_A_B, WM_GETTEXT, sizeof(cBuf) - 1, (LPARAM) cBuf); pLamp -> dcvAmbient.b = atof(cBuf)/255.;
                    goto __Lamp_Done;

                case IDC_S_A:
                    SendDlgItemMessage(hWnd, IDV_S_A, WM_GETTEXT, sizeof(cBuf) - 1, (LPARAM) cBuf); pLamp -> dcvSpecular.a = atof(cBuf)/255.;
                    goto __Lamp_Done;

                case IDV_S_R:
                    SendDlgItemMessage(hWnd, IDV_S_R, WM_GETTEXT, sizeof(cBuf) - 1, (LPARAM) cBuf); pLamp -> dcvSpecular.r = atof(cBuf)/255.;
                    goto __Lamp_Done;

                case IDV_S_V:
                    SendDlgItemMessage(hWnd, IDV_S_V, WM_GETTEXT, sizeof(cBuf) - 1, (LPARAM) cBuf); pLamp -> dcvSpecular.g = atof(cBuf)/255.;
                    goto __Lamp_Done;

                case IDV_S_B:
                    SendDlgItemMessage(hWnd, IDV_S_B, WM_GETTEXT, sizeof(cBuf) - 1, (LPARAM) cBuf); pLamp -> dcvSpecular.b = atof(cBuf)/255.;
                    goto __Lamp_Done;

                case IDV_RNG:
                    SendDlgItemMessage(hWnd, IDV_RNG, WM_GETTEXT, sizeof(cBuf) - 1, (LPARAM) cBuf); pLamp -> dvRange = atof(cBuf);
                    goto __Lamp_Done;

                case IDV_FAL:
                    SendDlgItemMessage(hWnd, IDV_FAL, WM_GETTEXT, sizeof(cBuf) - 1, (LPARAM) cBuf); pLamp -> dvFalloff = atof(cBuf);
                    goto __Lamp_Done;

                case IDV_TET:
                    SendDlgItemMessage(hWnd, IDV_TET, WM_GETTEXT, sizeof(cBuf) - 1, (LPARAM) cBuf); pLamp -> dvTheta = atof(cBuf);
                    goto __Lamp_Done;

                case IDV_PHI:
                    SendDlgItemMessage(hWnd, IDV_PHI, WM_GETTEXT, sizeof(cBuf) - 1, (LPARAM) cBuf); pLamp -> dvPhi = atof(cBuf);
                    goto __Lamp_Done;

                case IDV_ATTN0:
                    SendDlgItemMessage(hWnd, IDV_ATTN0, WM_GETTEXT, sizeof(cBuf) - 1, (LPARAM) cBuf); pLamp -> dvAttenuation0 = atof(cBuf);
                    goto __Lamp_Done;

                case IDV_ATTN1:
                    SendDlgItemMessage(hWnd, IDV_ATTN1, WM_GETTEXT, sizeof(cBuf) - 1, (LPARAM) cBuf); pLamp -> dvAttenuation1 = atof(cBuf);
                    goto __Lamp_Done;

                case IDV_ATTN2:
                    SendDlgItemMessage(hWnd, IDV_ATTN2, WM_GETTEXT, sizeof(cBuf) - 1, (LPARAM) cBuf); pLamp -> dvAttenuation2 = atof(cBuf);
                    goto __Lamp_Done;

                case IDRESET:
                    Lampes[iLamp] = gLampBak;
__Lamp_Done:
    				vForce3DRefresh(XDC_MODE_COMPLET);
                    goto __Lamp_SetSliders;

    			case IDCANCEL:
                    Lampes[iLamp] = gLampBak;
    				vForce3DRefresh(XDC_MODE_COMPLET);
                case IDOK:	// Fin dialogue
                    iLampHilit = -1;
                    vForce2DRefresh(XDC_MODE_COMPLET);
                  	EndDialog(hWnd, -1);
    				break;
    		 }
    		 return TRUE;
    		 break;

    	 case WM_HSCROLL :	// Scroll slider
    		pLamp = &(Lampes[iLamp].lLamp);

    		switch(lParam)
    		{
                case IDC_LAMPNUM :
                    iLampHilit = iLamp = wParam;
                    vForce2DRefresh(XDC_MODE_COMPLET);
                    goto __Lamp_SetAll;
            }

    		// Redessiner la 3D
    		vForce3DRefresh(XDC_MODE_COMPLET);
    		return TRUE;

    	case WM_INITDIALOG :
            vCollect();

            iLampHilit = iLamp = 0;
            vForce2DRefresh(XDC_MODE_COMPLET);

__Lamp_SetAll:
            gLampBak = Lampes[iLamp];
            // Positionner le slider n° lampe
    		Si.fMask = SIF_POS | SIF_RANGE;
    		Si.nMin = 0;	          // Mini
    		Si.nMax = iLampLastUsed;  // Maxi
    		Si.nPos = iLamp;
            SetScrollInfo(GetDlgItem(hWnd, IDC_LAMPNUM), SB_CTL, &Si, TRUE);

__Lamp_SetSliders:
            sprintf(cBuf, "%04d", iLamp); SendDlgItemMessage(hWnd, IDV_LAMPNUM, WM_SETTEXT, 0, (LPARAM)&cBuf[0]);

            pLamp = &(Lampes[iLamp].lLamp);
            sprintf(cBuf, "%d", (int) (pLamp -> dcvDiffuse.a * 255));  SendDlgItemMessage(hWnd, IDV_D_A, WM_SETTEXT, 0, (LPARAM)&cBuf[0]);
            sprintf(cBuf, "%d", (int) (pLamp -> dcvDiffuse.r * 255));  SendDlgItemMessage(hWnd, IDV_D_R, WM_SETTEXT, 0, (LPARAM)&cBuf[0]);
            sprintf(cBuf, "%d", (int) (pLamp -> dcvDiffuse.g * 255));  SendDlgItemMessage(hWnd, IDV_D_V, WM_SETTEXT, 0, (LPARAM)&cBuf[0]);
            sprintf(cBuf, "%d", (int) (pLamp -> dcvDiffuse.b * 255));  SendDlgItemMessage(hWnd, IDV_D_B, WM_SETTEXT, 0, (LPARAM)&cBuf[0]);

            sprintf(cBuf, "%d", (int) (pLamp -> dcvAmbient.a * 255));  SendDlgItemMessage(hWnd, IDV_A_A, WM_SETTEXT, 0, (LPARAM)&cBuf[0]);
            sprintf(cBuf, "%d", (int) (pLamp -> dcvAmbient.r * 255));  SendDlgItemMessage(hWnd, IDV_A_R, WM_SETTEXT, 0, (LPARAM)&cBuf[0]);
            sprintf(cBuf, "%d", (int) (pLamp -> dcvAmbient.g * 255));  SendDlgItemMessage(hWnd, IDV_A_V, WM_SETTEXT, 0, (LPARAM)&cBuf[0]);
            sprintf(cBuf, "%d", (int) (pLamp -> dcvAmbient.b * 255));  SendDlgItemMessage(hWnd, IDV_A_B, WM_SETTEXT, 0, (LPARAM)&cBuf[0]);

            sprintf(cBuf, "%d", (int) (pLamp -> dcvSpecular.a * 255)); SendDlgItemMessage(hWnd, IDV_S_A, WM_SETTEXT, 0, (LPARAM)&cBuf[0]);
            sprintf(cBuf, "%d", (int) (pLamp -> dcvSpecular.r * 255)); SendDlgItemMessage(hWnd, IDV_S_R, WM_SETTEXT, 0, (LPARAM)&cBuf[0]);
            sprintf(cBuf, "%d", (int) (pLamp -> dcvSpecular.g * 255)); SendDlgItemMessage(hWnd, IDV_S_V, WM_SETTEXT, 0, (LPARAM)&cBuf[0]);
            sprintf(cBuf, "%d", (int) (pLamp -> dcvSpecular.b * 255)); SendDlgItemMessage(hWnd, IDV_S_B, WM_SETTEXT, 0, (LPARAM)&cBuf[0]);

            sprintf(cBuf, "%-1.0f", pLamp -> dvRange);                   SendDlgItemMessage(hWnd, IDV_RNG, WM_SETTEXT, 0, (LPARAM)&cBuf[0]);
            sprintf(cBuf, "%-1.0f", pLamp -> dvFalloff);                 SendDlgItemMessage(hWnd, IDV_FAL, WM_SETTEXT, 0, (LPARAM)&cBuf[0]);
            sprintf(cBuf, "%-1.0f", pLamp -> dvTheta);                   SendDlgItemMessage(hWnd, IDV_TET, WM_SETTEXT, 0, (LPARAM)&cBuf[0]);
            sprintf(cBuf, "%-1.0f", pLamp -> dvPhi);                     SendDlgItemMessage(hWnd, IDV_PHI, WM_SETTEXT, 0, (LPARAM)&cBuf[0]);

            sprintf(cBuf, "%-1.0f", pLamp -> dvAttenuation0);            SendDlgItemMessage(hWnd, IDV_ATTN0, WM_SETTEXT, 0, (LPARAM)&cBuf[0]);
            sprintf(cBuf, "%-1.0f", pLamp -> dvAttenuation1);            SendDlgItemMessage(hWnd, IDV_ATTN1, WM_SETTEXT, 0, (LPARAM)&cBuf[0]);
            sprintf(cBuf, "%-1.0f", pLamp -> dvAttenuation2);            SendDlgItemMessage(hWnd, IDV_ATTN2, WM_SETTEXT, 0, (LPARAM)&cBuf[0]);

            SendDlgItemMessage(hWnd, IDC_POINT, BM_SETCHECK,  (WPARAM) (pLamp -> dltType == D3DLIGHT_POINT), 0L);
            SendDlgItemMessage(hWnd, IDC_DIRECT, BM_SETCHECK, (WPARAM) (pLamp -> dltType == D3DLIGHT_DIRECTIONAL), 0L);
            SendDlgItemMessage(hWnd, IDC_SPOT, BM_SETCHECK,   (WPARAM) (pLamp -> dltType == D3DLIGHT_SPOT), 0L);

            SendDlgItemMessage(hWnd, IDC_LIT, BM_SETCHECK,   (WPARAM) Lampes[iLamp].bLit, 0L);
    		return TRUE;
	}
	return FALSE;
}

////////////////////// F A C E S ////////////////////////////////////////////
BOOL CALLBACK bFaceDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    static int iMtrl, iTriangle, iTexture, iNext, iDef;
	char cVal[255];
	float fValue;
    D3DMATERIAL7 *pMtrl;

	Si.cbSize = sizeof(Si);

    // Remettre à jour les n° matériau et texture
    iMtrl = Triangles[iTriangle].iMtrl;
    iTexture = Materials[iMtrl].iTexture;

	switch( uMsg )
    {
    	case WM_COMMAND :
             switch (LOWORD(wParam))
    		 {
                case IDC_REPLICATE:    // Dupliquer le réglage matériau sur toutes les facettes
                case IDC_REPLICATE_UV: // Dupliquer le réglage matériau ET UV sur toutes les facettes
                    for (iNext = 0 ; iNext <= iTriaLastUsed ; iNext++)
                        if (Triangles[iNext].bEnabled && bIsTriangleSelected(iNext) && iNext != iTriangle)
                        {
                            Triangles[iNext].iMtrl = iMtrl;
                            if (LOWORD(wParam) == IDC_REPLICATE_UV)
                            {
                                Triangles[iNext].u[0] = Triangles[iTriangle].u[0];
                                Triangles[iNext].u[1] = Triangles[iTriangle].u[1];
                                Triangles[iNext].u[2] = Triangles[iTriangle].u[2];
                                Triangles[iNext].v[0] = Triangles[iTriangle].v[0];
                                Triangles[iNext].v[1] = Triangles[iTriangle].v[1];
                                Triangles[iNext].v[2] = Triangles[iTriangle].v[2];
                            }
                        }

            		vForce3DRefresh(XDC_MODE_COMPLET);
                    break;

    			case IDC_PREV:  // Facette précédente
__Face_Prev:
                    for (iNext = iTriangle - 1 ; iNext >= 0 && !(Triangles[iNext].bEnabled && bIsTriangleSelected(iNext)); iNext--) ;
                    if (!(Triangles[iNext].bEnabled && bIsTriangleSelected(iNext))) { iTriangle = iTriaLastUsed + 1 ; goto __Face_Prev; }
                    goto __Face_Found;

                case IDC_NEXT:  // Facette suivante
__Face_Next:
                    for (iNext = iTriangle + 1 ; iNext <= iTriaLastUsed && !(Triangles[iNext].bEnabled && bIsTriangleSelected(iNext)); iNext++) ;
                    if (!(Triangles[iNext].bEnabled && bIsTriangleSelected(iNext))) { iTriangle = -1 ; goto __Face_Next; }

__Face_Found:
                    // Mémoriser le n° de cette facette
                    iTriangle = iNext;

                    // Rafraîchir la vue 3D en highlightant la facette
                    iTriaHilit = iTriangle;
            		vForce3DRefresh(XDC_MODE_COMPLET);
                    iTriaHilit = -1;

                    // Mettre à jour tous les gadgets
                    goto __Face_ResetAll;

    			case IDCANCEL:
                case IDOK:	// Fin dialogue
                    // Resetter les vues 2D et 3D pour supprimer le highlight de la facette courant
            		vForce2DRefresh(XDC_MODE_COMPLET);
            		vForce3DRefresh(XDC_MODE_COMPLET);

                    // Fin dialogue
                    EndDialog(hWnd, -1);
    				break;

                case IDC_NE:                // Affecter U/V sur le triangle NE suivant
                    Triangles[iTriangle].u[0] = iNE[iDef][0][0] * (Textures[iTexture].iWidth - 1);
                    Triangles[iTriangle].u[1] = iNE[iDef][1][0] * (Textures[iTexture].iWidth - 1);
                    Triangles[iTriangle].u[2] = iNE[iDef][2][0] * (Textures[iTexture].iWidth - 1);
                    Triangles[iTriangle].v[0] = iNE[iDef][0][1] * (Textures[iTexture].iHeight - 1);
                    Triangles[iTriangle].v[1] = iNE[iDef][1][1] * (Textures[iTexture].iHeight - 1);
                    Triangles[iTriangle].v[2] = iNE[iDef][2][1] * (Textures[iTexture].iHeight - 1);
                    goto __Face_NSEW;
                case IDC_SE:                // Affecter U/V sur le triangle SE suivant
                    Triangles[iTriangle].u[0] = iSE[iDef][0][0] * (Textures[iTexture].iWidth - 1);
                    Triangles[iTriangle].u[1] = iSE[iDef][1][0] * (Textures[iTexture].iWidth - 1);
                    Triangles[iTriangle].u[2] = iSE[iDef][2][0] * (Textures[iTexture].iWidth - 1);
                    Triangles[iTriangle].v[0] = iSE[iDef][0][1] * (Textures[iTexture].iHeight - 1);
                    Triangles[iTriangle].v[1] = iSE[iDef][1][1] * (Textures[iTexture].iHeight - 1);
                    Triangles[iTriangle].v[2] = iSE[iDef][2][1] * (Textures[iTexture].iHeight - 1);
                    goto __Face_NSEW;
                case IDC_NW:                // Affecter U/V sur le triangle NW suivant
                    Triangles[iTriangle].u[0] = iNW[iDef][0][0] * (Textures[iTexture].iWidth - 1);
                    Triangles[iTriangle].u[1] = iNW[iDef][1][0] * (Textures[iTexture].iWidth - 1);
                    Triangles[iTriangle].u[2] = iNW[iDef][2][0] * (Textures[iTexture].iWidth - 1);
                    Triangles[iTriangle].v[0] = iNW[iDef][0][1] * (Textures[iTexture].iHeight - 1);
                    Triangles[iTriangle].v[1] = iNW[iDef][1][1] * (Textures[iTexture].iHeight - 1);
                    Triangles[iTriangle].v[2] = iNW[iDef][2][1] * (Textures[iTexture].iHeight - 1);
                    goto __Face_NSEW;
                case IDC_SW:                // Affecter U/V sur le triangle SW suivant
                    Triangles[iTriangle].u[0] = iSW[iDef][0][0] * (Textures[iTexture].iWidth - 1);
                    Triangles[iTriangle].u[1] = iSW[iDef][1][0] * (Textures[iTexture].iWidth - 1);
                    Triangles[iTriangle].u[2] = iSW[iDef][2][0] * (Textures[iTexture].iWidth - 1);
                    Triangles[iTriangle].v[0] = iSW[iDef][0][1] * (Textures[iTexture].iHeight - 1);
                    Triangles[iTriangle].v[1] = iSW[iDef][1][1] * (Textures[iTexture].iHeight - 1);
                    Triangles[iTriangle].v[2] = iSW[iDef][2][1] * (Textures[iTexture].iHeight - 1);
__Face_NSEW:
                    // Incrémenter le compteur courant
                    iDef = (++iDef) % 6;

                    // Positionner les sliders U
                    Si.nMax = Textures[iTexture].iWidth - 1;
                    Si.nPos = Triangles[iTriangle].u[0]; SetScrollInfo(GetDlgItem(hWnd, IDC_U0), SB_CTL, &Si, TRUE);
                    Si.nPos = Triangles[iTriangle].u[1]; SetScrollInfo(GetDlgItem(hWnd, IDC_U1), SB_CTL, &Si, TRUE);
                    Si.nPos = Triangles[iTriangle].u[2]; SetScrollInfo(GetDlgItem(hWnd, IDC_U2), SB_CTL, &Si, TRUE);

                    // Positionner les sliders V
                    Si.nMax = Textures[iTexture].iHeight - 1;
                    Si.nPos = Triangles[iTriangle].v[0]; SetScrollInfo(GetDlgItem(hWnd, IDC_V0), SB_CTL, &Si, TRUE);
                    Si.nPos = Triangles[iTriangle].v[1]; SetScrollInfo(GetDlgItem(hWnd, IDC_V1), SB_CTL, &Si, TRUE);
                    Si.nPos = Triangles[iTriangle].v[2]; SetScrollInfo(GetDlgItem(hWnd, IDC_V2), SB_CTL, &Si, TRUE);

                    // Forcer un rafraîchissement de la vue 3D et des sliders U/V
                    goto __Face_SliderDone;
   		     }

    		 // Pour EndDialog() des IDOK et IDCANCEL...
             return TRUE;
    		 break;

    	 case WM_HSCROLL :	// Scroll slider
    		fValue = (float) wParam / 100.f;
    		pMtrl = &(Materials[iMtrl].mtrl);

    		switch(lParam)
    		{
                case IDC_MATNUM :   // Slider N° matériau
                    // Mémoriser les nouveaux indices matériau & texture du triangle
                    Triangles[iTriangle].iMtrl = iMtrl = wParam;
                    iTexture = Materials[iMtrl].iTexture;

                    // Forcer un rafraîchissement de la vue 3D et des sliders
                    iTriaHilit = iTriangle;
            		vForce3DRefresh(XDC_MODE_COMPLET);
                    iTriaHilit = -1;
                    goto __Face_SetSliders;

                // Sliders U/V : mémoriser u/v dans le triangle, forcer refresh vue 3D et valeurs U/V
                case IDC_U0: Triangles[iTriangle].u[0] = wParam; goto __Face_SliderDone;
                case IDC_U1: Triangles[iTriangle].u[1] = wParam; goto __Face_SliderDone;
                case IDC_U2: Triangles[iTriangle].u[2] = wParam; goto __Face_SliderDone;
                case IDC_V0: Triangles[iTriangle].v[0] = wParam; goto __Face_SliderDone;
                case IDC_V1: Triangles[iTriangle].v[1] = wParam; goto __Face_SliderDone;
                case IDC_V2: Triangles[iTriangle].v[2] = wParam;
__Face_SliderDone:
                    iTriaHilit = iTriangle;
            		vForce3DRefresh(XDC_MODE_COMPLET);
                    iTriaHilit = -1;
                    goto __Face_SetUV;
	        }
    		return TRUE;

    	case WM_INITDIALOG :
            // Trouver le premier triangle sélectionné
            for (iTriangle = 0 ; iTriangle <= iTriaLastUsed && !(Triangles[iTriangle].bEnabled && bIsTriangleSelected(iTriangle)); iTriangle++) ;

            if (!(Triangles[iTriangle].bEnabled && bIsTriangleSelected(iTriangle)))
            {
                vTrace(GetCatalogStr(hCat, MSG_0399, "*** E0098 : aucune facette sélectionnée"));
                EndDialog(hWnd, -1);
                return FALSE;
            }

            // Rafraîchir la vue 3D en highlightant la facette
            iTriaHilit = iTriangle;
    		vForce3DRefresh(XDC_MODE_COMPLET);
            iTriaHilit = -1;

__Face_ResetAll:
            // Mémoriser les indices courants de matériau et texture
            iMtrl = Triangles[iTriangle].iMtrl;
            iTexture = Materials[iMtrl].iTexture;

            // Highlighter le triangle courant dans les vues 2D
            iTriaHilit = iTriangle;
            vForce2DRefresh(XDC_MODE_COMPLET);
            iTriaHilit = -1;

            // Positionner le slider n° matériau
    		Si.fMask = SIF_POS | SIF_RANGE;
    		Si.nMin = 0;	          // Mini
    		Si.nMax = iMtrlLastUsed;  // Maxi
    		Si.nPos = iMtrl;
            SetScrollInfo(GetDlgItem(hWnd, IDC_MATNUM), SB_CTL, &Si, TRUE);

            // Positionner les sliders U
            Si.nMax = Textures[iTexture].iWidth - 1;
            Si.nPos = Triangles[iTriangle].u[0]; SetScrollInfo(GetDlgItem(hWnd, IDC_U0), SB_CTL, &Si, TRUE);
            Si.nPos = Triangles[iTriangle].u[1]; SetScrollInfo(GetDlgItem(hWnd, IDC_U1), SB_CTL, &Si, TRUE);
            Si.nPos = Triangles[iTriangle].u[2]; SetScrollInfo(GetDlgItem(hWnd, IDC_U2), SB_CTL, &Si, TRUE);

            // Positionner les sliders V
            Si.nMax = Textures[iTexture].iHeight - 1;
            Si.nPos = Triangles[iTriangle].v[0]; SetScrollInfo(GetDlgItem(hWnd, IDC_V0), SB_CTL, &Si, TRUE);
            Si.nPos = Triangles[iTriangle].v[1]; SetScrollInfo(GetDlgItem(hWnd, IDC_V1), SB_CTL, &Si, TRUE);
            Si.nPos = Triangles[iTriangle].v[2]; SetScrollInfo(GetDlgItem(hWnd, IDC_V2), SB_CTL, &Si, TRUE);

__Face_SetSliders:
            // Indiquer le nom du matériau et de la texture courants
            SendDlgItemMessage(hWnd, IDV_MATNUM, WM_SETTEXT, 0, (LPARAM) &Materials[iMtrl].sName[0]);
            SendDlgItemMessage(hWnd, IDV_TEXNUM, WM_SETTEXT, 0, (LPARAM) (Materials[iMtrl].bTextured ? &Textures[Materials[iMtrl].iTexture].sName[0] : GetCatalogStr(hCat, MSG_0400, "(non texturé)")));

            // Si le matériau est texturé, afficher la texture sinon rectfill avec la couleur diffuse du matériau
            if (Materials[iMtrl].bTextured)
               WritePixelArray( Textures[iTexture].hTexMap, 0, 0, 4 * Textures[iTexture].iWidth,
                                hWnd -> RPort,
                                56, 320 - Textures[iTexture].iHeight, Textures[iTexture].iWidth, Textures[iTexture].iHeight,
                                RECTFMT_ARGB
                              );
            else
                FillPixelArray( hWnd -> RPort,
                                56, 320 - Textures[iTexture].iHeight, Textures[iTexture].iWidth, Textures[iTexture].iHeight,
                                (((ULONG) (Materials[iMtrl].mtrl.diffuse.a * 255.)) & 0xFF) << 24 |
                                (((ULONG) (Materials[iMtrl].mtrl.diffuse.r * 255.)) & 0xFF) << 16 |
                                (((ULONG) (Materials[iMtrl].mtrl.diffuse.g * 255.)) & 0xFF) << 8  |
                                (((ULONG) (Materials[iMtrl].mtrl.diffuse.b * 255.)) & 0xFF)
                              );

__Face_SetUV:
            // Mettre à jour les valeurs U/V
            sprintf(cVal, "%04d", Triangles[iTriangle].u[0]); SendDlgItemMessage(hWnd, IDV_U0, WM_SETTEXT, 0, (LPARAM)&cVal[0]);
            sprintf(cVal, "%04d", Triangles[iTriangle].u[1]); SendDlgItemMessage(hWnd, IDV_U1, WM_SETTEXT, 0, (LPARAM)&cVal[0]);
            sprintf(cVal, "%04d", Triangles[iTriangle].u[2]); SendDlgItemMessage(hWnd, IDV_U2, WM_SETTEXT, 0, (LPARAM)&cVal[0]);
            sprintf(cVal, "%04d", Triangles[iTriangle].v[0]); SendDlgItemMessage(hWnd, IDV_V0, WM_SETTEXT, 0, (LPARAM)&cVal[0]);
            sprintf(cVal, "%04d", Triangles[iTriangle].v[1]); SendDlgItemMessage(hWnd, IDV_V1, WM_SETTEXT, 0, (LPARAM)&cVal[0]);
            sprintf(cVal, "%04d", Triangles[iTriangle].v[2]); SendDlgItemMessage(hWnd, IDV_V2, WM_SETTEXT, 0, (LPARAM)&cVal[0]);

    		return TRUE;
	}
	return FALSE;
}

////////////////////// E X P A N S E R  /  R E D U I R E  ////////////////////////////////////////////
BOOL CALLBACK bExpandDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	int wmId, nPos, iCnt;
	static D3DVECTOR dVect;
	char cVal[5];
	static int iExpandLock;
	float fExpandFactor;

	Si.cbSize = sizeof(Si);

    switch( uMsg )
    {
	case WM_COMMAND :
         wmId    = LOWORD(wParam);

         switch (wmId)
		 {
			case IDAPPLY:
				goto __Expand_Init;

			case IDCANCEL:	// Quitter
			case IDRESET:
				for (iCnt = 0 ; iCnt <= iVertLastUsed ; iCnt++)
					if (bIsVertexSelected(iCnt))
						Vertices[iCnt].vPoint = Vertices[iCnt].vPointBack;
				vForce2DRefresh(XDC_MODE_COMPLET);
				vForce3DRefresh(XDC_MODE_COMPLET);
				if (wmId == IDRESET) goto __Expand_InitSliders;

            case IDOK:	// Appliquer les modifs
				EndDialog(hWnd, 0);
				break;

			case IDC_LOCK:
				iExpandLock = SendDlgItemMessage(hWnd, IDC_LOCK, BM_GETCHECK, (WPARAM) 0, 0L);
				break;
		 }
		 return TRUE;

	 case WM_HSCROLL :	// Scroll slider
		 // Récupérer les valeurs de scroll
		 nPos = wParam;   // scroll value

		 sprintf(cVal, "%d%%", nPos);
		 fExpandFactor = (float) nPos / 100.f;
		 Si.fMask = SIF_POS;
		 Si.nPos = nPos;

		 if (iExpandLock)
		 {
			for (iCnt = 0 ; iCnt <= iVertLastUsed ; iCnt++)
				if (bIsVertexSelected(iCnt))
				{
					Vertices[iCnt].vPoint.x = dVect.x + (Vertices[iCnt].vPointBack.x - dVect.x) * fExpandFactor;
					Vertices[iCnt].vPoint.y = dVect.y + (Vertices[iCnt].vPointBack.y - dVect.y) * fExpandFactor;
					Vertices[iCnt].vPoint.z = dVect.z + (Vertices[iCnt].vPointBack.z - dVect.z) * fExpandFactor;
				}

			SendDlgItemMessage(hWnd, IDC_EXV, WM_SETTEXT, 0, (long)&cVal[0]);
			SendDlgItemMessage(hWnd, IDC_EYV, WM_SETTEXT, 0, (long)&cVal[0]);
			SendDlgItemMessage(hWnd, IDC_EZV, WM_SETTEXT, 0, (long)&cVal[0]);

		    switch(GetDlgCtrlID(lParam))
		    {
			    case IDC_EX :
        			SetScrollInfo(GetDlgItem(hWnd, IDC_EY), SB_CTL, &Si, TRUE);
        			SetScrollInfo(GetDlgItem(hWnd, IDC_EZ), SB_CTL, &Si, TRUE);
    			    break;

			    case IDC_EY :
        			SetScrollInfo(GetDlgItem(hWnd, IDC_EX), SB_CTL, &Si, TRUE);
        			SetScrollInfo(GetDlgItem(hWnd, IDC_EZ), SB_CTL, &Si, TRUE);
	    		    break;
			   
                case IDC_EZ :
        			SetScrollInfo(GetDlgItem(hWnd, IDC_EX), SB_CTL, &Si, TRUE);
        			SetScrollInfo(GetDlgItem(hWnd, IDC_EY), SB_CTL, &Si, TRUE);
		    	    break;
		    }
		 }
		 else
		 {
			 switch(GetDlgCtrlID(lParam))
			 {
				 case IDC_EX :
					SendDlgItemMessage(hWnd, IDC_EXV, WM_SETTEXT, 0, (long)&cVal[0]);
					for (iCnt = 0 ; iCnt <= iVertLastUsed ; iCnt++)
						if (bIsVertexSelected(iCnt))
							Vertices[iCnt].vPoint.x = dVect.x + (Vertices[iCnt].vPointBack.x - dVect.x) * fExpandFactor;
					 break;
				 case IDC_EY :
					SendDlgItemMessage(hWnd, IDC_EYV, WM_SETTEXT, 0, (long)&cVal[0]);
					for (iCnt = 0 ; iCnt <= iVertLastUsed ; iCnt++)
						if (bIsVertexSelected(iCnt))
							Vertices[iCnt].vPoint.y = dVect.y + (Vertices[iCnt].vPointBack.y - dVect.y) * fExpandFactor;
					 break;
				 case IDC_EZ :
					SendDlgItemMessage(hWnd, IDC_EZV, WM_SETTEXT, 0, (long)&cVal[0]);
					for (iCnt = 0 ; iCnt <= iVertLastUsed ; iCnt++)
						if (bIsVertexSelected(iCnt))
							Vertices[iCnt].vPoint.z = dVect.z + (Vertices[iCnt].vPointBack.z - dVect.z) * fExpandFactor;
					 break;
			 }
		 }

 		 // Redessiner 2D & 3D
 		 vForce2DRefresh(XDC_MODE_COMPLET);
 		 vForce3DRefresh(XDC_MODE_COMPLET);
		 return TRUE;

	case WM_INITDIALOG :
		SendDlgItemMessage(hWnd, IDC_LOCK, BM_SETCHECK, (WPARAM) iExpandLock, 0L);

__Expand_Init:
		// Déterminer le barycentre de la sélection (on travaille par rapport à lui)
		dVect = vCenter();

__Expand_InitSliders:
		// Positionner les sliders
		Si.fMask = SIF_POS | SIF_RANGE;
		Si.nMin = 0;	// Mini
		Si.nMax = 200;	// Maxi
		Si.nPos = 100;	// Position initiale
		sprintf(cVal, "%d%%", Si.nPos);

		SetScrollInfo(GetDlgItem(hWnd, IDC_EX), SB_CTL, &Si, TRUE); SendDlgItemMessage(hWnd, IDC_EXV, WM_SETTEXT, 0, (long)&cVal[0]);
		SetScrollInfo(GetDlgItem(hWnd, IDC_EY), SB_CTL, &Si, TRUE); SendDlgItemMessage(hWnd, IDC_EYV, WM_SETTEXT, 0, (long)&cVal[0]);
		SetScrollInfo(GetDlgItem(hWnd, IDC_EZ), SB_CTL, &Si, TRUE); SendDlgItemMessage(hWnd, IDC_EZV, WM_SETTEXT, 0, (long)&cVal[0]);

		return TRUE;
	}
	return FALSE;
}

////////////////////// H E L I C E ////////////////////////////////////////////
BOOL CALLBACK bHelixDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	int wmId;
	static int iRot, iTrans, iDP = 18, iAP = 6, iP = 20;	  // Degrés par pas, avance par pas, nombre de pas
	static BOOL bLierClones = TRUE;
	char cBuf[12];
	D3DVECTOR vShift = D3DVECTOR(0.f, 0.f, 0.f);;
	D3DMATRIX mRot;
	float fAngle;

	switch( uMsg )
    {
	case WM_COMMAND :
         wmId    = LOWORD(wParam);

         switch (wmId)
		 {
			// Bouton lier clones
			case IDC_LCL:
			    bLierClones = SendDlgItemMessage(hWnd, IDC_LCL, BM_GETCHECK, (WPARAM) 0, 0L);
				break;

			// Boutons sélection rotation autour axe X/Y/Z... (kwikandirti)
			case IDC_RX:
			case IDC_RY:
			case IDC_RZ:
				iRot = wmId;
#ifdef _AMIGA_  // Gérer l'exclusion mutuelle a la mano
        	    SendDlgItemMessage(hWnd, IDC_RX, BM_SETCHECK, (WPARAM) (iRot == IDC_RX), 0L);
        	    SendDlgItemMessage(hWnd, IDC_RY, BM_SETCHECK, (WPARAM) (iRot == IDC_RY), 0L);
        	    SendDlgItemMessage(hWnd, IDC_RZ, BM_SETCHECK, (WPARAM) (iRot == IDC_RZ), 0L);
#endif
				break;

			// Boutons sélection translation autour axe X/Y/Z... (kwikandirti)
			case IDC_TX:
			case IDC_TY:
			case IDC_TZ:
				iTrans = wmId;
#ifdef _AMIGA_  // Gérer l'exclusion mutuelle a la mano
        	    SendDlgItemMessage(hWnd, IDC_TX, BM_SETCHECK, (WPARAM) (iTrans == IDC_TX), 0L);
        	    SendDlgItemMessage(hWnd, IDC_TY, BM_SETCHECK, (WPARAM) (iTrans == IDC_TY), 0L);
        	    SendDlgItemMessage(hWnd, IDC_TZ, BM_SETCHECK, (WPARAM) (iTrans == IDC_TZ), 0L);
#endif
				break;

			// Annuler
			case IDCANCEL:
			    EndDialog(hWnd, -1);
				break;

            // Appliquer la transformation
			case IDOK:
				// Récupérer l'angle par pas, l'avance par pas, le nombre de pas
			    SendDlgItemMessage(hWnd, IDC_DP, WM_GETTEXT, sizeof(cBuf) - 1, (LPARAM) cBuf); iDP = atoi(cBuf);
			    SendDlgItemMessage(hWnd, IDC_AP, WM_GETTEXT, sizeof(cBuf) - 1, (LPARAM) cBuf); iAP = atoi(cBuf);
			    SendDlgItemMessage(hWnd, IDC_P, WM_GETTEXT, sizeof(cBuf) - 1, (LPARAM) cBuf); iP = atoi(cBuf);

				// Moduler l'angle @360°
				iDP = iDP % 360;

				// Calculer l'angle en radians
				fAngle = g_2_PI * (float) iDP / 360.f;

				// Si moins de 1 pas stop
			    if (iP < 1) EndDialog(hWnd, -1);

				// Calculer la matrice de rotation en fonction de l'axe et de l'angle choisis
				switch(iRot)
				{
					case IDC_RY : D3DUtil_SetRotateYMatrix(mRot, -fAngle); break;
					case IDC_RZ : D3DUtil_SetRotateZMatrix(mRot, fAngle);  break;
					case IDC_RX : D3DUtil_SetRotateXMatrix(mRot, -fAngle); break;
				}

				// Calculer le vecteur d'avance en fonction de l'axe et de l'avance
				switch(iTrans)
				{
					case IDC_TY : vShift.y += ((float) iAP / 10.f); break;
					case IDC_TZ : vShift.z += ((float) iAP / 10.f); break;
					case IDC_TX : vShift.x += ((float) iAP / 10.f); break;
				}

				// Pour chaque pas...
				for (int iPas = 0 ; iPas < iP ; iPas ++)
				{
					// Préparer un clone de la sélection, qui se retrouve sélectionné (en désélectionnant le reste)
					bCloneSelection(vShift, bLierClones ? XDC_MODE_EXTRUDE : XDC_MODE_CLONE);

					// Appliquer la matrice aux sommets sélectionnés
					for (int iVert = 0 ; iVert <= iVertLastUsed ; iVert++)
						if (bIsVertexSelected(iVert))
						{
							// Changer de repère => Cursor1
							D3DVECTOR vTrans = Vertices[iVert].vPoint - Cursor1;

							// Appliquer la rotation au point translaté
							D3DMath_VectorMatrixMultiply(vTrans,
														 vTrans,
														 mRot);

							// Remettre dans le repère d'origine
							Vertices[iVert].vPoint = vTrans + Cursor1;
						}
				}

				// Redessiner la 2D
				vForce2DRefresh(XDC_MODE_COMPLET);
				// Redessiner la 3D
				vForce3DRefresh(XDC_MODE_COMPLET);

			    EndDialog(hWnd, 0);
				break;
		 }
		 return TRUE;

	 case WM_INITDIALOG :
		switch(lWActive)
		{
			case XDC_WID_TOP : // X et Z
				iRot = IDC_RY;
				iTrans = IDC_TY;
				break;

			case XDC_WID_FACE : // X et Y
				iRot = IDC_RZ;
				iTrans = IDC_TZ;
				break;

			case XDC_WID_SIDE : // Z et Y
				iRot = IDC_RX;
				iTrans = IDC_TX;
				break;
		}

	    SendDlgItemMessage(hWnd, IDC_LCL, BM_SETCHECK, (WPARAM) bLierClones, 0L);
	    SendDlgItemMessage(hWnd, iRot, BM_SETCHECK, (WPARAM) 1, 0L);
	    SendDlgItemMessage(hWnd, iTrans, BM_SETCHECK, (WPARAM) 1, 0L);

	    sprintf(cBuf, "%d", iDP);  SendDlgItemMessage(hWnd, IDC_DP, WM_SETTEXT, 0, (LPARAM) cBuf);
	    sprintf(cBuf, "%d", iAP);  SendDlgItemMessage(hWnd, IDC_AP, WM_SETTEXT, 0, (LPARAM) cBuf);
	    sprintf(cBuf, "%d", iP);   SendDlgItemMessage(hWnd, IDC_P, WM_SETTEXT, 0, (LPARAM) cBuf);
		return TRUE;
	}
	return FALSE;
}

////////////////////// T R O U S   R E M P L I S S A G E  ////////////////////////////////////////////
BOOL CALLBACK bHoleDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	int wmId;
	char cBuf[12];

	switch( uMsg )
    {
		case WM_COMMAND :
			 wmId    = LOWORD(wParam);

			 switch (wmId)
			 {
				case IDC_FADE:
					bFillAndRemoveEdges = (bFillAndRemoveEdges ? FALSE : TRUE);
					goto _HUpdate;
					break;

				case IDRESET:
					iHoles = 0;
					goto _HUpdate;
					break;

				case IDOK:	// Fin dialogue
					hHoleDlgActive = NULL;
					SendDlgItemMessage(hWnd, IDC_SH, WM_GETTEXT, sizeof(cBuf) - 1, (LPARAM) cBuf); iHoles = atoi(cBuf);
					if (iHoles >= XDC_MAX_HOLES)
					{
						vTrace(GetCatalogStr(hCat, MSG_0412, "*** E0009 : trop de trous"));
						iHoles = 0;
					}
					EndDialog(hWnd, 0);
					break;
			 }
			 return TRUE;
			 break;

		 case WM_INITDIALOG :
			hHoleDlgActive = hWnd;
			iHoles = 0;

		 case WM_USER + 1:
_HUpdate:
			SendDlgItemMessage(hWnd, IDC_FADE, BM_SETCHECK, (WPARAM) bFillAndRemoveEdges, 0L);
	 		sprintf(cBuf, "%d", iHoles);  SendDlgItemMessage(hWnd, IDC_SH, WM_SETTEXT, 0, (LPARAM) cBuf);

#ifndef _AMIGA_
			SetForegroundWindow(hWnd);
#endif

			return TRUE;
	}
	return FALSE;
}

////////////////////// S A I S I E   1   P A R A M E T R E  ////////////////////////////////////////////
BOOL CALLBACK bStringDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	int wmId;

	switch( uMsg )
    {
	case WM_COMMAND :
         wmId    = LOWORD(wParam);
         switch (wmId)
		 {
			case IDCANCEL:
				EndDialog(hWnd, -1);
				break;

            case IDOK:	// Fin dialogue
				SendDlgItemMessage(hWnd, IDC_SH, WM_GETTEXT, sizeof(cString) - 1, (LPARAM) cString);
				EndDialog(hWnd, 0);
				break;
		 }
		 return TRUE;
		 break;

	 case WM_INITDIALOG :
		 SendDlgItemMessage(hWnd, IDC_SH, WM_SETTEXT, 0, (LPARAM) cString);
		 return TRUE;
		 break;
	}

	return FALSE;
}

////////////////////// H I N T S  W 3 D ////////////////////////////////////////////
BOOL CALLBACK bHintDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	int wmId;
    static UBYTE uHintBack[10];

	switch( uMsg )
    {
	case WM_COMMAND :
         wmId    = LOWORD(wParam);

         switch (wmId)
		 {
			case IDC_TEXMAPPING_FAST :
			case IDC_TEXMAPPING_AVERAGE :
			case IDC_TEXMAPPING_NICE :
                uHint[0] = (wmId == IDC_TEXMAPPING_FAST ? W3D_H_FAST : (wmId == IDC_TEXMAPPING_AVERAGE ? W3D_H_AVERAGE : W3D_H_NICE));
        	    SendDlgItemMessage(hWnd, IDC_TEXMAPPING_FAST,    BM_SETCHECK, (WPARAM) (uHint[0] == W3D_H_FAST),    0L);
        	    SendDlgItemMessage(hWnd, IDC_TEXMAPPING_AVERAGE, BM_SETCHECK, (WPARAM) (uHint[0] == W3D_H_AVERAGE), 0L);
        	    SendDlgItemMessage(hWnd, IDC_TEXMAPPING_NICE,    BM_SETCHECK, (WPARAM) (uHint[0] == W3D_H_NICE),    0L);
                goto __Hints_Done;

			case IDC_MIPMAPPING_FAST :
			case IDC_MIPMAPPING_AVERAGE :
			case IDC_MIPMAPPING_NICE :
                uHint[1] = (wmId == IDC_MIPMAPPING_FAST ? W3D_H_FAST : (wmId == IDC_MIPMAPPING_AVERAGE ? W3D_H_AVERAGE : W3D_H_NICE));
        	    SendDlgItemMessage(hWnd, IDC_MIPMAPPING_FAST,    BM_SETCHECK, (WPARAM) (uHint[1] == W3D_H_FAST),    0L);
        	    SendDlgItemMessage(hWnd, IDC_MIPMAPPING_AVERAGE, BM_SETCHECK, (WPARAM) (uHint[1] == W3D_H_AVERAGE), 0L);
        	    SendDlgItemMessage(hWnd, IDC_MIPMAPPING_NICE,    BM_SETCHECK, (WPARAM) (uHint[1] == W3D_H_NICE),    0L);
                goto __Hints_Done;

			case IDC_BILINEARFILTER_FAST :
			case IDC_BILINEARFILTER_AVERAGE :
			case IDC_BILINEARFILTER_NICE :
                uHint[2] = (wmId == IDC_BILINEARFILTER_FAST ? W3D_H_FAST : (wmId == IDC_BILINEARFILTER_AVERAGE ? W3D_H_AVERAGE : W3D_H_NICE));
        	    SendDlgItemMessage(hWnd, IDC_BILINEARFILTER_FAST,    BM_SETCHECK, (WPARAM) (uHint[2] == W3D_H_FAST),    0L);
        	    SendDlgItemMessage(hWnd, IDC_BILINEARFILTER_AVERAGE, BM_SETCHECK, (WPARAM) (uHint[2] == W3D_H_AVERAGE), 0L);
        	    SendDlgItemMessage(hWnd, IDC_BILINEARFILTER_NICE,    BM_SETCHECK, (WPARAM) (uHint[2] == W3D_H_NICE),    0L);
                goto __Hints_Done;

			case IDC_MMFILTER_FAST :
			case IDC_MMFILTER_AVERAGE :
			case IDC_MMFILTER_NICE :
                uHint[3] = (wmId == IDC_MMFILTER_FAST ? W3D_H_FAST : (wmId == IDC_MMFILTER_AVERAGE ? W3D_H_AVERAGE : W3D_H_NICE));
        	    SendDlgItemMessage(hWnd, IDC_MMFILTER_FAST,    BM_SETCHECK, (WPARAM) (uHint[3] == W3D_H_FAST),    0L);
        	    SendDlgItemMessage(hWnd, IDC_MMFILTER_AVERAGE, BM_SETCHECK, (WPARAM) (uHint[3] == W3D_H_AVERAGE), 0L);
        	    SendDlgItemMessage(hWnd, IDC_MMFILTER_NICE,    BM_SETCHECK, (WPARAM) (uHint[3] == W3D_H_NICE),    0L);
                goto __Hints_Done;

			case IDC_PERSPECTIVE_FAST :
			case IDC_PERSPECTIVE_AVERAGE :
			case IDC_PERSPECTIVE_NICE :
                uHint[4] = (wmId == IDC_PERSPECTIVE_FAST ? W3D_H_FAST : (wmId == IDC_PERSPECTIVE_AVERAGE ? W3D_H_AVERAGE : W3D_H_NICE));
        	    SendDlgItemMessage(hWnd, IDC_PERSPECTIVE_FAST,    BM_SETCHECK, (WPARAM) (uHint[4] == W3D_H_FAST),    0L);
        	    SendDlgItemMessage(hWnd, IDC_PERSPECTIVE_AVERAGE, BM_SETCHECK, (WPARAM) (uHint[4] == W3D_H_AVERAGE), 0L);
        	    SendDlgItemMessage(hWnd, IDC_PERSPECTIVE_NICE,    BM_SETCHECK, (WPARAM) (uHint[4] == W3D_H_NICE),    0L);
                goto __Hints_Done;

			case IDC_BLENDING_FAST :
			case IDC_BLENDING_AVERAGE :
			case IDC_BLENDING_NICE :
                uHint[5] = (wmId == IDC_BLENDING_FAST ? W3D_H_FAST : (wmId == IDC_BLENDING_AVERAGE ? W3D_H_AVERAGE : W3D_H_NICE));
        	    SendDlgItemMessage(hWnd, IDC_BLENDING_FAST,    BM_SETCHECK, (WPARAM) (uHint[5] == W3D_H_FAST),    0L);
        	    SendDlgItemMessage(hWnd, IDC_BLENDING_AVERAGE, BM_SETCHECK, (WPARAM) (uHint[5] == W3D_H_AVERAGE), 0L);
        	    SendDlgItemMessage(hWnd, IDC_BLENDING_NICE,    BM_SETCHECK, (WPARAM) (uHint[5] == W3D_H_NICE),    0L);
                goto __Hints_Done;

			case IDC_FOGGING_FAST :
			case IDC_FOGGING_AVERAGE :
			case IDC_FOGGING_NICE :
                uHint[6] = (wmId == IDC_FOGGING_FAST ? W3D_H_FAST : (wmId == IDC_FOGGING_AVERAGE ? W3D_H_AVERAGE : W3D_H_NICE));
        	    SendDlgItemMessage(hWnd, IDC_FOGGING_FAST,    BM_SETCHECK, (WPARAM) (uHint[6] == W3D_H_FAST),    0L);
        	    SendDlgItemMessage(hWnd, IDC_FOGGING_AVERAGE, BM_SETCHECK, (WPARAM) (uHint[6] == W3D_H_AVERAGE), 0L);
        	    SendDlgItemMessage(hWnd, IDC_FOGGING_NICE,    BM_SETCHECK, (WPARAM) (uHint[6] == W3D_H_NICE),    0L);
                goto __Hints_Done;

			case IDC_ANTIALIASING_FAST :
			case IDC_ANTIALIASING_AVERAGE :
			case IDC_ANTIALIASING_NICE :
                uHint[7] = (wmId == IDC_ANTIALIASING_FAST ? W3D_H_FAST : (wmId == IDC_ANTIALIASING_AVERAGE ? W3D_H_AVERAGE : W3D_H_NICE));
        	    SendDlgItemMessage(hWnd, IDC_ANTIALIASING_FAST,    BM_SETCHECK, (WPARAM) (uHint[7] == W3D_H_FAST),    0L);
        	    SendDlgItemMessage(hWnd, IDC_ANTIALIASING_AVERAGE, BM_SETCHECK, (WPARAM) (uHint[7] == W3D_H_AVERAGE), 0L);
        	    SendDlgItemMessage(hWnd, IDC_ANTIALIASING_NICE,    BM_SETCHECK, (WPARAM) (uHint[7] == W3D_H_NICE),    0L);
                goto __Hints_Done;

			case IDC_DITHERING_FAST :
			case IDC_DITHERING_AVERAGE :
			case IDC_DITHERING_NICE :
                uHint[8] = (wmId == IDC_DITHERING_FAST ? W3D_H_FAST : (wmId == IDC_DITHERING_AVERAGE ? W3D_H_AVERAGE : W3D_H_NICE));
        	    SendDlgItemMessage(hWnd, IDC_DITHERING_FAST,    BM_SETCHECK, (WPARAM) (uHint[8] == W3D_H_FAST),    0L);
        	    SendDlgItemMessage(hWnd, IDC_DITHERING_AVERAGE, BM_SETCHECK, (WPARAM) (uHint[8] == W3D_H_AVERAGE), 0L);
        	    SendDlgItemMessage(hWnd, IDC_DITHERING_NICE,    BM_SETCHECK, (WPARAM) (uHint[8] == W3D_H_NICE),    0L);
                goto __Hints_Done;

			case IDC_ZBUFFER_FAST :
   			case IDC_ZBUFFER_AVERAGE :
			case IDC_ZBUFFER_NICE :
                uHint[9] = (wmId == IDC_ZBUFFER_FAST ? W3D_H_FAST : (wmId == IDC_ZBUFFER_AVERAGE ? W3D_H_AVERAGE : W3D_H_NICE));
        	    SendDlgItemMessage(hWnd, IDC_ZBUFFER_FAST,    BM_SETCHECK, (WPARAM) (uHint[9] == W3D_H_FAST),    0L);
        	    SendDlgItemMessage(hWnd, IDC_ZBUFFER_AVERAGE, BM_SETCHECK, (WPARAM) (uHint[9] == W3D_H_AVERAGE), 0L);
        	    SendDlgItemMessage(hWnd, IDC_ZBUFFER_NICE,    BM_SETCHECK, (WPARAM) (uHint[9] == W3D_H_NICE),    0L);
__Hints_Done:
                vSetHints();
                vForce3DRefresh(XDC_MODE_COMPLET);
				break;

			// Annuler
			case IDCANCEL:
                memcpy(uHint, uHintBack, sizeof(uHint));
			case IDOK:
                vSetHints();
                bSaveHints();
			    EndDialog(hWnd, 0);
				break;
		 }
		 return TRUE;

	 case WM_INITDIALOG :
        memcpy(uHintBack, uHint, sizeof(uHint));
	    SendDlgItemMessage(hWnd, IDC_TEXMAPPING_FAST,        BM_SETCHECK, (WPARAM) (uHint[0] == W3D_H_FAST),    0L);
	    SendDlgItemMessage(hWnd, IDC_TEXMAPPING_AVERAGE,     BM_SETCHECK, (WPARAM) (uHint[0] == W3D_H_AVERAGE), 0L);
	    SendDlgItemMessage(hWnd, IDC_TEXMAPPING_NICE,        BM_SETCHECK, (WPARAM) (uHint[0] == W3D_H_NICE),    0L);
 	    SendDlgItemMessage(hWnd, IDC_MIPMAPPING_FAST,        BM_SETCHECK, (WPARAM) (uHint[1] == W3D_H_FAST),    0L);
	    SendDlgItemMessage(hWnd, IDC_MIPMAPPING_AVERAGE,     BM_SETCHECK, (WPARAM) (uHint[1] == W3D_H_AVERAGE), 0L);
	    SendDlgItemMessage(hWnd, IDC_MIPMAPPING_NICE,        BM_SETCHECK, (WPARAM) (uHint[1] == W3D_H_NICE),    0L);
 	    SendDlgItemMessage(hWnd, IDC_BILINEARFILTER_FAST,    BM_SETCHECK, (WPARAM) (uHint[2] == W3D_H_FAST),    0L);
	    SendDlgItemMessage(hWnd, IDC_BILINEARFILTER_AVERAGE, BM_SETCHECK, (WPARAM) (uHint[2] == W3D_H_AVERAGE), 0L);
	    SendDlgItemMessage(hWnd, IDC_BILINEARFILTER_NICE,    BM_SETCHECK, (WPARAM) (uHint[2] == W3D_H_NICE),    0L);
 	    SendDlgItemMessage(hWnd, IDC_MMFILTER_FAST,          BM_SETCHECK, (WPARAM) (uHint[3] == W3D_H_FAST),    0L);
	    SendDlgItemMessage(hWnd, IDC_MMFILTER_AVERAGE,       BM_SETCHECK, (WPARAM) (uHint[3] == W3D_H_AVERAGE), 0L);
	    SendDlgItemMessage(hWnd, IDC_MMFILTER_NICE,          BM_SETCHECK, (WPARAM) (uHint[3] == W3D_H_NICE),    0L);
 	    SendDlgItemMessage(hWnd, IDC_PERSPECTIVE_FAST,       BM_SETCHECK, (WPARAM) (uHint[4] == W3D_H_FAST),    0L);
	    SendDlgItemMessage(hWnd, IDC_PERSPECTIVE_AVERAGE,    BM_SETCHECK, (WPARAM) (uHint[4] == W3D_H_AVERAGE), 0L);
	    SendDlgItemMessage(hWnd, IDC_PERSPECTIVE_NICE,       BM_SETCHECK, (WPARAM) (uHint[4] == W3D_H_NICE),    0L);
 	    SendDlgItemMessage(hWnd, IDC_BLENDING_FAST,          BM_SETCHECK, (WPARAM) (uHint[5] == W3D_H_FAST),    0L);
	    SendDlgItemMessage(hWnd, IDC_BLENDING_AVERAGE,       BM_SETCHECK, (WPARAM) (uHint[5] == W3D_H_AVERAGE), 0L);
	    SendDlgItemMessage(hWnd, IDC_BLENDING_NICE,          BM_SETCHECK, (WPARAM) (uHint[5] == W3D_H_NICE),    0L);
 	    SendDlgItemMessage(hWnd, IDC_FOGGING_FAST,           BM_SETCHECK, (WPARAM) (uHint[6] == W3D_H_FAST),    0L);
	    SendDlgItemMessage(hWnd, IDC_FOGGING_AVERAGE,        BM_SETCHECK, (WPARAM) (uHint[6] == W3D_H_AVERAGE), 0L);
	    SendDlgItemMessage(hWnd, IDC_FOGGING_NICE,           BM_SETCHECK, (WPARAM) (uHint[6] == W3D_H_NICE),    0L);
 	    SendDlgItemMessage(hWnd, IDC_ANTIALIASING_FAST,      BM_SETCHECK, (WPARAM) (uHint[7] == W3D_H_FAST),    0L);
	    SendDlgItemMessage(hWnd, IDC_ANTIALIASING_AVERAGE,   BM_SETCHECK, (WPARAM) (uHint[7] == W3D_H_AVERAGE), 0L);
	    SendDlgItemMessage(hWnd, IDC_ANTIALIASING_NICE,      BM_SETCHECK, (WPARAM) (uHint[7] == W3D_H_NICE),    0L);
 	    SendDlgItemMessage(hWnd, IDC_DITHERING_FAST,         BM_SETCHECK, (WPARAM) (uHint[8] == W3D_H_FAST),    0L);
	    SendDlgItemMessage(hWnd, IDC_DITHERING_AVERAGE,      BM_SETCHECK, (WPARAM) (uHint[8] == W3D_H_AVERAGE), 0L);
	    SendDlgItemMessage(hWnd, IDC_DITHERING_NICE,         BM_SETCHECK, (WPARAM) (uHint[8] == W3D_H_NICE),    0L);
 	    SendDlgItemMessage(hWnd, IDC_ZBUFFER_FAST,           BM_SETCHECK, (WPARAM) (uHint[9] == W3D_H_FAST),    0L);
	    SendDlgItemMessage(hWnd, IDC_ZBUFFER_AVERAGE,        BM_SETCHECK, (WPARAM) (uHint[9] == W3D_H_AVERAGE), 0L);
	    SendDlgItemMessage(hWnd, IDC_ZBUFFER_NICE,           BM_SETCHECK, (WPARAM) (uHint[9] == W3D_H_NICE),    0L);
		return TRUE;
	}
	return FALSE;
}

