/// Inlcudes
#define MAIN
#include "MicroGlut.h"
#include "GL_utilities.h"
#include "VectorUtils4.h"
#include "LittleOBJLoader.h"
#include "LoadTGA.h"
/// Globals
GLuint program;
mat4 projection;
Model * terrain;
GLuint tex;
/// Generate terrain
Model * GenerateTerrain(const char * filename)
{
TextureData textureData;
if (!LoadTGATextureData(filename, &textureData))
return nullptr;
int vertexCount = textureData.width * textureData.height;
int triangleCount = (textureData.width-1) * (textureData.height-1) * 2;
vec3 * position = (vec3 *) malloc(sizeof(GLfloat) * 3 * vertexCount);
vec3 * normal = (vec3 *) malloc(sizeof(GLfloat) * 3 * vertexCount);
vec2 * texCoord = (vec2 *) malloc(sizeof(GLfloat) * 2 * vertexCount);
GLuint * indices = (GLuint *)malloc(sizeof(GLuint) * 3 * triangleCount);
int bytesPerPixel = textureData.bpp / 8;
for (unsigned int x = 0; x < textureData.width; ++x)
for (unsigned int z = 0; z < textureData.height; ++z)
{
int indexBase = (x + z * textureData.width);
// Vertex array. You need to scale this properly.
GLubyte data = textureData.imageData[indexBase * bytesPerPixel];
position[indexBase].x = x / 1.0;
position[indexBase].y = data / 100.0;
position[indexBase].z = z / 1.0;
// Normal vectors. You need to calculate these.
normal[indexBase].x = 0.0;
normal[indexBase].y = 1.0;
normal[indexBase].z = 0.0;
// Texture coordinates. You may want to scale them.
texCoord[indexBase].x = x; // (float)x / textureData.width;
texCoord[indexBase].y = z; // (float)z / textureData.height;
}
for (unsigned int x = 0; x < textureData.width-1; ++x)
for (unsigned int z = 0; z < textureData.height-1; ++z)
{
int indexBase = (x + z * (textureData.width-1))*6;
// Triangle 1
indices[indexBase + 0] = (x+0) + (z+0) * textureData.width;
indices[indexBase + 1] = (x+0) + (z+1) * textureData.width;
indices[indexBase + 2] = (x+1) + (z+0) * textureData.width;
// Triangle 2
indices[indexBase + 3] = (x+1) + (z+0) * textureData.width;
indices[indexBase + 4] = (x+0) + (z+1) * textureData.width;
indices[indexBase + 5] = (x+1) + (z+1) * textureData.width;
}
// Create Model and upload to GPU:
Model * model = LoadDataToModel(
position,
normal,
texCoord,
nullptr,
indices,
vertexCount,
triangleCount * 3
);
free(textureData.imageData);
return model;
}
/// Init
void init(void)
{
// GL inits.
glClearColor(0.2, 0.2, 0.5, 0.0);
glEnable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
printError("init GL");
// Load and compile shader.
program = loadShaders("terrain.vert", "terrain.frag");
glUseProgram(program);
printError("init shader");
// Matrices.
projection = frustum(-0.1, 0.1, -0.1, 0.1, 0.2, 50.0);
glUniformMatrix4fv(glGetUniformLocation(program, "projection"), 1, GL_TRUE, projection.m);
printError("init matrices");
// Textures.
LoadTGATextureSimple("../assets/terrain/dandelion.tga", &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glUniform1i(glGetUniformLocation(program, "tex"), 0);
printError("init textures");
// Generate terrain.
terrain = GenerateTerrain("../assets/terrain/simple-4.tga");
printError("init terrain");
}
/// Display
void display(void)
{
// Clear the screen.
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Uniforms.
mat4 view = lookAt(
vec3(0, 5, 8), // Position.
vec3(2, 0, 2), // Target.
vec3(0, 1, 0) // Up.
);
mat4 model = IdentityMatrix();
mat4 modelView = view * model;
glUniformMatrix4fv(glGetUniformLocation(program, "modelView"), 1, GL_TRUE, modelView.m);
printError("display uniforms");
// Draw.
DrawModel(terrain, program, "inPosition", nullptr, "inTexCoord");
printError("display draw");
// Show on the screen.
glutSwapBuffers();
}
/// Mouse
void mouse(int x, int y)
{
// This function is included in case you want some hints about using
// passive mouse movement. Uncomment to see mouse coordinates:
// printf("%d %d\n", x, y);
}
/// Main
int main(int argc, char * argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH);
glutInitContextVersion(3, 2);
glutInitWindowSize(600, 600);
glutCreateWindow("TSBK07");
glutRepeatingTimer(20);
glutDisplayFunc(display);
glutPassiveMotionFunc(mouse);
dumpInfo();
init();
glutMainLoop();
}