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