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 } }