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