//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop

#include "obraz.h"
#include "3d.h"
#include "ftech6.h"
#include "math.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)
{
}
//---------------------------------------------------------------------------
//  Zabudowa sceny trójkątami w tylnej ćwiartce XYZ.
//  Trójkąty świecą i nie pochłaniają światła odbitego,
//  bo s i o zadeklarowano konstruktorami domyślnymi
void __fastcall TForm1::FormShow(TObject *Sender)
{
/*
                                //przypadkowy zbiór trójkątów
 int r = 10, d = 3;
 TSwiatlo s( 200, 200, 200);
 TOdbicie o(0.7, 0.7, 0.9);
 for( int i = 0; i < 20; i ++)
 {
    TPunkt p1( -random(r), -random(r), -random(r));
    TPunkt p2( p1.x+d-random(2*d), p1.y+d-random(2*d), p1.z+d-random(2*d));
    TPunkt p3( p1.x-d+random(2*d), p1.y-d+random(2*d), p1.z-d+random(2*d));
    scena.dodaj_trojkat( TTrojkat( p1, p2, p3, s, o));
 }
*/

                                //dwa równoległe trójkąty, między którymi więźnie promień ...
 TrackBar4 -> Position = 229;   //promień o ciekawej drodze ...
 TrackBar5 -> Position = 148;
 TPunkt p1( -10, 0, 0), p2( 0, -10, 0), p3( 0, 0, -10);
 TPunkt p4( -5, 8, 0), p5( 0, 3, 0), p6( 0, 8, -5);
 scena.dodaj_trojkat( TTrojkat( p1, p2, p3, TSwiatlo( 200,200,200), TOdbicie( 0.9,0.9,1.0)));
 scena.dodaj_trojkat( TTrojkat( p4, p5, p6, TSwiatlo( 150,150,150), TOdbicie( 0.9,0.9,1.0)));

 inicjuj_parametry();
}
//---------------------------------------------------------------------------
//  Przygotowanie sceny
void TForm1::inicjuj_parametry( void)
{
 double k = M_PI / 180.;
 double R = TrackBar1 -> Position,
        fi = k * TrackBar2 -> Position,
        teta = k * TrackBar3 -> Position, x, y, z;

 x = R * cos( fi) * sin( teta);
 y = R * sin( fi) * sin( teta);
 z = R * cos( teta);

 Pobs = TPunkt( x, y, z);

 piksel_x = TrackBar4 -> Position;
 piksel_y = TrackBar5 -> Position;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::TrackBar1Change(TObject *Sender)
{
 inicjuj_parametry();
 PaintBox1 -> Refresh();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::PaintBox1Paint(TObject *Sender)
{
 int piksel_szer = 360, piksel_wys = 240;
 TPunkt oko( 10, 10, 10);
 T3d d( Pobs, 0, 0, PaintBox1 -> Width, PaintBox1 -> Height, 0.3);
 TObraz obraz( oko,                   //pozycja oka
               piksel_szer, piksel_wys, //pikselowe pole obrazu
               3,                       //odległość oka od pola obrazu
               1.8, 1.2,                //metryczne pole obrazu
               &scena,                  //zabudowana obiektami
               3,                       //głębokość rekurencji
               &d,                      //projektor T3d
               PaintBox1 -> Canvas,     //aparat graficzny
               CheckBox1 -> Checked     //wykreślanie promienia
               );


 TPunkt p0( 0, 0, 0);               //środek układu XYZ
 TPunkt p1, p2, p3, p4;             //rogi ekranu
 TPunkt p;
 TColor kolor;
 int jasn_proc = 70;                //lekkie stłumienie jaskrawości

                                    //trójkąty
 PaintBox1 -> Canvas -> Pen -> Color = clGreen;
 for( int i = 0; i < scena.il(); i ++)
 {
    int xe1, ye1, xe2, ye2, xe3, ye3;
    TPoint p[ 3];                   //rogi rozpinanego trójkąta

    d.punkt_3d(xe1, ye1, scena.trojkaty[ i].p1);
    d.punkt_3d(xe2, ye2, scena.trojkaty[ i].p2);
    d.punkt_3d(xe3, ye3, scena.trojkaty[ i].p3);
    p[0].x = xe1, p[0].y = ye1;
    p[1].x = xe2, p[1].y = ye2;
    p[2].x = xe3, p[2].y = ye3;
    PaintBox1 -> Canvas -> Polygon( p, 2);
 }

                                    //rogi ekranu
 p1 = obraz.daj_punkt( 0, 0);
 p2 = obraz.daj_punkt( piksel_szer, 0);
 p3 = obraz.daj_punkt( piksel_szer, piksel_wys);
 p4 = obraz.daj_punkt( 0, piksel_wys);


 linia3d( p1, p2, &d, PaintBox1 -> Canvas, clGray);
 linia3d( p2, p3, &d, PaintBox1 -> Canvas, clGray);
 linia3d( p3, p4, &d, PaintBox1 -> Canvas, clGray);
 linia3d( p4, p1, &d, PaintBox1 -> Canvas, clGray);

 if( CheckBox1 -> Checked)           //jeden piksel
 {
    kolor = obraz.kolor_piksela( piksel_x, piksel_y, jasn_proc);
    p = obraz.daj_punkt( piksel_x, piksel_y);
    punkt3d( p, &d, PaintBox1 -> Canvas, kolor);
 }
 else
 {
    for( int i = 0; i < piksel_szer; i ++)      //obraz
    {
        for( int j = 0; j < piksel_wys; j ++)
        {
            kolor = obraz.kolor_piksela( i, j, jasn_proc);
            p = obraz.daj_punkt( i, j);
            punkt3d( p, &d, PaintBox1 -> Canvas, kolor);
        }
    }
 }

                                    //Układ odniesienia
 linia3d( p0, TPunkt( 10, 0, 0), &d, PaintBox1 -> Canvas, clSilver);
 linia3d( p0, TPunkt( 0, 10, 0), &d, PaintBox1 -> Canvas, clSilver);
 linia3d( p0, TPunkt( 0, 0, 10), &d, PaintBox1 -> Canvas, clSilver);

                                    //Graniastosłup widzenia
// linia3d( oko, p1, &d, PaintBox1 -> Canvas, clSilver);
// linia3d( oko, p2, &d, PaintBox1 -> Canvas, clSilver);
// linia3d( oko, p3, &d, PaintBox1 -> Canvas, clSilver);
// linia3d( oko, p4, &d, PaintBox1 -> Canvas, clSilver);

                                    //oś główna
// linia3d( oko, p0, &d, PaintBox1 -> Canvas, clGray);
}
//---------------------------------------------------------------------------
//  Wyświetlenie punktu. Pomocnicze.
void TForm1 :: punkt3d( TPunkt p, T3d *d, TCanvas *cnv, TColor kolor)
{
 int xe, ye;
 d -> punkt_3d( xe, ye, p);
 cnv -> Pixels[ xe][ ye] = kolor;
}
//---------------------------------------------------------------------------
//  Wyświetlenie linii łączącej 2 punkty. Do uruchamiania.
void TForm1 :: linia3d( TPunkt p1, TPunkt p2, T3d *d, TCanvas *cnv, TColor kolor)
{
 int xe, ye;
 cnv -> Pen -> Color = kolor;
 d -> punkt_3d( xe, ye, p1);
 cnv -> MoveTo( xe, ye);
 d -> punkt_3d( xe, ye, p2);
 cnv -> LineTo( xe, ye);
}
//---------------------------------------------------------------------------

