{ Testing the wSurface2D0.pp unit.
  Many surfaces can be seen with this unit.
  The surface must be defined :  Z = Func(X, Y),
  X in [Xmin..Xmax],  Y in [Ymin, Ymax]

  Many examples are given here.
  Once the function is defined and stored in a matrix, it can be
  seen, rotated, zoomed, cut. Test it, you will see.
  The help indicates the key functions.
  --------------------------------------------}
program tEx055;

// 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
 ,wSurface2DFrame0
 ,wDialogCreatorLOW2
 ,wDebug0
 ,wGlobals2
 ,Windows;

type
  PMyWindow = ^TMyWindow;
  TMyWindow = object(TWindow)
  //"""""""""""""""""""""""""
  aavMat      : array[-30..30,-30..30] of Float;
  // The matrix containing the surface to show

  aavMatDemo  : array[0..60,0..70] of Float;
  // This is not efficient to have this matrix, but
  // just to demonstrate that other matrices can be used

  aavMatDemo2  : array[0..256,0..3] of Float;
  // This is not efficient to have this matrix, but
  // just to demonstrate that other matrices can be used and
  // with very different dimensions.

  poSurf2D : PSurface2DFrame;

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

  procedure Test1; virtual;
  procedure Test2; virtual;
  procedure Test3; virtual;
  procedure Test4; virtual;
  procedure Test5; virtual;
  procedure Test6; virtual;
  procedure Test7; virtual;
  procedure Test8; virtual;
  procedure Test9; virtual;

  procedure Test21; virtual;
  // A moving function

  procedure Test22; virtual;
  // Another moving function

  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(TWindow0)

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

var
  oApp        : TApplication;
  poMyMainWin : PMyWindow;

//******************************************************************
// TMyWindow = object(TWindow0)
//******************************************************************

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

new(poSurf2D, Init(@Self));

new(poStatusLine, Init(@Self));
end;  // TMyWindow.Init

destructor TMyWindow.Done;
//========================
begin
// Do not dispose poSurf2D, 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.
begin
inherited WinCreate(strWinClass);

poSurf2D^.nYSizePix:=poSurf2D^.nYSizePix - int32(poStatusLine^.wHeight);
poSurf2D^.CtrlCreate;
end;  // TMyWindow.WinCreate

procedure TMyWindow.Test1;
//========================
// Set the five numbers data associated to a string
var
  nX,nY       : integer;
  wError      : Word32;
begin
wError:=0;

with poSurf2D^ do begin
  // These values MUST be defined before calling  Surf2DCompute
  //""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
  pavMat:=@aavMatDemo;

  nMatMinIndexX := 0;
  nMatMaxIndexX :=60;
  nMatMinIndexY := 0;
  nMatMaxIndexY :=70;
  // Tells which are the real indexes and dimensions of the matrix.
  // This means that the matrix has been defined as an
  // array[nMatMinIndexX..nMatMaxIndexX, nMatMinIndexY..nMatMaxIndexY] of Float;

  nDefinedMinIndexX := 0;
  nDefinedMaxIndexX :=50;
  nDefinedMinIndexY := 0;
  nDefinedMaxIndexY :=50;
  // Tells which indexes have been assigned to the matrix.
  // if  Mat  is the matrix defined with the above type, then
  // Mat[nx,ny] has been defined for
  // nx in [nDefinedMinIndexX..nDefinedMaxIndexX]
  // ny in [nDefinedMinIndexY..nDefinedMaxIndexY]
  // For other values of nx and ny, the matrix could not have been assigned values.

  // These values can be defined. Default values are shown
  //""""""""""""""""""""""""""""""""""""""""""""""""""""""
   vP1 :=-1;
   vP2 :=-2;
   vP3 := 3;

   // initialises internal values from the given values.
   // If parameter = 1, initialise also the default values.
   // Should be called, just after vP1, vP2 and vP3 has been defined.
   Initialise(1);

  vZMinLimit :=-1e30;
  vZMaxLimit := 1e30;

  nUseMinIndexX := 32767;  // tells to give the same values as the nDefined...
  nUseMaxIndexX :=-32767;
  nUseMinIndexY := 32767;
  nUseMaxIndexY :=-32767;

  nDeltaIndexX  :=1; // no points are skipped, i.e. view with maximum resolution
  nDeltaIndexY  :=1;

   vSurfXOrg :=0.0;
   vSurfYOrg :=0.0;
   vSurfDX   :=1.0;
   vSurfDY   :=1.0;
   wFlags    :=  0;

   ColorSuperior :=RGB(255,255,255); // white
   ColorInferior :=RGB(255,  0,  0); // red
   ColorFrame    :=RGB(  0,  0,255); // Blue
   ColorAxes     :=RGB(  0,255,  0); // LightGreen

   // These values are changed with the key when visualising.
   vProjZoomFactor :=1;
   nXProjTranslate :=0;
   nYProjTranslate :=0;

   // Compute the matrix
   for nX:=0 to nDefinedMaxIndexX do for nY:=0 to nDefinedMaxIndexY do
      aavMatDemo[nX,nY]:=(sqr(nX-20)+sqr(nY-20)) / 20.0;

   // Change some default value
   wFlags :=flaSurf2D_DrawAxes or flaSurf2D_DrawGroundFrame;
   vProjZoomFactor :=0.8;

   // Compute the dimensions for a nice view
   EraseBackground;
   Surf2DCompute(wError);

   // Fixe the dimensions
   wFlags :=wFlags or flaSurf2D_UserLimits;
   end; // with

if (wError <> 0) then DBW(1, 'wError=' + ITS(wError));

end;  // TMyWindow.Test1

procedure TMyWindow.Test2;
//========================
// Set the five numbers data associated to a string
var
  nX,nY       : integer;
  wError      : Word32;
begin
wError:=0;

with poSurf2D^ do begin
  // These values MUST be defined before calling  Surf2DCompute
  //""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
  pavMat:=@aavMat;

  nMatMinIndexX :=-30;
  nMatMaxIndexX := 30;
  nMatMinIndexY :=-30;
  nMatMaxIndexY := 30;

  nDefinedMinIndexX :=-20;
  nDefinedMaxIndexX := 20;
  nDefinedMinIndexY :=-28;
  nDefinedMaxIndexY := 26;

   // initialises internal values from the given values.
   // If parameter = 1, initialise also the default values.
   // Should be called, just after vP1, vP2 and vP3 has been defined.
   Initialise(1);

   for nX:=nDefinedMinIndexX to nDefinedMaxIndexX do
    for nY:=nDefinedMinIndexY to nDefinedMaxIndexY do
      aavMat[nX,nY]:=(sqr(nX)+sqr(nY)) / 20.0;

   // I want to see the axis
   wFlags :=flaSurf2D_DrawAxes or flaSurf2D_DrawGroundFrame;
   vProjZoomFactor :=0.8;

   // Compute the dimensions for a nice view
   EraseBackground;
   Surf2DCompute(wError);

   // Fixe the dimensions
   wFlags :=wFlags or flaSurf2D_UserLimits;
   end; // with

if (wError <> 0) then DBW(1, 'wError=' + ITS(wError));
end;  // TMyWindow.Test2

procedure TMyWindow.Test3;
//========================
var
  nX,nY       : int32;
  wError      : Word32;
begin
wError:=0;

with poSurf2D^ do begin
  // These values MUST be defined before calling  Surf2DCompute
  //""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
  pavMat:=@aavMat;

  nMatMinIndexX :=-30;
  nMatMaxIndexX := 30;
  nMatMinIndexY :=-30;
  nMatMaxIndexY := 30;

  nDefinedMinIndexX :=-30;
  nDefinedMaxIndexX := 30;
  nDefinedMinIndexY :=-30;
  nDefinedMaxIndexY := 30;

   // initialises internal values from the given values.
   // If parameter = 1, initialise also the default values.
   // Should be called, just after vP1, vP2 and vP3 has been defined.
   Initialise(1);

   for nX:=nDefinedMinIndexX to nDefinedMaxIndexX do
    for nY:=nDefinedMinIndexY to nDefinedMaxIndexY do
      aavMat[nX,nY]:=30*cos(sqrt(sqr(nX)+sqr(nY))*Pi/5) *
                      exp(-sqrt(sqr(nX)+sqr(nY))*0.08);

   // I want to see the axis
   wFlags :=flaSurf2D_DrawAxes or flaSurf2D_DrawGroundFrame;
   vProjZoomFactor :=0.8;

   // Compute the dimensions for a nice view
   EraseBackground;
   Surf2DCompute(wError);

   // Fixe the dimensions
   wFlags :=wFlags or flaSurf2D_UserLimits;
   end; // with

if (wError <> 0) then DBW(1, 'wError=' + ITS(wError));
end;  // TMyWindow.Test3

procedure TMyWindow.Test4;
//========================
var
  nX,nY       : int32;
  wError      : Word32;
  vX,vY       : Float;
begin
wError:=0;

with poSurf2D^ do begin
  // These values MUST be defined before calling  Surf2DCompute
  //""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
  pavMat:=@aavMat;

  nMatMinIndexX :=-30;
  nMatMaxIndexX := 30;
  nMatMinIndexY :=-30;
  nMatMaxIndexY := 30;

  nDefinedMinIndexX :=-30;
  nDefinedMaxIndexX := 30;
  nDefinedMinIndexY :=-30;
  nDefinedMaxIndexY := 30;

   // initialises internal values from the given values.
   // If parameter = 1, initialise also the default values.
   // Should be called, just after vP1, vP2 and vP3 has been defined.
   Initialise(1);

   for nX:=nDefinedMinIndexX to nDefinedMaxIndexX do
    for nY:=nDefinedMinIndexY to nDefinedMaxIndexY do begin
      vX:=nX / Float(nDefinedMaxIndexX); // in [-1..1]
      vY:=nY / Float(nDefinedMaxIndexY); // in [-1..1]
      if (vX = 0) then vX:=0.00001; // to avoid dividion by zero

      aavMat[nX,nY]:=20 * vX * vY / (sqr(vX) + sqr(vY));
      end;

   // instead of multiplying by  20  you can also fixe :
//   vSurfDX   :=1.0 / 20.0;
//   vSurfDY   :=1.0 / 20.0;

   // I want to see the axis
   wFlags :=flaSurf2D_DrawAxes or flaSurf2D_DrawGroundFrame;
   vProjZoomFactor :=0.8;

   // Compute the dimensions for a nice view
   EraseBackground;
   Surf2DCompute(wError);

   // Fixe the dimensions
   wFlags :=wFlags or flaSurf2D_UserLimits;
   end; // with

if (wError <> 0) then DBW(1, 'wError=' + ITS(wError));
end;  // TMyWindow.Test4

procedure TMyWindow.Test5;
//========================
var
  nX,nY       : int32;
  wError      : Word32;
  vX,vY       : Float;
begin
wError:=0;

with poSurf2D^ do begin
  // These values MUST be defined before calling  Surf2DCompute
  //""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
  pavMat:=@aavMat;

  nMatMinIndexX :=-30;
  nMatMaxIndexX := 30;
  nMatMinIndexY :=-30;
  nMatMaxIndexY := 30;

  nDefinedMinIndexX :=-30;
  nDefinedMaxIndexX := 30;
  nDefinedMinIndexY :=-30;
  nDefinedMaxIndexY := 30;

   // initialises internal values from the given values.
   // If parameter = 1, initialise also the default values.
   // Should be called, just after vP1, vP2 and vP3 has been defined.
   Initialise(1);

   for nX:=nDefinedMinIndexX to nDefinedMaxIndexX do
    for nY:=nDefinedMinIndexY to nDefinedMaxIndexY do begin
      vX:=nX / Float(nDefinedMaxIndexX); // in [-1..1]
      vY:=nY / Float(nDefinedMaxIndexY); // in [-1..1]
      if (vX = 0) then vX:=0.00001; // to avoid dividion by zero

      if (abs(vY) > 5 * abs(vX)) then vY:=5*vX;

      aavMat[nX,nY]:=sqr(vY / vX);
      end;

   // I want to see the axis
   wFlags :=flaSurf2D_DrawAxes or flaSurf2D_DrawGroundFrame;
   vProjZoomFactor :=0.8;

   // Compute the dimensions for a nice view
   EraseBackground;
   Surf2DCompute(wError);

   // Fixe the dimensions
   wFlags :=wFlags or flaSurf2D_UserLimits;
   end; // with

if (wError <> 0) then DBW(1, 'wError=' + ITS(wError));
end;  // TMyWindow.Test5

procedure TMyWindow.Test6;
//========================
var
  nX,nY       : int32;
  wError      : Word32;
  vX,vY       : Float;
begin
wError:=0;

with poSurf2D^ do begin
  // These values MUST be defined before calling  Surf2DCompute
  //""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
  pavMat:=@aavMat;

  nMatMinIndexX :=-30;
  nMatMaxIndexX := 30;
  nMatMinIndexY :=-30;
  nMatMaxIndexY := 30;

  nDefinedMinIndexX :=-30;
  nDefinedMaxIndexX := 30;
  nDefinedMinIndexY :=-30;
  nDefinedMaxIndexY := 30;

   // initialises internal values from the given values.
   // If parameter = 1, initialise also the default values.
   // Should be called, just after vP1, vP2 and vP3 has been defined.
   Initialise(1);

   for nX:=nDefinedMinIndexX to nDefinedMaxIndexX do
    for nY:=nDefinedMinIndexY to nDefinedMaxIndexY do begin
      vX:=nX / Float(nDefinedMaxIndexX); // in [-1..1]
      vY:=nY / Float(nDefinedMaxIndexY); // in [-1..1]
      if (vX = 0) then vX:=0.00001; // to avoid dividion by zero

      aavMat[nX,nY]:=20*(sqr(vX) - sqr(vY)) / (sqr(vX) + sqr(vY));
      end;

   // I want to see the axis
   wFlags :=flaSurf2D_DrawAxes or flaSurf2D_DrawGroundFrame;
   vProjZoomFactor :=0.8;

   // Compute the dimensions for a nice view
   EraseBackground;
   Surf2DCompute(wError);

   // Fixe the dimensions
   wFlags :=wFlags or flaSurf2D_UserLimits;
   end; // with

if (wError <> 0) then DBW(1, 'wError=' + ITS(wError));
end;  // TMyWindow.Test6

procedure TMyWindow.Test7;
//========================
var
  nX,nY       : int32;
  wError      : Word32;
  vX,vY       : Float;
begin
wError:=0;

with poSurf2D^ do begin
  // These values MUST be defined before calling  Surf2DCompute
  //""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
  pavMat:=@aavMat;

  nMatMinIndexX :=-30;
  nMatMaxIndexX := 30;
  nMatMinIndexY :=-30;
  nMatMaxIndexY := 30;

  nDefinedMinIndexX :=-30;
  nDefinedMaxIndexX := 30;
  nDefinedMinIndexY :=-30;
  nDefinedMaxIndexY := 30;

   // initialises internal values from the given values.
   // If parameter = 1, initialise also the default values.
   // Should be called, just after vP1, vP2 and vP3 has been defined.
   Initialise(1);

   for nX:=nDefinedMinIndexX to nDefinedMaxIndexX do
    for nY:=nDefinedMinIndexY to nDefinedMaxIndexY do begin
      vX:=nX / Float(nDefinedMaxIndexX); // in [-1..1]
      vY:=nY / Float(nDefinedMaxIndexY); // in [-1..1]

      aavMat[nX,nY]:=50*vY * sqr(vX);
      end;

   // I want to see the axis
   wFlags :=flaSurf2D_DrawAxes or flaSurf2D_DrawGroundFrame;
   vProjZoomFactor :=0.8;

   // Compute the dimensions for a nice view
   EraseBackground;
   Surf2DCompute(wError);

   // Fixe the dimensions
   wFlags :=wFlags or flaSurf2D_UserLimits;
   end; // with

if (wError <> 0) then DBW(1, 'wError=' + ITS(wError));
end;  // TMyWindow.Test7

procedure TMyWindow.Test8;
//========================
var
  nX,nY       : int32;
  wError      : Word32;
  vX,vY       : Float;
begin
wError:=0;

with poSurf2D^ do begin
  // These values MUST be defined before calling  Surf2DCompute
  //""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
  pavMat:=@aavMat;

  nMatMinIndexX :=-30;
  nMatMaxIndexX := 30;
  nMatMinIndexY :=-30;
  nMatMaxIndexY := 30;

  nDefinedMinIndexX :=-30;
  nDefinedMaxIndexX := 30;
  nDefinedMinIndexY :=-30;
  nDefinedMaxIndexY := 30;

   // initialises internal values from the given values.
   // If parameter = 1, initialise also the default values.
   // Should be called, just after vP1, vP2 and vP3 has been defined.
   Initialise(1);

   for nX:=nDefinedMinIndexX to nDefinedMaxIndexX do
    for nY:=nDefinedMinIndexY to nDefinedMaxIndexY do begin
      vX:=nX / Float(nDefinedMaxIndexX); // in [-1..1]
      vY:=nY / Float(nDefinedMaxIndexY); // in [-1..1]

        aavMat[nX,nY]:=vY*(vY-1)*(0.1-vX*(vX+1)*(vX-1.1))+
                      (vY+1)*(vY-1)*(vX+1)*sqr(vX*(vX-1)*(vX+1.1))+
                       vY*(vY+1)*(-0.2 + (vX+1)*sqr(vX)*(vX-0.7));
      end;

   vSurfDX   :=1.0 / 30.0;
   vSurfDY   :=1.0 / 30.0;

   // I want to see the axis
//   wFlags :=flaSurf2D_DrawAxes or flaSurf2D_DrawGroundFrame;
   vProjZoomFactor :=0.8;

   // Compute the dimensions for a nice view
   EraseBackground;
   Surf2DCompute(wError);

   // Fixe the dimensions
   wFlags :=wFlags or flaSurf2D_UserLimits;
   end; // with

if (wError <> 0) then DBW(1, 'wError=' + ITS(wError));
end;  // TMyWindow.Test8

procedure TMyWindow.Test9;
//========================
var
  nX,nY       : int32;
  wError      : Word32;
  vX,vY       : Float;
  r1,r2,r3,r4 : Float;
  x3,x6,y3,y6 : Float;
begin
wError:=0;

with poSurf2D^ do begin
  // These values MUST be defined before calling  Surf2DCompute
  //""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
  pavMat:=@aavMat;

  nMatMinIndexX :=-30;
  nMatMaxIndexX := 30;
  nMatMinIndexY :=-30;
  nMatMaxIndexY := 30;

  nDefinedMinIndexX :=-30;
  nDefinedMaxIndexX := 30;
  nDefinedMinIndexY :=-30;
  nDefinedMaxIndexY := 30;

   // initialises internal values from the given values.
   // If parameter = 1, initialise also the default values.
   // Should be called, just after vP1, vP2 and vP3 has been defined.
   Initialise(1);

   for nX:=nDefinedMinIndexX to nDefinedMaxIndexX do
    for nY:=nDefinedMinIndexY to nDefinedMaxIndexY do begin
      vX:=5*(nX-nDefinedMinIndexX) / Float(nDefinedMaxIndexX); // in [0..10]
      vY:=5*(nY-nDefinedMinIndexY) / Float(nDefinedMaxIndexY); // in [0..10]

      x3:=sqr(vX-3);   x6:=sqr(vX-6);   y3:=sqr(vY-3);  y6:=sqr(vY-6);
      r1:=x3+y6;       r2:=x6+y6;       r3:=x6+y3;      r4:=x3+y3;

      aavMat[nX,nY]:=1/(r1+0.5)+1/(r2+0.3)+1/(r3+0.5)-1/(r4+1);
      end;

   vSurfDX   :=1.0 / 7.0;
   vSurfDY   :=1.0 / 7.0;

   // I want to see the axis
//   wFlags :=flaSurf2D_DrawAxes or flaSurf2D_DrawGroundFrame;
   vProjZoomFactor :=0.8;

   // Compute the dimensions for a nice view
   EraseBackground;
   Surf2DCompute(wError);

   // Fixe the dimensions
   wFlags :=wFlags or flaSurf2D_UserLimits;
   end; // with

if (wError <> 0) then DBW(1, 'wError=' + ITS(wError));
end;  // TMyWindow.Test9

procedure TMyWindow.Test21;
//========================
var
  nX,nY       : int32;
  wError      : Word32;
  vX,vY       : Float;
  nTime       : integer;

begin
wError:=0;

with poSurf2D^ do begin
  // These values MUST be defined before calling  Surf2DCompute
  //""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
  pavMat:=@aavMat;

  nMatMinIndexX :=-30;
  nMatMaxIndexX := 30;
  nMatMinIndexY :=-30;
  nMatMaxIndexY := 30;

  nDefinedMinIndexX :=-30;
  nDefinedMaxIndexX := 30;
  nDefinedMinIndexY :=-30;
  nDefinedMaxIndexY := 30;

   // initialises internal values from the given values.
   // If parameter = 1, initialise also the default values.
   // Should be called, just after vP1, vP2 and vP3 has been defined.
   Initialise(1);

   for nTime:=0 to 10000 do begin
      for nX:=nDefinedMinIndexX to nDefinedMaxIndexX do
      for nY:=nDefinedMinIndexY to nDefinedMaxIndexY do begin
         vX:=nX / Float(nDefinedMaxIndexX); // in [-1..1]
         vY:=nY / Float(nDefinedMaxIndexY); // in [-1..1]
         if (vX = 0) then vX:=0.00001; // to avoid dividion by zero

         aavMat[nX,nY]:=exp(-12*(sqr(vX-0.5*cos(nTime/10.0)) +
                                sqr(vY-0.3*sin(nTime/10.0))  ));
         end;

      if (nTime = 0) then begin
         // First initialisation
         vSurfDX   :=1.0 / 10.0;
         vSurfDY   :=1.0 / 10.0;

         vProjZoomFactor :=0.8;

         // Compute the dimensions for a nice view
         EraseBackground;
         Surf2DCompute(wError);

         // Fixe the dimensions
         wFlags :=wFlags or flaSurf2D_UserLimits;
         end
      else  Visualise(0);

      // Pressing the escape key will quit the loop
      // Key are transmitted to the application, thus the
      // view can change while the surface is moving
      // Be carefull, that any other action is accepted, even selecting a menu
      // This can make the application crash...
      if (oApp.IsKeyPressed(1) = VK_ESCAPE) then exit;
      end; // for nTime

   end; // with

if (wError <> 0) then DBW(1, 'wError=' + ITS(wError));
end;  // TMyWindow.Test21

procedure TMyWindow.Test22;
//========================
var
  nX,nY       : int32;
  wError      : Word32;
  vFunc,
  vX          : Float;
  nTime       : integer;

begin
wError:=0;

with poSurf2D^ do begin
  // These values MUST be defined before calling  Surf2DCompute
  //""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
  pavMat:=@aavMatDemo2;

  nMatMinIndexX :=   0;
  nMatMaxIndexX := 256;
  nMatMinIndexY :=   0;
  nMatMaxIndexY :=   3;

  nDefinedMinIndexX :=   0;
  nDefinedMaxIndexX := 256;
  nDefinedMinIndexY :=   0;
  nDefinedMaxIndexY :=   3;

  // Change the initial projection point.
  vP1:=0.2;
  vP2:=1.0;
  vP3:=0.3;

   // initialises internal values from the given values.
   // If parameter = 1, initialise also the default values.
   // Should be called, just after vP1, vP2 and vP3 has been defined.
   Initialise(1);

   for nTime:=0 to 10000 do begin
      for nX:=nDefinedMinIndexX to nDefinedMaxIndexX do
      for nY:=nDefinedMinIndexY to nDefinedMaxIndexY do begin
         vX:=(((nX+nTime) mod nDefinedMaxIndexX) - nDefinedMaxIndexX div 2) *
             24*Pi / Float(nDefinedMaxIndexX); // in [-12*Pi..12*Pi]

         if (abs(vX) < 2.5*Pi) then begin
            vFunc:=(1.0 - sqr(vX / (2.5*Pi)) ) * cos(vX);
            end
         else vFunc:=0;

         // A second wave, moving a little faster
         vX:=(((nX + 100 + (4*nTime) div 3) mod nDefinedMaxIndexX) - nDefinedMaxIndexX div 2) *
             24*Pi / Float(nDefinedMaxIndexX); // in [-12*Pi..12*Pi]

         if (abs(vX) < 2.5*Pi) then begin
            aavMatDemo2[nX,nY]:=vFunc - (1.0 - sqr(vX / (2.5*Pi)) ) * cos(vX);
            end
         else aavMatDemo2[nX,nY]:=vFunc;
         end;

      if (nTime = 0) then begin
         // First initialisation
         vSurfDX   :=10.0 / nDefinedMaxIndexX;
         vSurfDY   :=200.0 / nDefinedMaxIndexX;

         // Compute the dimensions for a nice view
         EraseBackground;
         Surf2DCompute(wError);

         // Fixe the dimensions
         wFlags :=wFlags or flaSurf2D_UserLimits;
         end
      else  Visualise(0);

      // Pressing the escape key will quit the loop
      // Key are transmitted to the application, thus the
      // view can change while the surface is moving
      // Be carefull, that any other action is accepted, even selecting a menu
      // This can make the application crash...
      if (oApp.IsKeyPressed(1) = VK_ESCAPE) then exit;

      if (wError <> 0) then begin
         DBW(1, 'wError=' + ITS(wError));
         exit;
         end;
      end; // for nTime

   end; // with

end;  // TMyWindow.Test22

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; // if (lPar <> 0) then begin

// for the menus,  lPar = 0
//=========================
wNrMenu   := LoWord(wPar);
Case wNrMenu Of
   100 : DBW0(0, '');  // just open the debugging window
   101 : Test1;
   102 : Test2;
   103 : Test3;
   104 : Test4;
   105 : Test5;
   106 : Test6;
   107 : Test7;
   108 : Test8;
   109 : Test9;

   121 : Test21;
   122 : Test22;

   201 : DialogCreateMSG(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;
//=======================================================================================
// All window messages are send here.

Begin
WindowProc := 0; // Default return value when processing a message

Case wMsg Of
   WM_KEYDOWN : if (wPar >= VK_NUMPAD0) and (wPar <= VK_DIVIDE) and
                   (poSurf2D <>  NIL) then poSurf2D^.Visualise(wPar);

   else begin // Case wMsg Of
      // Default processing of the messages.
      WindowProc:=inherited WindowProc(hWindow, wMsg, wPar, lPar);
      end; // Case wMsg Of
   End; // Case wMsg Of

End;  // TMyWindow.WindowProc

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

// Creation of the main window
new(poMyMainWin, Init('tEx055. Test the wSurface2D0.pp unit.'));

oApp.Run;
oApp.Done;  // The main window object is disposed here.
End.

