{ Testing the wDraw3DFrame.pp unit.
  Drawing of objects in the 3D space.
  You can see a projection of them on the screen, of if you use
  Red and Green galsses, you can see them in the space, behind or
  in front of the screen.
  The colors can be changed in the program.
     Many different Bodies can be defines and viewed.
  --------------------------------------------}
program tEx057;

// To tell FreePascal that the application is a Graphical User Interface
// i.e. is running in windows, not in text mode.
{$APPTYPE GUI}

Uses

  wApplication0
 ,wWindow0
 ,wVariableNumLink2
 ,wDialogCreatorLow2
 ,wUtiles0
 ,wDraw3DFrame0
 ,xVectR3
 ,wMessages2
 ,wGlobals2
 ,wDebug0
 ,Windows;

type
  PMyWindow = ^TMyWindow;
  TMyWindow = object(TWindow)
  //"""""""""""""""""""""""""
  poDraw3D : PDraw3DFrame;

  MAXFACES,  // Maximum number of faces to put in the space world
  MAXPOINTS  // Maximum number of points to put in the space world
             : word32;

  vecNewCenterPos : RVectR3Float;
  // To translate each new body, and place them on a line

  constructor Init(strWinTitlePrm:ShortString);
  destructor Done; virtual;
  procedure WinCreate(strWinClass:ShortString); virtual;

  procedure NewSpaceWorld;

  procedure FinalBodySetup;

  procedure ASurface;
  procedure ATorus;
  procedure AnEllipsoide;
  procedure ACube;
  procedure ATwistedTorus;
  procedure AMobiusRibbon;
  procedure ASpecialTorus;
  procedure SimpleSphere;
  procedure SimpleTetrahedron;
  procedure SimpleCube;
  procedure SimpleOctahedron;
  procedure SimpleDodecahedron;
  procedure SimpleIcosahedron;

  procedure TestZ; // To test special cases

  procedure ToggleView3D(fRedrawP:boolean);
  // Change the 3D viewing, with glasses or without glasses
  // Can be done with the contextual menu (Right click) also

  function WMCommand(wPar:WPARAM; lPar:LPARAM):LRESULT; virtual;
  // Handles the menu messages

  function WindowProc(hWindow:HWND; wMsg:UINT; wPar:WPARAM; lPar:LPARAM):LRESULT; virtual;
  end; // TMyWindow = object(TWindow)

var
  oApp        : TApplication;
  poMyMainWin : PMyWindow;

// var nNotUsed : integer; // only to avoid an error message while compliling in DevPascal 1.9

constructor TMyWindow.Init(strWinTitlePrm:ShortString);
//=====================================================
begin
inherited Init(strWinTitlePrm);

// To have a default at starting
MAXFACES  := 20100;
MAXPOINTS := 21000;

new(poDraw3D, Init(@Self));

vecNewCenterPos:=gglvecV3Zero;

// This line is all what is needed to have a status line.
new(poStatusLine, Init(@Self));
end;  // TMyWindow.Init

destructor TMyWindow.Done;
//=========================
begin
// Do not dispose poDraw3D, already done by the parent
inherited Done;
end;  // TMyWindow.Done

procedure TMyWindow.WinCreate(strWinClass:ShortString);
//=====================================================
// Create the window, and insert an edit box and a status line in it.
var wErrorL : word32;
begin
inherited WinCreate(strWinClass);

poDraw3D^.nYSizePix:=poDraw3D^.nYSizePix - int32(poStatusLine^.wHeight);
poDraw3D^.CtrlCreate;
SetFocus(poDraw3D^.hWin);

// Allocate memory for 11000 points and 10100 faces
poDraw3D^.AllocateMemory(MAXPOINTS, MAXFACES, wErrorL); // Hope there is no errors

// Viewing position and screen center in centimeters
// This defines also the distance between the viwer and the screen
poDraw3D^.Draw3DSetup(-9.0, -78.0, 10.0, 0, 0, 0); // Screen at (0,0,0)
end;  // TMyWindow.WinCreate

procedure TMyWindow.NewSpaceWorld;
//================================
// Clear the actual object in the space, define the maximum number of
// points and face, and reset all
var
  wMAXPOINTSNew,
  wMAXFACESNew,
  wErrorL : word32;
  nRep    : integer;
  vMemSize : Float; // Memory space allocated to store the points and faces

begin
// To define a new number of points and faces
wMAXPOINTSNew:=MAXPOINTS;
wMAXFACESNew :=MAXFACES;
Word32Field(1001, wMAXFACESNew);
Word32Field(1002, wMAXPOINTSNew);
Word32Field(1011, MAXFACES);
Word32Field(1012, MAXPOINTS);
FloatField( 1003, vMemSize);

// Last size of memory allocated
vMemSize:=(MAXPOINTS * SizeOf(TypePoint3D) +
           MAXFACES * SizeOf(TypeFace3D)) / 1000000.0;

nRep:=DialogExecMSG(12299, @Self);

if (nRep <> IDOK) then exit;

vMemSize:=(wMAXPOINTSNew * SizeOf(TypePoint3D) +
           wMAXFACESNew * SizeOf(TypeFace3D)) / 1000000.0;
if (vMemSize > 50) then begin
    // Very big amount of space, ask confirmation
   nRep:=DialogExecMSG(12399, @Self);

   if (nRep <> IDOK) then exit;
   end;

// Only here, accept the modifications
MAXPOINTS:=wMAXPOINTSNew;
MAXFACES :=wMAXFACESNew;

// Dispose the actual space world
dispose(poDraw3D, Done);
vecNewCenterPos:=gglvecV3Zero;

// create a new one
new(poDraw3D, Init(@Self));

// Size on the screen
poDraw3D^.nYSizePix:=poDraw3D^.nYSizePix - int32(poStatusLine^.wHeight);

// Create the corresponding control (A very sofisticated control !)
poDraw3D^.CtrlCreate;
SetFocus(poDraw3D^.hWin);

// Allocate memory for 11000 points and 10100 faces
poDraw3D^.AllocateMemory(MAXPOINTS, MAXFACES, wErrorL); // Hope there is no errors

// Viewing position and screen center in centimeters
// This defines also the distance between the viwer and the screen
poDraw3D^.Draw3DSetup(-9.0, -78.0, 10.0, 0, 0, 0); // Screen at (0,0,0)
end;  // TMyWindow.NewSpaceWorld

procedure TMyWindow.FinalBodySetup;
//=================================
begin
with poDraw3D^ do begin
   // This defines the number of points and faces in the Body
   // It defines also the colors. Must be called.
   papoBodies^[wNumBodies]^.BodySetup(0,0,0);

   // Positionning of the Body (must be called after the Body Setup
   papoBodies^[wNumBodies]^.BodySetPosition(vecNewCenterPos);

   vecNewCenterPos:=vecNewCenterPos + V3Assign(-14.0, 0, 0); // [cm]

   // This defines the rotation center
   vecRotationCenter :=papoBodies^[wNumBodies]^.vecGravityCenter;

   // Define the Position of the screen in the space.
   // This doesn't change the viewing direction, and moves the viewer.
//   SetScreenCenter(vecCenterGravity);

   // Define the viewing direction, without modifying the viewer position
   // Sets again the right horizontal.
   SetViewDirection(vecRotationCenter);
   end; // with
end;  // TMyWindow.FinalBodySetup

procedure TMyWindow.ASurface;
//===========================
const
  nMinX =-15;
  nMaxX = 15;
  nMinY =-15;
  nMaxY = 15;
  nDY   = 1 + nMaxY - nMinY;
var
  nX,nY       : int32;
  prPtOrg,    // point corresponding to the origine
  prPtX,      // point (1,0,0)
  prPtY,      // point (0,1,0)
  prPtZ       // point (0,0,1)
              : PTypePoint3D;
  parPtsL     : PArrayPoint3D;

begin
with poDraw3D^ do begin
   // Test that there is enough space to add a Body
   if (wNumPoints + word32((nMaxX-nMinX)*nDY + nMaxY-nMinY) +5 > MAXPOINTS) or
      (wNumFaces  + word32((nMaxX-nMinX)*(nMaxY-nMinY)) + 4 > MAXFACES) then begin
      DialogExecMSG(12099, @Self);
      exit;
      end;

   parPtsL:=@parPoints^[wNumPoints+1];

   // Creates a new body
   inc(wNumBodies);
   new(papoBodies^[wNumBodies], Init(poDraw3D));

   // Add the points. Units = centimeters
   for nX:=nMinX to nMaxX do
   for nY:=nMinY to nMaxY do begin
      // Add one point
      with parPtsL^[(nX-nMinX)*nDY + nY-nMinY] do begin
         vecV[1]:=nX / Float(nMaxX); // in [-1..1]
         vecV[2]:=nY / Float(nMaxY); // in [-1..1]
         vecV[3]:=exp(-(3*sqr(vecV[1]-0.6) + 9*sqr(vecV[2]-0.25)));
         vecV:=5.0*vecV;
         end; // with
      end;

   wNumPoints:=wNumPoints + word32((nMaxX-nMinX)*nDY + nMaxY-nMinY) +1;

   // Add the faces
   for nX:=nMinX to nMaxX-1 do
   for nY:=nMinY to nMaxY-1 do begin
      inc(wNumFaces);
      with parFaces^[wNumFaces] do begin
         nNbPoint:=4;
         aprPoint[1]:=@parPtsL^[(  nX-nMinX)*nDY +   nY-nMinY];
         aprPoint[2]:=@parPtsL^[(1+nX-nMinX)*nDY +   nY-nMinY];
         aprPoint[3]:=@parPtsL^[(1+nX-nMinX)*nDY + 1+nY-nMinY];
         aprPoint[4]:=@parPtsL^[(  nX-nMinX)*nDY + 1+nY-nMinY];
         end; // with
      end; // for

   // Add some points to draw the axis
   inc(wNumPoints);   prPtOrg:=@parPoints^[wNumPoints];
   with parPoints^[wNumPoints] do begin
      vecV[1]:=0;  vecV[2]:=0;  vecV[3]:=0;
      end; // with

   inc(wNumPoints);   prPtX:=@parPoints^[wNumPoints];
   with parPoints^[wNumPoints] do begin
      vecV[1]:=15;  vecV[2]:=0;  vecV[3]:=0;
      end; // with

   inc(wNumPoints);   prPtY:=@parPoints^[wNumPoints];
   with parPoints^[wNumPoints] do begin
      vecV[1]:=0;  vecV[2]:=15;  vecV[3]:=0;
      end; // with

   inc(wNumPoints);   prPtZ:=@parPoints^[wNumPoints];
   with parPoints^[wNumPoints] do begin
      vecV[1]:=0;  vecV[2]:=0;  vecV[3]:=15;
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=prPtOrg;  aprPoint[2]:=prPtX;
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=prPtOrg;  aprPoint[2]:=prPtY;
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=prPtOrg;  aprPoint[2]:=prPtZ;
      end; // with

   // Optional, defining if one or two colors are used, and
   // can change the default standard colors
   // The Created Pen will be destroyed automatically
   papoBodies^[wNumBodies]^.fUniColor:=FALSE; // Ask to have two colors
   papoBodies^[wNumBodies]^.colorSup.wColor:=RGB(255,255,  0);
   papoBodies^[wNumBodies]^.colorInf.wColor:=RGB(128,128,  0);
   papoBodies^[wNumBodies]^.colorAx.wColor :=RGB(  0,255,255);
   papoBodies^[wNumBodies]^.strBodyName:=GetMsg(11001); // A Surface;

   // To view in 3D, with Red - Green glasses (Can be acceded from the menu
//   poDraw3D^.fView3DWithGalsses:=FALSE;  ToggleView3D(FALSE); // Set the right bookmark

   // Some final setups, positionning and Drawing
   FinalBodySetup;

   // Final rotation for the viweing
   papoBodies^[wNumBodies]^.BodyRotateGC(vecRight, 35*Pi/180);

   // erase window, and draw
   Draw3DBodies;
   end; // with
end;  // TMyWindow.ASurface

procedure TMyWindow.ATorus;
//=========================
// A torus
const
  nMinX =0;
  nMaxX =30;
  nMinY =0;
  nMaxY =30;
  nDY   = 1 + nMaxY - nMinY;
var
  nX,nY       : int32;
  vPhi,vTheta : Float;
  parPtsL     : PArrayPoint3D;

begin
with poDraw3D^ do begin
   // Test that there is enough space to add a Body
   if (wNumPoints + word32((nMaxX-nMinX)*nDY + nMaxY-nMinY) +5 > MAXPOINTS) or
      (wNumFaces  + word32((nMaxX-nMinX)*(nMaxY-nMinY)) + 4 > MAXFACES) then begin
      DialogExecMSG(12099, @Self);
      exit;
      end;

   parPtsL:=@parPoints^[wNumPoints+1];

   // Creates a new body
   inc(wNumBodies);
   new(papoBodies^[wNumBodies], Init(poDraw3D));

   // Add the points. Units = cm
   for nX:=nMinX to nMaxX do
   for nY:=nMinY to nMaxY do begin
      vPhi   :=2*Pi*nX / Float(nMaxX); // in [0..2*Pi]
      vTheta :=2*Pi*nY / Float(nMaxY); // in [0..2*Pi]
      // Add one point
      with parPtsL^[nX*nDY + nY] do begin
         vecV[1]:=3.0 + 1.2*Cos(vPhi);
         vecV[2]:=0.0;
         vecV[3]:=      1.2*Sin(vPhi);
         vecV:=0.9*V3RotationOrg(vecV, V3Assign(0,0,1), -vTheta);
         end; // with
      end;

   wNumPoints:=wNumPoints + (nMaxX-nMinX)*nDY + nMaxY-nMinY +1;

   // Add the faces
   for nX:=nMinX to nMaxX-1 do
   for nY:=nMinY to nMaxY-1 do begin
      inc(wNumFaces);
      with parFaces^[wNumFaces] do begin
         nNbPoint:=4;
         aprPoint[1]:=@parPtsL^[(  nX-nMinX)*nDY +   nY-nMinY];
         aprPoint[2]:=@parPtsL^[(1+nX-nMinX)*nDY +   nY-nMinY];
         aprPoint[3]:=@parPtsL^[(1+nX-nMinX)*nDY + 1+nY-nMinY];
         aprPoint[4]:=@parPtsL^[(  nX-nMinX)*nDY + 1+nY-nMinY];
         end; // with
      end; // for

   // Optional, defining if one or two colors are used, and
   // can change the default standard colors
   // The Created Pen will be destroyed automatically
   papoBodies^[wNumBodies]^.fUniColor:=TRUE; // Ask to have a unique color
   papoBodies^[wNumBodies]^.colorSup.wColor:=RGB(255,128,128);
   papoBodies^[wNumBodies]^.strBodyName:=GetMsg(11002); // A Torus

   // Some final setups, positionning and Drawing
   FinalBodySetup;

   // Final rotation for the viweing
//   papoBodies^[wNumBodies]^.BodyRotateGC(vecRight, 35*Pi/180);

   // Erase the background and draw the Body
   Draw3DBodies;
   end; // with
end;  // TMyWindow.ATorus

procedure TMyWindow.AnEllipsoide;
//===============================
const
  nMinX =0;
  nMaxX =30;
  nMinY =0;
  nMaxY =30;
  nDY   = 1 + nMaxY - nMinY;
var
  nX,nY       : int32;
  vPhi,vTheta : Float;
  parPtsL     : PArrayPoint3D;

begin
with poDraw3D^ do begin
   // Test that there is enough space to add a Body
   if (wNumPoints + word32((nMaxX-nMinX)*nDY + nMaxY-nMinY) +5 > MAXPOINTS) or
      (wNumFaces  + word32((nMaxX-nMinX)*(nMaxY-nMinY)) + 4 > MAXFACES) then begin
      DialogExecMSG(12099, @Self);
      exit;
      end;

   parPtsL:=@parPoints^[wNumPoints+1];

   // Creates a new body
   inc(wNumBodies);
   new(papoBodies^[wNumBodies], Init(poDraw3D));

   // Add the points. Units = cm
   for nX:=nMinX to nMaxX do
   for nY:=nMinY to nMaxY do begin
      vPhi   :=2*Pi*nX / Float(nMaxX); // in [0..2*Pi]
      vTheta :=2*Pi*nY / Float(nMaxY); // in [0..2*Pi]
      // Add one point
      with parPtsL^[nX*nDY + nY] do begin
         vecV[1]:=2.0*Cos(vPhi) * Cos(vTheta);
         vecV[2]:=2.2*Sin(vPhi) * Cos(vTheta);
         vecV[3]:=6.0*            Sin(vTheta);
         vecV:=V3RotationOrg(vecV, V3Assign(0,1,0), 70*pi/180);
         end; // with
      end;

   wNumPoints:=wNumPoints + (nMaxX-nMinX)*nDY + nMaxY-nMinY +1;

   // Add the faces
   for nX:=nMinX to nMaxX-1 do
   for nY:=nMinY to nMaxY-1 do begin
      inc(wNumFaces);
      with parFaces^[wNumFaces] do begin
         nNbPoint:=4;
         aprPoint[1]:=@parPtsL^[(  nX-nMinX)*nDY +   nY-nMinY];
         aprPoint[2]:=@parPtsL^[(1+nX-nMinX)*nDY +   nY-nMinY];
         aprPoint[3]:=@parPtsL^[(1+nX-nMinX)*nDY + 1+nY-nMinY];
         aprPoint[4]:=@parPtsL^[(  nX-nMinX)*nDY + 1+nY-nMinY];
         end; // with
      end; // for

   // Optional, defining if one or two colors are used, and
   // can change the default standard colors
   // The Created Pen will be destroyed automatically
   papoBodies^[wNumBodies]^.fUniColor:=TRUE; // Ask to have a unique color
   papoBodies^[wNumBodies]^.colorSup.wColor:=RGB(64,255,128);
   papoBodies^[wNumBodies]^.strBodyName:=GetMsg(11003); // An Ellipsoid

   // Some final setups, positionning and Drawing
   FinalBodySetup;

   // Final rotation for the viweing
//   papoBodies^[wNumBodies]^.BodyRotateGC(vecRight, 35*Pi/180);

   // Erase the background and draw the Body
   Draw3DBodies;
   end; // with
end;  // TMyWindow.AnEllipsoide

procedure TMyWindow.ACube;
//========================
// A cube
const
  nMinX =0;
  nMaxX =5;
  nMinY =0;
  nMaxY =20;
  nDY   = 1 + nMaxY - nMinY;
var
  nX,nY       : int32;
  vPhi,vTheta : Float;
  parPtsL     : PArrayPoint3D;

begin
with poDraw3D^ do begin
   // Test that there is enough space to add a Body
   if (wNumPoints + word32((nMaxX-nMinX)*nDY + nMaxY-nMinY) +5 > MAXPOINTS) or
      (wNumFaces  + word32((nMaxX-nMinX)*(nMaxY-nMinY)) + 4 > MAXFACES) then begin
      DialogExecMSG(12099, @Self);
      exit;
      end;

   parPtsL:=@parPoints^[wNumPoints+1];

   // Creates a new body
   inc(wNumBodies);
   new(papoBodies^[wNumBodies], Init(poDraw3D));

   // Add the points. Units = cm
   for nX:=nMinX to nMaxX do
   for nY:=nMinY to nMaxY do begin
      vPhi   :=1.0* nX / Float(nMaxX); // in [0..2*Pi]
      vTheta :=4.0* nY / Float(nMaxY); // in [0..2*Pi]
      // Add one point
      with parPtsL^[nX*nDY + nY] do begin
         if (vTheta <= 1) then begin
            vecV[1]:=vTheta;
            vecV[2]:=0;
            end
         else if (vTheta <= 2) then begin
            vecV[1]:=1;
            vecV[2]:=vTheta -1;
            end
         else if (vTheta <= 3) then begin
            vecV[1]:=3-vTheta;
            vecV[2]:=1;
            end
         else begin
            vecV[1]:=0;
            vecV[2]:=4-vTheta;
            end;

         vecV[3]:=1.0-vPhi;
         vecV:=4*vecV;

         // It is better to rotate the Body after the Setup bellow
         // This will rotate its orientations axes too.
         // vecV:=4*V3RotationOrg(vecV, V3Assign(0,1,0), 40*pi/180);
         end; // with
      end;

   wNumPoints:=wNumPoints + (nMaxX-nMinX)*nDY + nMaxY-nMinY +1;

   // Add the faces
   for nX:=nMinX to nMaxX-1 do
   for nY:=nMinY to nMaxY-1 do begin
      inc(wNumFaces);
      with parFaces^[wNumFaces] do begin
         nNbPoint:=4;
         aprPoint[1]:=@parPtsL^[(  nX-nMinX)*nDY +   nY-nMinY];
         aprPoint[2]:=@parPtsL^[(1+nX-nMinX)*nDY +   nY-nMinY];
         aprPoint[3]:=@parPtsL^[(1+nX-nMinX)*nDY + 1+nY-nMinY];
         aprPoint[4]:=@parPtsL^[(  nX-nMinX)*nDY + 1+nY-nMinY];
         end; // with
      end; // for

   // Optional, defining if one or two colors are used, and
   // can change the default standard colors
   // The Created Pen will be destroyed automatically
   papoBodies^[wNumBodies]^.fUniColor:=FALSE; // Ask to have a unique color
   papoBodies^[wNumBodies]^.colorSup.wColor:=RGB(255,64,255);
   papoBodies^[wNumBodies]^.colorInf.wColor:=RGB(  0,64,255);
   papoBodies^[wNumBodies]^.strBodyName:=GetMsg(11004); // A Cube

   // Some final setups, positionning and Drawing
   FinalBodySetup;

   // Final rotation for the viweing
   papoBodies^[wNumBodies]^.BodyRotateGC(V3Assign(0,1,0), 40*Pi/180);

   // Erase the background and draw the Body
   Draw3DBodies;
   end; // with
end;  // TMyWindow.ACube

procedure TMyWindow.ATwistedTorus;
//========================
// A twisted torus
const
  nMinX =0;
  nMaxX =30;
  nMinY =0;
  nMaxY =30;
  nDY   = 1 + nMaxY - nMinY;
var
  nX,nY       : int32;
  vPhi,vTheta : Float;
  parPtsL     : PArrayPoint3D;

begin
with poDraw3D^ do begin
   // Test that there is enough space to add a Body
   if (wNumPoints + word32((nMaxX-nMinX)*nDY + nMaxY-nMinY) +5 > MAXPOINTS) or
      (wNumFaces  + word32((nMaxX-nMinX)*(nMaxY-nMinY)) + 4 > MAXFACES) then begin
      DialogExecMSG(12099, @Self);
      exit;
      end;

   parPtsL:=@parPoints^[wNumPoints+1];

   // Creates a new body
   inc(wNumBodies);
   new(papoBodies^[wNumBodies], Init(poDraw3D));

   // Add the points. Units = cm
   for nX:=nMinX to nMaxX do
   for nY:=nMinY to nMaxY do begin
      vPhi   :=2*Pi*nX / Float(nMaxX); // in [0..2*Pi]
      vTheta :=2*Pi*nY / Float(nMaxY); // in [0..2*Pi]
      // Add one point
      with parPtsL^[nX*nDY + nY] do begin
         vecV[1]:=3.0 + 1.2*Cos(vPhi+vTheta);
         vecV[2]:=0.0;
         vecV[3]:=      1.2*Sin(vPhi+vTheta);
         vecV:=0.9*V3RotationOrg(vecV, V3Assign(0,0,1), -vTheta);
         end; // with
      end;

   wNumPoints:=wNumPoints + (nMaxX-nMinX)*nDY + nMaxY-nMinY +1;

   // Add the faces
   for nX:=nMinX to nMaxX-1 do
   for nY:=nMinY to nMaxY-1 do begin
      inc(wNumFaces);
      with parFaces^[wNumFaces] do begin
         nNbPoint:=4;
         aprPoint[1]:=@parPtsL^[(  nX-nMinX)*nDY +   nY-nMinY];
         aprPoint[2]:=@parPtsL^[(1+nX-nMinX)*nDY +   nY-nMinY];
         aprPoint[3]:=@parPtsL^[(1+nX-nMinX)*nDY + 1+nY-nMinY];
         aprPoint[4]:=@parPtsL^[(  nX-nMinX)*nDY + 1+nY-nMinY];
         end; // with
      end; // for

   // Optional, defining if one or two colors are used, and
   // can change the default standard colors
   // The Created Pen will be destroyed automatically
   papoBodies^[wNumBodies]^.fUniColor:=TRUE; // Ask to have a unique color
   papoBodies^[wNumBodies]^.colorSup.wColor:=RGB(255,255,128);
   papoBodies^[wNumBodies]^.strBodyName:=GetMsg(11005); // A twited Torus

   // Some final setups, positionning and Drawing
   FinalBodySetup;

   // Final rotation for the viweing
//   papoBodies^[wNumBodies]^.BodyRotateGC(vecRight, 35*Pi/180);

   // Erase the background and draw the torus
   Draw3DBodies;
   end; // with
end;  // TMyWindow.ATwistedTorus

procedure TMyWindow.AMobiusRibbon;
//========================
// A Mobius Ribbon
const
  nMinX = 0;
  nMaxX =30;
  nMinY = 0;
  nMaxY = 4;
  nDY   = 1 + nMaxY - nMinY;
var
  nX,nY       : int32;
  vPhi,vTheta : Float;
  parPtsL     : PArrayPoint3D;

begin
with poDraw3D^ do begin
   // Test that there is enough space to add a Body
   if (wNumPoints + word32((nMaxX-nMinX)*nDY + nMaxY-nMinY) +5 > MAXPOINTS) or
      (wNumFaces  + word32((nMaxX-nMinX)*(nMaxY-nMinY)) + 4 > MAXFACES) then begin
      DialogExecMSG(12099, @Self);
      exit;
      end;

   parPtsL:=@parPoints^[wNumPoints+1];

   // Creates a new body
   inc(wNumBodies);
   new(papoBodies^[wNumBodies], Init(poDraw3D));

   // Add the points. Units = cm
   for nX:=nMinX to nMaxX do
   for nY:=nMinY to nMaxY do begin
      vPhi   :=2*Pi*nX / Float(nMaxX); // in [0..2*Pi]
      vTheta :=2*Pi*nY / Float(nMaxY); // in [0..2*Pi]
      // Add one point
      with parPtsL^[nX*nDY + nY] do begin
         vecV[1]:=((vTheta-Pi)/2)*Cos(vPhi);
         vecV[2]:=((vTheta-Pi)/2)*Sin(vPhi);
         vecV[3]:=0.0;
         vecV:= V3RotationOrg(vecV, V3Assign(-Sin(vPhi), Cos(vPhi), 0), vPhi/2) +
                V3Assign(4*Cos(vPhi), 4*Sin(vPhi), 0.0);
         end; // with
      end;

   wNumPoints:=wNumPoints + (nMaxX-nMinX)*nDY + nMaxY-nMinY +1;

   // Add the faces
   for nX:=nMinX to nMaxX-1 do
   for nY:=nMinY to nMaxY-1 do begin
      inc(wNumFaces);
      with parFaces^[wNumFaces] do begin
         nNbPoint:=4;
         aprPoint[1]:=@parPtsL^[(  nX-nMinX)*nDY +   nY-nMinY];
         aprPoint[2]:=@parPtsL^[(1+nX-nMinX)*nDY +   nY-nMinY];
         aprPoint[3]:=@parPtsL^[(1+nX-nMinX)*nDY + 1+nY-nMinY];
         aprPoint[4]:=@parPtsL^[(  nX-nMinX)*nDY + 1+nY-nMinY];
         end; // with
      end; // for

   // Optional, defining if one or two colors are used, and
   // can change the default standard colors
   // The Created Pen will be destroyed automatically
   papoBodies^[wNumBodies]^.fUniColor:=FALSE; // Ask to have a unique color
   papoBodies^[wNumBodies]^.colorSup.wColor:=RGB(255,255,128);
   papoBodies^[wNumBodies]^.colorInf.wColor:=RGB(255,255,128);
   papoBodies^[wNumBodies]^.strBodyName:=GetMsg(11006); // A Mobius Ribbon

   // Some final setups, positionning and Drawing
   FinalBodySetup;

   // Final rotation for the viweing
//   papoBodies^[wNumBodies]^.BodyRotateGC(vecRight, 35*Pi/180);

   // Erase the background and draw the Body
   Draw3DBodies;
   end; // with
end;  // TMyWindow.AMobiusRibbon

procedure TMyWindow.ASpecialTorus;
//================================
// A torus
const
  nMinX =0;
  nMaxX =15;
  nMinY =0;
  nMaxY =60;
  nDY   = 1 + nMaxY - nMinY;
var
  nX,nY       : int32;
  vPhi,vTheta : Float;
  parPtsL     : PArrayPoint3D;

begin
with poDraw3D^ do begin
   // Test that there is enough space to add a Body
   if (wNumPoints + word32((nMaxX-nMinX)*nDY + nMaxY-nMinY) +5 > MAXPOINTS) or
      (wNumFaces  + word32((nMaxX-nMinX)*(nMaxY-nMinY)) + 4 > MAXFACES) then begin
      DialogExecMSG(12099, @Self);
      exit;
      end;

   parPtsL:=@parPoints^[wNumPoints+1];

   // Creates a new body
   inc(wNumBodies);
   new(papoBodies^[wNumBodies], Init(poDraw3D));

   // Add the points. Units = cm
   for nX:=nMinX to nMaxX do
   for nY:=nMinY to nMaxY do begin
      vPhi   :=2*Pi*nX / Float(nMaxX); // in [0..2*Pi]
      vTheta :=2*Pi*nY / Float(nMaxY); // in [0..2*Pi]
      // Add one point
      with parPtsL^[nX*nDY + nY] do begin
         vecV[1]:=(4.0 + 1.2*cos(3*vTheta)) + 0.7*Cos(vPhi+5*vTheta);
         vecV[2]:=0.0;
         vecV[3]:=      0.7*Sin(vPhi+5*vTheta) + 1.3*sin(3*vTheta);
         vecV:=0.9*V3RotationOrg(vecV, V3Assign(0,0,1), -2*vTheta);
         end; // with
      end;

   wNumPoints:=wNumPoints + (nMaxX-nMinX)*nDY + nMaxY-nMinY +1;

   // Add the faces
   for nX:=nMinX to nMaxX-1 do
   for nY:=nMinY to nMaxY-1 do begin
      inc(wNumFaces);
      with parFaces^[wNumFaces] do begin
         nNbPoint:=4;
         aprPoint[1]:=@parPtsL^[(  nX-nMinX)*nDY +   nY-nMinY];
         aprPoint[2]:=@parPtsL^[(1+nX-nMinX)*nDY +   nY-nMinY];
         aprPoint[3]:=@parPtsL^[(1+nX-nMinX)*nDY + 1+nY-nMinY];
         aprPoint[4]:=@parPtsL^[(  nX-nMinX)*nDY + 1+nY-nMinY];
         end; // with
      end; // for

   // Optional, defining the colors
   papoBodies^[wNumBodies]^.fUniColor:=TRUE; // Ask to have a unique color
   papoBodies^[wNumBodies]^.colorSup.wColor:=RGB(128,255, 92);
   papoBodies^[wNumBodies]^.strBodyName:=GetMsg(11007); // A Special Torus

   // Some final setups, positionning and Drawing
   FinalBodySetup;

   // Final rotation for the viweing
//   papoBodies^[wNumBodies]^.BodyRotateGC(vecRight, 35*Pi/180);

   // Erase the background and draw the Body
   Draw3DBodies;
   end; // with
end;  // TMyWindow.ASpecialTorus

procedure TMyWindow.SimpleSphere;
//===============================
// A simple Sphere,  Faces are in reality the edges
var
  nx          : integer;
  parPtsL     : PArrayPoint3D;
  vPhi,
  vSizeL,
  vRadiusL    : Float; // Radius of the sphere containing the cube

begin
with poDraw3D^ do begin
   // Test that there is enough space to add a Body
   if (wNumPoints + 3*32 > MAXPOINTS) or
      (wNumFaces  + 3*32 > MAXFACES) then begin
      DialogExecMSG(12099, @Self);
      exit;
      end;

   parPtsL:=@parPoints^[wNumPoints+1];

   // Size of an edge, in [cm]
   vRadiusL:=6.0; // [cm]
   vSizeL  :=vRadiusL;

   // Creates a new body
   inc(wNumBodies);
   new(papoBodies^[wNumBodies], Init(poDraw3D));

   // Add the points. Units = cm
   for nX:=0 to 32 do begin
      vPhi:=Pi * nX / 16.0;
      parPtsL^[nX].vecV:=vSizeL * V3Assign(cos(vPhi),sin(vPhi),0);
      inc(wNumPoints);

      if (nX < 32) then begin
         // Add the "faces", i.e. the edges
         inc(wNumFaces);
         with parFaces^[wNumFaces] do begin
            nNbPoint:=2;  aprPoint[1]:=@parPtsL^[nX];  aprPoint[2]:=@parPtsL^[nX+1];
            end; // with
         end;
      end; // for

   parPtsL:=@parPoints^[wNumPoints+1];

   // Add the points. Units = cm
   for nX:=0 to 32 do begin
      vPhi:=Pi * nX / 16.0;
      parPtsL^[nX].vecV:=vSizeL * V3Assign(cos(vPhi), 0, sin(vPhi));
      inc(wNumPoints);

      if (nX < 32) then begin
         // Add the "faces", i.e. the edges
         inc(wNumFaces);
         with parFaces^[wNumFaces] do begin
            nNbPoint:=2;  aprPoint[1]:=@parPtsL^[nX];  aprPoint[2]:=@parPtsL^[nX+1];
            end; // with
         end;
      end; // for

   parPtsL:=@parPoints^[wNumPoints+1];

   // Add the points. Units = cm
   for nX:=0 to 32 do begin
      vPhi:=Pi * nX / 16.0;
      parPtsL^[nX].vecV:=vSizeL * V3Assign(0,cos(vPhi),sin(vPhi));
      inc(wNumPoints);

      if (nX < 32) then begin
         // Add the "faces", i.e. the edges
         inc(wNumFaces);
         with parFaces^[wNumFaces] do begin
            nNbPoint:=2;  aprPoint[1]:=@parPtsL^[nX];  aprPoint[2]:=@parPtsL^[nX+1];
            end; // with
         end;
      end; // for

   // Optional, defining if one or two colors are used, and
   // can change the default standard colors
   // The Created Pen will be destroyed automatically
   papoBodies^[wNumBodies]^.fUniColor:=TRUE; // Ask to have a unique color
//   papoBodies^[wNumBodies]^.colorSup.wColor:=RGB(255,255,128);
//   papoBodies^[wNumBodies]^.colorInf.wColor:=RGB(255,255,128);
   papoBodies^[wNumBodies]^.colorAx.wColor:=RGB( 64,128,128);
   papoBodies^[wNumBodies]^.strBodyName:=GetMsg(11010); // A simple Sphere

   // Some final setups, positionning and Drawing
   FinalBodySetup;

   // Final rotation for the viweing
//   papoBodies^[wNumBodies]^.BodyRotateGC(vecRight, 35*Pi/180);

   // Erase the background and draw the Body
   Draw3DBodies;
   end; // with
end;  // TMyWindow.SimpleSphere

procedure TMyWindow.SimpleTetrahedron;
//====================================
// Faces are in reality the edges
var
  parPtsL     : PArrayPoint3D;
  vXL,vYL,vZL,
//  vSizeL,
  vRadiusL    : Float; // Radius of the sphere containing the cube

begin
with poDraw3D^ do begin
   // Test that there is enough space to add a Body
   if (wNumPoints +  4 > MAXPOINTS) or
      (wNumFaces  +  6 > MAXFACES) then begin
      DialogExecMSG(12099, @Self);
      exit;
      end;

   parPtsL:=@parPoints^[wNumPoints+1];

   // Size of an edge, in [cm]
   vRadiusL:=6.0; // [cm]
//   vSizeL  :=sqrt(3) * vRadiusL;

   // Coordonate of the points of a Tetrahedron
   vXL:=(sqrt(2)/3) * vRadiusL;
   vYL:=(sqrt(2/3)) * vRadiusL;
   vZL:=      (4/3) * vRadiusL;

   // Creates a new body
   inc(wNumBodies);
   new(papoBodies^[wNumBodies], Init(poDraw3D));

   // Add the points. Units = cm
   parPtsL^[0].vecV:=V3Assign(2*vXL,   0, -vZl/4);
   parPtsL^[1].vecV:=V3Assign( -vXL, vYL, -vZl/4);
   parPtsL^[2].vecV:=V3Assign( -vXL,-vYL, -vZl/4);
   parPtsL^[3].vecV:=V3Assign(    0,   0,3*vZL/4);

   wNumPoints:=wNumPoints + 4;

   // Add the "faces", i.e. the 6 edges
   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[0];  aprPoint[2]:=@parPtsL^[1];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[0];  aprPoint[2]:=@parPtsL^[2];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[0];  aprPoint[2]:=@parPtsL^[3];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[1];  aprPoint[2]:=@parPtsL^[2];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[1];  aprPoint[2]:=@parPtsL^[3];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[2];  aprPoint[2]:=@parPtsL^[3];
      end; // with

   // Optional, defining if one or two colors are used, and
   // can change the default standard colors
   // The Created Pen will be destroyed automatically
   papoBodies^[wNumBodies]^.fUniColor:=TRUE; // Ask to have a unique color
//   papoBodies^[wNumBodies]^.colorSup.wColor:=RGB(255,255,128);
//   papoBodies^[wNumBodies]^.colorInf.wColor:=RGB(255,255,128);
   papoBodies^[wNumBodies]^.colorAx.wColor:=RGB(255,255,128);
   papoBodies^[wNumBodies]^.strBodyName:=GetMsg(11011); // A simple Tetrahedron

   // Some final setups, positionning and Drawing
   FinalBodySetup;

   // Final rotation for the viweing
//   papoBodies^[wNumBodies]^.BodyRotateGC(vecRight, 35*Pi/180);

   // Erase the background and draw the Body
   Draw3DBodies;
   end; // with
end;  // TMyWindow.SimpleTetrahedron

procedure TMyWindow.SimpleCube;
//=============================
// Faces are in reality the edges
var
  parPtsL     : PArrayPoint3D;
  vSizeL,
  vRadiusL    : Float; // Radius of the sphere containing the cube

begin
with poDraw3D^ do begin
   // Test that there is enough space to add a Body
   if (wNumPoints +  8 > MAXPOINTS) or
      (wNumFaces  + 12 > MAXFACES) then begin
      DialogExecMSG(12099, @Self);
      exit;
      end;

   parPtsL:=@parPoints^[wNumPoints+1];

   // Size of an edge, in [cm]
   vRadiusL:=6.0; // [cm]
   vSizeL  :=(1/sqrt(3)) * vRadiusL;

   // Creates a new body
   inc(wNumBodies);
   new(papoBodies^[wNumBodies], Init(poDraw3D));

   // Add the points. Units = cm
   parPtsL^[0].vecV:=vSizeL * V3Assign(-1,-1,-1);
   parPtsL^[1].vecV:=vSizeL * V3Assign( 1,-1,-1);
   parPtsL^[2].vecV:=vSizeL * V3Assign(-1, 1,-1);
   parPtsL^[3].vecV:=vSizeL * V3Assign(-1,-1, 1);
   parPtsL^[4].vecV:=vSizeL * V3Assign( 1, 1,-1);
   parPtsL^[5].vecV:=vSizeL * V3Assign( 1,-1, 1);
   parPtsL^[6].vecV:=vSizeL * V3Assign(-1, 1, 1);
   parPtsL^[7].vecV:=vSizeL * V3Assign( 1, 1, 1);

   wNumPoints:=wNumPoints + 8;

   // Add the "faces", i.e. the twelve edges
   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[0];  aprPoint[2]:=@parPtsL^[1];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[0];  aprPoint[2]:=@parPtsL^[2];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[0];  aprPoint[2]:=@parPtsL^[3];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[4];  aprPoint[2]:=@parPtsL^[1];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[4];  aprPoint[2]:=@parPtsL^[2];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[4];  aprPoint[2]:=@parPtsL^[7];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[5];  aprPoint[2]:=@parPtsL^[1];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[5];  aprPoint[2]:=@parPtsL^[3];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[5];  aprPoint[2]:=@parPtsL^[7];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[6];  aprPoint[2]:=@parPtsL^[2];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[6];  aprPoint[2]:=@parPtsL^[3];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[6];  aprPoint[2]:=@parPtsL^[7];
      end; // with

   // Optional, defining if one or two colors are used, and
   // can change the default standard colors
   // The Created Pen will be destroyed automatically
   papoBodies^[wNumBodies]^.fUniColor:=TRUE; // Ask to have a unique color
//   papoBodies^[wNumBodies]^.colorSup.wColor:=RGB(255,255,128);
//   papoBodies^[wNumBodies]^.colorInf.wColor:=RGB(255,255,128);
   papoBodies^[wNumBodies]^.colorAx.wColor:=RGB(128,255,255);
   papoBodies^[wNumBodies]^.strBodyName:=GetMsg(11012); // A simple Cube

   // Some final setups, positionning and Drawing
   FinalBodySetup;

   // Final rotation for the viweing
//   papoBodies^[wNumBodies]^.BodyRotateGC(vecRight, 35*Pi/180);

   // Erase the background and draw the Body
   Draw3DBodies;
   end; // with
end;  // TMyWindow.SimpleCube

procedure TMyWindow.SimpleOctahedron;
//===================================
// Faces are in reality the edges
var
  parPtsL     : PArrayPoint3D;
  vSizeL,
  vRadiusL    : Float; // Radius of the sphere containing the cube

begin
with poDraw3D^ do begin
   // Test that there is enough space to add a Body
   if (wNumPoints +  6 > MAXPOINTS) or
      (wNumFaces  + 12 > MAXFACES) then begin
      DialogExecMSG(12099, @Self);
      exit;
      end;

   parPtsL:=@parPoints^[wNumPoints+1];

   // Size of an edge, in [cm]
   vRadiusL:=6.0; // [cm]
   vSizeL  :=vRadiusL;

   // Creates a new body
   inc(wNumBodies);
   new(papoBodies^[wNumBodies], Init(poDraw3D));

   // Add the points. Units = cm
   parPtsL^[0].vecV:=vSizeL * V3Assign( 1, 0, 0);
   parPtsL^[1].vecV:=vSizeL * V3Assign( 0, 1, 0);
   parPtsL^[2].vecV:=vSizeL * V3Assign(-1, 0, 0);
   parPtsL^[3].vecV:=vSizeL * V3Assign( 0,-1, 0);
   parPtsL^[4].vecV:=vSizeL * V3Assign( 0, 0, 1);
   parPtsL^[5].vecV:=vSizeL * V3Assign( 0, 0,-1);

   wNumPoints:=wNumPoints + 6;

   // Add the "faces", i.e. the twelve edges
   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[4];  aprPoint[2]:=@parPtsL^[0];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[4];  aprPoint[2]:=@parPtsL^[1];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[4];  aprPoint[2]:=@parPtsL^[2];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[4];  aprPoint[2]:=@parPtsL^[3];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[5];  aprPoint[2]:=@parPtsL^[0];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[5];  aprPoint[2]:=@parPtsL^[1];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[5];  aprPoint[2]:=@parPtsL^[2];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[5];  aprPoint[2]:=@parPtsL^[3];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[0];  aprPoint[2]:=@parPtsL^[1];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[1];  aprPoint[2]:=@parPtsL^[2];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[2];  aprPoint[2]:=@parPtsL^[3];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[3];  aprPoint[2]:=@parPtsL^[0];
      end; // with

   // Optional, defining if one or two colors are used, and
   // can change the default standard colors
   // The Created Pen will be destroyed automatically
   papoBodies^[wNumBodies]^.fUniColor:=TRUE; // Ask to have a unique color
//   papoBodies^[wNumBodies]^.colorSup.wColor:=RGB(255,255,128);
//   papoBodies^[wNumBodies]^.colorInf.wColor:=RGB(255,255,128);
   papoBodies^[wNumBodies]^.colorAx.wColor:=RGB(255,128, 32);
   papoBodies^[wNumBodies]^.strBodyName:=GetMsg(11013); // A simple Octahedron

   // Some final setups, positionning and Drawing
   FinalBodySetup;

   // Final rotation for the viweing
//   papoBodies^[wNumBodies]^.BodyRotateGC(vecRight, 35*Pi/180);

   // Erase the background and draw the Body
   Draw3DBodies;
   end; // with
end;  // TMyWindow.SimpleOctahedron

procedure TMyWindow.SimpleDodecahedron;
//=====================================
// Faces are in reality the edges
var
  parPtsL     : PArrayPoint3D;
  vL,
  vPhi,
  vTheta,
  vSinPhi,
  vCosPhi,
  vSinPhiT,
  vCosPhiT,
  vSizeL,
  vRadiusL    : Float; // Radius of the sphere containing the cube

begin
with poDraw3D^ do begin
   // Test that there is enough space to add a Body
   if (wNumPoints + 20 > MAXPOINTS) or
      (wNumFaces  + 30 > MAXFACES) then begin
      DialogExecMSG(12099, @Self);
      exit;
      end;

   parPtsL:=@parPoints^[wNumPoints+1];

   // Size of an edge, in [cm]
   vRadiusL:=6.0; // [cm]
   vSizeL  :=vRadiusL;

   vL       :=sqrt(5/3) - sqrt(1/3);
   vPhi     :=  ArcSin(vL / (2*Sin(35*Pi/180)));
   vTheta   :=2*ArcSin(vL / 2);
   vSinPhi  :=vL / (2*Sin(35*Pi/180));
   vCosPhi  :=Cos(vPhi);
   vSinPhiT :=Sin(vPhi+vTheta);
   vCosPhiT :=Cos(vPhi+vTheta);

   // Creates a new body
   inc(wNumBodies);
   new(papoBodies^[wNumBodies], Init(poDraw3D));

   // Add the 20 points. Units = cm
   parPtsL^[ 0].vecV:=vSizeL * V3Assign(-vSinPhi,               0,                           vCosPhi);
   parPtsL^[ 1].vecV:=vSizeL * V3Assign(-vSinPhi *cos( 72*Pi/180),-vSinPhi*sin( 72*Pi/180),  vCosPhi);
   parPtsL^[ 2].vecV:=vSizeL * V3Assign(-vSinPhi *cos(144*Pi/180),-vSinPhi*sin(144*Pi/180),  vCosPhi);
   parPtsL^[ 3].vecV:=vSizeL * V3Assign(-vSinPhi *cos(216*Pi/180),-vSinPhi*sin(216*Pi/180),  vCosPhi);
   parPtsL^[ 4].vecV:=vSizeL * V3Assign(-vSinPhi *cos(288*Pi/180),-vSinPhi*sin(288*Pi/180),  vCosPhi);
   parPtsL^[ 5].vecV:=vSizeL * V3Assign(-vSinPhiT               ,                         0, vCosPhiT);
   parPtsL^[ 6].vecV:=vSizeL * V3Assign(-vSinPhiT*cos( 72*Pi/180),-vSinPhiT*sin( 72*Pi/180), vCosPhiT);
   parPtsL^[ 7].vecV:=vSizeL * V3Assign(-vSinPhiT*cos(144*Pi/180),-vSinPhiT*sin(144*Pi/180), vCosPhiT);
   parPtsL^[ 8].vecV:=vSizeL * V3Assign(-vSinPhiT*cos(216*Pi/180),-vSinPhiT*sin(216*Pi/180), vCosPhiT);
   parPtsL^[ 9].vecV:=vSizeL * V3Assign(-vSinPhiT*cos(288*Pi/180),-vSinPhiT*sin(288*Pi/180), vCosPhiT);
   parPtsL^[10].vecV:=-1.0 * parPtsL^[ 9].vecV;
   parPtsL^[11].vecV:=-1.0 * parPtsL^[ 8].vecV;
   parPtsL^[12].vecV:=-1.0 * parPtsL^[ 7].vecV;
   parPtsL^[13].vecV:=-1.0 * parPtsL^[ 6].vecV;
   parPtsL^[14].vecV:=-1.0 * parPtsL^[ 5].vecV;
   parPtsL^[15].vecV:=-1.0 * parPtsL^[ 4].vecV;
   parPtsL^[16].vecV:=-1.0 * parPtsL^[ 3].vecV;
   parPtsL^[17].vecV:=-1.0 * parPtsL^[ 2].vecV;
   parPtsL^[18].vecV:=-1.0 * parPtsL^[ 1].vecV;
   parPtsL^[19].vecV:=-1.0 * parPtsL^[ 0].vecV;

   wNumPoints:=wNumPoints + 20;

   // Add the "faces", i.e. the 30 edges
   // The top Pentagone with 5 sides
   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[ 0];  aprPoint[2]:=@parPtsL^[ 1];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[ 1];  aprPoint[2]:=@parPtsL^[ 2];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[ 2];  aprPoint[2]:=@parPtsL^[ 3];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[ 3];  aprPoint[2]:=@parPtsL^[ 4];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[ 4];  aprPoint[2]:=@parPtsL^[ 0];
      end; // with

   // Oblique 5 lines
   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[ 0];  aprPoint[2]:=@parPtsL^[ 5];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[ 1];  aprPoint[2]:=@parPtsL^[ 6];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[ 2];  aprPoint[2]:=@parPtsL^[ 7];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[ 3];  aprPoint[2]:=@parPtsL^[ 8];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[ 4];  aprPoint[2]:=@parPtsL^[ 9];
      end; // with

   // Near horizontal 10 lines
   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[ 5];  aprPoint[2]:=@parPtsL^[11];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[11];  aprPoint[2]:=@parPtsL^[ 6];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[ 6];  aprPoint[2]:=@parPtsL^[10];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[10];  aprPoint[2]:=@parPtsL^[ 7];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[ 7];  aprPoint[2]:=@parPtsL^[14];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[14];  aprPoint[2]:=@parPtsL^[ 8];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[ 8];  aprPoint[2]:=@parPtsL^[13];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[13];  aprPoint[2]:=@parPtsL^[ 9];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[ 9];  aprPoint[2]:=@parPtsL^[12];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[12];  aprPoint[2]:=@parPtsL^[ 5];
      end; // with

   // Again 5 oblique lines
   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[11];  aprPoint[2]:=@parPtsL^[16];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[10];  aprPoint[2]:=@parPtsL^[15];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[14];  aprPoint[2]:=@parPtsL^[19];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[13];  aprPoint[2]:=@parPtsL^[18];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[12];  aprPoint[2]:=@parPtsL^[17];
      end; // with

   inc(wNumFaces);
   // The Bottom pentagone
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[15];  aprPoint[2]:=@parPtsL^[16];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[16];  aprPoint[2]:=@parPtsL^[17];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[17];  aprPoint[2]:=@parPtsL^[18];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[18];  aprPoint[2]:=@parPtsL^[19];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[19];  aprPoint[2]:=@parPtsL^[15];
      end; // with

   // Optional, defining if one or two colors are used, and
   // can change the default standard colors
   // The Created Pen will be destroyed automatically
   papoBodies^[wNumBodies]^.fUniColor:=TRUE; // Ask to have a unique color
//   papoBodies^[wNumBodies]^.colorSup.wColor:=RGB(255,255,128);
//   papoBodies^[wNumBodies]^.colorInf.wColor:=RGB(255,255,128);
   papoBodies^[wNumBodies]^.colorAx.wColor:=RGB(  0,192,255);
   papoBodies^[wNumBodies]^.strBodyName:=GetMsg(11014); // A simple Dodecahedron

   // Some final setups, positionning and Drawing
   FinalBodySetup;

   // Final rotation for the viweing
//   papoBodies^[wNumBodies]^.BodyRotateGC(vecRight, 35*Pi/180);

   // Erase the background and draw the Body
   Draw3DBodies;
   end; // with
end;  // TMyWindow.SimpleDodecahedron

procedure TMyWindow.SimpleIcosahedron;
//====================================
// Faces are in reality the edges
var
  parPtsL     : PArrayPoint3D;
  vXL,vZL,
  vSizeL,
  vRadiusL    : Float; // Radius of the sphere containing the cube

begin
with poDraw3D^ do begin
   // Test that there is enough space to add a Body
   if (wNumPoints + 12 > MAXPOINTS) or
      (wNumFaces  + 30 > MAXFACES) then begin
      DialogExecMSG(12099, @Self);
      exit;
      end;

   parPtsL:=@parPoints^[wNumPoints+1];

   // Size of an edge, in [cm]
   vRadiusL:=6.0; // [cm]
   vSizeL  :=vRadiusL;

   vXL:=2/sqrt(5);
   vZL:=1/sqrt(5);

   // Creates a new body
   inc(wNumBodies);
   new(papoBodies^[wNumBodies], Init(poDraw3D));

   // Add the points. Units = cm
   parPtsL^[ 0].vecV:=vSizeL * V3Assign(0,                0,                        1);
   parPtsL^[ 1].vecV:=vSizeL * V3Assign(vXL                ,                  0,  vZL);
   parPtsL^[ 2].vecV:=vSizeL * V3Assign(vXL*cos( 72*Pi/180),vXL*sin( 72*Pi/180),  vZL);
   parPtsL^[ 3].vecV:=vSizeL * V3Assign(vXL*cos(144*Pi/180),vXL*sin(144*Pi/180),  vZL);
   parPtsL^[ 4].vecV:=vSizeL * V3Assign(vXL*cos(216*Pi/180),vXL*sin(216*Pi/180),  vZL);
   parPtsL^[ 5].vecV:=vSizeL * V3Assign(vXL*cos(288*Pi/180),vXL*sin(288*Pi/180),  vZL);
   parPtsL^[ 6].vecV:=-1.0 * parPtsL^[ 1].vecV;
   parPtsL^[ 7].vecV:=-1.0 * parPtsL^[ 5].vecV;
   parPtsL^[ 8].vecV:=-1.0 * parPtsL^[ 4].vecV;
   parPtsL^[ 9].vecV:=-1.0 * parPtsL^[ 3].vecV;
   parPtsL^[10].vecV:=-1.0 * parPtsL^[ 2].vecV;
   parPtsL^[11].vecV:=-1.0 * parPtsL^[ 0].vecV;

   wNumPoints:=wNumPoints + 12;

   // Add the "faces", i.e. the 30 edges
   // The 5 top edges
   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[0];  aprPoint[2]:=@parPtsL^[1];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[0];  aprPoint[2]:=@parPtsL^[2];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[0];  aprPoint[2]:=@parPtsL^[3];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[0];  aprPoint[2]:=@parPtsL^[4];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[0];  aprPoint[2]:=@parPtsL^[5];
      end; // with

   // The 5 top horizontal edges
   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[1];  aprPoint[2]:=@parPtsL^[2];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[2];  aprPoint[2]:=@parPtsL^[3];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[3];  aprPoint[2]:=@parPtsL^[4];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[4];  aprPoint[2]:=@parPtsL^[5];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[5];  aprPoint[2]:=@parPtsL^[1];
      end; // with

   // The ten zig-zag edges
   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[1];  aprPoint[2]:=@parPtsL^[8];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[8];  aprPoint[2]:=@parPtsL^[2];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[2];  aprPoint[2]:=@parPtsL^[7];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[7];  aprPoint[2]:=@parPtsL^[3];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[3];  aprPoint[2]:=@parPtsL^[6];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[6];  aprPoint[2]:=@parPtsL^[4];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[4];  aprPoint[2]:=@parPtsL^[10];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[10];  aprPoint[2]:=@parPtsL^[5];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[5];  aprPoint[2]:=@parPtsL^[9];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[9];  aprPoint[2]:=@parPtsL^[1];
      end; // with

   // The five bottom horizontal
   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[6];  aprPoint[2]:=@parPtsL^[7];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[7];  aprPoint[2]:=@parPtsL^[8];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[8];  aprPoint[2]:=@parPtsL^[9];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[9];  aprPoint[2]:=@parPtsL^[10];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[10];  aprPoint[2]:=@parPtsL^[6];
      end; // with

   // The five bottom edges
   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[11];  aprPoint[2]:=@parPtsL^[6];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[11];  aprPoint[2]:=@parPtsL^[7];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[11];  aprPoint[2]:=@parPtsL^[8];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[11];  aprPoint[2]:=@parPtsL^[9];
      end; // with

   inc(wNumFaces);
   with parFaces^[wNumFaces] do begin
      nNbPoint:=2;  aprPoint[1]:=@parPtsL^[11];  aprPoint[2]:=@parPtsL^[10];
      end; // with

   // Optional, defining if one or two colors are used, and
   // can change the default standard colors
   // The Created Pen will be destroyed automatically
   papoBodies^[wNumBodies]^.fUniColor:=TRUE; // Ask to have a unique color
//   papoBodies^[wNumBodies]^.colorSup.wColor:=RGB(255,255,128);
//   papoBodies^[wNumBodies]^.colorInf.wColor:=RGB(255,255,128);
   papoBodies^[wNumBodies]^.colorAx.wColor:=RGB( 64,255, 64);
   papoBodies^[wNumBodies]^.strBodyName:=GetMsg(11015); // A simple Icosahedron

   // Some final setups, positionning and Drawing
   FinalBodySetup;

   // Final rotation for the viweing
//   papoBodies^[wNumBodies]^.BodyRotateGC(vecRight, 35*Pi/180);

   // Erase the background and draw the Body
   Draw3DBodies;
   end; // with
end;  // TMyWindow.SimpleIcosahedron

procedure TMyWindow.TestZ;
//========================
// To test special cases
begin
with poDraw3D^ do begin
   // Test that there is enough space to add a Body
   if (wNumPoints + 20 > MAXPOINTS) or
      (wNumFaces  +  4 > MAXFACES) then begin
      DialogExecMSG(12099, @Self);
      exit;
      end;

   // Creates a new body
   inc(wNumBodies);
   new(papoBodies^[wNumBodies], Init(poDraw3D));

   // Add points and faces, for particual tests. Units = cm
   inc(wNumFaces);
   inc(wNumPoints);
   parPoints^[wNumPoints].vecV:=V3Assign(0.00, 0.00,0.00);
   parFaces^[wNumFaces].aprPoint[1]:=@parPoints^[wNumPoints]; inc(wNumPoints);
   parPoints^[wNumPoints].vecV:=5.0*V3Assign(0.50,-0.50,0.50);
   parFaces^[wNumFaces].aprPoint[2]:=@parPoints^[wNumPoints]; inc(wNumPoints);
   parPoints^[wNumPoints].vecV:=5.0*V3Assign(1.00, 0.00,0.00);
   parFaces^[wNumFaces].aprPoint[3]:=@parPoints^[wNumPoints]; inc(wNumPoints);
   parPoints^[wNumPoints].vecV:=5.0*V3Assign(0.50, 0.50,0.50);
   parFaces^[wNumFaces].aprPoint[4]:=@parPoints^[wNumPoints]; inc(wNumPoints);
   parFaces^[wNumFaces].nNbPoint:=4;

   // Add two faces, to see that proglems can occure with only two
   // faces, if we want to distinguish the top from the bottom of the faces
   // For some point of view,
   // The edge (2.50, 0.10, 0.00) --- (2.50, 0.00, 0.00)
   // should be both colors since it belongs to a face which upper face is
   // visible and to a face which lower face is visible.
   inc(wNumFaces);
   parPoints^[wNumPoints].vecV:=5.0*V3Assign(2.00, 0.00, 0.00);
   parFaces^[wNumFaces].aprPoint[1]:=@parPoints^[wNumPoints]; inc(wNumPoints);
   parPoints^[wNumPoints].vecV:=5.0*V3Assign(2.50, 0.30, 0.00);
   parFaces^[wNumFaces].aprPoint[2]:=@parPoints^[wNumPoints]; inc(wNumPoints);
   parPoints^[wNumPoints].vecV:=5.0*V3Assign(2.50, 0.30, 1.00);
   parFaces^[wNumFaces].aprPoint[3]:=@parPoints^[wNumPoints]; inc(wNumPoints);
   parPoints^[wNumPoints].vecV:=5.0*V3Assign(2.00, 0.00, 1.00);
   parFaces^[wNumFaces].aprPoint[4]:=@parPoints^[wNumPoints]; inc(wNumPoints);
   parFaces^[wNumFaces].nNbPoint:=4;

   inc(wNumFaces);
   parPoints^[wNumPoints].vecV:=5.0*V3Assign(2.50, 0.30, 0.00);
   parFaces^[wNumFaces].aprPoint[1]:=@parPoints^[wNumPoints]; inc(wNumPoints);
   parPoints^[wNumPoints].vecV:=5.0*V3Assign(3.00, 0.00, 0.00);
   parFaces^[wNumFaces].aprPoint[2]:=@parPoints^[wNumPoints]; inc(wNumPoints);
   parPoints^[wNumPoints].vecV:=5.0*V3Assign(3.00, 0.00, 1.00);
   parFaces^[wNumFaces].aprPoint[3]:=@parPoints^[wNumPoints]; inc(wNumPoints);
   parPoints^[wNumPoints].vecV:=5.0*V3Assign(2.50, 0.30, 1.00);
   parFaces^[wNumFaces].aprPoint[4]:=@parPoints^[wNumPoints]; inc(wNumPoints);
   parFaces^[wNumFaces].nNbPoint:=4;

   dec(wNumPoints);

   // Optional, defining if one or two colors are used, and
   // can change the default standard colors
   // The Created Pen will be destroyed automatically
   papoBodies^[wNumBodies]^.fUniColor:=FALSE; // Ask to have two colors
   papoBodies^[wNumBodies]^.colorSup.wColor:=RGB(255,255,255);
   papoBodies^[wNumBodies]^.colorInf.wColor:=RGB(255,  0,  0);
   papoBodies^[wNumBodies]^.strBodyName:=GetMsg(11101); // A Problem

   // Some final setups, positionning and Drawing
   FinalBodySetup;

   // Final rotation for the viweing
//   papoBodies^[wNumBodies]^.BodyRotateGC(vecRight, 35*Pi/180);

   // Erase the background and draw the problem figure
   Draw3DBodies;
   end; // with
end;  // TMyWindow.TestZ

procedure TMyWindow.ToggleView3D(fRedrawP:boolean);
//================================================
// Change the 3D viewing, with glasses or without glasses
begin
poDraw3D^.fView3DWithGalsses:=not poDraw3D^.fView3DWithGalsses;

if poDraw3D^.fView3DWithGalsses then
     CheckMenuItem(hMenuWin, 121, MF_BYCOMMAND or MF_CHECKED)
else CheckMenuItem(hMenuWin, 121, MF_BYCOMMAND or MF_UNCHECKED);

if fRedrawP then InvalidateRgn(hWin, 0, TRUE);
end;  // TMyWindow.ToggleView3D

function TMyWindow.WMCommand(wPar:WPARAM; lPar:LPARAM):LRESULT;
//=============================================================
// Handles the menu messages
Var wNrMenu     : word;
begin
WMCommand := 0; // Default return value when processing a message

if (lPar <> 0) then begin
   // call the parent WMCommand method.
   WMCommand:=inherited WMCommand(wPar, lPar);
   exit;
   end;

// for the menus,  lPar = 0
//=========================
wNrMenu   := LoWord(wPar);
Case wNrMenu Of
    51 : NewSpaceWorld;
   101 : ASurface;
   102 : ATorus;
   103 : AnEllipsoide;
   104 : ACube;
   105 : ATwistedTorus;
   106 : AMobiusRibbon;
   107 : ASpecialTorus;
   110 : SimpleSphere;
   111 : SimpleTetrahedron;
   112 : SimpleCube;
   113 : SimpleOctahedron;
   114 : SimpleDodecahedron;
   115 : SimpleIcosahedron;
   190 : TestZ;

   201 : ToggleView3D(TRUE);

   // Indicate just to use the right click for more help and a menu
   301 : DialogExecMSG(12199, @Self);

   else WMCommand:=inherited WMCommand(wPar, lPar);
   end;  // Case NrMenu Of
end;  // TMyWindow.WMCommand

function TMyWindow.WindowProc(hWindow:HWND; wMsg:UINT; wPar:WPARAM; lPar:LPARAM):LRESULT;
//======================================================================================
begin

if (wMsg = WM_SETFOCUS) then begin
   if (poDraw3D^.hWin > 0) then  SetFocus(poDraw3D^.hWin);
   WindowProc:=0;
   exit;
   end;

// Default treatment of a message. Does nearly nothing
WindowProc := inherited WindowProc(hWindow, wMsg, wPar, lPar);
end;  // TMyWindow.WindowProc

Begin // MAIN ******
// Name under which the main window is registered. Spaces are not allowed
oApp.Init('Example057');

// Creation of the main window
new(poMyMainWin, Init('tEx057. Testing the 3D drawings (wDraw3DFrame0.pp)'));

// The App.WindowClass can be modified here, if wanted. (Not usual)
oApp.Run;
oApp.Done;  // The main window object is disposed here.
End.

