using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using OpenGL;
using System.Runtime.InteropServices;
namespace Jcu.Pgr.L01
{
public partial class GLForm : Form
{
#region instancni promenne
// zdroj dat GLForm.resx
ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(GLForm));
private Context context; // vytvoreni contextu pro OpenGL
// nasobitel pro rychlost pohybu
private const float step = 0.1f; // rychlejsi pohyb = napr. 1.0f
// nasobitel pro rychlost mysi (pohled)
private const int rychlostMysiX = 1; // rychlejsi pohyb = napr. 2
// konstanty pro svet a okoli
private const float s = 200.00f; // rozmer sveta
private const float posun = 1f; // posun textur pred nebem
private bool fillPolygon = true; // jestli vyplnovat polygony
// posun mysi
private float azimuth = 0;
private float horizont = 0;
// pohled mysi v dany cas
private float azimuth_onTime = 0;
private float horizont_onTime = 0;
// vychozi pozice
private float posX = -120;
private float posY = -20f;
private float posZ = -80f;
// vychozi pozice v dany cas
private float posX_onTime = 0;
private float posY_onTime = 0;
private float posZ_onTime = 0;
// casy pro synchronizaci posunu a rotace, zajistujeme tim stejnou rychlost pohybu na ruzne rychlych pocitacich
private long casVychozi = 0;
private long casAktualni = 0;
private long casPredSekundou = 0;
private const long zpozdeni = 200000; // 200000 odpovida 20 milisekundam a to je zhruba 50 FPS
private int fps = 0;
private int fpsVypis = 0;
private bool jeCas = false; // jestli je cas udelat zmeny posunu a rotace, zalezi na "zpozdeni" ktere je nastaveno vyse
// chuze
private bool walk = true; // jestli chodit nebo litat
private bool houpaniPriChuzi = false; // jestli se houpat pri chuzi
private float chuze = 0.0f; // amplituda chuze
private float uhelChuze = 0.0f; // kde jsme v sinusu
private float vyska; // vyska nad terenem, ve ktere se bude postava pohybovat
private const float velikostPostavy = 2f; // vyska kamery (oci) nad terenem
// pohyb
private bool pohybVpred;
private bool pohybDozadu;
private bool pohybVpravo;
private bool pohybVlevo;
// trojuhelnikova sit
private const int NETsize = 20; // 20 - velikost site pro teren
private const float NETdist = 10f; // 10 - vzdalenost trojuhelniku v siti
private const float displace = 12f; // amplituda terenu
private float[,][] net = new float[NETsize+1, NETsize+1][]; // pole trojuhelniku pro teren
private float texX, texY, texXplus, texYplus; // souradnice pro texturu k terenu
private Bitmap povrch; // bitmapa pro vyskovou mapu
// morska sit
private const int SEAsize = 40; // 40 - velikost site pro more
private const float SEAdist = 10f; // 10 - vzdalenost trojuhelniku v siti
private const float sea_displace = 0.5f; // amplituda terenu
private float[,][] sea_net = new float[SEAsize+1, SEAsize+1][]; // pole trojuhelniku pro more
private float sea_texX, sea_texY, sea_texXplus, sea_texYplus; // souradnice pro texturu k mori
private int perioda = 0;
// texturovani
private int[] texture; // pole textur
private bool finished; // pokud byly textury nahraty v poradku
// posun textur
// TODO: mozna existuje nejaka funkce, ktera orizne okraj textury ... gl.Cell ...
private const float jedna = 0.998f;
private const float nulka = 0.002f;
private float[] krok = {0,0,0}; // rychlost letedla0, letadla1, lode2
// svetla
public bool light = false; // zapnuti x vypnuti svetla
public float[] LightAmbient1 = {0.7f, 0.7f, 0.7f, 1.0f}; // celkove
public float[] LightDiffuse1 = {1.0f, 1.0f, 1.0f, 1.0f}; // bodove
public float[] LightPosition1 = {200.0f, 100.0f, -100.0f, 1.0f}; // pozice (200,100,-100,1)
#endregion
#region inicializace formulare a OpenGL
///
/// GLForm() - konstruktor, ktery inicializuje komponenty formulare
///
public GLForm()
{
InitializeComponent(); // inicializace formulare
l_xy.Visible = true; // zviditelni vypis
}
///
/// InitGL() - inicializace OpenGL
///
/// vraci, jestli inicializace probehla v poradku
public bool InitGL()
{
try
{
povrch = (Bitmap)(resources.GetObject("heightMap")); // nahrati vyskove mapy do bitmapy
context = new Context(this, 32, 32, 0); // deklarace kontextu
Windows.ShowCursor(false); // jestli bude videt kurzor mysi
gl.ShadeModel(gl.SMOOTH); // vychozi nastaveni gl
gl.ClearColor(0.0f, 0.0f, 0.0f, 0.0f);
gl.ClearDepth(1.0f);
gl.Enable(gl.DEPTH_TEST);
gl.DepthFunc(gl.LEQUAL);
gl.Hint(gl.PERSPECTIVE_CORRECTION_HINT, gl.NICEST);
// svetla
gl.Lightfv(gl.LIGHT1, gl.AMBIENT, LightAmbient1); // abientni (celkove)
gl.Lightfv(gl.LIGHT1, gl.DIFFUSE, LightDiffuse1); // difusni (smerove)
gl.Lightfv(gl.LIGHT1, gl.POSITION, LightPosition1); // pozice difusniho svetla
gl.Enable(gl.LIGHT1);
if (light) // pokud je zapnute sviceni tak svitime
{
gl.Enable(gl.LIGHTING);
}
gl.MatrixMode(gl.PROJECTION); // dalsi defaultni nastaveni
gl.LoadIdentity();
glu.Perspective(45.0f, (float)this.Width / (float)this.Height, 0.1f, 700f);
gl.MatrixMode(gl.MODELVIEW);
gl.LoadIdentity();
gl.Enable(gl.TEXTURE_2D);
gl.MatrixMode(gl.MODELVIEW);
}
catch (Exception e) // vyjimka se zpravou pro uzivatele
{
MessageBox.Show(e.Message);
return false;
}
FillNet(); // vypnime sit body, potrebnymi pro trojuhelnikovou sit
FillSea();
if(!NahratTextury()) // pokud se nepodari nahrat textury, vubec se formular nepusti
{
return false;
}
casVychozi = DateTime.Now.Ticks; // zjisteni potrebnych casu pro synchronizaci animace s casem
casPredSekundou = DateTime.Now.Ticks;
return true; // pokud inicializace gl probehne v poradku, vratime true
}
#endregion
#region DrawGL a casovani
///
/// DrawGL() - vykresli scenu
///
public void DrawGL()
{
gl.ClearColor(0.0f, 0.0f, 0.0f, 0.0f); // vycisti barvu
gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); // a buffer
gl.LoadIdentity(); // reset matice
if(fillPolygon) // pokud chceme polygony vyplnene
{
gl.PolygonMode(gl.FRONT_AND_BACK, gl.FILL);
}
else
{
gl.PolygonMode(gl.FRONT_AND_BACK, gl.LINE);
}
OnTime(); // synchornizujeme pohyb a animace s casem
gl.Rotatef(horizont_onTime, 1.0f, 0.0f, 0.0f); // rotace podle osy x
gl.Rotatef(azimuth_onTime, 0.0f, 1.0f, 0.0f); // rotace podle osy y
Pohyb(); // zjistime pohyb kamery
gl.Translatef(posX_onTime, posY_onTime, posZ_onTime); // provedem posun podle pohybu
if(light) // pokud povolena svetla, tak osvetlime ostrov
{ // TODO: nefunkcni
gl.Enable(gl.LIGHTING);
gl.Normal3f(0,1,0);
DrawNet();
gl.Disable(gl.LIGHTING);
}
else
{
DrawNet();
}
gl.PushMatrix();
gl.Translatef(-s/2, 1f, -s/2);
DrawSea();
gl.PopMatrix();
gl.Translatef(s/2, 0f, s/2); // posun abychom mohli lepe vykreslit skybox
VykresliSkyBox();
VykresliPozadi();
gl.Translatef(0, 1f, 0);
VykresliRostliny(20);
gl.PushMatrix();
VykresliLetadlo(0, 20f, 120f, 100f, 0.7f, 17, 16); // parametry: id, polomer, radius, vyska, rychlost, maska, obrazek
gl.PopMatrix();
gl.PushMatrix();
VykresliLetadlo(1, 20f, 100f, 50f, 0.5f, 17, 16);
gl.PopMatrix();
gl.PushMatrix();
VykresliLod(2, 20f, 120f, 20f, 0.01f, 19, 18);
gl.PopMatrix();
gl.LoadIdentity(); // reset matice
VykresliTercik(0.005f, 0.2f); // parametry: rozmer, vzdalenost od kamery
gl.Flush();
context.SwapBuffers();
}
///
/// OnTime() - metoda slouzi k synchronizaci pohybu a animace vuci casu a diky prekreslovani formulare je v cyklu
///
public void OnTime()
{
jeCas = false; // jestli je cas synchronizovat
casAktualni = DateTime.Now.Ticks; // zjistime si aktualni cas v tickach
if(casAktualni > casVychozi + zpozdeni) // jestli ze je tedy aktualni cas vyssi nez minulej cas s nasim zpozdenim
{
azimuth_onTime = azimuth; // teprva tedkom predame potrebne hodnoty
horizont_onTime = horizont;
posX_onTime = posX;
posY_onTime = posY;
posZ_onTime = posZ;
casVychozi += zpozdeni; // posunem si vychozi cas o dalsi zpozdeni
fps++; // inkrementujeme si fps
// vypis do labelu
l_xy.Text = "POSITION - " +
" posX:" + posX.ToString("f2") +
" posY:" + posY.ToString("f2") +
" posZ:" + posZ.ToString("f2") +
" azimuth:" + azimuth.ToString("f2") +
" horizont:" + horizont.ToString("f2") +
"\nCONTROL - " +
" stepUp(W), stepDown(S), stepLeft(A), stepRight(D), look: Up Down Left Right(MOUSE)" +
"\nFPS:" + fpsVypis +
" resetPosition(R)" +
" fly(F):" + (!walk).ToString() +
" sinWalk(G):" + houpaniPriChuzi.ToString() +
" light(L):" + light.ToString() +
" fillPolygon(P):" + fillPolygon.ToString() +
" info(I):" + (l_xy.Visible).ToString();
jeCas = true; // nastavime si ze prave ted byl cas i na aktualizaci animaci letadel a lode
}
if(casAktualni > casPredSekundou + 10000000) // jestlize je aktualni cas vetsi nez cas pred sekundou
{
fpsVypis = fps; // dojde k aktualizaci fps
fps = 0; // a jeho vymaz, abychom ho mohli merit znova
casPredSekundou = casAktualni; // novej vychozi cas
}
}
#endregion
#region textury
///
/// NahratTextury() - vytvori pole textur, ktere pak budeme mapovat na polygony
///
/// jestli byli textury nahrany v poradku
public bool NahratTextury()
{
// nazvy textur ve resx
string[] res = {
"hawaiiAmore",
"sb_top",
"sb_0",
"sb_1",
"sb_2",
"sb_3",
"hladina512",
"ostruvek",
"mesto",
"mesto-maska",
"sochaSvobody",
"sochaSvobody-maska",
"tercik",
"tercik-maska",
"agava",
"agava-maska",
"letadlo",
"letadlo-maska",
"lod",
"lod-maska",
"stromek",
"stromek-maska"
};
// pocet textur: 21
int pocetTextur = res.Length;
texture = new int[pocetTextur];
Bitmap[] image = new Bitmap[pocetTextur]; // pole bitmap pro textury
finished = false;
try
{
for(int i = 0; i < res.Length; i++)
{
image[i] = (Bitmap)(resources.GetObject(res[i])); // naplnime si bitmapy daty z resx
}
}
catch (System.ArgumentException)
{
MessageBox.Show("Could not load data files. Please make sure that Data is a subfolder from where the application is running.", "Error", MessageBoxButtons.OK);
this.finished = true;
}
if (!this.finished) // pokud probehl upload textur v poradku, muzeme je generovat
{
gl.GenTextures(image.Length, this.texture);
for (int i=0; i < image.Length; i++)
{
Rectangle rect = new Rectangle(0, 0, image[i].Width, image[i].Height);
System.Drawing.Imaging.BitmapData bitmapdata = image[i].LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
gl.BindTexture(gl.TEXTURE_2D, this.texture[i]);
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.TexImage2D(gl.TEXTURE_2D, 0, (int)gl.RGB, image[i].Width, image[i].Height, 0, gl.BGR, gl.UNSIGNED_BYTE, bitmapdata.Scan0);
image[i].UnlockBits(bitmapdata);
image[i].Dispose();
}
return true;
}
return false;
}
#endregion
#region trojuhelniky
///
/// FillNet() - vyplni pole body, ktere budou potreba pro trojuhelnikovou sit
///
private void FillNet()
{
int osa_x;
int osa_y;
float hloubka;
for (int i = 0; i <= NETsize; i++) // pro celou osu x
{
osa_x = (int)(povrch.Width / NETsize * i); // zjistime si vysky v bodech na ose x
for (int j = 0; j <= NETsize; j++) // pro celou osu y
{
osa_y = (int)(povrch.Height / NETsize * j); // zjistime si vysky v bodech na ose y
hloubka = (float)povrch.GetPixel(osa_x, osa_y).R / 255; // zjistime si jas bodu x,y ve vyskove mape, tim dostaneme hloubku
net[i, j] = new float[3]; // kazdej bod site bude mit 3 souradnice
net[i, j][0] = j * NETdist; //x
net[i, j][1] = hloubka * displace; //y
net[i, j][2] = i * NETdist; //z
}
}
}
///
/// DrawNet() - vykresli trojuhelnikovou sit (teren)
///
private void DrawNet()
{
gl.BindTexture(gl.TEXTURE_2D, this.texture[0]); // nabindime texturu
gl.Begin(gl.TRIANGLES); // a kreslime trojuhelniky
for (int i = 0; i < NETsize; i++) // pro vsechny body v siti
{
texX = ((float)(i-0.5)/NETsize); // zjistime si souradnice bodu x
texXplus = ((float)(i+0.5)/NETsize); // pouze pomocna a slouzi k posunu na dalsi bod
for (int j = 0; j < NETsize; j++)
{
texY = ((float)(j-0.5)/NETsize); // zjistime si souradnice bodu y
texYplus = ((float)(j+0.5)/NETsize); // pouze pomocna a slouzi k posunu na dalsi bod
// trojuhelnik 1
gl.TexCoord2f(texX, texY); // a kreslime dva trojuhelniky
gl.Vertex3fv(net[i, j]);
gl.TexCoord2f(texX, texYplus);
gl.Vertex3fv(net[i, j + 1]);
gl.TexCoord2f(texXplus, texY);
gl.Vertex3fv(net[i + 1, j]);
// trojuhelnik 2
gl.TexCoord2f(texXplus, texY);
gl.Vertex3fv(net[i + 1, j]);
gl.TexCoord2f(texX, texYplus);
gl.Vertex3fv(net[i, j + 1]);
gl.TexCoord2f(texXplus, texYplus);
gl.Vertex3fv(net[i + 1, j + 1]);
}
}
gl.End();
}
///
/// FillSea() - vyplni pole body, ktere budou potreba pro morskou sit
///
private void FillSea()
{
for (int i = 0; i <= SEAsize; i++) // pro celou osu x
{
for (int j = 0; j <= SEAsize; j++) // pro celou osu y
{
sea_net[i, j] = new float[3]; // kazdej bod site bude mit 3 souradnice
sea_net[i, j][0] = j * SEAdist; //x
sea_net[i, j][1] = (float)(Math.Sin(((i*45) / 360.0f) * Math.PI * 2)) * sea_displace; //y
sea_net[i, j][2] = i * SEAdist; //z
}
}
}
///
/// DrawSea() - vykresli trojuhelnikovou sit (more)
///
private void DrawSea()
{
gl.BindTexture(gl.TEXTURE_2D, this.texture[6]); // nabindime texturu
gl.Begin(gl.TRIANGLES); // a kreslime trojuhelniky
for (int i = 0; i < SEAsize; i++) // pro vsechny body v siti
{
sea_texX = ((float)(i)/SEAsize); // zjistime si souradnice bodu x
sea_texXplus = ((float)(i+1)/SEAsize); // pouze pomocna a slouzi k posunu na dalsi bod
for (int j = 0; j < SEAsize; j++)
{
sea_texY = ((float)(j)/SEAsize); // zjistime si souradnice bodu y
sea_texYplus = ((float)(j+1)/SEAsize); // pouze pomocna a slouzi k posunu na dalsi bod
// trojuhelnik 1
gl.TexCoord2f(sea_texX, sea_texY); // a kreslime dva trojuhelniky
gl.Vertex3fv(sea_net[i, j]);
gl.TexCoord2f(sea_texX, sea_texYplus);
gl.Vertex3fv(sea_net[i, j + 1]);
gl.TexCoord2f(sea_texXplus, sea_texY);
gl.Vertex3fv(sea_net[i + 1, j]);
// trojuhelnik 2
gl.TexCoord2f(sea_texXplus, sea_texY);
gl.Vertex3fv(sea_net[i + 1, j]);
gl.TexCoord2f(sea_texX, sea_texYplus);
gl.Vertex3fv(sea_net[i, j + 1]);
gl.TexCoord2f(sea_texXplus, sea_texYplus);
gl.Vertex3fv(sea_net[i + 1, j + 1]);
}
}
gl.End();
// vlneni more
if(jeCas)
{
if(perioda == 7)
{
float[] hold = new float[SEAsize];
for(int i = 0; i < SEAsize; i++)
{
for(int j = 0; j < SEAsize; j++)
{
hold[j] = sea_net[0,j][1];
}
for(int j = 0; j < SEAsize - 1; j++)
{
sea_net[i,j][1] = sea_net[i+1,j][1];
}
for(int j = 0; j < SEAsize; j++)
{
sea_net[SEAsize,j][1] = hold[j];
}
}
perioda = 0;
}
perioda++;
}
}
#endregion
#region vykreslovani
///
/// VykresliSkyBox() - stara se o vykresleni skyBoxu (nebe)
///
public void VykresliSkyBox()
{
// predek
gl.BindTexture(gl.TEXTURE_2D, this.texture[3]);
gl.Begin(gl.QUADS);
gl.TexCoord2f(jedna, jedna); gl.Vertex3f(-s, 0, s);
gl.TexCoord2f(nulka, jedna); gl.Vertex3f(s, 0, s);
gl.TexCoord2f(nulka, nulka); gl.Vertex3f(s, s, s);
gl.TexCoord2f(jedna, nulka); gl.Vertex3f(-s, s, s);
gl.End();
// zadek
gl.BindTexture(gl.TEXTURE_2D, this.texture[5]);
gl.Begin(gl.QUADS);
gl.TexCoord2f(jedna, jedna); gl.Vertex3f(-s, 0, -s);
gl.TexCoord2f(jedna, nulka); gl.Vertex3f(-s, s, -s);
gl.TexCoord2f(nulka, nulka); gl.Vertex3f(s, s, -s);
gl.TexCoord2f(nulka, jedna); gl.Vertex3f(s, 0, -s);
gl.End();
// vrsek
gl.BindTexture(gl.TEXTURE_2D, texture[1]);
gl.Begin(gl.QUADS);
gl.TexCoord2f(nulka, nulka); gl.Vertex3f(-s, s, -s);
gl.TexCoord2f(jedna, nulka); gl.Vertex3f(-s, s, s);
gl.TexCoord2f(jedna, jedna); gl.Vertex3f(s, s, s);
gl.TexCoord2f(nulka, jedna); gl.Vertex3f(s, s, -s);
gl.End();
// spodek
/*
gl.BindTexture(gl.TEXTURE_2D, texture[6]);
gl.Begin(gl.QUADS);
gl.TexCoord2f(jedna, jedna); gl.Vertex3f(-s, 0, -s);
gl.TexCoord2f(nulka, jedna); gl.Vertex3f(s, 0, -s);
gl.TexCoord2f(nulka, nulka); gl.Vertex3f(s, 0, s);
gl.TexCoord2f(jedna, nulka); gl.Vertex3f(-s, 0, s);
gl.End();
*/
// prava
gl.BindTexture(gl.TEXTURE_2D, texture[4]);
gl.Begin(gl.QUADS);
gl.TexCoord2f(nulka, jedna); gl.Vertex3f(s, 0, -s);
gl.TexCoord2f(nulka, nulka); gl.Vertex3f(s, s, -s);
gl.TexCoord2f(jedna, nulka); gl.Vertex3f(s, s, s);
gl.TexCoord2f(jedna, jedna); gl.Vertex3f(s, 0, s);
gl.End();
// leva
gl.BindTexture(gl.TEXTURE_2D, texture[2]);
gl.Begin(gl.QUADS);
gl.TexCoord2f(jedna, jedna); gl.Vertex3f(-s, 0, -s);
gl.TexCoord2f(nulka, jedna); gl.Vertex3f(-s, 0, s);
gl.TexCoord2f(nulka, nulka); gl.Vertex3f(-s, s, s);
gl.TexCoord2f(jedna, nulka); gl.Vertex3f(-s, s, -s);
gl.End();
}
///
/// VykresliPozadi() - vykresli pozadi sceny (mesto + ostrov)
///
public void VykresliPozadi()
{
gl.Enable(gl.BLEND); // povolime blending (pruhlednost)
// zadek - ostrov
gl.BlendFunc(gl.DST_COLOR, gl.ZERO);
gl.BindTexture(gl.TEXTURE_2D, this.texture[7]); // obrazek
gl.Begin(gl.QUADS);
gl.TexCoord2f(jedna, jedna); gl.Vertex3f(-s/2, 0, -s+posun);
gl.TexCoord2f(jedna, nulka); gl.Vertex3f(-s/2, s/2, -s+posun);
gl.TexCoord2f(nulka, nulka); gl.Vertex3f(s/2, s/2, -s+posun);
gl.TexCoord2f(nulka, jedna); gl.Vertex3f(s/2, 0, -s+posun);
gl.End();
// predek - mesto
gl.BlendFunc(gl.DST_COLOR, gl.ZERO);
gl.BindTexture(gl.TEXTURE_2D, this.texture[9]); // maska
gl.Begin(gl.QUADS);
gl.TexCoord2f(jedna, jedna); gl.Vertex3f(-s/2, 0, s-posun);
gl.TexCoord2f(nulka, jedna); gl.Vertex3f(s/2, 0, s-posun);
gl.TexCoord2f(nulka, nulka); gl.Vertex3f(s/2, s/2, s-posun);
gl.TexCoord2f(jedna, nulka); gl.Vertex3f(-s/2, s/2, s-posun);
gl.End();
gl.BlendFunc(gl.ONE, gl.ONE);
gl.BindTexture(gl.TEXTURE_2D, this.texture[8]); // obrazek
gl.Begin(gl.QUADS);
gl.TexCoord2f(jedna, jedna); gl.Vertex3f(-s/2, 0, s-posun);
gl.TexCoord2f(nulka, jedna); gl.Vertex3f(s/2, 0, s-posun);
gl.TexCoord2f(nulka, nulka); gl.Vertex3f(s/2, s/2, s-posun);
gl.TexCoord2f(jedna, nulka); gl.Vertex3f(-s/2, s/2, s-posun);
gl.End();
// predek - sochaSvobody
gl.BlendFunc(gl.DST_COLOR, gl.ZERO);
gl.BindTexture(gl.TEXTURE_2D, this.texture[11]); // maska
gl.Begin(gl.QUADS);
gl.TexCoord2f(jedna, jedna); gl.Vertex3f(-150, 0, s-posun);
gl.TexCoord2f(nulka, jedna); gl.Vertex3f(-100, 0, s-posun);
gl.TexCoord2f(nulka, nulka); gl.Vertex3f(-100, 50, s-posun);
gl.TexCoord2f(jedna, nulka); gl.Vertex3f(-150, 50, s-posun);
gl.End();
gl.BlendFunc(gl.ONE, gl.ONE);
gl.BindTexture(gl.TEXTURE_2D, this.texture[10]); // obrazek
gl.Begin(gl.QUADS);
gl.TexCoord2f(jedna, jedna); gl.Vertex3f(-150, 0, s-posun);
gl.TexCoord2f(nulka, jedna); gl.Vertex3f(-100, 0, s-posun);
gl.TexCoord2f(nulka, nulka); gl.Vertex3f(-100, 50, s-posun);
gl.TexCoord2f(jedna, nulka); gl.Vertex3f(-150, 50, s-posun);
gl.End();
gl.Disable(gl.BLEND); // zakazeme blending
}
///
/// VykresliTercik() - vykresli zamerovac pred kamerou
///
/// velikost zamerovace
/// vzdalenost zamerovace od kamery
public void VykresliTercik(float rozmer, float vzdalenost)
{
gl.Enable(gl.BLEND);
gl.BlendFunc(gl.DST_COLOR, gl.ZERO);
gl.BindTexture(gl.TEXTURE_2D, this.texture[13]); // maska
gl.Begin(gl.QUADS);
gl.TexCoord2f(jedna, jedna); gl.Vertex3f(-rozmer,-rozmer,-vzdalenost);
gl.TexCoord2f(nulka, jedna); gl.Vertex3f(-rozmer,rozmer,-vzdalenost);
gl.TexCoord2f(nulka, nulka); gl.Vertex3f(rozmer,rozmer,-vzdalenost);
gl.TexCoord2f(jedna, nulka); gl.Vertex3f(rozmer,-rozmer,-vzdalenost);
gl.End();
gl.BlendFunc(gl.ONE, gl.ONE);
gl.BindTexture(gl.TEXTURE_2D, this.texture[12]); // obrazek
gl.Begin(gl.QUADS);
gl.TexCoord2f(jedna, jedna); gl.Vertex3f(-rozmer,-rozmer,-vzdalenost);
gl.TexCoord2f(nulka, jedna); gl.Vertex3f(-rozmer,rozmer,-vzdalenost);
gl.TexCoord2f(nulka, nulka); gl.Vertex3f(rozmer,rozmer,-vzdalenost);
gl.TexCoord2f(jedna, nulka); gl.Vertex3f(rozmer,-rozmer,-vzdalenost);
gl.End();
gl.Disable(gl.BLEND);
}
///
/// VykresliLetadlo() - metoda vykresluje letadlo
///
/// identifikacni cislo
/// polomer polygonu
/// radius
/// vyska
/// rychlost obehu
/// textura pro masku
/// textura pro obrazek
public void VykresliLetadlo(int cislo, float polomer, float radius, float vyska, float rychlost, int maska, int obrazek)
{
gl.Rotatef(-krok[cislo], 0, 1, 0); // rotace
gl.Translatef(radius, vyska, radius); // posun
if(jeCas) // navysime kdyz je cas (synchronizace s caseum)
{
krok[cislo] += rychlost;
}
if(krok[cislo] > 360) // pokud obleti letadlo kolecko, leti znova
{
krok[cislo] = 0;
}
gl.Enable(gl.BLEND);
gl.BlendFunc(gl.DST_COLOR, gl.ZERO);
gl.BindTexture(gl.TEXTURE_2D, this.texture[maska]); // maska
gl.Begin(gl.QUADS);
gl.TexCoord2f(jedna, jedna); gl.Vertex3f(+polomer, 0, -polomer);
gl.TexCoord2f(nulka, jedna); gl.Vertex3f(-polomer, 0, -polomer);
gl.TexCoord2f(nulka, nulka); gl.Vertex3f(-polomer, 0, +polomer);
gl.TexCoord2f(jedna, nulka); gl.Vertex3f(+polomer, 0, +polomer);
gl.End();
gl.BlendFunc(gl.ONE, gl.ONE);
gl.BindTexture(gl.TEXTURE_2D, this.texture[obrazek]); // obrazek
gl.Begin(gl.QUADS);
gl.TexCoord2f(jedna, jedna); gl.Vertex3f(+polomer, 0, -polomer);
gl.TexCoord2f(nulka, jedna); gl.Vertex3f(-polomer, 0, -polomer);
gl.TexCoord2f(nulka, nulka); gl.Vertex3f(-polomer, 0, +polomer);
gl.TexCoord2f(jedna, nulka); gl.Vertex3f(+polomer, 0, +polomer);
gl.End();
gl.Disable(gl.BLEND);
}
///
/// VykresliLod() - metoda vykresluje lod
///
/// identifikacni cislo
/// polomer polygonu
/// radius
/// vyska
/// rychlost obehu
/// textura pro masku
/// textura pro obrazek
public void VykresliLod(int cislo, float polomer, float radius, float vyska, float rychlost, int maska, int obrazek)
{
gl.Rotatef(krok[cislo], 0, 1, 0);
gl.Translatef(radius, vyska, radius);
if(jeCas)
{
krok[cislo] += rychlost;
}
if(krok[cislo] > 360)
{
krok[cislo] = 0;
}
Vykresli(false, polomer, 0,0,0, 19,18); // vykresli objekt
}
///
/// VykresliRostliny() - vykresli rostliny
///
/// mrizka je pro rozestup rostlin
public void VykresliRostliny(int mrizka)
{
float korinek;
float stred_x, stred_y, stred_z;
for(float i = 0; i > -s; i -= mrizka) // pro celou mrizku
{
for(float j = 0; j > -s; j -= mrizka)
{
stred_x = i;
stred_z = j;
// zjistime si, do jake vysky si mame umistit koren rostliny
korinek = (float)povrch.GetPixel(-(int)((-s+1-stred_z)*povrch.Width/s), -(int)((-s+1-stred_x)*povrch.Height/s)).R / 255;
stred_x += s/2;
stred_y = korinek * displace - 0.3f;
stred_z += s/2;
if(stred_y >= 2 && stred_y < 4) // na danych souradnicich vykreslujeme stromky
{
Vykresli(true, 2, stred_x, stred_y, stred_z, 21, 20);
}
if(stred_y >= 4 && stred_y < 8) // na danych souradnicich vykreslujeme agave
{
Vykresli(true, 1, stred_x, stred_y, stred_z, 15, 14);
}
}
}
}
///
/// Vykresli() - stara se o vykresleni urciteho objektu
///
/// kriz rika jestli jde o 2 textury na sebe kolme
/// polomer objektu
/// pozice x
/// pozice y
/// pozice z
/// maska pro texturu
/// obrazek pro texturu
public void Vykresli(bool kriz, float polomer, float stred_x, float stred_y, float stred_z, int maska, int obrazek)
{
gl.Enable(gl.BLEND);
gl.BlendFunc(gl.DST_COLOR, gl.ZERO);
gl.BindTexture(gl.TEXTURE_2D, this.texture[maska]); // maska
gl.Begin(gl.QUADS);
gl.TexCoord2f(jedna, jedna); gl.Vertex3f(stred_x+polomer, stred_y-polomer, stred_z-polomer);
gl.TexCoord2f(nulka, jedna); gl.Vertex3f(stred_x-polomer, stred_y-polomer, stred_z+polomer);
gl.TexCoord2f(nulka, nulka); gl.Vertex3f(stred_x-polomer, stred_y+polomer, stred_z+polomer);
gl.TexCoord2f(jedna, nulka); gl.Vertex3f(stred_x+polomer, stred_y+polomer, stred_z-polomer);
gl.End();
gl.BlendFunc(gl.ONE, gl.ONE);
gl.BindTexture(gl.TEXTURE_2D, this.texture[obrazek]); // obrazek
gl.Begin(gl.QUADS);
gl.TexCoord2f(jedna, jedna); gl.Vertex3f(stred_x+polomer, stred_y-polomer, stred_z-polomer);
gl.TexCoord2f(nulka, jedna); gl.Vertex3f(stred_x-polomer, stred_y-polomer, stred_z+polomer);
gl.TexCoord2f(nulka, nulka); gl.Vertex3f(stred_x-polomer, stred_y+polomer, stred_z+polomer);
gl.TexCoord2f(jedna, nulka); gl.Vertex3f(stred_x+polomer, stred_y+polomer, stred_z-polomer);
gl.End();
if(kriz) // obrazek natocen o 90 stupnu
{
gl.BlendFunc(gl.DST_COLOR, gl.ZERO);
gl.BindTexture(gl.TEXTURE_2D, this.texture[maska]); // maska
gl.Begin(gl.QUADS);
gl.TexCoord2f(jedna, jedna); gl.Vertex3f(stred_x+polomer, stred_y-polomer, stred_z+polomer);
gl.TexCoord2f(nulka, jedna); gl.Vertex3f(stred_x-polomer, stred_y-polomer, stred_z-polomer);
gl.TexCoord2f(nulka, nulka); gl.Vertex3f(stred_x-polomer, stred_y+polomer, stred_z-polomer);
gl.TexCoord2f(jedna, nulka); gl.Vertex3f(stred_x+polomer, stred_y+polomer, stred_z+polomer);
gl.End();
gl.BlendFunc(gl.ONE, gl.ONE);
gl.BindTexture(gl.TEXTURE_2D, this.texture[obrazek]); // obrazek
gl.Begin(gl.QUADS);
gl.TexCoord2f(jedna, jedna); gl.Vertex3f(stred_x+polomer, stred_y-polomer, stred_z+polomer);
gl.TexCoord2f(nulka, jedna); gl.Vertex3f(stred_x-polomer, stred_y-polomer, stred_z-polomer);
gl.TexCoord2f(nulka, nulka); gl.Vertex3f(stred_x-polomer, stred_y+polomer, stred_z-polomer);
gl.TexCoord2f(jedna, nulka); gl.Vertex3f(stred_x+polomer, stred_y+polomer, stred_z+polomer);
gl.End();
}
gl.Disable(gl.BLEND);
}
#endregion
#region pohyb
///
/// Pohyb() - obsluhuje pohyb kamery ve svete a jeji natoceni (chuze po povrchu + letani)
///
public void Pohyb()
{
double azRad = azimuth * Math.PI / 180;
double hoRad = horizont * Math.PI / 180;
if (pohybVpred)
{
posX += step * (float)Math.Cos(azRad + Math.PI / 2);
posZ += step * (float)Math.Sin(azRad + Math.PI / 2);
posY += step * (float)Math.Sin(hoRad);
}
if (pohybDozadu)
{
posX -= step * (float)Math.Cos(azRad + Math.PI / 2);
posZ -= step * (float)Math.Sin(azRad + Math.PI / 2);
posY -= step * (float)Math.Sin(hoRad);
}
if (pohybVlevo)
{
posX += step * (float)Math.Cos(azRad);
posZ += step * (float)Math.Sin(azRad);
}
if (pohybVpravo)
{
posX -= step * (float)Math.Cos(azRad);
posZ -= step * (float)Math.Sin(azRad);
}
if(walk) // pro pohyb po povrchu
{
if(posX < 0 && posX > -s && posZ < 0 && posZ > -s)
{
vyska = (float)povrch.GetPixel(-(int)((posZ)*povrch.Width/s), -(int)((posX)*povrch.Height/s)).R / 255;
posY = -vyska * displace - velikostPostavy;
}
else
{
posY = -velikostPostavy;
}
if((pohybVpred || pohybDozadu) && houpaniPriChuzi) // pro houpani pri chuzi
{
if (uhelChuze >= 179.0f) // chodime po kopeckach a ne po vlnovkach :)
{
uhelChuze = 0.0f;
}
else
{
uhelChuze += 1f; // frekvence houpani
}
chuze = (float)Math.Sin(uhelChuze * Math.PI / 180.0) / 2.0f; // ve jmenovateli nastavime amplitudu kopecku
posY += chuze;
}
}
}
#endregion
#region lidske rozhrani
///
/// GLFormKeyDown() - obsluhuje stisknuti tlacitka na klavesnici
///
/// objekt
/// udalost
private void GLFormKeyDown(object sender, KeyEventArgs e)
{
switch (e.KeyCode)
{
case Keys.W: pohybVpred = true; break;
case Keys.A: pohybVlevo = true; break;
case Keys.S: pohybDozadu = true; break;
case Keys.D: pohybVpravo = true; break;
}
}
///
/// GLFormKeyUp() - obsluhuje uvolneni tlacitka na klavesnici
///
/// objekt
/// udalost
private void GLFormKeyUp(object sender, KeyEventArgs e)
{
switch (e.KeyCode)
{
case Keys.W: pohybVpred = false; break;
case Keys.A: pohybVlevo = false; break;
case Keys.S: pohybDozadu = false; break;
case Keys.D: pohybVpravo = false; break;
}
}
///
/// GLFormMouseMove() - obsluhuje pohyb mysi
///
/// objekt
/// udalost
private void GLFormMouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
{
azimuth = ((float)e.X / this.Width) * 360 * rychlostMysiX;
horizont = (((float)e.Y / this.Height) * 180) - 90; // -90 zajisti pohled od shora az dolu bez pretoceni na druhou stranu
if(e.X < 1)
{
Cursor.Position = new Point(this.Width -2, e.Y);
}
if(e.X > this.Width - 2)
{
Cursor.Position = new Point(1, e.Y);
}
/************************************
/* snizeni citlivosti mysi na ose Y *
/************************************
// private bool dva = false; - tahle radka patri do instancnich promenych
int horniHranice = 0; // tahle maskarada je tady kvuli labelu umistenymu na hornim okraji formulare
if(l_xy.Visible)
{
horniHranice += l_xy.Height;
}
if((e.Y < 1 + horniHranice) && dva)
{
Cursor.Position = new Point(e.X, this.Height - 2);
dva = !dva;
}
if((e.Y > this.Height - 2) && !dva)
{
Cursor.Position = new Point(e.X, 1 + horniHranice);
dva = !dva;
}
if(dva)
{
horizont += 90;
}
*/
}
///
/// GLFormPreviewKeyDown() - obsluhuje kliknuti na tlacitko na klavesnici
///
/// objekt
/// udalost
private void GLFormPreviewKeyDown(object sender, System.Windows.Forms.PreviewKeyDownEventArgs e)
{
switch (e.KeyCode)
{
case Keys.F:
walk = !walk;
break;
case Keys.R:
posX = 0;
posY = 0;
posZ = 0;
break;
case Keys.L:
light = !light;
break;
case Keys.G:
houpaniPriChuzi = !houpaniPriChuzi;
break;
case Keys.I:
l_xy.Visible = !l_xy.Visible;
break;
case Keys.P:
fillPolygon = !fillPolygon;
break;
}
}
#endregion
}
}