#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 "shaders.h" //
#include "sky.h" //
#include "terrain.h" //
#include "player.h" //
#define nullptr ((void*)0)
#define vstr(s) str(s)
#define str(s) #s
float waterTime = 0.0f; // frame consistent copy of updateCurrentTime
unsigned int depthFB, depthFBsample, depthFBdepth, depthFBstencil;
unsigned int cfd_state = 0;
int CreateFrameDepth() {
if(cfd_state == 1) { // fu
glDeleteFramebuffers(1, &depthFB);
glDeleteTextures(1, &depthFBsample);
glDeleteTextures(1, &depthFBdepth); // reset next run
//glDeleteTextures(1, &depthFBstencil); // reset next run
//glDeleteRenderbuffers(1, &depthFBdepth); // reset next run
//cfd_state = 0;
//printf("deletingo old custom fbo--waterdepth\n");
}
cfd_state = 1;
//printf("setting up new custom fbo--waterdepth\n");
glGenFramebuffers(1, &depthFB);
glBindFramebuffer(GL_FRAMEBUFFER, depthFB); //bind both read/write to the target framebuffer
glGenTextures(1, &depthFBsample); // texture object
glBindTexture(GL_TEXTURE_2D, depthFBsample);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, SCR_WIDTH, SCR_HEIGHT, 0, GL_RED, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_2D, 0);
glGenTextures(1, &depthFBdepth); // texture object can access in shader
glBindTexture(GL_TEXTURE_2D, depthFBdepth);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_DEPTH_COMPONENT24, SCR_WIDTH, SCR_HEIGHT);
glBindTexture(GL_TEXTURE_2D, 0);
//glGenTextures(1, &depthFBstencil); // texture object can access in shader
//glBindTexture(GL_TEXTURE_2D, depthFBstencil);
//glTexStorage2D(GL_TEXTURE_2D, 1, GL_STENCIL_COMPONENTS, SCR_WIDTH, SCR_HEIGHT);
//glBindTexture(GL_TEXTURE_2D, 0);
//glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, SCR_WIDTH, SCR_HEIGHT, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
//glTexStorage2D(GL_TEXTURE_2D, 1, GL_DEPTH_COMPONENT32F, SCR_WIDTH, SCR_HEIGHT);
//glBindTexture(GL_TEXTURE_2D, 0);
//glGenRenderbuffers(1, &depthFBdepth); // renderbuffer object cannot access in shader
//glBindRenderbuffer(GL_RENDERBUFFER, depthFBdepth);
//glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT,SCR_WIDTH, SCR_HEIGHT);
//glBindRenderbuffer(GL_RENDERBUFFER, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, depthFBsample, 0);
//
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthFBdepth, 0);
//glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, depthFBstencil, 0);
//glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthFBdepth);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
{
printf("error on setup of custombuffer-waterdepth\n");
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
//glBindTexture(GL_TEXTURE_2D, 0);
return 0;
}
int WFO_WIDTH=128;
int WFO_HEIGHT=128;
unsigned int heightFB, heightFBsample;
unsigned int cfh_state = 0;
int CreateFrameHeight() {
if(cfh_state == 1) { // fu
glDeleteFramebuffers(1, &heightFB);
glDeleteTextures(1, &heightFBsample);
}
cfh_state = 1;
//printf("setting up new custom fbo--waterheight\n");
glGenFramebuffers(1, &heightFB);
glBindFramebuffer(GL_FRAMEBUFFER, heightFB); //bind both read/write to the target framebuffer
glGenTextures(1, &heightFBsample); // texture object
glBindTexture(GL_TEXTURE_2D, heightFBsample);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, WFO_WIDTH, WFO_HEIGHT, 0, GL_RED, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_2D, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, heightFBsample, 0);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
{
printf("error on setup of custombuffer-waterheight\n");
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
//glBindTexture(GL_TEXTURE_2D, 0);
return 0;
}
unsigned int waterVAO,waterVBO,waterEBO;
int InitializeWater() {
float quadVertices[] = { // vertex attributes for a quad that fills the entire screen in Normalized Device Coordinates.
// positions // texCoords
-1.0f, 1.0f, 0.0f, 1.0f,
-1.0f, -1.0f, 0.0f, 0.0f,
1.0f, -1.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f, 1.0f,
1.0f, -1.0f, 1.0f, 0.0f,
1.0f, 1.0f, 1.0f, 1.0f
};
// setup screen VAO
glGenVertexArrays(1, &waterVAO);
glGenBuffers(1, &waterVBO);
glBindVertexArray(waterVAO);
glBindBuffer(GL_ARRAY_BUFFER, waterVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices, GL_STATIC_DRAW); // static vertices
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
return 0;
}
// Define grid resolution (e.g., 32x32 subdivisions)
#define GRID_SIZE 128
#define VERTEX_COUNT (GRID_SIZE + 1) * (GRID_SIZE + 1)
#define INDEX_COUNT (GRID_SIZE * GRID_SIZE * 6) // 6 indices per quad (2 triangles)
// Function to generate water grid mesh
void generateWaterMesh(GLuint* vao, GLuint* vbo, GLuint* ebo) {
// Vertex data: position (x, z) and UV (u, v)
float vertices[VERTEX_COUNT * 5]; // 5 floats per vertex: x, y (0 initially), z, u, v
unsigned int indices[INDEX_COUNT];
// Generate vertices
unsigned int vertexIdx = 0;
for (unsigned int z = 0; z <= GRID_SIZE; z++) {
for (unsigned int x = 0; x <= GRID_SIZE; x++) {
// Map x, z from [0, GRID_SIZE] to UV space [0, 1]
float u = (float)x / GRID_SIZE;
float v = (float)z / GRID_SIZE;
// Position in XZ plane (Y will be set in shader)
vertices[vertexIdx*5] = u; // x
vertices[vertexIdx*5+1] = 0.0f; // y (height added in shader)
vertices[vertexIdx*5+2] = v; // z
vertices[vertexIdx*5+3] = u; // u (UV)
vertices[vertexIdx*5+4] = v; // v (UV)
vertexIdx++;
}
}
// Generate indices for triangles
unsigned int indexIdx = 0;
for (unsigned int z = 0; z < GRID_SIZE; z++) {
for (unsigned int x = 0; x < GRID_SIZE; x++) {
int topLeft = z * (GRID_SIZE + 1) + x;
int topRight = topLeft + 1;
int bottomLeft = (z + 1) * (GRID_SIZE + 1) + x;
int bottomRight = bottomLeft + 1;
//if(indexIdx<300) {
//printf("adding indices TL:%d, TR:%d, BL:%d, BR:%d\n",topLeft,topRight,bottomLeft,bottomRight);
//}
// Triangle 1: topLeft -> bottomLeft -> topRight
indices[indexIdx*6] = topLeft;
indices[indexIdx*6+1] = topRight;
indices[indexIdx*6+2] = bottomLeft;
// Triangle 2: t*6+1Right -> bottomLeft -> bottomRight
indices[indexIdx*6+3] = bottomLeft;
indices[indexIdx*6+4] = bottomRight;
indices[indexIdx*6+5] = topRight;
indexIdx++;
}
}
// OpenGL setup
glGenVertexArrays(1, vao);
glGenBuffers(1, vbo);
glGenBuffers(1, ebo);
glBindVertexArray(*vao);
// Vertex buffer
glBindBuffer(GL_ARRAY_BUFFER, *vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*(GRID_SIZE+1)*(GRID_SIZE+1)*5, &vertices[0], GL_STATIC_DRAW);
// Index buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, *ebo);
//glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int)*(GRID_SIZE*2)*(GRID_SIZE-1), &indices[0], GL_STATIC_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int)*GRID_SIZE*GRID_SIZE*6, &indices[0], GL_STATIC_DRAW);
// Vertex attributes: position (x, y, z) + UV (u, v)
int stride = 5 * sizeof(float);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, stride, 0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, stride, (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
glBindVertexArray(0);
}
int RenderWater() { // change realtime to heightmap use?
glUseProgram(0);
glUseProgram(programWater);
//glUseProgram(programLava);
glDisable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glDepthFunc(GL_LEQUAL);
//glEnable(GL_STENCIL_TEST);
//glStencilFunc(GL_EQUAL, 0, 0xFF);
//glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
//glStencilMask(0x00); // test stencil only
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//glBlendFunc(GL_DST_ALPHA, GL_ZERO);
setRenderModePerspective();
mat4x4_invert(ip,p); // invert projection for underwater frag post
execRenderModePerspective(v);
setUniform4m(&programWater,"MVP", mvp);
setUniform3f(&programWater,"sunPos", sunpos.x, sunpos.y, sunpos.z);
setUniform3f(&programWater,"moonPos", moonpos.x, moonpos.y,moonpos.z);
setUniform3f(&programWater,"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);
setUniform1f(&programWater,"daytime", daytime);
setUniform4m(&programWater, "invProjection", ip);
setUniform4m(&programWater, "invView", iv);
setUniform3f(&programWater,"data", waterTime, -1.0f, 2.0f); // time,y-offset,scale
setUniform1i(&programWater, "waterHeightTex", 0);
//glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, heightFBsample);
glActiveTexture(GL_TEXTURE0+1);
glBindTexture(GL_TEXTURE_2D, depthFBdepth);
glActiveTexture(GL_TEXTURE0+2);
glBindTexture(GL_TEXTURE_2D, mainFBdepth);
glBindVertexArray(waterVAO);
// single quad old
//glDrawArrays(GL_TRIANGLES, 0, 6);
//
// multi quad new
glDrawElements(GL_TRIANGLES, INDEX_COUNT, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE0+1);
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, 0);
RenderBoundBox(-1.0f,0.0f,-1.0f,1.0f,0.0f,1.0f,1,mvp);
glBlendFunc(GL_ONE, GL_ZERO);
glDisable(GL_BLEND);
//glStencilMask(0x00);
//glDisable(GL_STENCIL_TEST);
glDepthFunc(GL_LESS);
glDepthMask(GL_TRUE);
glEnable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
glBindVertexArray(0);
return 0;
}
float waterHeightSample = 0.0f;
float lastWaterHeightSample = 0.0f;
int RenderWaterHeight() {
glUseProgram(0);
glUseProgram(programWaterHeight);
//glUseProgram(programLava);
//glDisable(GL_CULL_FACE);
//glEnable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
//glDepthFunc(GL_LEQUAL);
//setRenderModePerspective();
//execRenderModePerspective(v);
setRenderModeOrthographic();
execRenderModeOrthographic(v2);
setUniform4m(&programWaterHeight,"MVP", mvp);
//setUniform3f(&programWater,"sunPos", sunpos.x, sunpos.y, sunpos.z);
//setUniform3f(&programWater,"moonPos", moonpos.x, moonpos.y,moonpos.z);
setUniform3f(&programWaterHeight,"data", waterTime, -1.0f, 2.0f); // time,y-offset,scale
setUniform1i(&programWaterHeight, "viewport_width", WFO_WIDTH);
setUniform1i(&programWaterHeight, "viewport_height", WFO_HEIGHT);
glBindTexture(GL_TEXTURE_2D, 0);
glBindVertexArray(quadVAO);
glDrawArrays(GL_TRIANGLES, 0, 6);
//glDepthFunc(GL_LESS);
glDepthMask(GL_TRUE);
glEnable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
// do water height check here?
float pixel_color[3];
unsigned int xclip=0;
unsigned int yclip=0;
// player coordinates within -256,-256 to 256,256 (512 map?)
float posX=player->transform->position->x;
float posZ=player->transform->position->z;
posX=CLAMP(posX,256.0f,-256.0f);
posZ=CLAMP(posZ,256.0f,-256.0f); // clamp
xclip=(((unsigned int)posX+256))/10;
yclip=(512-((unsigned int)posZ+256))/10; // offset 0-512
//glClampColor(GL_CLAMP_READ_COLOR, GL_FIXED_ONLY);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glReadBuffer(GL_COLOR_ATTACHMENT0);
glReadPixels(xclip, yclip, 1, 1, GL_RED, GL_FLOAT, &pixel_color[0]);
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
pixel_color[0]*=1.0f; // scale
pixel_color[0]-=2.1f; // offset
waterHeightSample = pixel_color[0];
//printf("water height sample from texture = %f, pos=(%d,%d)\n",pixel_color[0],xclip,yclip);
glBindVertexArray(0);
return 0;
}
Top