using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; using OpenGL4NET; using System.Drawing; using System.Windows.Forms; namespace ZPG_2011_Moulis_Jan_A09B0359P { class Window : Form { // nastaveni fullscreenoveho zobrazeni private Boolean fullScreen = true; // stred obrazovky private int mouseCenterX; private int mouseCenterY; // velikost nacitane vyskove mapy private int fieldSize = 128; // jmeno vyskove mapy private String fieldsFileName = "mapa128x128.raw"; // rendering context private RenderingContext rendContext; // pozorovaci uhel kamery private float camAngleOfView = 45f; // nejblizsi renderovaci vzdalenost private float camNear = 0.5f; // nejdelsi renderovaci vzdalenost private float camFar = 500f; // pole odkazu na textury private uint[] textures; // pole vyskove mapy private float[][] groundHeight; // velikost povrchu private int groundSize; // objekt povrch private Ground ground; // objekt slunce private Planet sun; // objekt mesic private Planet moon; // objekty nacitane z obj souboru private OBJObject bender; private OBJObject steve; private OBJObject pan; private OBJObject zombie; private OBJObject cl4p_tp; // polomer obehu objektu cl4p_tp private float cl4p_tpR = 100f; // x-ova souradnice objektu cl4p_tp private float cl4p_tpX; // y-ova souradnice objektu cl4p_tp private float cl4p_tpZ; // hodnota osvetleni v urcitou dobu private float light; // hodnota ambientni slozky svetla private float amb; // hodnota difusni slozky svetla private float dif; // ambientni slozka svetla private float[] LightAmbient1 = { 0.5f, 0.5f, 0.5f, 1.0f }; // difusni slozka svetla private float[] LightDiffuse1 = { 1.0f, 1.0f, 1.0f, 1.0f }; // pozice svetla private float[] LightPosition1; // casova promenna private Time time; // aktualni cas private long actualTime; // cas predchoziho kroku private long previousTime; // cas pred sekundou private long timeBeforSec; // cas mezi tiky private long timeAmongTicks; // cas mezi sekundamy private float timeAmongSec; // sekunda v tikach private const float secInTicks = 10000000; // pocet snimku za sekundu private int fps = 0; // vyska oci pozorovatele private float charactersHeight = 1.85f; // chuze/let private bool walk = true; // rychlost chuze/letu private float walkSpeed = 3; // m/s // delka kroku private float step = 1f; // pohyby, invertovani mysi, zobrazeni hran private bool right, left, forward, backward, up, down, invertedMouse, showFaces; // uhel obihajiciho slunce/mesice private float sunAngle = 270.0f; // uhel slunce °, 0° = poledne // polomer obehu slunce/mesice private float sunR = 300f; // polomer obehu // doba obehu slunce/mesice/cl4p_tp private float sunCirculationTime = 120; // s // uhel ubehnuty za sekundu private float angleSec; // radian private double rad = Math.PI / 180; // PI/2 private double pi2 = Math.PI / 2; // natoceni pozorovatele private float azimuth = 0; // natoceni pozorovatele v radianech private double azimuthRad; // uhel pohledu pozorovatele private float zenith = 0; // uhel pohledu pozorovatele v radianech private double zenithRad; // natoceni a uhel pozorovatele v cas rendrovani private float azimuth_onTime = 0; private float zenith_onTime = 0; // stred vyskove mapy private float center; // x-ova pozice pozorovatele private float posX; // y-ova pozice pozorovatele private float posY; // z-ova pozice pozorovatele private float posZ; // x-ova pozice pozorovatele v cas rendrovani private float posX_onTime = 0; // y-ova pozice pozorovatele v cas rendrovani private float posY_onTime = 0; // z-ova pozice pozorovatele v cas rendrovani private float posZ_onTime = 0; static void Main(string[] args) { Window window = new Window(); if (!window.init()) { window.destroy(); return; } else { window.Show(); window.Activate(); } while (window.Created) { window.render(); Application.DoEvents(); } window.destroy(); } public bool init() { // nastaveni parametru zobrazovaciho okna if (fullScreen) { this.ClientSize = new Size(System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width, System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height); this.CenterToScreen(); this.WindowState = FormWindowState.Maximized; this.FormBorderStyle = FormBorderStyle.None; this.TopMost = true; } else { this.ClientSize = new Size(600, 480); this.CenterToScreen(); } this.Cursor.Dispose(); // nastaveni stredovych pozic mysi mouseCenterX = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width / 2; mouseCenterY = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height / 2; try { // inicializace rendContext = RenderingContext.CreateContext(this, new RenderingContextSetting() { multisample = 0 }); // nacteni vyskove mapy if ((groundHeight = LoadData.loadGroundHeight(fieldsFileName, fieldSize)) == null) { return false; } groundSize = groundHeight.Length * 2 - 2; ground = new Ground(groundHeight); // vytvoreni slunce a mesice sun = new Planet(40f); moon = new Planet(20f); // inicializace casove promenne time = new Time(); // nastaveni stredu vyskove mapy center = -fieldSize; // nastaveni pozice pozorovate na stred mapy posX = posZ = center; // nastaveni pozorovatele do spravne vysky Pohyb(); // invertovani mysi vypnute invertedMouse = false; // zobrazeni ploch zapnute showFaces = true; // vypocteni rychlosti otaceni slunce za sekundu angleSec = 360 / sunCirculationTime; // inicializace GL gl.ShadeModel(GL.SMOOTH); gl.ClearDepth(1.0f); gl.Enable(GL.DEPTH_TEST); gl.DepthFunc(GL.LEQUAL); gl.Enable(GL.COLOR_MATERIAL); // nastaveni svetel gl.Lightf(GL.LIGHT1, GL.CONSTANT_ATTENUATION, 0); gl.Lightf(GL.LIGHT1, GL.LINEAR_ATTENUATION, 0.05f); gl.Lightf(GL.LIGHT1, GL.QUADRATIC_ATTENUATION, 0.005f); gl.Enable(GL.LIGHT1); gl.Enable(GL.LIGHTING); // nacteni textur textures = new uint [3]; gl.Enable(GL.TEXTURE_2D); gl.GenTextures(textures.Length, textures); LoadData.loadTexture(textures, 0, "textury/ground.jpg"); LoadData.loadTexture(textures, 1, "textury/sun.bmp"); LoadData.loadTexture(textures, 2, "textury/moon.bmp"); // nacteni obj objektu bender = LoadData.loadOBJFile("objekty/bender.obj", 0.8f, textures); steve = LoadData.loadOBJFile("objekty/steve.obj", 1f, textures); pan = LoadData.loadOBJFile("objekty/pan.obj", 2.9f, textures); zombie = LoadData.loadOBJFile("objekty/zombie.obj", 1.2f, textures); cl4p_tp = LoadData.loadOBJFile("objekty/cl4p_tp.obj", 0.5f, textures); // nastaveni pocatecni pozice objektu cl4p_tp cl4p_tpX = center; cl4p_tpZ = center; // nastaveni casu predchoziho kroku previousTime = DateTime.Now.Ticks; // vycentrovani kurzoru Cursor.Position = new Point(mouseCenterX, mouseCenterY); return true; } catch (Exception e) { Console.WriteLine(e.Message); return false; } } public void render() { actualTime = DateTime.Now.Ticks; if (90 < sunAngle && sunAngle < 270) { // noc LightPosition1 = new float[] { (float)(-center - sunR * Math.Cos((sunAngle + 90) * rad)), -(float)(sunR * Math.Sin((sunAngle + 90) * rad)), -center, 0 }; light = Math.Abs((float)Math.Cos(sunAngle * rad)); amb = 0.15f * light; dif = 0.2f * light; LightAmbient1 = new float[] { amb, amb, amb, 1.0f }; LightDiffuse1 = new float[] { dif, dif, dif + 0.1f, 1.0f }; gl.ClearColor(0, 0, 0, 0); } else { // den LightPosition1 = new float[] { (float)(-center + sunR * Math.Cos((sunAngle + 90) * rad)), (float)(sunR * Math.Sin((sunAngle + 90) * rad)), -center, 0 }; light = Math.Abs((float)Math.Cos(sunAngle * rad)); amb = 0.5f * light; dif = 1.5f * light; LightAmbient1 = new float[] { amb, amb, amb, 1.0f }; LightDiffuse1 = new float[] { dif, dif, dif, 1.0f }; gl.ClearColor(0, 0, light, 0); } gl.Clear(GL.COLOR_BUFFER_BIT | GL.DEPTH_BUFFER_BIT); gl.Clear(GL.COLOR_BUFFER_BIT); gl.MatrixMode(GL.PROJECTION); gl.LoadIdentity(); gl.LoadMatrixf(Matrix.Perspective(camAngleOfView, (float)ClientSize.Width / ClientSize.Height, camNear, camFar)); if (showFaces) { gl.PolygonMode(GL.FRONT_AND_BACK, GL.FILL); } else { gl.PolygonMode(GL.FRONT_AND_BACK, GL.LINE); } OnTime(); gl.Rotatef(zenith_onTime, 1.0f, 0.0f, 0.0f); gl.Rotatef(azimuth_onTime, 0.0f, 1.0f, 0.0f); Pohyb(); gl.Translatef(posX_onTime, posY_onTime, posZ_onTime); gl.Lightfv(GL.LIGHT1, GL.POSITION, LightPosition1); gl.Lightfv(GL.LIGHT1, GL.AMBIENT, LightAmbient1); gl.Lightfv(GL.LIGHT1, GL.DIFFUSE, LightDiffuse1); gl.Enable(GL.LIGHT1); gl.Enable(GL.LIGHTING); ground.render(textures[0]); if (bender != null) { gl.PushMatrix(); gl.Translatef(-center - 15, 20f, 5f); bender.render(textures); gl.PopMatrix(); } if (steve != null) { gl.PushMatrix(); gl.Translatef(-center - 5, 19.7f, 5f); steve.render(textures); gl.PopMatrix(); } if (pan != null) { gl.PushMatrix(); gl.Translatef(-center + 5, 21f, 5f); pan.render(textures); gl.PopMatrix(); } if (zombie != null) { gl.PushMatrix(); gl.Translatef(-center + 15, 20.1f, 5f); zombie.render(textures); gl.PopMatrix(); } if (cl4p_tp != null) { gl.PushMatrix(); cl4p_tpX = (float)(center + cl4p_tpR * Math.Cos((sunAngle + 90) * rad)); cl4p_tpZ = (float)(center + cl4p_tpR * Math.Sin((sunAngle + 90) * rad)); gl.Translatef(-cl4p_tpX, 4f+getSurfaceHeight(cl4p_tpX, cl4p_tpZ), -cl4p_tpZ); gl.Rotatef(90f - sunAngle, 0f, 1f, 0f); cl4p_tp.render(textures); gl.PopMatrix(); } gl.Disable(GL.LIGHTING); gl.Translatef(-center, 0, -center); gl.Rotatef(sunAngle, 0f, 0f, 1f); gl.Translatef(0, sunR, 0); gl.PushMatrix(); gl.Rotatef(90.0f, 1f, 0f, 0f); sun.render(textures[1]); gl.PopMatrix(); gl.Translatef(0, -2*sunR, 0); gl.Rotatef(90.0f, 1f, 0f, 0f); moon.render(textures[2]); rendContext.SwapBuffers(); mouse(); } public void OnTime() { timeAmongTicks = actualTime - previousTime; timeAmongSec = timeAmongTicks / secInTicks; azimuth_onTime = azimuth; zenith_onTime = zenith; posX_onTime = posX; posY_onTime = posY; posZ_onTime = posZ; sunAngle += timeAmongSec * angleSec; sunAngle %= 360; step = timeAmongSec * walkSpeed; fps++; if (actualTime - timeBeforSec > secInTicks) { System.Console.Out.WriteLine("FPS = " + fps); fps = 0; timeBeforSec = actualTime; } previousTime = actualTime; } public void Pohyb() { azimuthRad = azimuth * rad; zenithRad = zenith * rad; if ((forward && left) || (forward && right) || (backward && left) || (backward && right)) { if (forward && left) { posX += step * (float)Math.Cos(azimuthRad + pi2 / 2); posZ += step * (float)Math.Sin(azimuthRad + pi2 / 2); posY += step * (float)Math.Sin(zenithRad); } if (forward && right) { posX -= step * (float)Math.Cos(azimuthRad - pi2 / 2); posZ -= step * (float)Math.Sin(azimuthRad - pi2 / 2); posY += step * (float)Math.Sin(zenithRad); } if (backward && left) { posX += step * (float)Math.Cos(azimuthRad - pi2 / 2); posZ += step * (float)Math.Sin(azimuthRad - pi2 / 2); posY -= step * (float)Math.Sin(zenithRad); } if (backward && right) { posX -= step * (float)Math.Cos(azimuthRad + pi2 / 2); posZ -= step * (float)Math.Sin(azimuthRad + pi2 / 2); posY -= step * (float)Math.Sin(zenithRad); } } else { if (forward) { posX += step * (float)Math.Cos(azimuthRad + pi2); posZ += step * (float)Math.Sin(azimuthRad + pi2); posY += step * (float)Math.Sin(zenithRad); } if (backward) { posX -= step * (float)Math.Cos(azimuthRad + pi2); posZ -= step * (float)Math.Sin(azimuthRad + pi2); posY -= step * (float)Math.Sin(zenithRad); } if (left) { posX += step * (float)Math.Cos(azimuthRad); posZ += step * (float)Math.Sin(azimuthRad); } if (right) { posX -= step * (float)Math.Cos(azimuthRad); posZ -= step * (float)Math.Sin(azimuthRad); } } if (up) { posY -= step; } if (down) { posY += step; } if (walk) { // opusteni mapy if (posX > 0) { posX = 0; } if (posX < -groundSize + 0.01f) { posX = -groundSize + 0.01f; } if (posZ > 0) { posZ = 0; } if (posZ < -groundSize + 0.01f) { posZ = -groundSize + 0.01f; } // modely if (posZ < -2.5f && posZ > -7.5f) { // zprava if (posX < -145 && posX > -145.5) { posX = -145.5f; } // zleva if (posX < -109.5f && posX > -110f) { posX = -109.5f; } } if (posX < -110 && posX > -145) { // zdola if (posZ < -7.5 && posZ > -8f) { posZ = -8f; } // zhora if (posZ < -2f && posZ > -2.5f) { posZ = -2f; } } posY = -getSurfaceHeight(posX, posZ) - charactersHeight; /* System.Console.Out.WriteLine("-------------------------------------------------------------------"); System.Console.Out.WriteLine("posX = " + posX + " ; posZ = " + posZ); System.Console.Out.WriteLine("x2 = " + x2 + " ; z2 = " + z2); System.Console.Out.WriteLine("xz = " + xz + " ; x1z = " + x1z + " ; xz1 = " + xz1 + " ; x1z1 = " + x1z1); System.Console.Out.WriteLine("xPos = " + xPos + " ; zPos = " + zPos); System.Console.Out.WriteLine("vyska = " + surfaceHeight+ " ; posY = " + posY); */ } } private float getSurfaceHeight(float x, float z) { int x2 = getPositionInField(x); int z2 = getPositionInField(z); float xz = groundHeight[z2][x2]; float x1z = groundHeight[z2][x2 + 1]; float xz1 = groundHeight[z2 + 1][x2]; float x1z1 = groundHeight[z2 + 1][x2 + 1]; float xPos = -x - 2 * x2; float zPos = -z - 2 * z2; float surfaceHeight = xz / 4 * (2 - xPos) * (2 - zPos) + x1z / 4 * (xPos) * (2 - zPos) + xz1 / 4 * (2 - xPos) * (zPos) + x1z1 / 4 * (xPos) * (zPos); return surfaceHeight; } private int getPositionInField(float position) { int p = (int)(-position); return p % 2 == 0 ? p /= 2 : p = (int)((p - 1) / 2); } private void mouse() { float x = Cursor.Position.X; float y = Cursor.Position.Y; if (x != 0 && y != 0) { azimuth += 360.0f * (x - mouseCenterX) / this.Width; azimuth %= 360; if (!invertedMouse) { zenith += 180.0f * (y - mouseCenterY) / this.Height; } else { zenith += -180.0f * (y - mouseCenterY) / this.Height; } if (zenith > 90) { zenith = 90; } if (zenith < -90) { zenith = -90; } Cursor.Position = new Point(mouseCenterX, mouseCenterY); //Console.WriteLine("azimuth: " + azimuth + " ; zenith: " + zenith); } } protected override void OnKeyDown(KeyEventArgs e) { switch (e.KeyCode) { case Keys.A: case Keys.Left: left = true; break; case Keys.D: case Keys.Right: right = true; break; case Keys.W: forward = true; break; case Keys.S: backward = true; break; case Keys.Space: walk = !walk; if (!walk) walkSpeed = 30; else walkSpeed = 3; break; case Keys.Add: up = true; break; case Keys.Subtract: down = true; break; case Keys.U: invertedMouse = !invertedMouse; break; case Keys.F: showFaces = !showFaces; break; case Keys.R: posX = posZ = center; break; case Keys.Escape: Close(); break; } } protected override void OnKeyUp(KeyEventArgs e) { switch (e.KeyCode) { case Keys.A: case Keys.Left: left = false; break; case Keys.D: case Keys.Right: right = false; break; case Keys.W: forward = false; break; case Keys.S: backward = false; break; case Keys.Add: up = false; break; case Keys.Subtract: down = false; break; } } public void destroy() { if (ground != null) { ground.destroy(); } if (sun != null) { sun.destroy(); } if (moon != null) { moon.destroy(); } if (bender != null) { bender.destroy(); } if (steve != null) { steve.destroy(); } if (pan != null) { pan.destroy(); } if (zombie != null) { zombie.destroy(); } if (cl4p_tp != null) { cl4p_tp.destroy(); } } } }