(********************************************************************)
  (*       Program pro vykresleni barev s danymi souradnicemi         *)
  (*       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~         *)
  (* Ovladani:                                                        *)
  (*   Pomoci sipek se pohybuji v rovine, ktera je prave aktivni      *)
  (*   Aktivni rovina: stav promenne mod_k;                           *)
  (*     klavesa F1 - rovina r=konstanta - mod_k=1                    *)
  (*             F2 - rovina g=konstanta - mod_k=2                    *)
  (*             F3 - rovina b=konstanta - mod_k=3                    *)
  (********************************************************************)

program RGBKrychle;

uses 
  graph,crt;

const
  KROK = 1;              { posunuti v krychli }

  b_podklad = 3;         { barva podkladu }
  b_kurzor  =14;         { barva kurzoru }
  b_krychle = 0;         { barva hran krychle }
  b_napisy  = 0;         { barva vysledku vypoctu }
  b_limity  = 0;
  b_ram_bar = 0;
  b_ramec   =15;
  b_info    = 0;

  poz_krychle_x = 100;   { pozice krychle na obrazovce }
  poz_krychle_y = 200;
  str_krychle   = 150;   { delka strany krychle }

  nahoru  = 72;          { cisla klaves }
  doprava = 77;
  dolu    = 80;
  doleva  = 75;
  F1      = 59;
  F2      = 60;
  F3      = 61;
  ESC     = 27;

  barvy: array[1..2,1..4]of byte = ( { na prepisovani barev setRGBpalette }
    (4, 40,  7,  7),
    (7, 49, 49, 49));

type
  c_unit = record                  { barevny bod ze 3 barev }
    r,g,b: real;                   { hodnoty z intervalu 0..1 }
    ro,gama,beta: real;            { pomerne hodnoty; soucet = 1 }
    jas: real;                     { v cernobilem }
    ir,ig,ib,ij: byte;             { intenzita jednotlivych barev 0..63 }
  end;

  bod_3 = record                   { bod v 3D modelu }
    x,y,z: integer;
  end;

  bod_2 = record                   { bod v 2D modelu }
    x,y: integer;
  end;

  krychle = record
    kurzor: bod_2;
    pozice: bod_3;                 { vzhledem k novemu souradnicovemu systemu body }
  end;

  s_cislo = array[0..5]of char;    { pro prevod cisla na retezec; 1: des. tecka }

var
  g_driver, g_mode: integer;       { pro grafiku }
  mod_k: byte;                     { 1:F1, 2:F2, 3:F3 pro ruzne roviny }
  kr: krychle;
  pom_c: word;                     { pouziti pri prepisu; barva }
  col: c_unit;                     { hodnoty jednotlivych promennych vypisovane na obrazovku }
  zn: char;
  as: longint;
{ sipky: 0: napravo     1: nalevo
         2: nahoru      3: dolu    }


procedure transform(b1: bod_3; var b2: bod_2);
{ transformace 3D na 2D, prevraceni y souradnice a posunuti }
var p: integer;
begin
  p := round(b1.x * sqrt(2)/4);
  b2.x :=  b1.y - p + poz_krychle_x;
  b2.y := -b1.z + p + poz_krychle_y;
end;

procedure vypocet;
{ vypocet vsech zobrazitelnych prvku pro novou pozici kurzoru }
var p,pom: real;
begin
  pom := 1/str_krychle;
  col.r := kr.pozice.x * pom;   col.ir := round(col.r * 63);
  col.g := kr.pozice.y * pom;   col.ig := round(col.g * 63);
  col.b := kr.pozice.z * pom;   col.ib := round(col.b * 63);

  p := col.r + col.g + col.b;
  if p<>0 then begin
    pom := 1/p;
    col.ro   := col.r * pom;
    col.gama := col.g * pom;
    col.beta := col.b * pom;
  end else begin
    col.ro   := 0;
    col.gama := 0;
    col.beta := 0;
  end;
  col.jas := 0.3 * col.r + 0.59 * col.g + 0.11 * col.b;
  col.ij  := round(col.jas * 63);
end;

procedure zobrazit;
{ zobrazi vypoctene prvky pro novou pozici kurzoru }
var s: string[10];
begin
  setfillstyle(1,b_podklad);
  bar(450,20,500,120);
  setcolor(b_napisy);
  str(col.r:5:4, s);     outtextxy(450,20, s);
  str(col.g:5:4, s);     outtextxy(450,32, s);
  str(col.b:5:4, s);     outtextxy(450,44, s);
  str(col.ro:5:4, s);    outtextxy(450,60, s);
  str(col.gama:5:4, s);  outtextxy(450,72, s);
  str(col.beta:5:4, s);  outtextxy(450,84, s);
  str(col.jas:5:4, s);   outtextxy(450,100, s);

  SetRGBPalette(barvy[1,1], col.ir, col.ig, col.ib);
  SetRGBPalette(barvy[2,1], col.ij, col.ij, col.ij);

  setfillstyle(1, barvy[1,1]);   bar(400,150,550,250);
  setfillstyle(1, barvy[2,1]);   bar(400,260,550,360);
end;

procedure pohyb_k(kam: byte);  { kam: ktera sipka }
{ reakce na pohyb kurzoru v ramci krychle }
var 
  flag:boolean;
  kraj:byte;
  pom_b:bod_2;

  procedure prepis(var b1: bod_2; b2: bod_2);
  { b1: stara pozice kurzoru; b2: nova pozice kurzoru }
  begin
    putpixel(b1.x, b1.y, pom_c);
    pom_c := getpixel(b2.x, b2.y);
    putpixel(b2.x, b2.y, b_kurzor);
    b1.x := b2.x;
    b1.y := b2.y;
  end;

begin
  flag := FALSE;
  kraj := str_krychle - KROK;
  case mod_k of
    1: case kam of
       0: if kr.pozice.y <= kraj then begin
            flag := TRUE;
            kr.pozice.y := kr.pozice.y + KROK;
          end;
       1: if kr.pozice.y >= KROK then begin
            flag := TRUE;
            kr.pozice.y := kr.pozice.y - KROK;
          end;
       2: if kr.pozice.z <= kraj then begin
            flag := TRUE;
            kr.pozice.z := kr.pozice.z + KROK;
          end;
       3: if kr.pozice.z >= KROK then begin
            flag := TRUE;
            kr.pozice.z := kr.pozice.z - KROK;
          end;
       end;

    2: case kam of
       0: if kr.pozice.x >= KROK then begin
            flag := TRUE;
            kr.pozice.x := kr.pozice.x - KROK;
          end;
       1: if kr.pozice.x <= kraj then begin
            flag := TRUE;
            kr.pozice.x := kr.pozice.x + KROK;
          end;
       2: if kr.pozice.z <= kraj then begin
            flag := TRUE;
            kr.pozice.z := kr.pozice.z + KROK;
          end;
       3: if kr.pozice.z >= KROK then begin
            flag := TRUE;
            kr.pozice.z := kr.pozice.z - KROK;
          end;
       end;

    3: case kam of
       0: if kr.pozice.y <= kraj then begin
            flag := TRUE;
            kr.pozice.y := kr.pozice.y + KROK;
          end;
       1: if kr.pozice.y >= KROK then begin
            flag := TRUE;
            kr.pozice.y := kr.pozice.y - KROK;
          end;
       2: if kr.pozice.x >= KROK then begin
            flag := TRUE;
            kr.pozice.x := kr.pozice.x - KROK;
          end;
       3: if kr.pozice.x <= kraj then begin
            flag := TRUE;
            kr.pozice.x := kr.pozice.x + KROK;
          end;
       end;
  end;

  if flag then begin
    transform(kr.pozice, pom_b);
    prepis(kr.kurzor, pom_b);
    vypocet;
    zobrazit;
  end;
end;

procedure inicializace;
{ inicializace grafiky, vykresleni zakladnich prvku obrazovky }
var
  pom_body: array [0..7]of bod_2;
  pb: bod_2;
  pom_b3: bod_3;
  old_line: linesettingstype;

begin
  g_driver := VGA;
  g_mode   := VGAHi;
  initgraph(g_driver,g_mode,'d:\bp\bgi\');
  if graphresult <> grOK then begin
    write('Je mi lito, vas zpusob grafiky zda se mi ponekud nestastny');
    halt;
  end;

  setfillstyle(1, b_podklad);
  bar(0, 0, getmaxx, getmaxy);
  kr.kurzor.x := poz_krychle_x;
  kr.kurzor.y := poz_krychle_y;
  with kr.pozice do begin
    x := 0;
    y := 0;
    z := 0;
  end;

{ transformace jednotlivych vrcholu krychle: }
  pom_b3.x := 0;
  pom_b3.y := 0;
  pom_b3.z := 0;
  transform(pom_b3, pom_body[0]);

  pom_b3.y := str_krychle;
  transform(pom_b3, pom_body[1]);

  pom_b3.z := str_krychle;
  transform(pom_b3, pom_body[2]);

  pom_b3.y := 0;
  transform(pom_b3, pom_body[3]);

  pom_b3.x := str_krychle;
  pom_b3.y := 0;
  pom_b3.z := 0;
  transform(pom_b3, pom_body[4]);

  pom_b3.y := str_krychle;
  transform(pom_b3, pom_body[5]);

  pom_b3.z := str_krychle;
  transform(pom_b3, pom_body[6]);

  pom_b3.y := 0;
  transform(pom_b3, pom_body[7]);

{ vykresleni hran krychle: }
  getlinesettings(old_line);      { ulozeni starych hodnot }
  setlinestyle(0, old_line.pattern, old_line.thickness);
  setcolor(b_krychle);
  line(pom_body[3].x, pom_body[3].y, pom_body[3].x,    pom_body[3].y-40);
  line(pom_body[1].x, pom_body[1].y, pom_body[1].x+40, pom_body[1].y);
  pom_b3.x := str_krychle+40;
  pom_b3.y := 0;
  pom_b3.z := 0;
  transform(pom_b3,pb);
  line(pom_body[4].x, pom_body[4].y, pb.x,          pb.y);
  line(pom_body[4].x, pom_body[4].y, pom_body[5].x, pom_body[5].y);
  line(pom_body[6].x, pom_body[6].y, pom_body[7].x, pom_body[7].y);
  line(pom_body[4].x, pom_body[4].y, pom_body[7].x, pom_body[7].y);
  line(pom_body[5].x, pom_body[5].y, pom_body[6].x, pom_body[6].y);
  line(pom_body[2].x, pom_body[2].y, pom_body[3].x, pom_body[3].y);
  line(pom_body[1].x, pom_body[1].y, pom_body[2].x, pom_body[2].y);
  line(pom_body[3].x, pom_body[3].y, pom_body[7].x, pom_body[7].y);
  line(pom_body[2].x, pom_body[2].y, pom_body[6].x, pom_body[6].y);
  line(pom_body[1].x, pom_body[1].y, pom_body[5].x, pom_body[5].y);
  setlinestyle(1, old_line.pattern, old_line.thickness);
  line(pom_body[0].x, pom_body[0].y, pom_body[1].x, pom_body[1].y);
  line(pom_body[0].x, pom_body[0].y, pom_body[3].x, pom_body[3].y);
  line(pom_body[0].x, pom_body[0].y, pom_body[4].x, pom_body[4].y);
  setlinestyle(0, old_line.pattern, old_line.thickness);

{ zobrazeni prvku, ktere se nebudou menit }
  outtextxy(pom_body[4].x-10, pom_body[4].y+16, 'r');
  outtextxy(pom_body[1].x+20, pom_body[1].y+ 5, 'g');
  outtextxy(pom_body[3].x-10, pom_body[3].y-20, 'b');
  setcolor(b_limity);
  outtextxy(100, poz_krychle_y+100, '[0,0,0]  BLACK');
  outtextxy(100, poz_krychle_y+110, '[0,0,1]  BLUE');
  outtextxy(100, poz_krychle_y+120, '[0,1,0]  GREEN');
  outtextxy(100, poz_krychle_y+130, '[0,1,1]  CYAN');
  outtextxy(100, poz_krychle_y+140, '[1,0,0]  RED');
  outtextxy(100, poz_krychle_y+150, '[1,0,1]  MAGENTA');
  outtextxy(100, poz_krychle_y+160, '[1,1,0]  YELLOW');
  outtextxy(100, poz_krychle_y+170, '[1,1,1]  WHITE');
  setcolor(b_napisy);
  outtextxy(400,20, 'r   :');    outtextxy(400,60, 'ro  :');
  outtextxy(400,32, 'g   :');    outtextxy(400,72, 'gama:');
  outtextxy(400,44, 'b   :');    outtextxy(400,84, 'beta:');
  outtextxy(400,100,'jas :');
  setfillstyle(1, b_info);
  bar(0, getmaxy-45, getmaxx, getmaxy);
  setcolor(b_podklad);
  outtextxy(10, getmaxy-42, 'Pohyb v krychli: çipky');
  outtextxy(10, getmaxy-32, 'zmØna m¢du F1(rovina r=konst), F2(rovina g=konst), F3(rovina b=konst)');
  outtextxy(10, getmaxy-22, 'Konec: ESC');
  setfillstyle(1, b_ram_bar);
  bar(390,140,560,370);
  setcolor(b_ramec);
  rectangle(395,145,555,365);
  mod_k := 1;
  putpixel(poz_krychle_x, poz_krychle_y, b_kurzor);
  pom_c := b_krychle;
  vypocet;
  zobrazit;  { vypocet a zobrazeni promennych hodnot }
end;

procedure konec;
{ vrati paletu barev a ukonci graficky mod }
begin
  SetRGBPalette(barvy[1,1], barvy[1,2], barvy[1,3], barvy[1,4]);
  SetRGBPalette(barvy[2,1], barvy[2,2], barvy[2,3], barvy[2,4]);
  closegraph;
end;

begin     { zacatek programu }
  inicializace;
  repeat
    zn := readkey;
    as := ord(zn);
    if as=ESC then break;
    if as=0 then begin
      zn := readkey;
      as := ord(zn);
      case as of
        F1:       mod_k := 1;
        F2:       mod_k := 2;
        F3:       mod_k := 3;
        doprava:  pohyb_k(0);
        doleva:   pohyb_k(1);
        nahoru:   pohyb_k(2);
        dolu:     pohyb_k(3);
      end;
    end;
  until false;
  konec;
end.