using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.InteropServices; using OpenGL4NET; namespace ZPG_2011_Moulis_Jan_A09B0359P { class Ground { private Window window; private uint vboData; private uint iboData; private uint size; private float[][] groundHeight; private int triCount; private PositionNormalTexCoor[] vertex; private uint[] index; private float texX; private float texZ; public Ground(float[][] groundHeight) { this.groundHeight = groundHeight; size = (uint) groundHeight.Length; vertex = new PositionNormalTexCoor[size * size]; copyGroundsHeightToVertex(); createTriangleWeb(); //countNormals(); spoctiNormaly(); prepareVBOIBO(); } private void copyGroundsHeightToVertex() { for (int z = 0; z < size; z++) { texZ = ((float)(z) / size); for (int x = 0; x < size; x++) { texX = ((float)(x) / size); vertex[z * size + x] = new PositionNormalTexCoor(2 * x, groundHeight[z][x], 2 * z, 0, 0, 0, texX, texZ); } } } private void createTriangleWeb() { // Vytvoreni trojuhelnikove site triCount = (int)(3 * (size - 1) * (size - 1) * 2); index = new uint[triCount]; int p = 0; for (uint i = 0; i < size - 1; i++) { for (uint j = 0; j < size - 1; j++) { index[p++] = i * size + j; index[p++] = (i + 1) * size + j; index[p++] = i * size + j + 1; index[p++] = i * size + j + 1; index[p++] = (i + 1) * size + j; index[p++] = (i + 1) * size + j + 1; } } } private void countNormals() { // Projit kazdy trojuhelnik (sklada se ze 3 vrcholu) for (int i = 0; i < index.Length; i += 3) { // Zjisit vektor od vrcholu 0 k 1 Vector3 v1 = vertex[index[i + 1]].position - vertex[index[i]].position; // Zjisit vektor od vrcholu 0 k 2 Vector3 v2 = vertex[index[i + 2]].position - vertex[index[i]].position; // Vektorovy soucin urci kolmy vektor Vector3 n = Vector3.Cross(ref v1, ref v2); n.Normalize(); // K normale kazdeho vrcholu pricist spocitanou normalu vertex[index[i]].normal += n; vertex[index[i + 1]].normal += n; vertex[index[i + 2]].normal += n; } // Normaly normalizovat! Ve vypoctu osvetleni se na to spoleha // Lze obejit povoleni glEnable(GL_NORMALIZE), pocita se vsak v kazdem snimku a brzdi vykreslovani for (int i = 0; i < vertex.Length; i++) { vertex[i].normal.Normalize(); } } private void spoctiNormaly() { Vector3 p0; Vector3 p1; Vector3 p2; Vector3 p3; Vector3 p4; Vector3 v1; Vector3 v2; Vector3 v3; Vector3 v4; Vector3 n; for (int z = 0; z < size; z++) { for (int x = 0; x < size; x++) { p0 = new Vector3(x, groundHeight[z][x], z); if (z != 0 && x != 0 && z != size - 1 && x != size - 1) { // vnitrek site krome kraju p1 = new Vector3(x, groundHeight[z + 1][x], z + 1); p2 = new Vector3(x + 1, groundHeight[z][x + 1], z); p3 = new Vector3(x, groundHeight[z - 1][x], z - 1); p4 = new Vector3(x - 1, groundHeight[z][x - 1], z); v1 = p1 - p0; v2 = p2 - p0; v3 = p3 - p0; v4 = p4 - p0; n = Vector3.Cross(ref v1, ref v2) + Vector3.Cross(ref v2, ref v3) + Vector3.Cross(ref v3, ref v4) + Vector3.Cross(ref v4, ref v1); n.Normalize(); vertex[z * size + x].normal = new Vector3(n.x, n.y, n.z); } else { if (x > 0 && x < size - 1) { if (z == 0) { p1 = new Vector3(x, groundHeight[z + 1][x], z + 1); p2 = new Vector3(x + 1, groundHeight[z][x + 1], z); p4 = new Vector3(x - 1, groundHeight[z][x - 1], z); v1 = p1 - p0; v2 = p2 - p0; v4 = p4 - p0; n = Vector3.Cross(ref v1, ref v2) + Vector3.Cross(ref v2, ref v4) + Vector3.Cross(ref v4, ref v1); n.Normalize(); vertex[z * size + x].normal = new Vector3(n.x, n.y, n.z); } if (z == size - 1) { p2 = new Vector3(x + 1, groundHeight[z][x + 1], z); p3 = new Vector3(x, groundHeight[z - 1][x], z - 1); p4 = new Vector3(x - 1, groundHeight[z][x - 1], z); v2 = p2 - p0; v3 = p3 - p0; v4 = p4 - p0; n = Vector3.Cross(ref v2, ref v3) + Vector3.Cross(ref v3, ref v4) + Vector3.Cross(ref v4, ref v2); n.Normalize(); vertex[z * size + x].normal = new Vector3(n.x, n.y, n.z); } } else if (z > 0 && z < size - 1) { if (x == 0) { p1 = new Vector3(x, groundHeight[z + 1][x], z + 1); p2 = new Vector3(x + 1, groundHeight[z][x + 1], z); p3 = new Vector3(x, groundHeight[z - 1][x], z - 1); v1 = p1 - p0; v2 = p2 - p0; v3 = p3 - p0; n = Vector3.Cross(ref v1, ref v2) + Vector3.Cross(ref v2, ref v3) + Vector3.Cross(ref v3, ref v1); n.Normalize(); vertex[z * size + x].normal = new Vector3(n.x, n.y, n.z); } if (x == size - 1) { p1 = new Vector3(x, groundHeight[z + 1][x], z + 1); p3 = new Vector3(x, groundHeight[z - 1][x], z - 1); p4 = new Vector3(x - 1, groundHeight[z][x - 1], z); v1 = p1 - p0; v3 = p3 - p0; v4 = p4 - p0; n = Vector3.Cross(ref v1, ref v3) + Vector3.Cross(ref v3, ref v4) + Vector3.Cross(ref v4, ref v1); n.Normalize(); vertex[z * size + x].normal = new Vector3(n.x, n.y, n.z); } } else { vertex[z * size + x].normal = new Vector3(0,0,0); } } } } } private void prepareVBOIBO() { // Priprava vbo vboData = gl.GenBuffer(); gl.BindBuffer(GL.ARRAY_BUFFER, vboData); gl.BufferData(GL.ARRAY_BUFFER, vertex.Length * PositionNormalTexCoor.SizeInBytes, vertex, GL.STATIC_DRAW); gl.BindBuffer(GL.ARRAY_BUFFER, 0); // Priiprava ibo iboData = gl.GenBuffer(); gl.BindBuffer(GL.ELEMENT_ARRAY_BUFFER, iboData); gl.BufferData(GL.ELEMENT_ARRAY_BUFFER, index.Length * sizeof(uint), index, GL.STATIC_DRAW); gl.BindBuffer(GL.ELEMENT_ARRAY_BUFFER, 0); gl.BindBuffer(GL.ARRAY_BUFFER, 0); } public void render(uint texture) { gl.ActiveTexture(GL.TEXTURE0); gl.Enable(GL.TEXTURE_2D); gl.BindTexture(GL.TEXTURE_2D, texture); gl.TexEnvf(GL.TEXTURE_ENV, GL.TEXTURE_ENV_MODE, GL.MODULATE); gl.BindBuffer(GL.ARRAY_BUFFER, vboData); // NAČTENÍ BUFFERU gl.BindBuffer(GL.ELEMENT_ARRAY_BUFFER, iboData); gl.ClientActiveTexture(GL.TEXTURE0); gl.EnableClientState(GL.TEXTURE_COORD_ARRAY); // TEXTURA gl.TexCoordPointer(2, GL.FLOAT, PositionNormalTexCoor.SizeInBytes, (IntPtr)24); gl.EnableClientState(GL.NORMAL_ARRAY); // NORMÁLY gl.NormalPointer(GL.FLOAT, PositionNormalTexCoor.SizeInBytes, (IntPtr)12); gl.EnableClientState(GL.VERTEX_ARRAY); // POZICE BODU gl.VertexPointer(3, GL.FLOAT, PositionNormalTexCoor.SizeInBytes, (IntPtr)0); gl.DrawElements(GL.TRIANGLES, triCount, GL.UNSIGNED_INT, (IntPtr)0); // VYKRESLENÍ gl.DisableClientState(GL.VERTEX_ARRAY); gl.DisableClientState(GL.NORMAL_ARRAY); gl.DisableClientState(GL.TEXTURE_COORD_ARRAY); gl.BindBuffer(GL.ARRAY_BUFFER, 0); gl.BindBuffer(GL.ELEMENT_ARRAY_BUFFER, 0); gl.BindTexture(GL.TEXTURE_2D, 0); gl.ActiveTexture(GL.TEXTURE0); gl.Disable(GL.TEXTURE_2D); gl.BindTexture(GL.TEXTURE_2D, 0); } public void destroy() { gl.DeleteBuffer(vboData); gl.DeleteBuffer(iboData); } [StructLayout(LayoutKind.Sequential)] struct PositionNormalTexCoor { public Vector3 position; public Vector3 normal; public float texCoorX; public float texCoorY; /// /// Konstruktor z floatu /// /// X /// Y /// Z /// nX /// nY /// nZ /// texCoorX /// texCoorY public PositionNormalTexCoor(float x, float y, float z, float nx, float ny, float nz, float texCoorX, float texCoorY) { position = new Vector3(x, y, z); normal = new Vector3(nx, ny, nz); this.texCoorX = texCoorX; this.texCoorY = texCoorY; } /// /// Velikost struktury v bytech /// public static int SizeInBytes { get { return Marshal.SizeOf(typeof(PositionNormalTexCoor)); } } } } }