using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Drawing; using System.Windows.Forms; using OpenGL4NET; using System.IO; namespace ZPG_semestralka { class GLW : Form { // nastavní parametrů výchozí mapy int sirkaMatice = 128; int vyskaMatice = 128; int krokMatice = 2; float deleniByte = 10.0f; String nazevMatice = "mapa128x128.raw"; // String nazevMatice = "sloup15x25.raw"; // Nastavení pozorovatele private float pocPozX = 127.0f; private float pocPozY = 127.0f; private float casPredchozihoObrazu = 0; private float rychlostChuze = 3.0f; private float vyskaOci = 1.85f; //Aktuální pozice pozorovatele private float y = 0.0f; private float x = 0.0f; private float z = 0.0f; private float azimut = (float)(0); private float zenith = (float)(-90); private float staryZenith = 0; // Oběkty na mapě private Dum dum1; private Dum dum2; private Dum dum3; private Dum dum4; private TrojuhelSit zem = null; private Silnice silnice; private RenderingContext rc; //Pole klíčů ; private bool[] poleKlicu = new bool[5]; private Klice[] poleObjektuKlicu = new Klice[5]; //Stiky kláves bool stikMezerniku = false; private bool dratenymodel = false; // private bool prepnutiZenitu = false; private bool orientaceZenitu = false; private bool zaznamenejZmenuZenitu = false; private bool pohybVpred; private bool pohybVlevo; private bool pohybDozadu; private bool pohybVpravo; //Pole textur public static uint[] texture = new uint[2]; // private float predchozyFrame = 0; Time cas; float vychoziCas; private float uhelSlunce = 0.0f; // Nastavení pozledové pyramidy float camAngleOfView = 45f; float camNasobitel = 1; float camNear = 0.01f; float camFar = 100f; // Nastavení světel public float[] ambientniSvetlo = { 0.5f, 0.5f, 0.5f, 1.0f }; public float[] diiffusniSvetlo = { 1.0f, 1.0f, 1.0f, 1.0f }; // metoda pro spuštění static void Main(string[] args) { GLW window = new GLW(); if (window.Init()) { window.Show(); window.Activate(); while (window.Created) { window.pohybPoScene(); window.Render(); Application.DoEvents(); } window.Destroy(); } else { Thread.Sleep(3000); } } // metoda pro inicializaci hlavního okna public bool Init() { this.ClientSize = new Size(800, 600); x = pocPozX; y = pocPozY; this.Cursor.Dispose(); try { rc = RenderingContext.CreateContext(this); cas = new Time(); vychoziCas = aktualniCas(); if (!File.Exists(nazevMatice)) { System.Console.Error.WriteLine("ERROR: Nebyl nalezen soubor s maticí."); return false; } zem = new TrojuhelSit(nazevMatice, sirkaMatice, vyskaMatice, krokMatice, deleniByte); dum1 = new Dum(140, 110, 8, 10, 12, 3, 1); dum2 = new Dum(140, 131, 8, 10, 12, 3, 2); dum3 = new Dum(110, 110, 8, 10, 12, 3, 3); dum4 = new Dum(111, 131, 8, 10, 12, 3, 4); silnice = new Silnice(); poleObjektuKlicu[0] = new Klice(132, 145, 9, 1); poleObjektuKlicu[1] = new Klice(133,110,10,2); poleObjektuKlicu[2] = new Klice(156, 127, 10, 4); poleObjektuKlicu[3] = new Klice(80, 126, 10, 3); gl.ClearDepth(1.0f); gl.Enable(GL.LIGHT1); gl.Enable(GL.LIGHTING); gl.Enable(GL.COLOR_MATERIAL); gl.Enable(GL.DEPTH_TEST); gl.Lightfv(GL.LIGHT1, GL.AMBIENT, ambientniSvetlo); } catch (Exception e) { Console.WriteLine(e.Message); Console.ReadLine(); return false; } return true; } // Hlavní metoda pro vyhreslování scény public void Render() { cas.NextFrame(); uhelSlunce = (float)((((((double)360 / 120000)) * cas.FrameTime) / (Math.PI * 18) %6)); // vypočet úhlu slunce float barva; if (Math.PI < uhelSlunce && uhelSlunce < (Math.PI *2)) // vypočet barvy oblohy { gl.Lightfv(GL.LIGHT1, GL.DIFFUSE, new float[] { 0.5f, 0.5f, 0.5f, 1.0f }); barva = 0; } else { if(uhelSlunce <1.5) barva =(float)((uhelSlunce * Math.PI / 180f) *100); else barva = (float)(5.1-((uhelSlunce * Math.PI / 180f) * 100)); gl.Lightfv(GL.LIGHT1, GL.DIFFUSE, new float[] { barva, barva, barva, 1.0f }); } gl.Clear(GL.COLOR_BUFFER_BIT | GL.DEPTH_BUFFER_BIT); // vyčištění buffru gl.ClearColor(0, 0, barva, 0); // nastavní barvy okolí gl.Clear(GL.COLOR_BUFFER_BIT); gl.MatrixMode(GL.PROJECTION); // nastavení pohledové pryramidy gl.LoadIdentity(); gl.LoadMatrixf(Matrix.Perspective(camAngleOfView * camNasobitel, (float)ClientSize.Width / ClientSize.Height, camNear, camFar)); Vector4 lightPos = new Vector4(((float)Math.Cos(uhelSlunce))*127 +127, 127, (float)Math.Sin(uhelSlunce)*127 +10, 1); // Pozice světla if (Math.PI < uhelSlunce && uhelSlunce < (2*Math.PI)) // Nastavení deního a nočního světla { gl.Lightfv(GL.LIGHT0, GL.POSITION, new float[] { 0, 127, 127, 0 }); gl.Lightf(GL.LIGHT0, GL.CONSTANT_ATTENUATION, 0); gl.Lightf(GL.LIGHT0, GL.LINEAR_ATTENUATION, 0.01f); gl.Lightf(GL.LIGHT0, GL.QUADRATIC_ATTENUATION, 0.001f); gl.Lightfv(GL.LIGHT0, GL.AMBIENT, new float[] { .3f, .3f, .3f }); gl.Lightfv(GL.LIGHT0, GL.DIFFUSE, new float[] { 1f, 1f, 1f }); gl.Disable(GL.LIGHTING); gl.Enable(GL.LIGHTING); } else { gl.Lightfv(GL.LIGHT1, GL.POSITION, new float[] { lightPos.x, lightPos.y, lightPos.z, lightPos.w }); gl.Lightf(GL.LIGHT1, GL.CONSTANT_ATTENUATION, 0); gl.Lightf(GL.LIGHT1, GL.LINEAR_ATTENUATION, 0.01f); gl.Lightf(GL.LIGHT1, GL.QUADRATIC_ATTENUATION, 0.00001f); gl.Lightfv(GL.LIGHT1, GL.AMBIENT, new float[] { .3f, .3f, .3f }); gl.Lightfv(GL.LIGHT1, GL.DIFFUSE, new float[] { 1f, 1f, 1f }); gl.PointSize(38); // Vykresleni slunce gl.Disable(GL.LIGHTING); gl.Begin(GL.POINTS); gl.Color3f(1, 1, 1); gl.Vertex3d(lightPos.x, lightPos.y, lightPos.z); gl.End(); gl.Enable(GL.LIGHTING); } // if (dratenymodel) // gl.PolygonMode(GL.FRONT_AND_BACK, GL.LINE);//fill // else gl.PolygonMode(GL.FRONT_AND_BACK, GL.FILL); pohybPoScene(); // metoda obsluhující pohyb po scéně gl.MatrixMode(GL.MODELVIEW); // vykreslení scény gl.LoadIdentity(); gl.Rotatef(zenith, 1, 0, 0); gl.Rotatef(azimut, 0, 0, 1); z = -interpolace((x), (y), zem.pole) + vyskaOci; gl.Translatef(-x, -y, -z); zem.Render(dratenymodel); dum1.Render(); dum2.Render(); dum3.Render(); dum4.Render(); silnice.Render(); for (int i = 0; i < poleObjektuKlicu.Length; i++) { if(poleObjektuKlicu[i] != null) poleObjektuKlicu[i].Render(); } casPredchozihoObrazu = aktualniCas(); rc.SwapBuffers(); } /* metoda pro výpočet interpolace mezi jednotlivými body mapy */ private float interpolace(float x, float y, float[][] pole) { x = (sirkaMatice * 2 - x) - 2; y = (vyskaMatice * 2 - y) - 2; int poleX = vratPoziciVPoly(x); int poleY = vratPoziciVPoly(y); float rozdilX = x - 2 * poleX; float rozdilY = y - 2 * poleY; float levDol = (float)pole[poleY][poleX]; float pravDol = (float)pole[poleY][poleX + 1]; float levHor = (float)pole[poleY + 1][poleX]; float pravHor = (float)pole[poleY + 1][poleX + 1]; return -(levDol / 4 * (2 - rozdilX) * (2 - rozdilY) + pravDol / 4 * (rozdilX) * (2 - rozdilY) + levHor / 4 * (2 - rozdilX) * (rozdilY) + pravHor / 4 * (rozdilX) * (rozdilY)); } /* * Metoda vrací pozci v poli na které se nacházíme. */ private int vratPoziciVPoly(float pozice) { int pom = (int)(pozice); if (pom % 2 == 0) { pom= pom / 2; } else { pom = (int)((pom - 1) / 2); } return pom; } // metoda pro vyčištění paměti public void Destroy() { dum1.Destroy(); dum2.Destroy(); dum3.Destroy(); dum4.Destroy(); silnice.Destroy(); zem.Destroy(); for (int i = 0; i < poleObjektuKlicu.Length; i++) { if(poleObjektuKlicu[i] != null) poleObjektuKlicu[i].Destroy(); } } // metoda provádějící výpočty ohledně pohybu po planetě public void pohybPoScene() { Thread.Sleep(2); float rychlost = (float)(((aktualniCas() - casPredchozihoObrazu)) * 0.0008 * rychlostChuze); int zaokr = (int)rychlost; rychlost = rychlost - zaokr; float staraX = x; float staraY = y; if ((pohybVpred && pohybVpravo) || (pohybVpred && pohybVlevo) || (pohybDozadu && pohybVlevo) || (pohybDozadu && pohybVpravo)) { if (pohybVpred && pohybVpravo) { y = y + rychlost * (float)Math.Sin((-azimut * Math.PI / 180) + Math.PI / 4); x = x + rychlost * (float)Math.Cos((-azimut * Math.PI / 180) + Math.PI / 4); } if (pohybDozadu && pohybVlevo) { y = y - rychlost * (float)Math.Sin((-azimut * Math.PI / 180) + Math.PI / 4); x = x - rychlost * (float)Math.Cos((-azimut * Math.PI / 180) + Math.PI / 4); } if (pohybVlevo && pohybVpred) { x = x + rychlost * (float)Math.Cos((-azimut * Math.PI / 180) + 3 * Math.PI / 4); y = y + rychlost * (float)Math.Sin((-azimut * Math.PI / 180) + 3 * Math.PI / 4); } if (pohybDozadu && pohybVpravo) { x = x - rychlost * (float)Math.Cos((-azimut * Math.PI / 180) + 3 * Math.PI / 4); y = y - rychlost * (float)Math.Sin((-azimut * Math.PI / 180) + 3 * Math.PI / 4); } } else { if (pohybVpred) { y = y + rychlost * (float)Math.Sin((-azimut * Math.PI / 180) + Math.PI / 2); x = x + rychlost * (float)Math.Cos((-azimut * Math.PI / 180) + Math.PI / 2); } if (pohybDozadu) { x = x - rychlost * (float)Math.Cos((-azimut * Math.PI / 180) + Math.PI / 2); y = y - rychlost * (float)Math.Sin((-azimut * Math.PI / 180) + Math.PI / 2); } if (pohybVlevo) { x = x - rychlost * (float)Math.Cos((-azimut * Math.PI / 180)); y = y - rychlost * (float)Math.Sin((-azimut * Math.PI / 180)); } if (pohybVpravo) { x = x + rychlost * (float)Math.Cos((-azimut * Math.PI / 180)); y = y + rychlost * (float)Math.Sin((-azimut * Math.PI / 180)); } } overPohybPoDome( staraX, staraY, dum1,poleKlicu); // ošetření pohybu vůči jednotlivím oběktům overPohybPoDome(staraX, staraY, dum2, poleKlicu); overPohybPoDome(staraX, staraY, dum3, poleKlicu); overPohybPoDome(staraX, staraY, dum4, poleKlicu); for (int i = 0; i < poleObjektuKlicu.Length; i++) // ověření zda byl klíč sebrá či nikoliv { if (poleObjektuKlicu[i] != null) { if (poleObjektuKlicu[i].sebralJsemPredmet(x, y)) { poleKlicu[poleObjektuKlicu[i].cisloKlice] = true; poleObjektuKlicu[i] = null; } } } if (x < 2) // ošetření pohybu mimo krajinu { x = 2; } if (y < 2) { y = 2; } if (x > (sirkaMatice - 2) * krokMatice) { x = (sirkaMatice - 2) * krokMatice; } if (y > (vyskaMatice - 2) * krokMatice) { y = (vyskaMatice - 2) * krokMatice; } cas.NextFrame(); } // metoda obsluhující stisk kláves protected override void OnKeyDown(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; case Keys.Space: stikMezerniku = true; break; /* case Keys.T: if (dratenymodel) { dratenymodel = false; } else { dratenymodel = true; } break; */ case Keys.U: if (orientaceZenitu) { orientaceZenitu = false; zaznamenejZmenuZenitu = true; } else { orientaceZenitu = true; zaznamenejZmenuZenitu = true; } break; } } // metoda pro uvolnění stisku klávesy protected override void OnKeyUp(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; } } // metoda pro obsluhující pohyby myši protected override void OnMouseMove(MouseEventArgs e) { /* azimut = ((float)e.X / (this.Width-100)) * 360; if (e.X < 42) { Cursor.Position = new Point(this.Location.X + this.Width - 51, this.Location.Y + e.Y + 30); } if (e.X > this.Width - 58) { Cursor.Position = new Point(this.Location.X + 53 , this.Location.Y + e.Y + 30); } */ float rozdil = (float)(((this.Width / 2) - 8) - e.X); if (rozdil != 0) { azimut += (float)(-rozdil / this.Width * 360); Cursor.Position = new Point((this.Location.X + (this.Width / 2)), this.Location.Y + e.Y + 30); } if (zaznamenejZmenuZenitu) { zaznamenejZmenuZenitu = false; Cursor.Position = new Point(this.Location.X + 8 +e.X,this.Location.Y+30+(this.Height/2) + (this.Height /2 -e.Y)); } if (!orientaceZenitu) { zenith = (((float)e.Y / this.Height) * 180) +180 ; } else { zenith = -(((float)e.Y / this.Height) * 180) ; } } // metoda pro určování času v milisekundách public float aktualniCas() { return DateTime.Now.Hour * 3600000 + DateTime.Now.Minute * 60000 + DateTime.Now.Second * 1000 + DateTime.Now.Millisecond; } /* metoda pro hlídání pohybu v a okolo domu * staraX - X pozice postavy před započetím chůze * staraY - Y pozice postavy před započetím chůze * dum1 - oběkt pro který počítáme kolize * poleKlicu - pole klíčů, které jsme již sebraly. */ private void overPohybPoDome( float staraX, float staraY, Dum dum1, bool[]poleKlicu) { if (dum1.jsemPredVraty(x, y) && !dum1.odevriVrata) // zjištění zda stojíme před vraty { if (stikMezerniku) { stikMezerniku = false; dum1.odevriVrata = true; } } if (dum1.jsemPredVraty(x, y)) { if (stikMezerniku) { stikMezerniku = false; dum1.odevriVrata = true; } } else { dum1.odevriVrata = false; } if (dum1.jsemPredDvermy1(x, y) && poleKlicu[dum1.klicNaDvere1]) // zjištění zda jsem před dveřmy { if (stikMezerniku) { stikMezerniku = false; System.Console.Out.WriteLine("sem pred dverma"); dum1.otevriDvere1(); } } else { dum1.zavriDvere1(); } int pocet = dum1.overNarazDoSteny(x, y); // přenastavení pozice při nárazu do stěny if (pocet == 1) { if (dum1.narazeniNaStenuX(staraX, y)) { x = staraX; } if (dum1.narazeniNaStenuY(x, staraY)) { y = staraY; } dum1.nalezenej = -1; } else if (pocet == 2) { if (dum1.narazeniNaStenuForX(staraX, y)) { x = staraX; } if (dum1.narazeniNaStenuForY(x, staraY)) { y = staraY; } dum1.nalezenej = -1; } } /* metoda pro určení pozice čísla na textuře * return Vector4 (počátek textury na ose X, konec textury na ose X, počátek textury na ose Y, konec textury na ose Y) */ public static Vector4 vratPozTexCisla(int cislo) { switch (cislo) { case 0: return new Vector4((float)0.025, (float)0.21, (float)0, (float)0.5); case 1: return new Vector4((float)0.21, (float)0.385, (float)0, (float)0.5); case 2: return new Vector4((float)0.385, (float)0.585, (float)0, (float)0.5); case 3: return new Vector4((float)0.585, (float)0.787, (float)0, (float)0.5); case 4: return new Vector4((float)0.787, (float)1, (float)0, (float)0.5); } return new Vector4(0, 1, 0,1); } } }