using System; using System.Collections.Generic; using System.Text; using System.Windows.Forms; using OpenGL4NET; namespace Cv01_OpenGL4Net { class GLWindow : Form { /// /// Graficky kontext. Musi existovat po celou dobu aplikace /// RenderingContext rc; /// /// Meric casu - meri cas :-) /// Time time; float azimuth; float zenith; Box slunce; Box zeme; const double POCET_OBEHU_ZEME = 0.25; const double POCET_OTACEK_ZEME = 1; float zemeObeh; float zemeOtacka; float camFov = 45f; float camFovNasobitel = 1.0f; float camFovRychlost = 0.5f; float camNear = 0.5f; float camFar = 100f; bool plus = false, minus = false; protected override void OnKeyDown(KeyEventArgs e) { switch (e.KeyCode) { case Keys.Add: plus = true; break; case Keys.Subtract: minus = true; break; } } protected override void OnKeyUp(KeyEventArgs e) { switch (e.KeyCode) { case Keys.Add: plus = false; break; case Keys.Subtract: minus = false; break; } } /// /// Inicializace okna a grafickeho kontextu /// /// bool Init() { try { // Nastaveni velikosti okna ClientSize = new System.Drawing.Size(400, 400); // Vytvoreni kontextu, prvni parametr je odkaz na kontrolku, do ktere se ma kreslit. // V pripade potreby je mozne nastavit dalsi vlastnosti kontextu pomoci tridy RenderingContextSetting. // Mezi nejzasadnejsi vlastnosti patri multisample a major a minor pozadovana verze OpenGL. rc = RenderingContext.CreateContext(this, new RenderingContextSetting() { multisample = 255 }); // Podporuje karta vertikalni synchronizaci? if (wgl.Extension.isEXT_swap_control) { // Pokud ano, omezit se na obnovovaci frekvenci zarizeni. // Pokud je synchronizace podporovana, vsimnete si rozdilu ve vyuziti procesoru pri nastaveni intervalu na 0. wgl.SwapInterval(1); } if (!gl.Extension.isARB_vertex_buffer_object) throw new Exception("Tohle je moc stara karta nebo ovladac OpenGL - neumi VBO (ARB_vertex_buffer_object). S tim pracovat nebudu!"); if (!gl.Extension.isEXT_vertex_array) throw new Exception("Tohle je moc stara karta nebo ovladac OpenGL - neumi vertex array (EXT_vertex_array). S tim pracovat nebudu!"); // Vytvoreni merice casu time = new Time(); slunce = new Box(); } catch (Exception e) { // Inicializace se nepovedla, proc? Console.WriteLine(e.Message); return false; } // Inicializace probehla vporadku. return true; } /// /// Aktualizace sceny /// void UpdateScene() { // meric casu vi, ze zacne dalsi snimek time.NextFrame(); zemeObeh = (float) (POCET_OBEHU_ZEME * 360 * time.FrameTime / 1000.0); zemeOtacka = (float)(POCET_OTACEK_ZEME * 360 * time.FrameTime / 1000.0); if (plus) { camFovNasobitel = Math.Max(0.4f, camFovNasobitel - camFovRychlost * time.LastFrameDuration / 1000f); } if (minus) { camFovNasobitel = Math.Max(2f, camFovNasobitel + camFovRychlost * time.LastFrameDuration / 1000f); } } /// /// Vykresleni sceny /// void Render() { gl.ClearColor(0, 0, 0, 0); gl.Clear(GL.COLOR_BUFFER_BIT); gl.Disable(GL.CULL_FACE); gl.PolygonMode(GL.FRONT_AND_BACK, GL.LINE); gl.MatrixMode(GL.PROJECTION); gl.LoadMatrixf(Matrix.Perspective(camFov * camFovNasobitel,(float)ClientSize.Width/ClientSize.Height,camNear,camFar)); gl.MatrixMode(GL.MODELVIEW); gl.LoadIdentity(); gl.Translatef(0, 0, -5f); gl.Rotatef(azimuth, 0, 1, 0); gl.Rotatef(zenith, 1, 0, 0); slunce.Render(); gl.Rotatef(zemeObeh, 0, 0, 1); gl.Translatef(4, 0, 0); gl.Rotatef(zemeOtacka, 0, 0, 1); gl.Scalef(0.3f, 0.3f, 0.3f); zeme.Render(); // zobrazi vykreslenou scenu na obrazovku rc.SwapBuffers(); } /// /// Uvolneni pripadnych naalokovanych zdroju /// void Destroy() { if (slunce != null) slunce.Destroy(); if (zeme != null) zeme.Destroy(); } protected override void OnMouseMove(System.Windows.Forms.MouseEventArgs e) { azimuth = (float)(((float)e.X / this.ClientSize.Width)*360); zenith = (float)(-((float)e.Y / this.ClientSize.Height)*180-90); } /// /// Vstup do programu /// /// Parametry prikazove radky static void Main(string[] args) { GLWindow window = new GLWindow(); if (window.Init()) { window.Show(); window.Activate(); // Tento zpusob neni zdaleka nejlepsi, ale nejjednodussi. // Problem je, ze metoda DoEvents() alokuje s kazdym zavolanim spoustu // pameti, kterou bude muset GC pozdeji uvolnit. // Pro zajemce např. // - blog Toma Millera http://blogs.msdn.com/b/tmiller/ // - http://code.dawnofthegeeks.com/2009/05/07/c-lesson-1-the-main-loop/ // - http://bobobobo.wordpress.com/2009/06/12/game-loop-in-c/ while (window.Created) { window.UpdateScene(); window.Render(); Application.DoEvents(); } } window.Destroy(); } } class Box { uint vertexVBO; uint indexVBO; /// /// Vytvoreni boxu /// public Box() { // Vytvoreni a naplneni pole vrcholu Vector3[] vrchol = new Vector3[] { new Vector3(-1, -1, -1), new Vector3(1, -1, -1), new Vector3(-1, 1, -1), new Vector3(1, 1, -1), new Vector3(-1, 1, 1), new Vector3(1, 1, 1), new Vector3(-1, -1, 1), new Vector3(1, -1, 1), new Vector3(-1, -1, -1), new Vector3(1, -1, -1) }; // Vygenerovani ID pro buffer vrcholu vertexVBO = gl.GenBuffer(); // Pripojeni a naplneni bufferu vrcholu gl.BindBuffer(GL.ARRAY_BUFFER, vertexVBO); gl.BufferData(GL.ARRAY_BUFFER, 8 * Vector3.Size , vrchol, GL.STATIC_DRAW); // Vytvoreni a naplneni pole indexu uint[] index = new uint[] { 1, 0, 2, 3, 3, 2, 4, 5, 2, 0, 6, 4, 1, 3, 5, 7, 0, 1, 7, 6, 5,4,6,7}; // Vygenerovani ID pro buffer indexu indexVBO = gl.GenBuffer(); // Pripojeni a naplneni bufferu indexu gl.BindBuffer(GL.ELEMENT_ARRAY_BUFFER, indexVBO); gl.BufferData(GL.ELEMENT_ARRAY_BUFFER, 24 * sizeof(int), index, GL.STATIC_DRAW); // Odpojeni bufferu gl.BindBuffer(GL.ARRAY_BUFFER, 0); gl.BindBuffer(GL.ELEMENT_ARRAY_BUFFER, 0); } /// /// Vykresleni boxu /// public void Render() { // Pripojeni bufferu se souradnicemi vrcholu gl.BindBuffer(GL.ARRAY_BUFFER, vertexVBO); // Povoleni pouziti ukazatele na pole vrcholu gl.EnableClientState(GL.VERTEX_ARRAY); // Nastaveni ukazatele na pole vrcholu gl.VertexPointer(3, GL.FLOAT, Vector3.Size, (IntPtr)0); // Pripojeni bufferu s indexy gl.BindBuffer(GL.ELEMENT_ARRAY_BUFFER, indexVBO); // Vykresleni ctyruhelniku gl.DrawElements(GL.QUADS, 24, GL.UNSIGNED_INT, (IntPtr)0); // Zakazani pouziti ukazatele na pole vrcholu gl.DisableClientState(GL.VERTEX_ARRAY); // Odpojeni bufferu gl.BindBuffer(GL.ARRAY_BUFFER, 0); gl.BindBuffer(GL.ELEMENT_ARRAY_BUFFER, 0); } /// /// Smazani boxu /// public void Destroy() { // Smazani bufferu gl.DeleteBuffer(vertexVBO); gl.DeleteBuffer(indexVBO); } } }