#define GL_GLEXT_PROTOTYPES
#define _USE_MATH_DEFINES
#include <uthash.h>
#if defined(_WIN32)
#if defined(__GNUC__)
#include <cpuid.h>
#elif defined(_MSC_VER)
#include <intrin.h>
#endif
//#define APIENTRY __stdcall
#include <windows.h>
#include <errno.h>
#define GLEW_STATIC
#include <GL/glew.h>
//#include "glew/glew.h"
//#include <GL/gl.h>
//#include <GLES2/gl2.h>
//#include <GLES2/gl2ext.h>
//#define GLFW_INCLUDE_ES3
#define GLFW_EXPOSE_NATIVE_WGL
#define GLFW_EXPOSE_NATIVE_WIN32
#else
#include <GL/gl.h>
//#include <GL/glext.h>
#define GLFW_EXPOSE_NATIVE_X11
#define GLFW_EXPOSE_NATIVE_GLX
#endif
#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
#include <GLFW/glfw3native.h>
//#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
//#include "lodepng.h" // alternative to stb_image, may be slower
#include "linmathv2.h"
//#include "geometry.h"
#include <math.h>
#ifndef M_PI
#define M_PI 3.14159265358979323846264338327950288
#endif
#define degToRad(angleInDegrees) ((angleInDegrees) * M_PI / 180.0)
#define radToDeg(angleInRadians) ((angleInRadians) * 180.0 / M_PI)
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))
#define CLAMP(x, upper, lower) (MIN(upper, MAX(x, lower)))
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include "custom.h" // early declarations
//#include "input.h"
#include "shaders.h" //
#include "water.h" //
#include "sky.h" //
#include "terrain.h" //
#define nullptr ((void*)0)
#define vstr(s) str(s)
#define str(s) #s
float *keepLines;
unsigned int keepLinesLen=0;
unsigned int NUM_STRIPS;
unsigned int NUM_VERTS_PER_STRIP;
unsigned int terrainVAO, terrainVBO, terrainEBO;
Vec3 terrainMin,terrainMax;
float *terrainCollider; // collider data
float gridWidth,gridHeight; // size
float gridTop,gridLeft; // offset
float terrainScale = 4.0f;
int InitializeTerrain() { // buffer only needs to be made once?
// updating buffers means transfering
// the data back again to the GPU,
// create the buffer once and simply
// rebind before every draw = no transfer
// between cpu/gpu, and make modification
// with the translate of m * v * p matrices
// flip is already set in spinningquad once
//--int width, height, nChannels;
//unsigned char *data = stbi_load("data/textures/iceland_heightmap.png", &width, &height, &nChannels, 0);
//unsigned char *data = stbi_load("data/textures/mini_island.png", &width, &height, &nChannels, 0);
int width, height, nChannels;
unsigned char *data = stbi_load("data/textures/awv6.png", &width, &height, &nChannels, 0);
//unsigned char *data = stbi_load("data/textures/mini_island2.png", &width, &height, &nChannels, 0);
gridWidth = width;
gridHeight = height;
gridTop = -height/2.0f;
gridLeft = -width/2.0f;
//float yScale = 64.0f / 256.0f;
float yScale = 0.25f;
//float yShift = 16.0f;
float yShift = 8.0f;
// Example rendering setup in plain C
// Assume you have a pointer to vertex data structure, which includes x, y, and z (height)
// malloc size 3 + 3 + 2 position,color,uv
//uint8_t *colorData = malloc(sizeof(float) * width * height * 3); // Each point has x,y,z
float *vertexData = malloc(sizeof(float) * width * height * 7); // Each point has x,y,z
terrainCollider = malloc(sizeof(float) * width * height); // keeing for calculations after - heights only(Y)
// scaling 1:1 pixel to float position, offset -width/2
unsigned int *indicesData = malloc(sizeof(unsigned int) * width * (height - 1) * 2); // Each side of strip indices
printf("\nTerrain loading\n*vertexData=[");
printf("_redacted_for_speed_");
//int lastZ=-1;
for (int c = 0; c < width * height; ++c) {
int j = c % width; // width cycles | equal j in learnopengl
int i = c / height; // height // equal i in learnopengl
//int z1 = z-1; // height-1
//int x1 = x-1; // height-1
//int modUV = c % 4; // wrap 0-1-2-3
//if(lastZ!=z) {
// printf("new strip start. z=%d\n",z);
//}
//lastZ=z;
// retrieve texel for (i,j) tex coord
unsigned char* texel = data + (j + width * i) * nChannels;
// raw height at coordinate
unsigned char y = texel[0];
//const stbi_us y = texel[0];
float heightMap = (int)y * yScale - yShift;
float realZ = gridTop + i;
float realX = gridLeft + j;
//float colorY = (heightMap+(yShift*2))/(256.0f-yShift*10);
vertexData[c*7] = realX;
vertexData[c*7 + 1] = heightMap;
vertexData[c*7 + 2] = realZ;
//vertexData[c*6 + 3] = 0.0f;
//vertexData[c*6 + 4] = colorY;
//vertexData[c*6 + 5] = 0.0f;
//terrainCollider[c*3] = realX;
terrainCollider[c] = heightMap;
//terrainCollider[c*3 + 2] = realZ;
//colorData[i*3] = colorY; // color
//colorData[i*3 + 1] = colorY; // color
//colorData[i*3 + 2] = colorY; // color
vertexData[c*7 + 6] = realX; // uv
vertexData[c*7 + 7] = realZ; // uv
//vertexData[c*7 + 6] = 1.0f; // uv
//vertexData[c*7 + 7] = 0.0f; // uv
//--printf("%f,0.0f,%f, ",realX,realZ);
//--printf("colorY = %f\n",colorY);
if(heightMap<terrainMin.y) { // for bounds
terrainMin.y = heightMap;
}
if(heightMap>terrainMax.y) {
terrainMax.y = heightMap;
}
if(c==0) {
terrainMin.x = realX;
terrainMin.z = realZ;
} else if(c==(width*height)-1) {
terrainMax.x = realX;
terrainMax.z = realZ;
}
//printf("i=%d, x=%d, z=%d [x=%f, y=%f, z=%f]\n",i,x,z,realX,heightMap,realZ);
}
keepLines = malloc(sizeof(float)*(width * (height - 1))*7);
printf("]\n*indicesData=[");
printf("_redacted_for_speed_");
unsigned int count = 0;
for (int c = 0; c < width * (height - 1); ++c) {
int j = c % width; // width cycles | equal j in learnopengl
int i = c / height; // height // equal i in learnopengl
//int cN=((i - 1) * j) + j;
//int cE=(i * j) + j + 1;
//int cW=(i * j) + j - 1;
//int cS=((i + 1) * j) + j - 1;
//-0int cN=((j+width)*6)*(i-1);
//-0int cE=((j+1+width)*6)*i;
//-0int cW=((j-1+width)*6)*i;
//-0int cS=((j+width)*6)*(i+1);
int cpos=c * 7;
int left=cpos-7;
int right=cpos+7;
//int top=cpos-(width*6);
int bottom=cpos+(width*7);
//int cN=top;
int cE=right;
int cW=left;
int cS=bottom;
//--printf("cN: %d, cE: %d, cW: %d, cS: %d\n",cN,cE,cW,cS);
//--Vec3 vN={0.0f,0.0f,0.0f};
Vec3 vE={0.0f,0.0f,0.0f};
Vec3 vW={0.0f,0.0f,0.0f};
Vec3 vS={0.0f,0.0f,0.0f};
int cLen = width * height * 7;
int row = width * 7;
//--if(cN>=0 && i>0) {
//-- vN.x=vertexData[cN];
//-- vN.y=vertexData[cN+1];
//-- vN.z=vertexData[cN+2];
//--}
if(cE<=cLen && j<width-1) {
vE.x=vertexData[cE];
vE.y=vertexData[cE+1];
vE.z=vertexData[cE+2];
}
if(cW>=0 && j>0) {
vW.x=vertexData[cW];
vW.y=vertexData[cW+1];
vW.z=vertexData[cW+2];
}
if(cS<=cLen-row && i<height-1) {
vS.x=vertexData[cS];
vS.y=vertexData[cS+1];
vS.z=vertexData[cS+2];
}
//--Vec3 vC={vertexData[c*6],vertexData[c*6+1],vertexData[c*6+2]};
//--Vec3 measure={0.0f,2.0f,0.0f};
//Vec3 up={0.0f,1.0f,0.0f};
//measure.y=((vS.y-vN.y)+(vW.y-vE.y))/2;
//Vec3 test={0.0f,0.0f,0.0f};
//i//test.
//Vec3 crossy=cross(vW,vN);
//measure.z=vS.x-vN.x;
//measure.x=vW.z-vE.z;
//Vec3 n0 = normalize(cross(Vec3_sub(vC,vN), Vec3_sub(vW,vC)));
//Vec3 n1 = normalize(cross(Vec3_sub(vE,vC), Vec3_sub(vW,vC)));
//Vec3 n2 = normalize(cross(Vec3_sub(vC,vW), Vec3_sub(vN,vC)));
//Vec3 n3 = normalize(cross(Vec3_sub(vW,vC), Vec3_sub(vE,vC)));
//Vec3 n0 = Vec3_sub(vS,vC);
//Vec3 n1 = Vec3_sub(vC,vN);
//Vec3 n2 = Vec3_sub(vW,vC);
//Vec3 n3 = Vec3_sub(vC,vE);
Vec3 uVec = Vec3_sub(vW,vE);
Vec3 vVec = Vec3_sub(vS,vE);
Vec3 normal = normalize(cross(uVec,vVec));
//measure.z=n0.x;
//measure.x=n2.z;
//measure.y=-n0.y;
//measure.z=vS.x-vN.x;
//measure.x=vW.z-vE.z;
vertexData[c*7 + 3] = normal.x;
vertexData[c*7 + 4] = normal.y;
vertexData[c*7 + 5] = normal.z;
// keepLines for mesh normals that are generated once
// but want lines to keep rendering indefinitely--
//--keepLines[c*6] = vertexData[c*6];
//--keepLines[c*6+1] = vertexData[c*6+1];
//--keepLines[c*6+2] = vertexData[c*6+2];
//--keepLines[c*6+3] = vertexData[c*6]+normal.x;
//--keepLines[c*6+4] = vertexData[c*6+1]+normal.y;
//--keepLines[c*6+5] = vertexData[c*6+2]+normal.z;
//--keepLinesLen++;
//--printf("c=%d, i=%d, j=%d, [nX: %f, nY: %f, nZ: %f]\n",c,i,j,vertexData[c*6 + 3],vertexData[c*6 + 4],vertexData[c*6 + 5]);
for(int k=0;k<2;k++) { // alternate index k=h
unsigned int indice=j + width * (i + k);
indicesData[count] = indice;
count++;
//if(k==0) {
// printf("k0: %d\n",indice);
// // |----/
// // | _/
// // | /
// // |/
//} else {
// printf("k1: %d\n",indice);
// // /|
// // _/ |
// // / |
// // /----|
//}
}
}
printf("]\n");
printf("\nterrainMin.x=%f, terrainMin.y=%f, terrainMin.z=%f\n",terrainMin.x,terrainMin.y,terrainMin.z);
printf("terrainMax.x=%f, terrainMax.y=%f, terrainMax.z=%f\n\n",terrainMax.x,terrainMax.y,terrainMax.z);
stbi_image_free(data); // free after building vertex array
NUM_STRIPS = height-1;
NUM_VERTS_PER_STRIP = width*2;
glGenVertexArrays(1,&terrainVAO);
glBindVertexArray(terrainVAO);
glGenBuffers(1,&terrainVBO);
glBindBuffer(GL_ARRAY_BUFFER,terrainVBO);
glBufferData(GL_ARRAY_BUFFER,sizeof(float)*width*height*7,&vertexData[0],GL_STATIC_DRAW);
//glBufferData(GL_ARRAY_BUFFER,0,NULL,GL_STATIC_DRAW);
//glBufferSubData(GL_ARRAY_BUFFER,0,sizeof(float)*width*height*3,&vertexData[0]);
//glBufferSubData(GL_ARRAY_BUFFER,sizeof(float)*width*height*3,sizeof(float)*width*height*3,&colorData[0]);
//glBindBuffer(GL_ARRAY_BUFFER, 0);
// element buffer add if using indices--
glGenBuffers(1,&terrainEBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,terrainEBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(unsigned int)*(width*2)*(height-1),&indicesData[0],GL_STATIC_DRAW);
//glBindBuffer(GL_ARRAY_BUFFER, 0);
// position attribute
int stride = 7 * sizeof(float); // float size = 4
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, stride, 0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, stride, (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, stride, (void*)(6 * sizeof(float)));
glEnableVertexAttribArray(2);
// // texture coord attribute
// glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
// glEnableVertexAttribArray(2);
//glDisableVertexAttribArray(2);
// fine to free malloc after glBufferData is pushed to gpu
//free(colorData);
free(vertexData);
free(indicesData);
return 0;
}
int RenderTerrain() {
// draw main rotating quad in mbp
glUseProgram(0);
//glUseProgram(programTerrain);
glUseProgram(programTerrain);
glDisable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
setRenderModePerspective();
mat4x4_invert(ip,p); // invert projection for underwater frag post
applyScalingToModel(m, terrainScale, 1.0f, terrainScale);
execRenderModePerspective(v);
//setUniform4m(&programTerrain, "MVP", mvp);
setUniform4m(&programTerrain,"MVP", mvp);
setUniform3f(&programTerrain,"sunPos", sunpos.x, sunpos.y, sunpos.z);
setUniform3f(&programTerrain,"moonPos", moonpos.x, moonpos.y, moonpos.z);
setUniform3f(&programTerrain,"viewPos", camera->eye->position->x + player->transform->position->x, camera->eye->position->y + player->transform->position->y, camera->eye->position->z + player->transform->position->z);
setUniform3f(&programTerrain,"data", waterTime, cloudFreq, cloudAmp); // time, freq=1.0, amp=0.5
setUniform1f(&programTerrain,"daytime", daytime);
setUniform4m(&programTerrain, "invProjection", ip);
setUniform4m(&programTerrain, "invView", iv);
setUniform1i(&programTerrain, "splat1", 0);
setUniform1i(&programTerrain, "texture1", 1); // default black/sand/underwater
setUniform1i(&programTerrain, "texture2", 2); // grass1 (green)
setUniform1i(&programTerrain, "texture3", 3); // stone1 norm.y (green)
setUniform1i(&programTerrain, "texture4", 4); // dirt (red)
setUniform1i(&programTerrain, "texture5", 5); // road (blue)
//setUniform1i(&programTerrain, "texture6", 6);
//setUniform1i(&programTerrain, "texture7", 7);
//setUniform1i(&programTerrain, "texture8", 8);
glBindVertexArray(terrainVAO);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, terrainMasks[0]); // splat
glActiveTexture(GL_TEXTURE0+1);
glBindTexture(GL_TEXTURE_2D, terrainTextures[6]); // sand
glActiveTexture(GL_TEXTURE0+2);
glBindTexture(GL_TEXTURE_2D, terrainTextures[2]); // grass1
glActiveTexture(GL_TEXTURE0+3);
glBindTexture(GL_TEXTURE_2D, terrainTextures[3]); // stone1
glActiveTexture(GL_TEXTURE0+4);
glBindTexture(GL_TEXTURE_2D, terrainTextures[5]); // dirt
glActiveTexture(GL_TEXTURE0+5);
glBindTexture(GL_TEXTURE_2D, terrainTextures[4]); // road
//glBindTexture(GL_TEXTURE_2D, texture1);
for(unsigned int strip=0;strip<NUM_STRIPS;++strip) {
glDrawElements(GL_TRIANGLE_STRIP,NUM_VERTS_PER_STRIP,GL_UNSIGNED_INT,(void*)(sizeof(unsigned int) * NUM_VERTS_PER_STRIP * strip));
}
RenderBoundBox(terrainMin.x,terrainMin.y,terrainMin.z,terrainMax.x,terrainMax.y,terrainMax.z,1,mvp);
// render normal direction aligned lines (heavy)
//--for(unsigned int i=0;i<keepLinesLen;i++) {
//-- RenderLine(keepLines[i*6],keepLines[i*6+1],keepLines[i*6+2],keepLines[i*6+3],keepLines[i*6+4],keepLines[i*6+5],1,mvp);
//--}
// starting +5
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE0+4);
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE0+3);
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE0+2);
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE0+1);
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, 0);
glBindVertexArray(0);
return 0;
}
Top