unit ModelUnit;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls, OpenGL, MaticeUnit, Math, Vcl.StdCtrls, Vcl.ExtDlgs;

type
  TMyColor = record
    R, G, B: GLubyte;
  end;
  TBod_Vektor = array [1..3] of glDouble;
  TPozorovatel = record
    Vzdalenost: Single;
    HorzUhel, VertUhel: Single;
    Pozice, SmerPohledu: TBod_Vektor;
  end;
  TModelForm = class(TForm)
    Panel: TPanel;
    Edit1: TEdit;
    Edit2: TEdit;
    Button1: TButton;
    Label1: TLabel;
    Label2: TLabel;
    Edit3: TEdit;
    Label3: TLabel;
    Panel1: TPanel;
    SavePictureDialog1: TSavePictureDialog;
    Button2: TButton;
    procedure FormActivate(Sender: TObject);
    procedure PanelMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
    procedure PanelMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
    procedure PanelMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure PanelClick(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure FormResize(Sender: TObject);
    procedure Edit2Change(Sender: TObject);
  private
    { Private declarations }
    rc: HGLRC;
    dc: HDC;
    Barva: TMyColor;
    Pozorovatel: TPozorovatel;
    XSour, YSour, ZSour: Single;
    CisloTlacitka: Byte;

    procedure InitGL;
    procedure glDraw;
  public
    { Public declarations }
    MaticeVysek: TMatice;
    MaticeHodnot: TMatice;
  end;

var
  ModelForm: TModelForm;


implementation

{$R *.dfm}

{ TForm1 }

procedure TModelForm.Button1Click(Sender: TObject);
begin
  Pozorovatel.Vzdalenost := StrToFloat(Edit3.Text);
  Pozorovatel.HorzUhel := StrTOFloat(Edit1.Text);
  Pozorovatel.VertUhel := StrTOFloat(Edit2.Text);
  glDraw;
end;

procedure TModelForm.Button2Click(Sender: TObject);
var
  bmp: TBitmap;
  Index: Integer;
  pbuf, p1, p2: pointer;
begin
  if SavePictureDialog1.Execute then begin
     bmp := TBitmap.Create;
    try
      GetMem(pbuf, Panel.Width * Panel.Height * 3);
      glReadBuffer(GL_FRONT);
      glReadPixels(0, 0, Panel.Width, Panel.Height, GL_BGR_EXT, GL_UNSIGNED_BYTE, pbuf);
      bmp.PixelFormat := pf24bit;
      bmp.Height := Panel.Height;
      bmp.Width := Panel.Width;

      for Index := 0 to Panel.Height -1 do begin
        p1 := bmp.ScanLine[Panel.Height - 1 - Index];
        p2 := pointer(integer(pbuf)+(Index*bmp.Width*3));
        CopyMemory(p1, p2, bmp.Width*3);
      end;
      bmp.SaveToFile(SavePictureDialog1.FileName);
    finally
      bmp.Free;
      FreeMem(pbuf);
    end;
  end;
end;


procedure TModelForm.Edit2Change(Sender: TObject);
begin
  if StrToInt(Edit2.Text)> 89 then
    Edit2.Text := IntToStr(89);
  if StrToInt(Edit2.Text) < 0 then
    Edit2.Text := IntToStr(0);
end;

procedure TModelForm.FormActivate(Sender: TObject);
var
  pfd: TPixelFormatDescriptor;
  PF: Integer;
begin
  dc := GetDC(Panel.Handle);

  pfd.nSize := sizeof(pfd);
  pfd.nVersion := 1;
  pfd.dwFlags := PFD_DRAW_TO_WINDOW or PFD_SUPPORT_OPENGL or PFD_DOUBLEBUFFER or 0;
  pfd.iPixelType := PFD_TYPE_RGBA;
  pfd.cColorBits := 32;
  pf := ChoosePixelFormat(dc, @pfd);
  SetPixelFormat(dc, pf, @pfd);
  rc := wglCreateContext(dc);
  wglMakeCurrent(dc, rc);

  screen.Cursor := crDefault;
  InitGL;
  Pozorovatel.Vzdalenost := StrToFloat(Edit3.Text);
  Pozorovatel.HorzUhel := StrTOFloat(Edit1.Text);
  Pozorovatel.VertUhel := StrTOFloat(Edit2.Text);
end;

procedure TModelForm.FormCreate(Sender: TObject);
var
  pfd: TPixelFormatDescriptor;
  PF: Integer;
begin
//  dc := GetDC(Panel.Handle);
//
//  pfd.nSize := sizeof(pfd);
//  pfd.nVersion := 1;
//  pfd.dwFlags := PFD_DRAW_TO_WINDOW or PFD_SUPPORT_OPENGL or PFD_DOUBLEBUFFER or 0;
//  pfd.iPixelType := PFD_TYPE_RGBA;
//  pfd.cColorBits := 32;
//  pf := ChoosePixelFormat(dc, @pfd);
//  SetPixelFormat(dc, pf, @pfd);
//  rc := wglCreateContext(dc);
//  wglMakeCurrent(dc, rc);
//
//  screen.Cursor := crDefault;
//  InitGL;
end;

procedure TModelForm.FormDestroy(Sender: TObject);
begin
  wglMakeCurrent(0, 0);
  wglDeleteContext(rc);
end;

procedure TModelForm.FormResize(Sender: TObject);
begin
  Panel.Width := ClientHeight-Panel1.Height;
  Panel.Height := ClientHeight-Panel1.Height;
  Panel.Left := Round((ClientWidth-Panel.Width)/2);
end;

procedure TModelForm.glDraw;
var
  A, B, C, D: TBod_Vektor;
  i, j: Integer;
  vyska, sirka: Double;
const
  pozicesvetla: TGLArrayf4 = (0, 0, -1, 0.0);
begin
  glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
  glLoadIdentity;

  Pozorovatel.SmerPohledu[1] := cos((Pozorovatel.HorzUhel*pi/180-pi/2))*cos(Pozorovatel.VertUhel*pi/180);
  Pozorovatel.SmerPohledu[2] := sin((Pozorovatel.HorzUhel*pi/180-pi/2))*cos(Pozorovatel.VertUhel*pi/180);
  Pozorovatel.SmerPohledu[3] := sin(Pozorovatel.VertUhel*pi/180);
  Pozorovatel.Pozice[1] := Pozorovatel.Vzdalenost*Pozorovatel.SmerPohledu[1];
  Pozorovatel.Pozice[2]  := Pozorovatel.Vzdalenost*Pozorovatel.SmerPohledu[2];
  Pozorovatel.Pozice[3]  := Pozorovatel.Vzdalenost*Pozorovatel.SmerPohledu[3];

//  sirka := sqrt(sqr(0.01*MaticeVysek.m/2)+sqr(0.01*MaticeVysek.n/2));
//  vyska := MaticeVysek.Maximum*0.1;
  sirka := Pozorovatel.Vzdalenost;
  vyska := sirka;

  glOrtho(-5*sirka, 5*sirka, -5*sirka, 5*sirka, -5*vyska, 5*vyska);
  gluLookAt(Pozorovatel.Pozice[1], Pozorovatel.Pozice[2], Pozorovatel.Pozice[3], 0 , 0, 0, 0, 0, 1);
  glPolygonMode(GL_FRONT,GL_FILL);
  glPolygonMode(GL_BACK,GL_POINT);
  glShadeModel(GL_SMOOTH);
  glLightfv(GL_LIGHT0, GL_POSITION, @pozicesvetla);
  glEnable(GL_LIGHT0);


  for i := 0 to MaticeVysek.m - 2 do begin
    for j := 0 to MaticeVysek.n - 2 do begin
      A[1] := (j-MaticeVysek.n/2)*0.01;
      A[2] := (i-MaticeVysek.m/2)*0.01;
      A[3] := 0.05*MaticeVysek.elem[MaticeVysek.m-1-i,j];
      B[1] := (j-MaticeVysek.n/2 + 1)*0.01;
      B[2] := (i-MaticeVysek.m/2)*0.01;
      B[3] := 0.05*MaticeVysek.elem[MaticeVysek.m-1-i, j + 1];
      C[1] := (j-MaticeVysek.n/2 + 1)*0.01;
      C[2] := (i-MaticeVysek.m/2 + 1)*0.01;
      C[3] := 0.05*MaticeVysek.elem[MaticeVysek.m-1-i - 1, j + 1];
      D[1] := (j-MaticeVysek.n/2)*0.01;
      D[2] := (i-MaticeVysek.m/2 + 1)*0.01;
      D[3] := 0.05*MaticeVysek.elem[MaticeVysek.m-1-i - 1, j];
      glBegin(GL_POLYGON);
        glColor3ub(Round(MaticeHodnot.elem[MaticeVysek.m-1-i,3*j+2]), Round(MaticeHodnot.elem[MaticeVysek.m-1-i,3*j+1]), Round(MaticeHodnot.elem[MaticeVysek.m-1-i,3*j]));
        glVertex(A[1],A[2],A[3]);
        glColor3ub(Round(MaticeHodnot.elem[MaticeVysek.m-1-i,3*(j+1)+2]), Round(MaticeHodnot.elem[MaticeVysek.m-1-i,3*(j+1)+1]), Round(MaticeHodnot.elem[MaticeVysek.m-1-i,3*(j)]));
        glVertex(B[1],B[2],B[3]);
        glColor3ub(Round(MaticeHodnot.elem[MaticeVysek.m-1-i - 1,3*(j+1)+2]), Round(MaticeHodnot.elem[MaticeVysek.m-1-i - 1,3*(j+1)+1]), Round(MaticeHodnot.elem[MaticeVysek.m-1-i - 1,3*(j+1)]));
        glVertex(C[1],C[2],C[3]);
        glColor3ub(Round(MaticeHodnot.elem[MaticeVysek.m-1-i,3*j+2]), Round(MaticeHodnot.elem[MaticeVysek.m-1-i,3*j+1]), Round(MaticeHodnot.elem[MaticeVysek.m-1-i,3*j+2]));
        glVertex(A[1],A[2],A[3]);
        glVertex(A[1],A[2],A[3]);
        glColor3ub(Round(MaticeHodnot.elem[MaticeVysek.m-1-i - 1,3*(j+1)+2]), Round(MaticeHodnot.elem[MaticeVysek.m-1-i - 1,3*(j+1)+1]), Round(MaticeHodnot.elem[MaticeVysek.m-1-i - 1,3*(j+1)]));
        glVertex(C[1],C[2],C[3]);
        glColor3ub(Round(MaticeHodnot.elem[MaticeVysek.m-1-i - 1,3*j+2]), Round(MaticeHodnot.elem[MaticeVysek.m-1-i - 1,3*j+1]), Round(MaticeHodnot.elem[MaticeVysek.m-1-i - 1,3*j]));
        glVertex(D[1],D[2],D[3]);
        glColor3ub(Round(MaticeHodnot.elem[MaticeVysek.m-1-i,3*j+2]), Round(MaticeHodnot.elem[MaticeVysek.m-1-i,3*j+1]), Round(MaticeHodnot.elem[MaticeVysek.m-1-i,3*j]));
        glVertex(A[1],A[2],A[3]);
      glEnd;
    end;
  end;
  SwapBuffers(dc);
end;

procedure TModelForm.InitGL;
begin
  glClearColor(255, 255, 255, 0);
  glClearDepth(1.0);
  glEnable(GL_DEPTH_TEST);
  glDepthFunc(GL_LESS);
  glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
end;


procedure TModelForm.PanelClick(Sender: TObject);
begin
  glDraw;
end;

procedure TModelForm.PanelMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  if Button = mbLeft then begin
    CisloTlacitka := 1;
    XSour := X;
    YSour := Y;
  end else if Button = mbRight then begin
    CisloTlacitka := 2;
    ZSour := Y;
  end;
end;

procedure TModelForm.PanelMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
var
  XRozdil, YRozdil: Single;
begin
  case CisloTlacitka of
    1: begin
      XRozdil := XSour - X;
      Pozorovatel.HorzUhel := Pozorovatel.HorzUhel + (XRozdil/2);
      YRozdil := YSour - Y;
      Pozorovatel.VertUhel := Pozorovatel.VertUhel - (YRozdil/2);
      if (Pozorovatel.HorzUhel >= 360) or (Pozorovatel.HorzUhel <= 0) then
        Pozorovatel.HorzUhel := Pozorovatel.HorzUhel-(Trunc(Pozorovatel.HorzUhel/360))*360;
      if (Pozorovatel.VertUhel>90) then Pozorovatel.VertUhel := 90
      else if (Pozorovatel.VertUhel<-90) then Pozorovatel.VertUhel := -90;
      XSour:=X;
      YSour:=Y;
      glDraw;
    end;
    2: begin
      YRozdil := YSour - Y;
      Pozorovatel.Vzdalenost := Pozorovatel.Vzdalenost - (YRozdil/2);
      if Pozorovatel.Vzdalenost>25 then Pozorovatel.Vzdalenost:=25
      else if Pozorovatel.Vzdalenost<3 then Pozorovatel.Vzdalenost:=3;
      YSour:=Y;
      glDraw;
    end;
  end;
end;

procedure TModelForm.PanelMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  CisloTlacitka := 0;
end;

end.
