home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 26 / AACD 26.iso / AACD / Graphics / sKulpt / skulpt-src / 2DWProc.cpp next >
Encoding:
C/C++ Source or Header  |  2000-08-30  |  53.3 KB  |  1,408 lines

  1. #define STRICT
  2.  
  3. // Includes standard Windows
  4. #include <windows.h>
  5.  
  6. #include <windowsx.h>
  7. #include <time.h>
  8. #include <stdlib.h>
  9. #include <malloc.h>
  10. #include <memory.h>
  11. #include <stdio.h>
  12.  
  13. // Includes D3D
  14. #define  D3D_OVERLOADS
  15. #include <ddraw.h>
  16. #include <d3d.h>
  17. #include <d3dx.h>
  18.  
  19. // Includes utilitaires D3D
  20. #include "d3dmath.h"
  21. #include "d3dutil.h"
  22. #include "D3DEnum.h"
  23.  
  24. // Ids Resources
  25. #include "resource.h"
  26.  
  27. // Constantes
  28. #include "const.h"
  29.  
  30. // Types
  31. #include "types.h"
  32.  
  33. // Variables globales projet
  34. #include "vars.h"
  35.  
  36. // Prototypes fonctions autres modules
  37. #include "proto.h"
  38.  
  39. // Macros
  40. #include "macros.h"
  41.  
  42. #undef XDC_LOCKBITMAP
  43.  
  44. // Variables statiques au module
  45. static WPARAM wModifier;                                // Mémorisé sur le LBUTTONDOWN : SHIFT / CTRL / ...
  46. static HBRUSH hbrDkBlueSk, hbrLtBlueSk;                        // Brosses de remplissage
  47. static HPEN hpenWhite, hpenGrey, hpenCyan, hpenYellow, hpenPink, hpenDkBlueSk, hpenRed, hpenLtBlueSk, hpenGrid;    // Crayons
  48. static HFONT hFont;
  49. static HBITMAP hbTBuf;    // Bitmap du triple buffer (unique pour les 3 fenêtres)
  50. static DC dcTBuf, *hdcTBuf = &dcTBuf;
  51.  
  52. // Forcer le redessin des 3 vues 2D (WM_PAINT)
  53. // Le paramètre sert à indiquer s'il faut tout redessiner (y/c triangles & sommets) -> TRUE
  54. // ou s'il ne faut redessiner que les curseurs, caméra & target
  55. void vForce2DRefresh(BOOL bMode)
  56. {
  57.     PostMessage(hWndTop,    WM_PAINT, 0, (LPARAM) bMode);
  58.     PostMessage(hWndFace,   WM_PAINT, 0, (LPARAM) bMode);
  59.     PostMessage(hWndRight,  WM_PAINT, 0, (LPARAM) bMode);
  60. }
  61.  
  62. // Callback management fenêtres vues 2D
  63. LRESULT CALLBACK lrPlanarWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  64. {                                            
  65.     // Variables à usage général
  66.     HDC hdcWin = GetDC(hWnd), hdcDoubleBuf;     // Récupérer notre identifiant (vue dessus, face, droite) et mémoriser dans une globale pour que les autres fonctions sachent quelle fenêtre 2D est active
  67.     POINT pClick;
  68.     WinThings *pWT;                                        // Pointeur sur structure étendue fenêtre (double buffer, gadgets etc.)
  69.     char cCoords[256];
  70.     char cAxis;
  71.     D3DVECTOR vVect1, vVect2, vVect3;
  72.     RECT rExtRect, rIntRect;                            // Zones client externe (avec gadgets) et interne (zone de dessin uniquement)
  73.     register int iX, iY, iZ, iT, iWindowXMin, iWindowXMax, iWindowYMin, iWindowYMax;
  74.     float fX, fY, fZ, fT, fXs, fYs, fZs, f3D2DXCoef, f3D2DYCoef;
  75.  
  76.     W3D_Point sP;
  77.     W3D_Line sL; sL.st_enable = FALSE; sL.linewidth = 1.0;
  78.     W3D_Vertex sV[4];
  79.     W3D_Triangles sTs; sTs.vertexcount = 4; sTs.v = sV;
  80.     W3D_Lines sLs; sLs.vertexcount = 4; sLs.v = sV; sLs.st_enable = FALSE; sLs.linewidth = 1.0;
  81.     W3D_Color sC = {0., 0., 0., 1.};
  82.     float fTopEdge, fLeftEdge, fU, fV;
  83.     long lError;
  84. #ifdef XDC_LOCKBITMAP
  85.     APTR hBM;
  86. #endif
  87.  
  88.     // Récupérer le rectangle complet de la zone client de la fenêtre
  89.     GetClientRect(hWnd, &rExtRect);
  90.  
  91.     // Cloner ce rectangle et le réduire pour laisser la place aux gadgets
  92.     CopyRect(&rIntRect, &rExtRect);
  93.     InflateRect(&rIntRect, -XDC_G_LARG, -XDC_G_HAUT);
  94.  
  95.     if (hWnd == hWndTop) lWActive = XDC_WID_TOP;
  96.     if (hWnd == hWndFace) lWActive = XDC_WID_FACE;
  97.     if (hWnd == hWndRight) lWActive = XDC_WID_SIDE;
  98.  
  99.     // Précalculer les coefficients de pente de conversion 3D/2D et déréférencer les coordonnées de la fenêtre
  100.     iWindowXMin = rIntRect.left; iWindowXMax = rIntRect.right;
  101.     iWindowYMax = rIntRect.top; iWindowYMin = rIntRect.bottom;
  102.     switch(lWActive)
  103.     {
  104.         case XDC_WID_TOP : // X et Z
  105.             f3D2DXCoef = (float) (iWindowXMax - iWindowXMin) / (fXmax - fXmin);
  106.             f3D2DYCoef = (float) (iWindowYMax - iWindowYMin) / (fZmax - fZmin);
  107.             break;
  108.  
  109.         case XDC_WID_FACE : // X et Y
  110.             f3D2DXCoef = (float) (iWindowXMax - iWindowXMin) / (fXmax - fXmin);
  111.             f3D2DYCoef = (float) (iWindowYMax - iWindowYMin) / (fYmax - fYmin);
  112.             break;
  113.                 
  114.         case XDC_WID_SIDE : // Z et Y
  115.             f3D2DXCoef = (float) (iWindowXMax - iWindowXMin) / (fZmax - fZmin);
  116.             f3D2DYCoef = (float) (iWindowYMax - iWindowYMin) / (fYmax - fYmin);
  117.             break;
  118.     }
  119.  
  120.     // Récupérer le pointeur sur la structure de données étendue de la fenêtre (double & triple buffer, gadgets etc.)
  121.     pWT = (WinThings *) hWnd -> UserData;
  122.  
  123.     switch( uMsg )
  124.     {
  125.         case WM_CREATE:    //************************* C R E A T E ************************
  126.             // Allouer les objets GDI (globaux à toutes les fenêtres 2D d'où if ...)
  127.             if (!hpenWhite)        hpenWhite = CreatePen(PS_SOLID, 1, XDC_COL_WHITE);
  128.             if (!hpenRed)        hpenRed = CreatePen(PS_SOLID, 1, XDC_COL_RED);
  129.             if (!hpenYellow)    hpenYellow = CreatePen(PS_SOLID, 1, XDC_COL_YELLOW);
  130.             if (!hpenCyan)        hpenCyan = CreatePen(PS_SOLID, 1, XDC_COL_CYAN);
  131.             if (!hpenPink)        hpenPink = CreatePen(PS_SOLID, 1, XDC_COL_PINK);
  132.             if (!hpenGrey)        hpenGrey = CreatePen(PS_SOLID, 1, XDC_COL_GREY);
  133.             if (!hpenDkBlueSk)    hpenDkBlueSk = CreatePen(PS_SOLID, 1, XDC_COL_DKBLUESK);
  134.             if (!hpenLtBlueSk)    hpenLtBlueSk = CreatePen(PS_SOLID, 1, XDC_COL_LTBLUESK);
  135.             if (!hpenGrid)      hpenGrid = CreatePen(PS_SOLID, 1, XDC_COL_GRID);
  136.  
  137. #ifndef _AMIGA_
  138.             if (!hbrDkBlueSk)   hbrDkBlueSk = CreateSolidBrush(XDC_COL_DKBLUESK);
  139.             if (!hbrLtBlueSk)   hbrLtBlueSk = CreateSolidBrush(XDC_COL_LTBLUESK);
  140.  
  141.             // Créer la fonte pour indiquer l'outil en cours à coté du curseur
  142.             if (!hFont)            hFont = CreateFont( -12,
  143.                                                     0, 0, 0, FW_BOLD, TRUE, FALSE, FALSE,
  144.                                                     ANSI_CHARSET,
  145.                                                     OUT_DEFAULT_PRECIS,
  146.                                                     CLIP_DEFAULT_PRECIS,
  147.                                                     DEFAULT_QUALITY,
  148.                                                     VARIABLE_PITCH,
  149.                                                     "Arial" );
  150. #endif
  151.  
  152.             // Créer la structure de données étendue et l'attacher à la fenêtre
  153.             if (!(pWT = (WinThings *) malloc(sizeof(WinThings))))
  154.             {
  155.                 // Si fail, sortir de l'application
  156.                 PostQuitMessage(0);
  157.                 break;
  158.             }
  159.  
  160.             // Attacher la structure de données étendue à la fenêtre
  161.             hWnd -> UserData = (UBYTE *) pWT;
  162.  
  163.             // Initialiser les pointeurs de gadgets sur l'imagerie gadgets (commune à toutes les fenêtres)
  164.             pWT -> Widgets[XDC_GID_AddPoint].Gad = &gAddPoint;
  165.             pWT -> Widgets[XDC_GID_Center].Gad = &gCenter;
  166.             pWT -> Widgets[XDC_GID_GoDown].Gad = &gGoDown;
  167.             pWT -> Widgets[XDC_GID_GoLeft].Gad = &gGoLeft;
  168.             pWT -> Widgets[XDC_GID_GoUp].Gad = &gGoUp;
  169.             pWT -> Widgets[XDC_GID_GoRight].Gad = &gGoRight;
  170.             pWT -> Widgets[XDC_GID_Grab].Gad = &gGrab;
  171.             pWT -> Widgets[XDC_GID_MakeTri].Gad = &gMakeTri;
  172.             pWT -> Widgets[XDC_GID_Reverse].Gad = &gReverse;
  173.             pWT -> Widgets[XDC_GID_RotAnti].Gad = &gRotAnti;
  174.             pWT -> Widgets[XDC_GID_RotClock].Gad = &gRotClock;
  175.             pWT -> Widgets[XDC_GID_ZoomIn].Gad = &gZoomIn;
  176.             pWT -> Widgets[XDC_GID_ZoomOut].Gad = &gZoomOut;
  177.  
  178.             // Mémoriser qu'on doit mettre à jour la zone de clipping fenêtre
  179.             pWT -> hClip = (struct Region *) ~NULL;
  180.  
  181.             // Créer le double buffer et l'attacher à la structure de données étendue
  182.             pWT -> hbDBuf = NULL; // Sera alloué par le premier WM_SIZE
  183.             pWT -> hdcDBuf = &(pWT -> dcDBuf); InitRastPort(pWT -> hdcDBuf);
  184.  
  185.             // Se rappeler que le prochain WM_PAINT sera le premier
  186.             pWT -> bFirstPaint = TRUE;
  187.  
  188.             break;
  189.  
  190.         case WM_USER + 1: //*********************** Rafraichir le point d'indice wParam dans le double buffer
  191.                           // (-> refresh 2D mode partiel à suivre)
  192.             // Si pas de contexte 3D ou pas de double buffer alors ne rien faire
  193.             if ((!hW3DContext) || !(pWT -> hbDBuf))
  194.             {
  195.                  vTrace("*** E0070 : [%s] / msg %d : contexte @%08lX, bmdBuf %08lX)", hWnd -> Title, uMsg, hW3DContext, pWT -> hbDBuf);
  196.                  break;
  197.             }
  198.             
  199.             // Déréférencer le point à rafraîchir
  200.             vVect1 = Vertices[wParam].vPoint;
  201.  
  202.             switch(lWActive)
  203.             {
  204.                 case XDC_WID_TOP : // X et Z
  205.                     fX = XDM_to2D(vVect1.x, fXmin, iWindowXMin, f3D2DXCoef);
  206.                     fY = XDM_to2D(vVect1.z, fZmin, iWindowYMin, f3D2DYCoef);
  207.                     break;
  208.  
  209.                 case XDC_WID_FACE : // X et Y
  210.                     fX = XDM_to2D(vVect1.x, fXmin, iWindowXMin, f3D2DXCoef);
  211.                     fY = XDM_to2D(vVect1.y, fYmin, iWindowYMin, f3D2DYCoef);
  212.                     break;
  213.                 
  214.                 case XDC_WID_SIDE : // Z et Y
  215.                     fX = XDM_to2D(vVect1.z, fZmin, iWindowXMin, f3D2DXCoef);
  216.                     fY = XDM_to2D(vVect1.y, fYmin, iWindowYMin, f3D2DYCoef);
  217.                     break;
  218.             }
  219.  
  220.             // Set Drawing region sur le double buffer
  221.             fLeftEdge = fTopEdge = 0.;
  222.             sScissor.left   = (int) fLeftEdge + iWindowXMin + 1;
  223.             sScissor.top    = (int) fTopEdge + iWindowYMax + 1;
  224.             sScissor.width  = iWindowXMax - iWindowXMin - 1;
  225.             sScissor.height = iWindowYMin - iWindowYMax - 1;
  226.             W3D_SetDrawRegion(hW3DContext, pWT -> hbDBuf, 0, &sScissor);
  227.  
  228. #ifdef XDC_LOCKBITMAP
  229.             // Verrouiller le bitmap en VRAM
  230.             lError = TAG_DONE;
  231.             if (!(hBM = LockBitMapTagList(pWT -> hbDBuf,(struct TagItem *) &lError)))
  232.             {
  233.                  vTrace("*** E0021 : [%s] / msg %d : lock bitmap (contexte @%08lX, code %ld)", hWnd -> Title, uMsg, hW3DContext, lError);
  234.                  break;
  235.             }
  236. #endif
  237.  
  238.             // Si on ne peut pas verrouiller le hardware 3D on ne fait rien
  239.             if (W3D_SUCCESS != (lError = W3D_LockHardware(hW3DContext)))
  240.             {
  241. #ifdef XDC_LOCKBITMAP
  242.                  // Déverrouiller le bitmap
  243.                  UnLockBitMap(hBM);
  244. #endif
  245.  
  246.                  vTrace("*** E0071 : [%s] / msg %d : lock hardware (contexte @%08lX, code %ld)", hWnd -> Title, uMsg, hW3DContext, lError);
  247.                  break;
  248.             }
  249.  
  250.             // Tracer le sommet (petite croix)
  251.             WSetPen(hW3DContext, Vertices[wParam].bSelected ? XDC_COL_YELLOW : XDC_COL_DKBLUESK);
  252.             WPixel(hW3DContext, fX, fY);
  253.             WPixel(hW3DContext, fX - 1, fY);
  254.             WPixel(hW3DContext, fX + 1, fY);
  255.             WPixel(hW3DContext, fX, fY - 1);
  256.             WPixel(hW3DContext, fX, fY + 1);
  257.  
  258.             // Déverrouiller le hardware 3D
  259.             W3D_UnLockHardware(hW3DContext);
  260.  
  261. #ifdef XDC_LOCKBITMAP
  262.             // Déverrouiller le bitmap
  263.             UnLockBitMap(hBM);
  264. #endif
  265.             break;
  266.  
  267.         case WM_PAINT: //************************** P A I N T ***********************
  268.             {
  269.                 // Si pas de contexte 3D ou pas de double buffer, on ne fait rien
  270.                 if ((!hW3DContext) || !(pWT -> hbDBuf))
  271.                 {
  272.                      vTrace("*** E0072 : [%s] / msg %d : contexte @%08lX, bmdBuf %08lX)", hWnd -> Title, uMsg, hW3DContext, pWT -> hbDBuf);
  273.                      break;
  274.                 }
  275.  
  276.                 // déréférencer le HDC du double buffer pour aller plus vite
  277.                 hdcDoubleBuf = pWT -> hdcDBuf;
  278.  
  279.                 // On redessine tout seulement si on nous le demande ou si c'est le premier WM_PAINT
  280.                 if (((BOOL) lParam || pWT -> bFirstPaint) == XDC_MODE_PARTIEL) goto _skip;
  281.  
  282.                 // Set Drawing region sur le double buffer
  283.                 fLeftEdge = fTopEdge = 0.;
  284.                 sScissor.left   = (int) fLeftEdge + iWindowXMin + 1;
  285.                 sScissor.top    = (int) fTopEdge + iWindowYMax + 1;
  286.                 sScissor.width  = iWindowXMax - iWindowXMin - 1;
  287.                 sScissor.height = iWindowYMin - iWindowYMax - 1;
  288.                 W3D_SetDrawRegion(hW3DContext, pWT -> hbDBuf, 0, &sScissor);
  289.  
  290. #ifdef XDC_LOCKBITMAP
  291.                 // Verrouiller le bitmap en VRAM
  292.                 lError = TAG_DONE;
  293.                 if (!(hBM = LockBitMapTagList(pWT -> hbDBuf,(struct TagItem *) &lError)))
  294.                 {
  295.                      vTrace("*** E0020 : [%s] / msg %d : lock bitmap (contexte @%08lX, code %ld)", hWnd -> Title, uMsg, hW3DContext, lError);
  296.                      break;
  297.                 }
  298. #endif
  299.  
  300.                 // Si on ne peut pas verrouiller le hardware 3D on ne fait rien
  301.                 if (W3D_SUCCESS != (lError = W3D_LockHardware(hW3DContext)))
  302.                 {
  303. #ifdef XDC_LOCKBITMAP
  304.                      // Déverrouiller le bitmap
  305.                      UnLockBitMap(hBM);
  306. #endif
  307.  
  308.                      vTrace("*** E0073 : [%s] : lock hardware (contexte @%08lX, code %ld)", hWnd -> Title, hW3DContext, lError);
  309.                      break;
  310.                 }
  311.  
  312.                 // Se rappeller que les WM_PAINT à venir ne sont pas les premiers
  313.                 pWT -> bFirstPaint = FALSE;
  314.  
  315.                 // Remplir le grand rectangle en bleu foncé :           déplacé dans WM_SIZE
  316.                 // Séparer les zones int/ext avec tour blanc :          déplacé dans WM_SIZE
  317.                 // Ajouter tous les gadgets Sculpt3D :                  déplacé dans WM_SIZE
  318.                 // Tracer les noms des axes :                           déplacé dans WM_SIZE
  319.                 // Définir la zone de clipping : rectangle interne :    déplacé dans WM_SIZE
  320.  
  321.                 // Remplir le petit rectangle en bleu clair
  322.                 WSetPen(hW3DContext, XDC_COL_LTBLUESK);
  323.                 WRectFill(hW3DContext, iWindowXMin + 1, iWindowYMax + 1, iWindowXMax - 1, iWindowYMin - 1);
  324.  
  325.                 // Tracer la grille (si elle est activée)
  326.                 if (bGrid)
  327.                 {
  328.                     WSetPen(hW3DContext, XDC_COL_GRID);
  329.                     switch(lWActive)
  330.                     {
  331.                     case XDC_WID_TOP : // Axes X (gauche > droite) et Z (bas > haut)
  332.                         for (fXs = XDM_toGrid(fXmin) ; fXs <= XDM_toGrid(fXmax) ; fXs += fGridSize)
  333.                             for (fZs = XDM_toGrid(fZmin) ; fZs <= XDM_toGrid(fZmax) ; fZs += fGridSize)
  334.                                 WPixel(hW3DContext, XDM_to2D(fXs, fXmin, iWindowXMin, f3D2DXCoef),
  335.                                        XDM_to2D(fZs, fZmin, iWindowYMin, f3D2DYCoef));
  336.                         break;
  337.  
  338.                     case XDC_WID_FACE : // Axes X (gauche > droite) et Y (bas > haut)
  339.                         for (fXs = XDM_toGrid(fXmin) ; fXs <= XDM_toGrid(fXmax) ; fXs += fGridSize)
  340.                             for (fYs = XDM_toGrid(fYmin) ; fYs <= XDM_toGrid(fYmax) ; fYs += fGridSize)
  341.                                 WPixel(hW3DContext, XDM_to2D(fXs, fXmin, iWindowXMin, f3D2DXCoef),
  342.                                        XDM_to2D(fYs, fYmin, iWindowYMin, f3D2DYCoef));
  343.                         break;
  344.  
  345.                     case XDC_WID_SIDE : // Axes Z (gauche > droite) et Y (bas > haut)
  346.                         for (fZs = XDM_toGrid(fZmin) ; fZs <= XDM_toGrid(fZmax) ; fZs += fGridSize)
  347.                             for (fYs = XDM_toGrid(fYmin) ; fYs <= XDM_toGrid(fYmax) ; fYs += fGridSize)
  348.                                 WPixel(hW3DContext, XDM_to2D(fZs, fZmin, iWindowXMin, f3D2DXCoef),
  349.                                        XDM_to2D(fYs, fYmin, iWindowYMin, f3D2DYCoef));
  350.                         break;
  351.                     }
  352.                 }
  353.  
  354.                 // Tracer les axes du repère, en gris
  355.                 WSetPen(hW3DContext, XDC_COL_GREY);
  356.  
  357.                 switch(lWActive)
  358.                 {
  359.                     case XDC_WID_TOP : // Axes X (gauche > droite) et Z (bas > haut)
  360.                         fY = XDM_to2D(0, fZmin, iWindowYMin, f3D2DYCoef);
  361.                         WDraw(hW3DContext, iWindowXMax, fY, iWindowXMin, fY);
  362.  
  363.                         fX = XDM_to2D(0, fXmin, iWindowXMin, f3D2DXCoef);
  364.                         WDraw(hW3DContext, fX, iWindowYMin, fX, iWindowYMax);
  365.                         break;
  366.  
  367.                     case XDC_WID_FACE : // Axes X (gauche > droite) et Y (bas > haut)
  368.                         fY = XDM_to2D(0, fYmin, iWindowYMin, f3D2DYCoef);
  369.                         WDraw(hW3DContext, iWindowXMax, fY, iWindowXMin, fY);
  370.  
  371.                         fX = XDM_to2D(0, fXmin, iWindowXMin, f3D2DXCoef);
  372.                         WDraw(hW3DContext, fX, iWindowYMin, fX, iWindowYMax);
  373.                         break;
  374.  
  375.                     case XDC_WID_SIDE : // Axes Z (gauche > droite) et Y (bas > haut)
  376.                         fY = XDM_to2D(0, fYmin, iWindowYMin, f3D2DYCoef);
  377.                         WDraw(hW3DContext, iWindowXMax, fY, iWindowXMin, fY);
  378.  
  379.                         fX = XDM_to2D(0, fZmin, iWindowXMin, f3D2DXCoef);
  380.                         WDraw(hW3DContext, fX, iWindowYMin, fX, iWindowYMax);
  381.                         break;
  382.                 }
  383.  
  384.                 // Tracer les objets géométriques
  385.                 {
  386.                           // 1 - Arêtes
  387.                         // Choisir le crayon rouge
  388.                         WSetPen(hW3DContext, XDC_COL_RED);
  389.                         for (int iEdge = 0 ; iEdge <= iEdgeLastUsed ; iEdge++)
  390.                         {
  391.                             // Ignorer les arêtes inexistants
  392.                             if (Edges[iEdge].bEnabled == FALSE) continue;
  393.  
  394.                             // Ignorer les arêtes cachés
  395.                             if (Edges[iEdge].bHidden == TRUE) continue;
  396.  
  397.                             vVect1 = Vertices[Edges[iEdge].iSommets[0]].vPoint;
  398.                             vVect2 = Vertices[Edges[iEdge].iSommets[1]].vPoint;
  399.  
  400.                             switch(lWActive)
  401.                             {
  402.                                 case XDC_WID_TOP : // X et Z
  403.                                     fX = XDM_to2D(vVect1.x, fXmin, iWindowXMin, f3D2DXCoef);
  404.                                     fY = XDM_to2D(vVect1.z, fZmin, iWindowYMin, f3D2DYCoef);
  405.                                     fZ = XDM_to2D(vVect2.x, fXmin, iWindowXMin, f3D2DXCoef);
  406.                                     fT = XDM_to2D(vVect2.z, fZmin, iWindowYMin, f3D2DYCoef);
  407.                                     break;
  408.  
  409.                                 case XDC_WID_FACE : // X et Y
  410.                                     fX = XDM_to2D(vVect1.x, fXmin, iWindowXMin, f3D2DXCoef);
  411.                                     fY = XDM_to2D(vVect1.y, fYmin, iWindowYMin, f3D2DYCoef);
  412.                                     fZ = XDM_to2D(vVect2.x, fXmin, iWindowXMin, f3D2DXCoef);
  413.                                     fT = XDM_to2D(vVect2.y, fYmin, iWindowYMin, f3D2DYCoef);
  414.                                     break;
  415.  
  416.                                 case XDC_WID_SIDE : // Z et Y
  417.                                     fX = XDM_to2D(vVect1.z, fZmin, iWindowXMin, f3D2DXCoef);
  418.                                     fY = XDM_to2D(vVect1.y, fYmin, iWindowYMin, f3D2DYCoef);
  419.                                     fZ = XDM_to2D(vVect2.z, fZmin, iWindowXMin, f3D2DXCoef);
  420.                                     fT = XDM_to2D(vVect2.y, fYmin, iWindowYMin, f3D2DYCoef);
  421.                                     break;
  422.                             }
  423.  
  424.                             // Tracer l'arête
  425.                             WDraw(hW3DContext, fX, fY, fZ, fT);
  426.                         }
  427.  
  428.                     // On ne dessine les triangles que si on n'est pas en dragging
  429.                     if (!bTracking)
  430.                     {
  431.                         // 2 - Triangles
  432.                         // Choisir le crayon rose
  433.                         WSetPen(hW3DContext, XDC_COL_PINK);
  434.                         for (int iTriangle = 0 ; iTriangle <= iTriaLastUsed ; iTriangle++)
  435.                         {
  436.                             // Ignorer les triangles inexistants
  437.                             if (Triangles[iTriangle].bEnabled == FALSE) continue;
  438.  
  439.                             // Ignorer les triangles cachés
  440.                             if (Triangles[iTriangle].bHidden == TRUE) continue;
  441.  
  442.                             vVect1 = Vertices[Triangles[iTriangle].iSommets[0]].vPoint;
  443.                             vVect2 = Vertices[Triangles[iTriangle].iSommets[1]].vPoint;
  444.                             vVect3 = Vertices[Triangles[iTriangle].iSommets[2]].vPoint;
  445.  
  446.                             switch(lWActive)
  447.                             {
  448.                                 case XDC_WID_TOP : // X et Z
  449.                                     fX = XDM_to2D(vVect1.x, fXmin, iWindowXMin, f3D2DXCoef);
  450.                                     fY = XDM_to2D(vVect1.z, fZmin, iWindowYMin, f3D2DYCoef);
  451.                                     fZ = XDM_to2D(vVect2.x, fXmin, iWindowXMin, f3D2DXCoef);
  452.                                     fT = XDM_to2D(vVect2.z, fZmin, iWindowYMin, f3D2DYCoef);
  453.                                     fU = XDM_to2D(vVect3.x, fXmin, iWindowXMin, f3D2DXCoef);
  454.                                     fV = XDM_to2D(vVect3.z, fZmin, iWindowYMin, f3D2DYCoef);
  455.                                     break;
  456.  
  457.                                 case XDC_WID_FACE : // X et Y
  458.                                     fX = XDM_to2D(vVect1.x, fXmin, iWindowXMin, f3D2DXCoef);
  459.                                     fY = XDM_to2D(vVect1.y, fYmin, iWindowYMin, f3D2DYCoef);
  460.                                     fZ = XDM_to2D(vVect2.x, fXmin, iWindowXMin, f3D2DXCoef);
  461.                                     fT = XDM_to2D(vVect2.y, fYmin, iWindowYMin, f3D2DYCoef);
  462.                                     fU = XDM_to2D(vVect3.x, fXmin, iWindowXMin, f3D2DXCoef);
  463.                                     fV = XDM_to2D(vVect3.y, fYmin, iWindowYMin, f3D2DYCoef);
  464.                                     break;
  465.  
  466.                                 case XDC_WID_SIDE : // Z et Y
  467.                                     fX = XDM_to2D(vVect1.z, fZmin, iWindowXMin, f3D2DXCoef);
  468.                                     fY = XDM_to2D(vVect1.y, fYmin, iWindowYMin, f3D2DYCoef);
  469.                                     fZ = XDM_to2D(vVect2.z, fZmin, iWindowXMin, f3D2DXCoef);
  470.                                     fT = XDM_to2D(vVect2.y, fYmin, iWindowYMin, f3D2DYCoef);
  471.                                     fU = XDM_to2D(vVect3.z, fZmin, iWindowXMin, f3D2DXCoef);
  472.                                     fV = XDM_to2D(vVect3.y, fYmin, iWindowYMin, f3D2DYCoef);
  473.                                     break;
  474.                             }
  475.  
  476.                             // Tracer l'arête du triangle
  477.                             WTriEdge(hW3DContext, fX, fY, fZ, fT, fU, fV);
  478.                         }
  479.                     }
  480.  
  481.                     // 3.1 - Points
  482.                     for (int iVertex = 0 ; iVertex <= iVertLastUsed ; iVertex++)
  483.                     {
  484.                         if (PeekSignal(l2DWinSigMask))
  485.                         {
  486.                             W3D_UnLockHardware(hW3DContext);
  487.                             goto _skip;
  488.                         }
  489.  
  490.                         // Ignorer les points inexistants
  491.                         if (Vertices[iVertex].bEnabled == FALSE) continue;
  492.  
  493.                         // Ignorer les points cachés
  494.                         if (Vertices[iVertex].bHidden == TRUE) continue;
  495.  
  496.                         vVect1 = Vertices[iVertex].vPoint;
  497.  
  498.                         switch(lWActive)
  499.                         {
  500.                             case XDC_WID_TOP : // X et Z
  501.                                 fX = XDM_to2D(vVect1.x, fXmin, iWindowXMin, f3D2DXCoef);
  502.                                 fY = XDM_to2D(vVect1.z, fZmin, iWindowYMin, f3D2DYCoef);
  503.                                 break;
  504.  
  505.                             case XDC_WID_FACE : // X et Y
  506.                                 fX = XDM_to2D(vVect1.x, fXmin, iWindowXMin, f3D2DXCoef);
  507.                                 fY = XDM_to2D(vVect1.y, fYmin, iWindowYMin, f3D2DYCoef);
  508.                                 break;
  509.  
  510.                             case XDC_WID_SIDE : // Z et Y
  511.                                 fX = XDM_to2D(vVect1.z, fZmin, iWindowXMin, f3D2DXCoef);
  512.                                 fY = XDM_to2D(vVect1.y, fYmin, iWindowYMin, f3D2DYCoef);
  513.                                 break;
  514.                         }
  515.  
  516.                         // Tracer le sommet du triangle (petite croix)
  517.                         WSetPen(hW3DContext, Vertices[iVertex].bSelected ? XDC_COL_YELLOW : XDC_COL_DKBLUESK);
  518.                         WPixel(hW3DContext, fX, fY);
  519.                         if (!bTracking)
  520.                         {
  521.                              WPixel(hW3DContext, fX - 1, fY);
  522.                              WPixel(hW3DContext, fX + 1, fY);
  523.                              WPixel(hW3DContext, fX, fY - 1);
  524.                              WPixel(hW3DContext, fX, fY + 1);
  525.                         }
  526.                     }
  527.  
  528.                     // 4 - Lampes
  529.                     for (int iLamp = 0 ; iLamp <= iLampLastUsed ; iLamp++)
  530.                     {
  531.                         // Ignorer les lampes inexistantes
  532.                         if (Lampes[iLamp].bEnabled == FALSE) continue;
  533.  
  534.                         WSetPen(hW3DContext, Lampes[iLamp].bSelected ? XDC_COL_YELLOW : XDC_COL_RED);
  535.  
  536.                         vVect1 = Lampes[iLamp].lLamp.dvPosition;
  537.  
  538.                         switch(lWActive)
  539.                         {
  540.                             case XDC_WID_TOP : // X et Z
  541.                                 fX = XDM_to2D(vVect1.x, fXmin, iWindowXMin, f3D2DXCoef);
  542.                                 fY = XDM_to2D(vVect1.z, fZmin, iWindowYMin, f3D2DYCoef);
  543.                                 break;
  544.  
  545.                             case XDC_WID_FACE : // X et Y
  546.                                 fX = XDM_to2D(vVect1.x, fXmin, iWindowXMin, f3D2DXCoef);
  547.                                 fY = XDM_to2D(vVect1.y, fYmin, iWindowYMin, f3D2DYCoef);
  548.                                 break;
  549.  
  550.                             case XDC_WID_SIDE : // Z et Y
  551.                                 fX = XDM_to2D(vVect1.z, fZmin, iWindowXMin, f3D2DXCoef);
  552.                                 fY = XDM_to2D(vVect1.y, fYmin, iWindowYMin, f3D2DYCoef);
  553.                                 break;
  554.                         }
  555.                         WDraw(hW3DContext, fX, fY, fX + 3, fY - 3);
  556.                         WDraw(hW3DContext, fX, fY, fX + 3, fY + 3);
  557.                     }
  558.                 }
  559.  
  560. #ifdef XDC_LOCKBITMAP
  561.                 // Déverrouiller le bitmap
  562.                 UnLockBitMap(hBM);
  563. #endif
  564.  
  565.                 // Déverrouiller le hardware 3D
  566.                 W3D_UnLockHardware(hW3DContext);
  567. _skip:
  568.                 // Set Drawing region sur la fenêtre ou sur le triple buffer s'il existe
  569.                 sScissor.width  = iWindowXMax - iWindowXMin - 1;
  570.                 sScissor.height = iWindowYMin - iWindowYMax - 1;
  571.  
  572.                 if (hbTBuf) // triple buffer, on va continuer à dessiner dedans
  573.                 {
  574.                     fLeftEdge = fTopEdge = 0.;
  575.                     sScissor.left   = (int) fLeftEdge + iWindowXMin + 1;
  576.                     sScissor.top    = (int) fTopEdge + iWindowYMax + 1;
  577.                     W3D_SetDrawRegion(hW3DContext, hbTBuf, 0, &sScissor);
  578.  
  579.                     // BitBlitter le double buffer dans le triple
  580.                     ClipBlit(hdcDoubleBuf, hWnd -> BorderLeft, hWnd -> BorderTop,
  581.                              hdcTBuf, hWnd -> BorderLeft, hWnd -> BorderTop,
  582.                              rExtRect.right, rExtRect.bottom,
  583.                              0xc0);
  584.                 }
  585.                 else // Pas de triple buffer, on va continuer à dessiner dans la fenêtre
  586.                 {
  587.                     fLeftEdge = hWnd -> LeftEdge; fTopEdge = hWnd -> TopEdge;
  588.                     sScissor.left   = (int) fLeftEdge + iWindowXMin + 1;
  589.                     sScissor.top    = (int) fTopEdge + iWindowYMax + 1;
  590.                     W3D_SetDrawRegion(hW3DContext, hdcWin -> BitMap, 0, &sScissor);
  591.  
  592.                     // BitBlitter le double buffer dans la fenêtre
  593.                     ClipBlit(hdcDoubleBuf, hWnd -> BorderLeft, hWnd -> BorderTop,
  594.                              hdcWin, hWnd -> BorderLeft, hWnd -> BorderTop,
  595.                              rExtRect.right, rExtRect.bottom,
  596.                              0xc0);
  597.                 }
  598.  
  599. #ifdef XDC_LOCKBITMAP
  600.                 // Verrouiller le bitmap en VRAM
  601.                 lError = TAG_DONE;
  602.                 if (!(hBM = LockBitMapTagList(hbTBuf ? hbTBuf : hdcWin -> BitMap, (struct TagItem *) &lError)))
  603.                 {
  604.                      vTrace("*** E0033 : [%s] / msg %d : lock bitmap (contexte @%08lX, code %ld)", hWnd -> Title, uMsg, hW3DContext, lError);
  605.                      break;
  606.                 }
  607. #endif
  608.  
  609.                 // Si on ne peut pas verrouiller le hardware 3D on ne fait rien
  610.                 if (W3D_SUCCESS != (lError = W3D_LockHardware(hW3DContext)))
  611.                 {
  612. #ifdef XDC_LOCKBITMAP
  613.                      // Déverrouiller le bitmap
  614.                      UnLockBitMap(hBM);
  615. #endif
  616.  
  617.                      vTrace("*** E0074 : [%s] : lock hardware (contexte @%08lX, code %ld)", hWnd -> Title, hW3DContext, lError);
  618.                      break;
  619.                 }
  620.  
  621.                 // 5 - Tracer le curseur principal et la zone de tolérance
  622.                 switch(lWActive)
  623.                 {
  624.                     case XDC_WID_TOP : // X et Z
  625.                         iZ = (int) (fX = XDM_to2D(Cursor1.x, fXmin, iWindowXMin, f3D2DXCoef));
  626.                         iT = (int) (fY = XDM_to2D(Cursor1.z, fZmin, iWindowYMin, f3D2DYCoef));
  627.                         fZ = XDM_to2D(Cursor1.x - (fXmax - fXmin) / XDC_ZONE, fXmin, iWindowXMin, f3D2DXCoef);
  628.                         fT = XDM_to2D(Cursor1.z - (fXmax - fXmin) / XDC_ZONE, fZmin, iWindowYMin, f3D2DYCoef);
  629.                         break;
  630.  
  631.                     case XDC_WID_FACE : // X et Y
  632.                         iZ = (int) (fX = XDM_to2D(Cursor1.x, fXmin, iWindowXMin, f3D2DXCoef));
  633.                         iT = (int) (fY = XDM_to2D(Cursor1.y, fYmin, iWindowYMin, f3D2DYCoef));
  634.                         fZ = XDM_to2D(Cursor1.x - (fXmax - fXmin) / XDC_ZONE, fXmin, iWindowXMin, f3D2DXCoef);
  635.                         fT = XDM_to2D(Cursor1.y - (fXmax - fXmin) / XDC_ZONE, fYmin, iWindowYMin, f3D2DYCoef);
  636.                         break;
  637.  
  638.                     case XDC_WID_SIDE : // Z et Y
  639.                         iZ = (int) (fX = XDM_to2D(Cursor1.z, fZmin, iWindowXMin, f3D2DXCoef));
  640.                         iT = (int) (fY = XDM_to2D(Cursor1.y, fYmin, iWindowYMin, f3D2DYCoef));
  641.                         fZ = XDM_to2D(Cursor1.z - (fXmax - fXmin) / XDC_ZONE, fZmin, iWindowXMin, f3D2DXCoef);
  642.                         fT = XDM_to2D(Cursor1.y - (fXmax - fXmin) / XDC_ZONE, fYmin, iWindowYMin, f3D2DYCoef);
  643.                         break;
  644.                 }
  645.  
  646.                 // Tracer le curseur 1
  647.                 WSetPen(hW3DContext, XDC_COL_CYAN);
  648.                 WDraw(hW3DContext, fX - 9, fY, fX + 10, fY);
  649.                 WDraw(hW3DContext, fX, fY - 9, fX, fY + 10);
  650.  
  651.                 // Tracer la zone de tolérance
  652.                 WSetPen(hW3DContext, (cTool == XDC_TOOL_UNSELECT) ? XDC_COL_DKBLUESK : XDC_COL_YELLOW);
  653.                 WDraw(hW3DContext, fZ, fT, fZ + 2 * (fX - fZ), fT);
  654.                 WDraw(hW3DContext, fZ, fT, fZ, fT + 2 * (fY - fT));
  655.  
  656.                 if ((cTool == XDC_TOOL_SELECT) || (cTool == XDC_TOOL_UNSELECT))
  657.                 {
  658.                     WDraw(hW3DContext, fZ, fT + 2 * (fY - fT), fZ + 2 * (fX - fZ), fT + 2 * (fY - fT));
  659.                     WDraw(hW3DContext, fZ + 2 * (fX - fZ), fT, fZ + 2 * (fX - fZ), fT + 2 * (fY - fT));
  660.                 }
  661.  
  662.                 // 6 - Tracer l'observateur
  663.                 WSetPen(hW3DContext, XDC_COL_WHITE);
  664.                 switch(lWActive)
  665.                 {
  666.                     case XDC_WID_TOP : // X et Z
  667.                         fX = XDM_to2D(Observer.x, fXmin, iWindowXMin, f3D2DXCoef);
  668.                         fY = XDM_to2D(Observer.z, fZmin, iWindowYMin, f3D2DYCoef);
  669.                         break;
  670.  
  671.                     case XDC_WID_FACE : // X et Y
  672.                         fX = XDM_to2D(Observer.x, fXmin, iWindowXMin, f3D2DXCoef);
  673.                         fY = XDM_to2D(Observer.y, fYmin, iWindowYMin, f3D2DYCoef);
  674.                         break;
  675.  
  676.                     case XDC_WID_SIDE : // Z et Y
  677.                         fX = XDM_to2D(Observer.z, fZmin, iWindowXMin, f3D2DXCoef);
  678.                         fY = XDM_to2D(Observer.y, fYmin, iWindowYMin, f3D2DYCoef);
  679.                         break;
  680.                 }
  681.                 WDraw(hW3DContext, fX, fY, fX + 3, fY - 3);
  682.                 WDraw(hW3DContext, fX, fY, fX + 3, fY + 3);
  683.  
  684.                 // 7 - Tracer le segment caméra / cible
  685.                 switch(lWActive)
  686.                 {
  687.                     case XDC_WID_TOP : // X et Z
  688.                         fZ = XDM_to2D(Target.x, fXmin, iWindowXMin, f3D2DXCoef);
  689.                         fT = XDM_to2D(Target.z, fZmin, iWindowYMin, f3D2DYCoef);
  690.                         break;
  691.  
  692.                     case XDC_WID_FACE : // X et Y
  693.                         fZ = XDM_to2D(Target.x, fXmin, iWindowXMin, f3D2DXCoef);
  694.                         fT = XDM_to2D(Target.y, fYmin, iWindowYMin, f3D2DYCoef);
  695.                         break;
  696.  
  697.                     case XDC_WID_SIDE : // Z et Y
  698.                         fZ = XDM_to2D(Target.z, fZmin, iWindowXMin, f3D2DXCoef);
  699.                         fT = XDM_to2D(Target.y, fYmin, iWindowYMin, f3D2DYCoef);
  700.                         break;
  701.                 }
  702.                 WDraw(hW3DContext, fX, fY, fZ, fT);
  703. if (bTracking) goto _fastrefresh;
  704.  
  705.                 // 8 - Tracer la cible
  706.                 WDraw(hW3DContext, fZ - 2, fT - 2, fZ + 3, fT + 3);
  707.                 WDraw(hW3DContext, fZ - 2, fT + 2, fZ + 3, fT - 3);
  708.  
  709.                 // 9 - Tracer le curseur 2
  710.                 WSetPen(hW3DContext, XDC_COL_CYAN);
  711.                 switch(lWActive)
  712.                 {
  713.                     case XDC_WID_TOP : // X et Z
  714.                         fX = XDM_to2D(Cursor2.x, fXmin, iWindowXMin, f3D2DXCoef);
  715.                         fY = XDM_to2D(Cursor2.z, fZmin, iWindowYMin, f3D2DYCoef);
  716.                         break;
  717.  
  718.                     case XDC_WID_FACE : // X et Y
  719.                         fX = XDM_to2D(Cursor2.x, fXmin, iWindowXMin, f3D2DXCoef);
  720.                         fY = XDM_to2D(Cursor2.y, fYmin, iWindowYMin, f3D2DYCoef);
  721.                         break;
  722.  
  723.                     case XDC_WID_SIDE : // Z et Y
  724.                         fX = XDM_to2D(Cursor2.z, fZmin, iWindowXMin, f3D2DXCoef);
  725.                         fY = XDM_to2D(Cursor2.y, fYmin, iWindowYMin, f3D2DYCoef);
  726.                         break;
  727.                 }
  728.                 WDraw(hW3DContext, fX - 4, fY, fX + 5, fY);
  729.                 WDraw(hW3DContext, fX, fY - 4, fX, fY + 5);
  730.  
  731.                 // 10 - Tracer le curseur 3
  732.                 switch(lWActive)
  733.                 {
  734.                     case XDC_WID_TOP : // X et Z
  735.                         fX = XDM_to2D(Cursor3.x, fXmin, iWindowXMin, f3D2DXCoef);
  736.                         fY = XDM_to2D(Cursor3.z, fZmin, iWindowYMin, f3D2DYCoef);
  737.                         break;
  738.  
  739.                     case XDC_WID_FACE : // X et Y
  740.                         fX = XDM_to2D(Cursor3.x, fXmin, iWindowXMin, f3D2DXCoef);
  741.                         fY = XDM_to2D(Cursor3.y, fYmin, iWindowYMin, f3D2DYCoef);
  742.                         break;
  743.  
  744.                     case XDC_WID_SIDE : // Z et Y
  745.                         fX = XDM_to2D(Cursor3.z, fZmin, iWindowXMin, f3D2DXCoef);
  746.                         fY = XDM_to2D(Cursor3.y, fYmin, iWindowYMin, f3D2DYCoef);
  747.                         break;
  748.                 }
  749.                 WDraw(hW3DContext, fX - 4, fY - 4, fX + 5, fY + 5);
  750.                 WDraw(hW3DContext, fX - 4, fY + 4, fX + 5, fY - 5);
  751.  
  752. _fastrefresh:
  753. #ifdef XDC_LOCKBITMAP
  754.                 // Déverrouiller le bitmap
  755.                 UnLockBitMap(hBM);
  756. #endif
  757.  
  758.                 // Déverrouiller le hardware 3D
  759.                 W3D_UnLockHardware(hW3DContext);
  760.  
  761.                 // Si triple buffer, blitter dans la fenêtre
  762.                 if (hbTBuf)
  763.                     ClipBlit(hdcTBuf, hWnd -> BorderLeft, hWnd -> BorderTop,
  764.                              hdcWin, hWnd -> BorderLeft, hWnd -> BorderTop,
  765.                              rExtRect.right, rExtRect.bottom,
  766.                              0xc0);
  767.  
  768.                 // Rappeller l'outil courant à coté du curseur
  769.                 if (cTool != XDC_TOOL_NONE)
  770.                     ExtTextOut(hdcWin, iZ + 2, iT  - 13, 0, (RECT *) NULL, &cTool, 1, (int *) NULL);
  771.  
  772.                 // 10 - Coordonnées courantes
  773.                 if (bCoords)
  774.                 {
  775.                     sprintf(cCoords, "(%012.5f, %012.5f, %012.5f)", vTracker.x, vTracker.y, vTracker.z);
  776.                     ExtTextOut(hdcWin, 18, 10, 0, (RECT *) NULL, cCoords, strlen(cCoords), (int *) NULL);
  777.                 }
  778.  
  779.                 // Libérer le clipping de la fenêtre : déporté dans WM_SIZE et WM_DESTROY
  780.                 break;
  781.             }
  782.  
  783.         case WM_LBUTTONDOWN : //**************** C L I C K  G A U C H E *******************
  784. #ifndef _AMIGA_
  785.             RECT rClipCurseur;
  786. #endif
  787.  
  788.             // Si on est déjà en tracking curseur alors ne rien faire
  789.             if (bTracking) break;
  790.  
  791.             // Noter le qualifier (touches enfoncées au moment du click)
  792.             wModifier = wParam;
  793.  
  794.             // Précalculer les offsets (déplacement, zoom, etc.) en fonction du modifieur
  795.             fXs = (fXmax - fXmin) / ((wModifier & IEQUALIFIER_LSHIFT) ? 4.f : 8.f),
  796.             fYs = (fYmax - fYmin) / ((wModifier & IEQUALIFIER_LSHIFT) ? 4.f : 8.f),
  797.             fZs = (fZmax - fZmin) / ((wModifier & IEQUALIFIER_LSHIFT) ? 4.f : 8.f);
  798.             
  799.             // Vérifier si le click n'est pas dans les boutons Sculpt.
  800.             pClick.x = LOWORD(lParam);
  801.             pClick.y = HIWORD(lParam);
  802.  
  803.             if (XDM_BoutonClic(XDC_GID_MakeTri, pClick)) //********* Bouton MakeTri
  804.             {
  805.                 int iPoint[3], iPoints = 0;
  806.  
  807.                 // Compter et mémoriser les points sélectionnés (jusqu'à 3)
  808.                 for (int iVertex = 0 ; iVertex <= iVertLastUsed ; iVertex++)
  809.                     if (bIsVertexSelected(iVertex))
  810.                     {
  811.                         if (iPoints < 3) iPoint[iPoints] = iVertex;
  812.                         iPoints++;
  813.                     }
  814.  
  815.                 // - soit il existe exactement 2 points sélectionnés et on fait une arête avec
  816.                 //   si elle n'existe pas déjà
  817.                 //   (on ne transforme pas 3 points reliés par 3 arêtes en triangle ***???)
  818.                 if (iPoints == 2)
  819.                 {
  820.                     vTrace("Deux points sélectionnés -> création arête");
  821.  
  822.                     if (-1 == iFindEdge(iPoint[0], iPoint[1]))
  823.                     {
  824.                         iMakeEdge(iPoint[0], iPoint[1]);
  825.                         vForce2DRefresh(XDC_MODE_COMPLET);
  826.                         vForce3DRefresh(XDC_MODE_COMPLET);
  827.                     }
  828.                     else
  829.                         vTrace("*** E0001 : L'arête existe déjà");
  830.                     break;
  831.                 }
  832.  
  833.                 // - soit il existe exactement 3 points sélectionnés et on fait un triangle avec
  834.                 //   (en supprimant les arêtes éventuelles existant entre ces 3 points) s'il n'existe pas déjà
  835.                 if (iPoints == 3)
  836.                 {
  837.                     vTrace("Trois points sélectionnés -> création facette");
  838.  
  839.                     if (-1 == iFindTriangle(iPoint[0], iPoint[1], iPoint[2]))
  840.                     {
  841.                         iMakeTriangle(iPoint[0], iPoint[1], iPoint[2], 0);
  842.                         vForce2DRefresh(XDC_MODE_COMPLET);
  843.                         vForce3DRefresh(XDC_MODE_COMPLET);
  844.                     }
  845.                     else
  846.                         vTrace("*** E0002 : Le triangle existe déjà");
  847.                     break;
  848.                 }
  849.  
  850.                 // - soit il existe exactement 0 points sélectionnés et on fait un triangle entre
  851.                 //   les 3 curseurs s'il n'existe pas déjà
  852.                 if (iPoints == 0)
  853.                 {
  854.                     vTrace("Zéro points sélectionnés -> création facette avec les 3 curseurs");
  855.                     iPoint[0] = iMakeVertex(Cursor2, XDC_ALLOWSAME),
  856.                     iPoint[1] = iMakeVertex(Cursor1, XDC_ALLOWSAME),
  857.                     iPoint[2] = iMakeVertex(Cursor3, XDC_ALLOWSAME);
  858.  
  859.                     if (-1 == iFindTriangle(iPoint[0], iPoint[1], iPoint[2]))
  860.                     {
  861.                         iMakeTriangle(iPoint[0], iPoint[1], iPoint[2], 0);
  862.                         vForce2DRefresh(XDC_MODE_COMPLET);
  863.                         vForce3DRefresh(XDC_MODE_COMPLET);
  864.                     }
  865.                     else
  866.                         vTrace("*** E0003 : Le triangle existe déjà");
  867.                     break;
  868.                 }
  869.  
  870.                 vTrace("*** E0004 : Nombre de points sélectionnés incorrect (doit être 0, 2 ou 3)");
  871.                 break;
  872.             }
  873.  
  874.             if (XDM_BoutonClic(XDC_GID_ZoomOut, pClick)) //********* Bouton Zoom Out
  875.             {
  876.                 fXmin -= fXs; fXmax += fXs;
  877.                 fYmin -= fYs; fYmax += fYs;
  878.                 fZmin -= fZs; fZmax += fZs;
  879.  
  880.                 vForce2DRefresh(XDC_MODE_COMPLET);
  881.                 break;
  882.             }
  883.  
  884.             if (XDM_BoutonClic(XDC_GID_ZoomIn, pClick)) //********* Bouton Zoom In
  885.             {
  886.                 fXmin += fXs; fXmax -= fXs;
  887.                 fYmin += fYs; fYmax -= fYs;
  888.                 fZmin += fZs; fZmax -= fZs;
  889.  
  890.                 vForce2DRefresh(XDC_MODE_COMPLET);
  891.                 break;
  892.             }
  893.  
  894.             if (    (XDM_BoutonClic(XDC_GID_RotClock, pClick)) //********* Bouton Rotation clockwise
  895.                  || (XDM_BoutonClic(XDC_GID_RotAnti, pClick))  //********* Bouton Rotation anti-clockwise
  896.                )
  897.             {
  898.                 D3DMATRIX mRot;
  899.                 float fAngle = g_PI / (wModifier & MK_SHIFT ? 10.f : 20.f);
  900.  
  901.                 if (XDM_BoutonClic(XDC_GID_RotClock, pClick)) fAngle *= -1.f;
  902.  
  903.                 // Préparer la matrice de rotation
  904.                 switch(lWActive)
  905.                 {
  906.                 case XDC_WID_TOP : // X et Z
  907.                     D3DUtil_SetRotateYMatrix(mRot, -fAngle);
  908.                     break;
  909.  
  910.                 case XDC_WID_FACE : // X et Y
  911.                     D3DUtil_SetRotateZMatrix(mRot, fAngle);
  912.                     break;
  913.                 
  914.                 case XDC_WID_SIDE : // Z et Y
  915.                     D3DUtil_SetRotateXMatrix(mRot, -fAngle);
  916.                     break;
  917.                 }
  918.  
  919.                 // Appliquer la matrice aux sommets sélectionnés
  920.                 for (int iVertex = 0 ; iVertex <= iVertLastUsed ; iVertex++)
  921.                     if (bIsVertexSelected(iVertex))
  922.                     {
  923.                         // Changer de repère => Cursor1
  924.                         D3DVECTOR vTrans = Vertices[iVertex].vPoint - Cursor1;
  925.                     
  926.                         // Appliquer la rotation au point translaté
  927.                         D3DMath_VectorMatrixMultiply(vTrans,
  928.                                                      vTrans,
  929.                                                      mRot);
  930.  
  931.                         // Remettre dans le repère d'origine
  932.                         Vertices[iVertex].vPoint = vTrans + Cursor1;
  933.                     }
  934.  
  935.                 // Rafraichir les vues 2D et 3D
  936.                 vForce2DRefresh(XDC_MODE_COMPLET);
  937.                 vForce3DRefresh(XDC_MODE_COMPLET);
  938.                 break;
  939.             }
  940.  
  941.             if (XDM_BoutonClic(XDC_GID_Reverse, pClick)) // ********* Bouton reverse (?)
  942.             {
  943.                 break;
  944.             }
  945.  
  946.             if (XDM_BoutonClic(XDC_GID_Grab, pClick)) // ********* Bouton Grabber (toggle)
  947.             {
  948.                 cTool = (cTool == XDC_TOOL_GRAB ? XDC_TOOL_NONE : XDC_TOOL_GRAB);
  949.                 vForce2DRefresh(XDC_MODE_PARTIEL);
  950.                 vUpdateMenu();
  951.                 break;
  952.             }
  953.  
  954.             if (XDM_BoutonClic(XDC_GID_GoRight, pClick)) //********* Bouton Go Right
  955.             {
  956.                 switch(lWActive)
  957.                 {
  958.                     case XDC_WID_TOP : // X et Z
  959.                     case XDC_WID_FACE : // X et Y
  960.                         fXmin += fXs; fXmax += fXs;
  961.                         break;
  962.                     case XDC_WID_SIDE : // Z et Y
  963.                         fZmin += fZs; fZmax += fZs;
  964.                         break;
  965.                 }
  966.  
  967.                 vForce2DRefresh(XDC_MODE_COMPLET);
  968.                 break;
  969.             }
  970.  
  971.             if (XDM_BoutonClic(XDC_GID_GoUp, pClick)) //********* Bouton Go up
  972.             {
  973.                 switch(lWActive)
  974.                 {
  975.                     case XDC_WID_TOP : // X et Z
  976.                         fZmin += fZs; fZmax += fZs;
  977.                         break;
  978.                     case XDC_WID_FACE : // X et Y
  979.                     case XDC_WID_SIDE : // Z et Y
  980.                         fYmin += fYs; fYmax += fYs;
  981.                         break;
  982.                 }
  983.  
  984.                 vForce2DRefresh(XDC_MODE_COMPLET);
  985.                 break;
  986.             }
  987.  
  988.             if (XDM_BoutonClic(XDC_GID_GoLeft, pClick)) //********* Bouton Go left
  989.             {
  990.                 switch(lWActive)
  991.                 {
  992.                     case XDC_WID_TOP : // X et Z
  993.                     case XDC_WID_FACE : // X et Y
  994.                         fXmin -= fXs; fXmax -= fXs;
  995.                         break;
  996.                     case XDC_WID_SIDE : // Z et Y
  997.                         fZmin -= fZs; fZmax -= fZs;
  998.                         break;
  999.                 }
  1000.  
  1001.                 vForce2DRefresh(XDC_MODE_COMPLET);
  1002.                 break;
  1003.             }
  1004.  
  1005.             if (XDM_BoutonClic(XDC_GID_GoDown, pClick)) //********* Bouton Go down
  1006.             {
  1007.                 switch(lWActive)
  1008.                 {
  1009.                     case XDC_WID_TOP : // X et Z
  1010.                         fZmin -= fZs; fZmax -= fZs;
  1011.                         break;
  1012.                     case XDC_WID_FACE : // X et Y
  1013.                     case XDC_WID_SIDE : // Z et Y
  1014.                         fYmin -= fYs; fYmax -= fYs;
  1015.                         break;
  1016.                 }
  1017.  
  1018.                 vForce2DRefresh(XDC_MODE_COMPLET);
  1019.                 break;
  1020.             }
  1021.  
  1022.             if (XDM_BoutonClic(XDC_GID_AddPoint, pClick)) //********* Bouton Add Point
  1023.             {
  1024.                 PostMessage(hWnd, WM_CHAR, 'p', 0);
  1025.                 break;
  1026.             }
  1027.  
  1028.             if (XDM_BoutonClic(XDC_GID_Center, pClick)) //********* Bouton Center
  1029.             {
  1030.                 float    fXs = (fXmax - fXmin) / 2.f,
  1031.                         fYs = (fYmax - fYmin) / 2.f,
  1032.                         fZs = (fZmax - fZmin) / 2.f;
  1033.                 
  1034.                 fXmin = Cursor1.x - fXs; fXmax = Cursor1.x + fXs;
  1035.                 fYmin = Cursor1.y - fYs; fYmax = Cursor1.y + fYs;
  1036.                 fZmin = Cursor1.z - fZs; fZmax = Cursor1.z + fZs;
  1037.  
  1038.                 vForce2DRefresh(XDC_MODE_COMPLET);
  1039.                 break;
  1040.             }
  1041.  
  1042.             // Si click dans le rectangle interne, alors :
  1043.             // - déclencher le tracking (curseur, observer ou target en fonction du qualifier
  1044.             // - n'autoriser le déplacement que dans le subrect client (clipcursor)
  1045.             // - initialiser le tracking (MOUSEMOVE)
  1046.             if (PtInRect(&rIntRect, pClick))
  1047.             {
  1048. #ifndef _AMIGA_ // Pas de fonction permettant le clipping curseur
  1049.                 CopyRect(&rClipCurseur, &rIntRect);
  1050.                 ClientToScreen(hWnd, (POINT *) &rClipCurseur);
  1051.                 ClientToScreen(hWnd, (POINT *) &rClipCurseur + 1);
  1052.                 ClipCursor(&rClipCurseur);
  1053. #endif
  1054.                 bTracking = TRUE;
  1055.                 ReportMouse(TRUE, hWnd);
  1056.                 PostMessage(hWnd, WM_MOUSEMOVE, wParam, lParam);
  1057.                 break;
  1058.  
  1059.             }
  1060.  
  1061.             break;
  1062.  
  1063.         case WM_LBUTTONDBLCLK:
  1064.             pClick.x = LOWORD(lParam);
  1065.             pClick.y = HIWORD(lParam);
  1066.  
  1067.             // Si le double click est dans le rectangle interne alors toggler la sélection du noeud indiqué
  1068.             // en envoyant le message ID_EDITION_SLECTIONNER_NOEUDINDIQU à la fenêtre menu avec lParam = XDC_TOGGLE
  1069.             // Sinon, traiter le message comme un simple click
  1070.             if (PtInRect(&rIntRect, pClick))
  1071.                 PostMessage(hWndMenu, WM_COMMAND, ID_EDITION_SLECTIONNER_NOEUDINDIQU, XDC_SINGLETOGGLE);
  1072.             else
  1073.                 PostMessage(hWnd, WM_LBUTTONDOWN, wParam, lParam);
  1074.             break;
  1075.  
  1076.         case WM_LBUTTONUP : //******************** R E L A C H E  B O U T O N  G A U C H E ******
  1077. /*
  1078.             // (ou envoyer les coordonnées à la dlg d'acquisition des trous des formes à remplir si elle est active).
  1079.             if (hHoleDlgActive)
  1080.             {
  1081.                 switch(lWActive)
  1082.                 {
  1083.                     case XDC_WID_TOP : // X et Z
  1084.                         dHoles[iHoles * 2 + 0] = XDM_to3D(LOWORD(lParam), fXmin, iWindowXMin, f3D2DXCoef);
  1085.                         dHoles[iHoles * 2 + 1] = XDM_to3D(HIWORD(lParam), fZmin, iWindowYMin, f3D2DYCoef);
  1086.                         break;
  1087.                     case XDC_WID_FACE : // X et Y
  1088.                         dHoles[iHoles * 2 + 0] = XDM_to3D(LOWORD(lParam), fXmin, iWindowXMin, f3D2DXCoef);
  1089.                         dHoles[iHoles * 2 + 1] = XDM_to3D(HIWORD(lParam), fYmin, iWindowYMin, f3D2DYCoef);
  1090.                         break;
  1091.                     case XDC_WID_SIDE : // Z et Y
  1092.                         dHoles[iHoles * 2 + 0] = XDM_to3D(LOWORD(lParam), fZmin, iWindowXMin, f3D2DXCoef);
  1093.                         dHoles[iHoles * 2 + 1] = XDM_to3D(HIWORD(lParam), fYmin, iWindowYMin, f3D2DYCoef);
  1094.                         break;
  1095.                 }
  1096.                 iHoles++;
  1097.                 SendMessage(hHoleDlgActive, WM_USER+1, 0, 0);
  1098.             }
  1099. */
  1100.             // Si on n'est pas en mode tracking, ne rien faire
  1101.             if (!bTracking)
  1102.                 break;
  1103.  
  1104.             // Si on est en mode tracking, arrêter le mode tracking et supprimer le clipping.
  1105.             bTracking = FALSE;
  1106.  
  1107.             // Arrêter le reporting des mouvements souris sur la fenêtre
  1108.             ReportMouse(FALSE, hWnd);
  1109.  
  1110.             // Forcer le redessin des fenêtres 2D
  1111.             vForce2DRefresh(XDC_MODE_COMPLET);
  1112.  
  1113. //              ClipCursor(NULL);
  1114.             break;
  1115.  
  1116.         case WM_MOUSEMOVE : //****************** M O U V E M E N T  S O U R I S *************
  1117.             D3DVECTOR *pObject;
  1118.  
  1119.             // Si on n'est pas en tracking alors on ne fait rien.
  1120.             if (!bTracking) break;
  1121.  
  1122.             // Déterminer l'objet à déplacer en fonction des qualifiers du WM_LBUTTONDOWN (par défaut, sans qualifiers, c'est le curseur principal)
  1123.             pObject = &Cursor1;
  1124.             if (wModifier & IEQUALIFIER_RALT)       pObject = &Target;
  1125.             if (wModifier & IEQUALIFIER_RCOMMAND)   pObject = &Observer;
  1126.             if (wModifier & IEQUALIFIER_CONTROL)    pObject = &Cursor2;
  1127.             if (wModifier & IEQUALIFIER_LSHIFT)     pObject = &Cursor3;
  1128.  
  1129.             // Mémoriser l'ancien vecteur
  1130.             vVect1 = *pObject;
  1131.  
  1132.             // Déterminer les nouvelles coordonnées 2D de l'objet à déplacer
  1133.             iX = LOWORD(lParam);  // horizontal position 
  1134.             iY = HIWORD(lParam);  // vertical position
  1135.  
  1136.             // Mettre à jour les coordonnées 3D de l'objet à déplacer
  1137.             switch(lWActive)
  1138.             {
  1139.                 case XDC_WID_TOP : // X et Z
  1140.                     pObject -> x = XDM_to3D(iX, fXmin, iWindowXMin, f3D2DXCoef);
  1141.                     pObject -> z = XDM_to3D(iY, fZmin, iWindowYMin, f3D2DYCoef);
  1142.                     break;
  1143.                 case XDC_WID_FACE : // X et Y
  1144.                     pObject -> x = XDM_to3D(iX, fXmin, iWindowXMin, f3D2DXCoef);
  1145.                     pObject -> y = XDM_to3D(iY, fYmin, iWindowYMin, f3D2DYCoef);
  1146.                     break;
  1147.                 case XDC_WID_SIDE : // Z et Y
  1148.                     pObject -> z = XDM_to3D(iX, fZmin, iWindowXMin, f3D2DXCoef);
  1149.                     pObject -> y = XDM_to3D(iY, fYmin, iWindowYMin, f3D2DYCoef);
  1150.                     break;
  1151.             }
  1152.  
  1153.             // Si la grille est activée, snapper l'objet à la grille (en x/y/z)
  1154.             if (bGrid)
  1155.             {
  1156.                 pObject -> x = XDM_toGrid(pObject -> x);
  1157.                 pObject -> y = XDM_toGrid(pObject -> y);
  1158.                 pObject -> z = XDM_toGrid(pObject -> z);
  1159.             }
  1160.  
  1161.             // Mémoriser les coordonnées pour l'affichage des coordonnées
  1162.             if (bCoords) vTracker = *pObject;
  1163.  
  1164.             // Si on a déplacé l'observer ou le target, mettre à jour la VIEW MATRIX
  1165.             // (la vue 3D se met automatiquement à jour par timer dans 3dwndproc)
  1166.             if ((pObject == &Target) || (pObject == &Observer))
  1167.             {
  1168.                 D3DUtil_SetViewMatrix(matView,
  1169.                           Observer,    // From
  1170.                           Target,    // To
  1171.                           D3DVECTOR(0.f, 0.f, 0.f));
  1172.  
  1173.                 // Mettre à jour les variables d'état du pipe D3D
  1174.                 vSetD3DState();
  1175.  
  1176.                 // Recalculer la scène
  1177.                 vForce3DRefresh(XDC_MODE_COMPLET);
  1178.             }
  1179.  
  1180.             // Si on a un outil sélectionné, appliquer l'outil à la sélection
  1181.             if ((pObject == &Cursor1) && (cTool != XDC_TOOL_NONE))
  1182.             {
  1183.                 switch(cTool)
  1184.                 {
  1185.                     case XDC_TOOL_SELECT:
  1186.                         PostMessage(hWndMenu, WM_COMMAND, ID_EDITION_SLECTIONNER_NOEUDINDIQU, XDC_SELECTALL);
  1187.                         break;
  1188.  
  1189.                     case XDC_TOOL_UNSELECT:
  1190.                         PostMessage(hWndMenu, WM_COMMAND, ID_EDITION_SLECTIONNER_NOEUDINDIQU, XDC_DESELECTALL);
  1191.                         break;
  1192.  
  1193.                     case XDC_TOOL_MAGNET:
  1194.                         break;
  1195.  
  1196.                     case XDC_TOOL_CURVE:
  1197.                         break;
  1198.  
  1199.                     case XDC_TOOL_EXTRUDE:
  1200.                         break;
  1201.  
  1202.                     case XDC_TOOL_EDGE:
  1203.                         break;
  1204.  
  1205.                     case XDC_TOOL_GRAB:
  1206.                          // Faire suivre le mouvement du curseur à tous les vertices sélectionnés
  1207.                          for (int iVertex = 0 ; iVertex <= iVertLastUsed ; iVertex++)
  1208.                              if (bIsVertexSelected(iVertex))
  1209.                                  Vertices[iVertex].vPoint += (Cursor1 - vVect1);
  1210.  
  1211.                         // Faire suivre le mouvement du curseur à toutes les lampes sélectionnées
  1212.                         for (int iLamp = 0 ; iLamp <= iLampLastUsed ; iLamp++)
  1213.                         {
  1214.                             if (Lampes[iLamp].bEnabled == FALSE) continue;
  1215.                             if (Lampes[iLamp].bSelected == FALSE) continue;
  1216.  
  1217.                             Lampes[iLamp].lLamp.dvPosition += (Cursor1 - vVect1);
  1218.                             bUpdateLamp(iLamp);
  1219.                         }
  1220.  
  1221.                         vForce2DRefresh(XDC_MODE_COMPLET);
  1222.                         vForce3DRefresh(XDC_MODE_COMPLET);
  1223.                         goto _break;
  1224.                 }
  1225.             }
  1226.  
  1227.             // Forcer le redessin des fenêtres 2D pour prendre en compte le déplacement de l'objet
  1228.             vForce2DRefresh(XDC_MODE_PARTIEL);
  1229. _break:
  1230.             break;
  1231.  
  1232.         case WM_SIZE: //**************** T A I L L E  F E N E T R E ****************
  1233.             // Si le contexte Warp3D n'est pas initialisé, on s'arrête là
  1234.             if (!hW3DContext) return 0;
  1235.  
  1236.             // Détruire et recréer le double buffer avec les nouvelles dimensions de la fenêtre
  1237.             iX = LOWORD(lParam);  // width of client area 
  1238.             iY = HIWORD(lParam);  // height of client area
  1239.  
  1240.             // Supprimer le bitmap offscreen du double buffer s'il est alloué
  1241.             if (pWT -> hbDBuf) FreeBitMap(pWT -> hbDBuf);
  1242.  
  1243.             // Créer le bitmap offscreen du double buffer
  1244.             if (!(pWT -> hbDBuf = AllocBitMap(hWnd -> Width, hWnd -> Height, 8, BMF_MINPLANES | BMF_DISPLAYABLE, hWnd -> RPort -> BitMap)))
  1245.             {
  1246.                 vTrace("*** E0075 : allocation double buffer %s", hWnd -> Title);
  1247.                 return 0;
  1248.             }
  1249.             pWT -> hdcDBuf -> BitMap = pWT -> hbDBuf;
  1250.  
  1251.             // Libérer le clipping de la fenêtre s'il est activé
  1252.             if (pWT -> hClip != (struct Region *) ~NULL)
  1253.             {
  1254.                 UnclipWindow(hWnd);
  1255.                 pWT -> hClip = (struct Region *) ~NULL;
  1256.             }
  1257.  
  1258.                // Remplir l'ensemble de la zone cliente en bleu foncé
  1259.             rExtRect.left   = hWnd -> BorderLeft;
  1260.             rExtRect.right  = iX - hWnd -> BorderRight - 1;
  1261.             rExtRect.top    = hWnd -> BorderTop;
  1262.             rExtRect.bottom = iY - hWnd -> BorderBottom - 1;
  1263.  
  1264.             SetAPen(hdcWin, hpenDkBlueSk);
  1265.             RectFill(hdcWin, rExtRect.left, rExtRect.top, rExtRect.right, rExtRect.bottom);
  1266.  
  1267.             // Séparer les zones int/ext avec tour blanc
  1268.             CopyRect(&rIntRect, &rExtRect);
  1269.             InflateRect(&rIntRect, -XDC_G_LARG, -XDC_G_HAUT);
  1270.  
  1271.             SetAPen(hdcWin, hpenWhite);
  1272.             {
  1273.                 short rRect[10];
  1274.                 rRect[0] = rIntRect.left; rRect[1] = rIntRect.bottom;
  1275.                 rRect[2] = rIntRect.right; rRect[3] = rIntRect.bottom;
  1276.                 rRect[4] = rIntRect.right; rRect[5] = rIntRect.top;
  1277.                 rRect[6] = rIntRect.left; rRect[7] = rIntRect.top;
  1278.                 rRect[8] = rIntRect.left; rRect[9] = rIntRect.bottom;
  1279.                 Move(hdcWin, iWindowXMin, iWindowYMin);
  1280.                 PolyDraw(hdcWin, 5, &rRect[0]);
  1281.             }
  1282.  
  1283.             // Tracer les noms des axes
  1284.             switch(lWActive)
  1285.             {
  1286.                 case XDC_WID_TOP : // Axes X (gauche > droite) et Z (bas > haut)
  1287.                     cAxis = 'z'; ExtTextOut(hdcWin, (rExtRect.right - rExtRect.left) / 2 + 13, -3, 0, (RECT *) NULL, &cAxis, 1, (int *) NULL);
  1288.                     cAxis = 'x'; ExtTextOut(hdcWin, rExtRect.right - XDC_G_LARG + 5, (rExtRect.bottom - rExtRect.top) / 2 + 4, 0, (RECT *) NULL, &cAxis, 1, (int *) NULL);
  1289.                     break;
  1290.  
  1291.                 case XDC_WID_FACE : // Axes X (gauche > droite) et Y (bas > haut)
  1292.                     cAxis = 'y'; ExtTextOut(hdcWin, (rExtRect.right - rExtRect.left) / 2 + 13, -3, 0, (RECT *) NULL, &cAxis, 1, (int *) NULL);
  1293.                     cAxis = 'x'; ExtTextOut(hdcWin, rExtRect.right - XDC_G_LARG + 5, (rExtRect.bottom - rExtRect.top) / 2 + 4, 0, (RECT *) NULL, &cAxis, 1, (int *) NULL);
  1294.                     break;
  1295.  
  1296.                 case XDC_WID_SIDE : // Axes Z (gauche > droite) et Y (bas > haut)
  1297.                     cAxis = 'y'; ExtTextOut(hdcWin, (rExtRect.right - rExtRect.left) / 2 + 13, -3, 0, (RECT *) NULL, &cAxis, 1, (int *) NULL);
  1298.                     cAxis = 'z'; ExtTextOut(hdcWin, rExtRect.right - XDC_G_LARG + 5, (rExtRect.bottom - rExtRect.top) / 2 + 4, 0, (RECT *) NULL, &cAxis, 1, (int *) NULL);
  1299.                     break;
  1300.             }
  1301.  
  1302.             // Ajouter tous les gadgets Sculpt
  1303.             XDM_Bouton(pWT -> Widgets[XDC_GID_AddPoint], rExtRect.left, rExtRect.top + 11);
  1304.             XDM_Bouton(pWT -> Widgets[XDC_GID_Center], XDC_G_LARG + 6, rExtRect.bottom - XDC_G_HAUT + 1);
  1305.             XDM_Bouton(pWT -> Widgets[XDC_GID_GoDown], (rExtRect.right - rExtRect.left) / 2 - 4, rExtRect.bottom - XDC_G_HAUT + 1);
  1306.             XDM_Bouton(pWT -> Widgets[XDC_GID_GoLeft], rExtRect.left, (rExtRect.bottom - rExtRect.top) / 2 + 6);
  1307.             XDM_Bouton(pWT -> Widgets[XDC_GID_GoUp], (rExtRect.right - rExtRect.left) / 2 - 4, rExtRect.top);
  1308.             XDM_Bouton(pWT -> Widgets[XDC_GID_GoRight], rExtRect.right - XDC_G_LARG + 1, (rExtRect.bottom - rExtRect.top) / 2 + 6);
  1309.             XDM_Bouton(pWT -> Widgets[XDC_GID_Grab], rExtRect.left, rExtRect.bottom - XDC_G_HAUT + 1);
  1310.             XDM_Bouton(pWT -> Widgets[XDC_GID_MakeTri], rExtRect.left, rExtRect.bottom - 19);
  1311.             XDM_Bouton(pWT -> Widgets[XDC_GID_Reverse], rExtRect.right - XDC_G_LARG + 1, 26);
  1312.             XDM_Bouton(pWT -> Widgets[XDC_GID_RotAnti], rExtRect.left, rExtRect.top);
  1313.             XDM_Bouton(pWT -> Widgets[XDC_GID_RotClock], XDC_G_LARG + 6, rExtRect.top);
  1314.             XDM_Bouton(pWT -> Widgets[XDC_GID_ZoomIn], rExtRect.right - 36, rExtRect.bottom - XDC_G_HAUT + 1);
  1315.             XDM_Bouton(pWT -> Widgets[XDC_GID_ZoomOut], rExtRect.right - XDC_G_LARG + 1, rExtRect.bottom - 20);
  1316.  
  1317.             // Définir la zone de clipping : rectangle interne
  1318.             pWT -> hClip = ClipWindow(hWnd,
  1319.                 rExtRect.left,
  1320.                 rExtRect.top,
  1321.                 rExtRect.right,
  1322.                 rExtRect.bottom);
  1323.  
  1324.             // Blitter la fenêtre dans le double buffer
  1325.             ClipBlit(hdcWin, hWnd -> BorderLeft, hWnd -> BorderTop,
  1326.                      pWT -> hdcDBuf, hWnd -> BorderLeft, hWnd -> BorderTop,
  1327.                      iX - hWnd -> BorderRight - 1, iY - hWnd -> BorderBottom - 1,
  1328.                      0xC0);
  1329.  
  1330.             // Déterminer s'il faut réallouer le triple buffer :
  1331.             // - s'il n'est pas déjà alloué ou
  1332.             // - s'il est plus petit que la fenêtre redimensionnée ou
  1333.             // - s'il est plus grand que les trois fenêtres
  1334.             {
  1335.                 int iXMax = 0, iYMax = 0;
  1336.                 if (iXMax < hWndTop -> Width) iXMax = hWndTop -> Width;
  1337.                 if (iXMax < hWndFace -> Width) iXMax = hWndFace -> Width;
  1338.                 if (iXMax < hWndRight -> Width) iXMax = hWndRight -> Width;
  1339.                 if (iYMax < hWndTop -> Height) iYMax = hWndTop -> Height;
  1340.                 if (iYMax < hWndFace -> Height) iYMax = hWndFace -> Height;
  1341.                 if (iYMax < hWndRight -> Height) iYMax = hWndRight -> Height;
  1342.                 iX = GetBitMapAttr(hbTBuf, BMA_WIDTH);
  1343.                 iY = GetBitMapAttr(hbTBuf, BMA_HEIGHT);
  1344.  
  1345.                 if (!hbTBuf || iX != iXMax || iY != iYMax)
  1346.                 {
  1347.                     InitRastPort(hdcTBuf);
  1348.                     if (hbTBuf) FreeBitMap(hbTBuf);
  1349.  
  1350.                     // Créer le bitmap offscreen du triple buffer
  1351.                     if (!(hbTBuf = AllocBitMap(iXMax, iYMax, 8, BMF_MINPLANES | BMF_DISPLAYABLE, hWnd -> RPort -> BitMap)))
  1352.                     {
  1353.                         vTrace("*** E0076 : allocation triple buffer %d x %d", iXMax, iYMax);
  1354.                         break;
  1355.                     }
  1356.                     hdcTBuf -> BitMap = hbTBuf;
  1357.                     vTrace("%s : Redim. triple buffer %d x %d ok", hWnd -> Title, iXMax, iYMax);
  1358.                 }
  1359.             }
  1360.  
  1361.             // Forcer le redessin complet de la fenêtre
  1362.             PostMessage(hWnd, WM_PAINT, 0, (LPARAM) XDC_MODE_COMPLET);
  1363.  
  1364.             break;
  1365.  
  1366.         case WM_COMMAND: // Rediriger les frappes clavier et chois menus vers la fenêtre menus
  1367.         case WM_CHAR :
  1368.             PostMessage(hWndMenu, uMsg, wParam, lParam );
  1369.             break;
  1370.  
  1371.         case WM_DESTROY:
  1372.             // Libérer les objets GDI
  1373.             if (hpenWhite)        { DeleteObject(hInst -> ViewPort.ColorMap, hpenWhite);        hpenWhite = NULL; }
  1374.             if (hpenRed)        { DeleteObject(hInst -> ViewPort.ColorMap, hpenRed);        hpenRed = NULL; }
  1375.             if (hpenYellow)        { DeleteObject(hInst -> ViewPort.ColorMap, hpenYellow);        hpenYellow = NULL; }
  1376.             if (hpenCyan)        { DeleteObject(hInst -> ViewPort.ColorMap, hpenCyan);        hpenCyan = NULL; }
  1377.             if (hpenPink)        { DeleteObject(hInst -> ViewPort.ColorMap, hpenPink);        hpenPink = NULL; }
  1378.             if (hpenGrey)        { DeleteObject(hInst -> ViewPort.ColorMap, hpenGrey);        hpenGrey = NULL; }
  1379.             if (hpenLtBlueSk)    { DeleteObject(hInst -> ViewPort.ColorMap, hbrLtBlueSk);    hbrLtBlueSk = NULL; }
  1380.             if (hpenDkBlueSk)    { DeleteObject(hInst -> ViewPort.ColorMap, hpenDkBlueSk);    hpenDkBlueSk = NULL; }
  1381.  
  1382.             // Libérer le clipping de la fenêtre s'il est activé
  1383.             if (pWT -> hClip != (struct Region *) ~NULL)
  1384.             {
  1385.                 UnclipWindow(hWnd);
  1386.                 pWT -> hClip = (struct Region *) ~NULL;
  1387.             }
  1388.  
  1389.             // Supprimer le bitmap offscreen du double buffer s'il est alloué
  1390.             if (pWT -> hbDBuf) FreeBitMap(pWT -> hbDBuf);
  1391.  
  1392.             // Détruire la structure de données attachée à la fenêtre
  1393.             free(pWT);
  1394.  
  1395.             // Supprimer le bitmap offscreen du triple buffer s'il est alloué
  1396.             if (hbTBuf)
  1397.             {
  1398.                 FreeBitMap(hbTBuf);
  1399.                 hbTBuf = NULL;
  1400.             }
  1401.  
  1402.             PostQuitMessage(0);
  1403.             return 0L;
  1404.     }
  1405.     return 0;
  1406. }
  1407.  
  1408.