#define GL_GLEXT_PROTOTYPES
#define _USE_MATH_DEFINES
#include <uthash.h>
#include <ft2build.h>
#include FT_FREETYPE_H
//#if defined(__IPHONE__) || defined(__ANDROID__)
// //#include "SDL_opengles2.h"
// //#include "SDL_opengles2_gl2.h"
// //#include "SDL_opengles2_gl2ext.h"
//#elif defined(__APPLE__)
// //#include <OpenGL/gl3.h>
// //#include <SDL2/SDL_opengl.h>
//#elif defined(_WIN32) ?
typedef __PTRDIFF_TYPE__ ptrdiff_t;
#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>
#include <pthread.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 <pthread.h>
#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
//#define STB_IMAGE_WRITE_IMPLEMENTATION
//#include "stb_image_write.h" //Just for test purposes
#include "linmathv2.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 <stdarg.h>
#include <time.h>
#include "custom.h" // early declarations
#include "cjson/cJSON.h" // https://github.com/DaveGamble/cJSON
#include "ufbx/ufbx.h" // https://github.com/ufbx/ufbx
#include "input.h" // input glfw callbacks/mouse
#include "shaders.h" // shaders before text/sky/terrain etc
#include "text.h" //
#include "geometry.h" // geometry before sky/terrain/player etc
#include "sky.h" //
#include "terrain.h" //
#include "water.h" //
#include "fire.h" //
#include "player.h" //
#include "network.h" //
// includes for Sleep POSIX etc
#ifdef _WIN32
#include <Windows.h>
#else
#include <unistd.h>
#endif
#define COMPARE(a, b) (((a) > (b)) - ((a) < (b)))
#define nullptr ((void*)0)
#define vstr(s) str(s)
#define str(s) #s
//--void GLAPIENTRY
//--MessageCallback( GLenum source,
//-- GLenum type,
//-- GLuint id,
//-- GLenum severity,
//-- GLsizei length,
//-- const GLchar* message,
//-- const void* userParam )
//--{
//-- fprintf( stderr, "GL CALLBACK: %s type = 0x%x, severity = 0x%x, message = %s\n",
//-- ( type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : "" ),
//-- type, severity, message );
//--}
static void error_callback(int x, const char* description)
{
fprintf(stderr, "Error (%d): %s\n",x,description);
}
// Global variables
GLFWwindow* window;
pthread_cond_t ready = PTHREAD_COND_INITIALIZER;
pthread_mutex_t glock = PTHREAD_MUTEX_INITIALIZER;
int should_render = 0; // Start 0 or segfault createframebuffer
uint8_t more = 1;
unsigned int smallest_side = 0;
// Renderer function
void render() {
// all render stuff here
int camMode = 2;
//double deltaLapsed = 0;
//waterTime = updateCurrentTime;
double phase = fmod(updateCurrentTime / 86400.0 * 2.0 * M_PI, 2.0 * M_PI);
waterTime = (float)phase;
renderCurrentTime = glfwGetTime();
if(renderLastTime != 0) {
renderDeltaTime = renderCurrentTime - renderLastTime;
//deltaLapsed += renderDeltaTime / (1.0f / limitFPS); // game loop limit not vsync
avgfps=renderDeltaTime;
//avgupdates=1.0f/fixedDeltaTime;
//
if(camMode == 2) { // both 3rd and 1st person zoomDist 0.01f
while (camera->theta > 180.0) { camera->theta -= 360.0; }
while (camera->theta < -180.0) { camera->theta += 360.0; }
camera->phi = CLAMP(camera->phi, 179.0f, 1.0f);
player->phi = CLAMP(player->phi, 179.0f, 1.0f);
getDirection(camera->dir,camera->theta,camera->phi); // player.c
while (camera->xOffset > 180.0) { camera->xOffset -= 360.0; }
while (camera->xOffset < -180.0) { camera->xOffset += 360.0; }
camera->eye->position->x=camera->dir->forward->x * zoomDist; // camera dir
camera->eye->position->y=camera->dir->forward->y * zoomDist; // to player/
camera->eye->position->z=camera->dir->forward->z * zoomDist; // camera center
//getDirection(player->dir,player->theta,player->phi); // player.c
//
//Quaternion qrot=directionToQuaternion(player=>dir->forward);
//Vec3 erot=ToEulerAngles(qrot);
//quaternion_rotation(qrot, up, anglerad);
}
vec3 eye={
camera->eye->position->x + player->transform->position->x,
camera->eye->position->y + player->transform->position->y,
camera->eye->position->z + player->transform->position->z
};
vec3 center={
camera->center->x + player->transform->position->x,
camera->center->y + player->transform->position->y,
camera->center->z + player->transform->position->z
};
// set up "view" (v)
// p and mvp is updated throughout
mat4x4_look_at(v,eye,center,up);
// inverted view et only once
mat4x4_invert(iv,v);
glColorMask (true, true, true, true);
Vec3 pdir={0,0,0};
float diffXoffset = camera->theta+camera->xOffset;
while (diffXoffset > 180.0) { diffXoffset -= 360.0; }
while (diffXoffset < -180.0) { diffXoffset += 360.0; }
float usePhi=camera->phi;
if(moveMode==1) usePhi=player->phi;
pdir=getDirection(player->dir,diffXoffset,usePhi); // player.c
if(readyXoffset && applyXoffset!=0) { // if not aliged keep offset
if(applyXoffset==1) { // camera to player
camera->theta += camera->xOffset;
camera->xOffset = 0;
applyXoffset = 0;
readyXoffset = false;
} else if(applyXoffset==2) { // player to camera
camera->xOffset = 0;
applyXoffset = 0;
readyXoffset = false;
}
}
if(moveMode==1 && isSwimming) {
pdir.x = player->dir->forward->x;
pdir.y = player->dir->forward->y;
pdir.z = player->dir->forward->z;
}
player->transform->rotation->x = pdir.x;
player->transform->rotation->y = pdir.y;
player->transform->rotation->z = pdir.z;
//printf("pdir.x=%f, pdir.y=%f, pdir.z=%f, theta=%f, phi=%f, xOffset=%f\n",pdir.x,pdir.y,pdir.z,camera->theta,camera->phi,camera->xOffset);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDepthMask(GL_FALSE);
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(0.5f, 0.0f, 0.5f, 1.0f); // pink bg / outside scope but within final fbo
//CreateFrameText();
glBindFramebuffer(GL_FRAMEBUFFER, textFB); //bind both read/write to the target framebuffer
glViewport(0, 0, TXT_WIDTH, TXT_HEIGHT); // Update viewport
// --- Sentences are constructed into reusable images
PrepareAllText(); // upscale ortho mode, linebreaks not implemented
glBindFramebuffer(GL_FRAMEBUFFER, 0);
if(hiddenWater==0) {
glViewport(0, 0, WFO_WIDTH, WFO_HEIGHT); // Update viewport
glBindFramebuffer(GL_FRAMEBUFFER, heightFB);
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(0.0, 0.0, 0.0, 0.0);
RenderWaterHeight(); // custom buffer in water.c
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
glViewport(0, 0, SCR_WIDTH, SCR_HEIGHT); // Update viewport
//glBindFramebuffer(GL_FRAMEBUFFER, msaaFB);
glDepthMask(GL_TRUE);
glEnable(GL_DEPTH_TEST); // enable death before death clear
glEnable(GL_CULL_FACE);
//glEnable(GL_STENCIL_TEST);
//glStencilMask(0x00); // == false;false,false,false
glBlendFunc(GL_ONE, GL_ZERO);
glDisable(GL_BLEND);
if(click_trace!=0) { // 1 = lMB, 2 = RMB
//glDepthMask(GL_TRUE); // true before glClear or glClear will fail clearing
//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // background framebuffer
//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
// draw GL_FLAT for click target with glReadPixel
// custom flat color shader
printf("click_trace=%d mouseX=%f, mouseY=%f\n",click_trace,lockMouseX,lockMouseY);
click_trace=0;
}
// -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// render stuff to mainFB (before msaa antialias prepared framebuffer)
glBindFramebuffer(GL_FRAMEBUFFER, msaaFB);
glClearColor(0.1f, 0.11f, 0.17f, 1.0f); // background framebuffer dim blue grey
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//if(!wireframeOn && gridOn) {
if(gridOn) {
// WORLD
RenderGridLines(); // as a static backdrop, conforms to camera
RenderGridLines2(); // as a static backdrop, conforms to camera
RenderGridLines3(); // as a static backdrop, conforms to camera
}
if(wireframeOn) { // on
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
//glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
}
if(!hiddenTerrain) {
RenderTerrain();
}
if(enableTracking) {
setRenderModePerspective();
execRenderModePerspective(v);
RenderLine(0,0,0,player->transform->position->x,player->transform->position->y,player->transform->position->z,1,mvp);
}
if(hiddenSky==1) { // sphere sky
if(skytexloaded==1) {
unloadSkyImages();
}
RenderSky();
} else if(hiddenSky==2) { // box sky
if(skytexloaded!=1) {
loadSkyImages();
}
drawSkyBox();
} else {
if(skytexloaded==1) {
unloadSkyImages();
}
}
if(hiddenCloud==1) {
RenderClouds();
}
RenderSpinningQuad(); // as a dynamic object, conforms to camera
RenderCube(); // player
RenderStair(); // blocks
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindFramebuffer(GL_FRAMEBUFFER, mainFB);
glDepthMask(GL_TRUE);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// blit depth here
glColorMask(false, false, false, false);
glBindFramebuffer(GL_READ_FRAMEBUFFER, msaaFB);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mainFB); // -water
//glReadBuffer(GL_DEPTH_ATTACHMENT);
//glDrawBuffer(GL_DEPTH_ATTACHMENT);
glBlitFramebuffer(0,0,SCR_WIDTH,SCR_HEIGHT,0,0,SCR_WIDTH,SCR_HEIGHT,GL_DEPTH_BUFFER_BIT,GL_NEAREST);
//glBindFramebuffer(GL_FRAMEBUFFER, 0);
glColorMask (true, true, true, true);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindFramebuffer(GL_FRAMEBUFFER, msaaFB); // cont.
//
// render 3D text
RenderAllText3D(0); // render text behind water
RenderFireQuad(0);
RenderFireBall(0); // pre render transparent on transparent
RenderVortexQuad(0);
if(hiddenWater==0) {
RenderWater(); // water intersects with text now works
}
// copy depth of main before water is rendered,
// have two depth terrain without water and with to compare
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindFramebuffer(GL_FRAMEBUFFER, depthFB);
glDepthMask(GL_TRUE);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// blit depth here
glColorMask(false, false, false, false);
glBindFramebuffer(GL_READ_FRAMEBUFFER, msaaFB);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, depthFB); // +water
//glReadBuffer(GL_DEPTH_ATTACHMENT);
//glDrawBuffer(GL_DEPTH_ATTACHMENT);
glBlitFramebuffer(0,0,SCR_WIDTH,SCR_HEIGHT,0,0,SCR_WIDTH,SCR_HEIGHT,GL_DEPTH_BUFFER_BIT,GL_NEAREST);
//glBindFramebuffer(GL_FRAMEBUFFER, 0);
glColorMask (true, true, true, true);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// custom stencil to depthFB color sample in red
glBindFramebuffer(GL_FRAMEBUFFER, depthFB);
RenderAllText3D(-1); // render text in depthFBsample
RenderFireQuad(-1); // depth
RenderFireBall(-1); // depth
RenderVortexQuad(-1); // depth
RenderAllLines(-1); // render text in depthFBsample
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindFramebuffer(GL_FRAMEBUFFER, msaaFB); // cont.
RenderAllText3D(0); // render text front of water?, no stencil needed
RenderFireQuad(0);
RenderFireBall(0);
RenderVortexQuad(0);
if(wireframeOn) { // off - opengl is a "state machine"
//glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
}
if(boundsTog) {
RenderAllBounds();
bidx=0; // reset bound list index
}
RenderAllLines(0);
lidx=0; // reset all single line draw
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindFramebuffer(GL_FRAMEBUFFER, uiFB);
glDepthMask(GL_FALSE);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // no bg and transparent ui
glClear(GL_COLOR_BUFFER_BIT);
if(waterHeightShow) {
//smallest_side = MAX(SCR_HEIGHT,SCR_WIDTH);
smallest_side = MIN(SCR_HEIGHT,SCR_WIDTH);
//smallest_side = smallest_side / 3;
unsigned int centerleft = 0;
unsigned int centerbot = 0;
if(SCR_WIDTH>SCR_HEIGHT) {
centerleft = (SCR_WIDTH - smallest_side) / 2;
} else {
centerbot = (SCR_HEIGHT - smallest_side) / 2;
}
//
//
// preview water framebuffer overlay
glColorMask(false, false, false, false);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindFramebuffer(GL_FRAMEBUFFER, uiFB);
glDepthMask(GL_FALSE);
// blit depth here
glBindFramebuffer(GL_READ_FRAMEBUFFER, heightFB);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, uiFB);
glReadBuffer(GL_COLOR_ATTACHMENT0);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
glBlitFramebuffer(0,0,WFO_WIDTH,WFO_HEIGHT,centerleft,centerbot,smallest_side+centerleft,smallest_side+centerbot,GL_COLOR_BUFFER_BIT,GL_NEAREST);
glColorMask (true, true, true, true);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindFramebuffer(GL_FRAMEBUFFER, uiFB);
}
// UI
RenderAllText2D(0); // as a 2d interface, conforms to screen(buffer)
//
//
// all post processing start here
// ---
glBindFramebuffer(GL_FRAMEBUFFER, 0); // to screen buffer
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
glUseProgram(0);
glUseProgram(programPost);
glBindVertexArray(quadVAO); // bound here until the end~
setUniform1i(&programPost, "viewport_width", SCR_WIDTH);
setUniform1i(&programPost, "viewport_height", SCR_HEIGHT);
setUniform1i(&programPost, "samples", samples);
//setUniform1i(&programPost, "waterDepthTex", depthFBsample);
setUniform1i(&programPost, "screenTexture", 0);
setUniform1i(&programPost, "waterDepthTex", 1);
setUniform1i(&programPost, "sceneDepthTex", 2);
setUniform1i(&programPost, "sceneStencilTex", 3);
setUniform1i(&programPost, "waterHeightTex", 4);
setUniform1i(&programPost, "rendMode", rendMode);
setUniform1f(&programPost, "time", waterTime);
setUniform1f(&programPost,"daytime", daytime);
setUniform4m(&programPost, "invProjection", ip);
setUniform4m(&programPost, "invView", iv);
setUniform3f(&programPost, "cameraPosition", eye[0], eye[1], eye[2]);
setUniform1f(&programPost, "fogDistance", rendMode);
setUniform3f(&programPost, "fogColor", 0.0, 0.2, 0.3);
setUniform3f(&programPost,"data", (float)hiddenWater, -1.0f, 2.0f); // time,y-offset,scale
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, msaaSample); // custom.c
glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(GL_TEXTURE_2D, mainFBdepth); // water.c (-water)
glActiveTexture(GL_TEXTURE0 + 2);
glBindTexture(GL_TEXTURE_2D, depthFBdepth); // water.c (+water)
glActiveTexture(GL_TEXTURE0 + 3);
glBindTexture(GL_TEXTURE_2D, depthFBsample); // water.c (stencil)
glActiveTexture(GL_TEXTURE0 + 4);
glBindTexture(GL_TEXTURE_2D, heightFBsample); // water.c
glDrawArrays(GL_TRIANGLES, 0, 6); // final draw frame to screen, conforms to screen
//glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0); // unbind 3
glActiveTexture(GL_TEXTURE0 + 3);
glBindTexture(GL_TEXTURE_2D, 0); // unbind 2
//
glActiveTexture(GL_TEXTURE0 + 2);
glBindTexture(GL_TEXTURE_2D, 0); // unbind 2
glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(GL_TEXTURE_2D, 0); // unbind 1
//
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0); // unbind 0
// draw full text/ui quad, cant use blit with transparency
glUseProgram(0);
glUseProgram(programUI); // as spinning quad? simple tex or UI
//glBindVertexArray(quadVAO); // quadVAO rebound from here and out
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//setUniform1i(&programMsaa, "samples", samples);
//setUniform1i(&program, "texture1", 0);
setUniform1i(&programUI, "sampler", 0);
setUniform1f(&programUI, "ris", 0.0f);
setUniform1f(&programUI, "alp", 1.0f);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, uiFBsample);
glDrawArrays(GL_TRIANGLES, 0, 6); // final draw frame to screen, conforms to screen
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
glBlendFunc(GL_ONE, GL_ZERO);
glDisable(GL_BLEND);
// -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//return 0;
}
renderLastTime = renderCurrentTime;
}
int update() { // render section below
handle_move(); // player.c
//if(!readyZoomTog) {
// readyZoomTog = true;
//}
// game mechanics here
//
if(reloadShaders) {
cleanupAllShaders(1);
reloadShaders=false;
}
if(reloadFont) {
cleanupFonts(1);
reloadFont=false;
}
return 0;
}
void* thread_render(__attribute__((unused)) void* arg) {
//GLFWwindow* window = (GLFWwindow*)arg;
while(more) {
// Acquire the mutex lock
pthread_mutex_lock(&glock);
while(!should_render) {
pthread_cond_wait(&ready, &glock);
}
should_render = 0;
// Make the OpenGL context current for this thread
glfwMakeContextCurrent(window);
//more=!glfwWindowShouldClose(window);
render();
frames++;
// Swap buffers to display the rendered content
glfwSwapBuffers(window);
// Release the OpenGL context
glfwMakeContextCurrent(NULL);
// Release the mutex lock
pthread_mutex_unlock(&glock);
// Optional: sleep to reduce CPU usage (adjust as needed)
//usleep(16000); // ~60 FPS
}
// ending
pthread_mutex_unlock(&glock);
return NULL;
}
float readyResize=0.0f;
bool resized = false;
void* thread_main(__attribute__((unused)) void *arg) {
//GLFWwindow* window = (GLFWwindow*)arg;
#if defined(_WIN32)
glewExperimental = true; // Needed for core profile, comment out if not using glew?
#endif
if (!glfwInit())
{
fprintf(stderr, "Failed to initialize GLFW\n");
exit(EXIT_FAILURE);
}
window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "AnaTwi Development LeanOpenGL", NULL, NULL); // start window
//
ratio = SCR_WIDTH / (float) SCR_HEIGHT;
TXT_HEIGHT=SCR_HEIGHT * txt_quality;
TXT_WIDTH=SCR_WIDTH * txt_quality;
//TXT_HEIGHT=to_nearest_pow2(TXT_HEIGHT);
//TXT_WIDTH=to_nearest_pow2(TXT_WIDTH);
glfwSetErrorCallback(error_callback);
//glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
glfwSetScrollCallback(window, scroll_callback);
glfwSetMouseButtonCallback(window, mouse_btn_callback);
glfwSetCursorPosCallback(window, mouse_mov_callback);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
#if defined(__APPLE__)
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
glfwWindowHint(GLFW_SAMPLES, samples);
glEnable(GL_MULTISAMPLE);
glEnable(GL_LINE_SMOOTH);
glHint( GL_GENERATE_MIPMAP_HINT, GL_NICEST);
monitor = glfwGetPrimaryMonitor();
vmode = glfwGetVideoMode(monitor);
//GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", monitor, NULL); // start fullscreen
//
if (!window)
{
glfwTerminate();
fprintf(stderr, "Failed to create GLFW window\n");
exit(EXIT_FAILURE);
}
//glfwSetWindowSize(window, 1920, 1080); // set window size for fullscreen
//glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
glfwSetInputMode(window, GLFW_RAW_MOUSE_MOTION, GLFW_TRUE);
//
//glfwSetWindowCloseCallback(window, window_close_callback);
glfwMakeContextCurrent(window); //initgl
// Initialize the mutex
if (pthread_mutex_init(&glock, NULL) != 0) {
fprintf(stderr, "Failed to initialize mutex\n");
glfwDestroyWindow(window);
glfwTerminate();
exit(EXIT_FAILURE);
}
#if defined(_WIN32)
if (glewInit() != GLEW_OK) // comment out if not using glew ?
{
glfwTerminate();
exit(EXIT_FAILURE);
}
#endif
printf("GL_VENDOR=%s\n",glGetString(GL_VENDOR));
printf("GL_RENDERER=%s\n",glGetString(GL_RENDERER));
printf("GL_VERSION=%s\n\n",glGetString(GL_VERSION));
if(vsync == 2) { // adaptive
glfwSwapInterval(-1);
} else if(vsync == 1) { // on
glfwSwapInterval(1);
} else { // off
glfwSwapInterval(0);
}
// --- Scene Frame and Shader Initialization
printf("AAA\n");
loadAllShaders();
InitializeShadersAll();
InitializeTextures();
InitializeSpinningQuad();
InitializeCube(); // used for player, can re use for other~
InitializeText();
InitializeFireBall();
CreateFrameHeight(); // fixed frame does not recreate
CreateFrameText();
CreateFrameUI();
CreateFrameDepth();
CreateFrameMain();
CreateFrameMsaa();
InitializeSky();
InitializeTerrain();
//InitializeWater();
generateWaterMesh(&waterVAO,&waterVBO,&waterEBO);
printKeys();
// ---
glEnable(GL_CULL_FACE);
glBlendFunc(GL_ONE, GL_ZERO);
glDisable(GL_BLEND);
fovrad=degToRad(FOV);
radian=degToRad(1);
glActiveTexture(GL_TEXTURE0); // all only uses _0_ currently
glColorMask (true, true, true, false); // avoid alpga on main buffer
struct Vec3 *pos = malloc(sizeof(struct Vec3));
struct Vec3 *rot = malloc(sizeof(struct Vec3));
int width,height;
// --------- runtime loop
while(more) // thread_main
{
//glfwPollEvents();
glfwWaitEventsTimeout(0.5/limitFPS); // split 60 between update and render max?
// Acquire the mutex lock
pthread_mutex_lock(&glock);
// Make the OpenGL context current
glfwMakeContextCurrent(window);
more=!glfwWindowShouldClose(window);
if(readyFullScreen==1) {
if(fullScreen==1) {
SCR_WIDTH=lastSW;
SCR_HEIGHT=lastSH;
glfwSetWindowMonitor(window, NULL, 0, 0, SCR_WIDTH,SCR_HEIGHT, vmode->refreshRate); // set window
//
fullScreen=0;
} else {
lastSW=SCR_WIDTH;
lastSH=SCR_HEIGHT;
glfwGetMonitorWorkarea(monitor,&mX,&mY,&mW,&mH);
printf("mX=%d mY=%d mW=%d mH=%d\n",mX,mY,mW,mH);
glfwSetWindowMonitor(window, monitor, mX, mY, mW, mH,GLFW_REFRESH_RATE); // set fullscreen
//
fullScreen=1;
}
if(readyResize<=0.0f) {
readyResize=.01f;
}
resized=true;
readyFullScreen=2;
spamonce=0;
}
// Check for window resize
glfwGetWindowSize(window, &width, &height);
if ((width != (int)SCR_WIDTH || height != (int)SCR_HEIGHT)) {
SCR_WIDTH = (unsigned int)width;
SCR_HEIGHT = (unsigned int)height;
ratio = SCR_WIDTH / (float) SCR_HEIGHT;
TXT_HEIGHT=SCR_HEIGHT * txt_quality;
TXT_WIDTH=SCR_WIDTH * txt_quality;
//TXT_HEIGHT=to_nearest_pow2(TXT_HEIGHT);
//TXT_WIDTH=to_nearest_pow2(TXT_WIDTH);
if(readyResize<=0.0f) {
readyResize=.01f;
}
resized=true;
}
if(resized && readyResize<=0.0f) {
glViewport(0, 0, width, height); // Update viewport
// recreate size dependent framebuffers
CreateFrameText();
CreateFrameUI();
CreateFrameDepth();
CreateFrameMain();
CreateFrameMsaa();
rerenderText=1;
render();
resized=false;
readyResize = 0.0f;
// resize down may appear instant because SCR_WIDTH/HEIGHT is set instant and frame buffer it renders to remain larger than needed, second resize function is for things that should be controlled in not bein re-recreated to often, keep the readyResize belo 0.1f, as low as 0.01f, can be tested at 1f to 10f
printf("resize\n");
} else if(readyResize>0.0f) {
readyResize-=updateDeltaTime;
}
updateCurrentTime = glfwGetTime();
if(updateLastTime != 0) {
updateDeltaTime = updateCurrentTime - updateLastTime;
updateDeltaLapsed += updateDeltaTime / (1.0f / limitFPS); // game loop limit not vsync
avgupdates=updateDeltaTime;
sprintf(fpstext, "Ums: %f, Rms: %f, Fms:%f, CT:%f", avgupdates, avgfps,avgfixed,updateCurrentTime);
rot->x=0.0f; rot->y=0.0f; rot->z=0.0f;
pos->x=0.0f; pos->y=0.0f; pos->z=0.0f;
UpdateText(1, pos, rot, 1.0f, Align.topleft);
while(updateDeltaLapsed >= 1.0f) {
fixedDeltaTime = updateCurrentTime - lastFixedFrameTime;
avgfixed=fixedDeltaTime;
if(lastFixedFrameTime != 0) {
update(); // - Update function use fixeddelta
updates++;
updateDeltaLapsed--;
lastFixedFrameTime=updateCurrentTime;
} else {
lastFixedFrameTime=updateCurrentTime;
}
}
processInput(window); // do not calc movement here --
totalTime += updateDeltaTime * timeSpeed;
if(hiddenSky==1) {
//daytime=fabs((86400*0.5f)-totalTime)/43200; // 1-0-1 night-day-night
daytime=((86400*0.5f)-totalTime)/43200; // 1-0-1 night-day-night
//printf("daytime = %f, totalTime=%f\n",daytime,totalTime);
} else {
daytime=0.0f; // 1-0-1 night-day-night
}
if(hiddenCloud==0) {
cloudAmp=0.0; // cloud disabled, terrain shader amp light
}
saveCount-=updateDeltaTime;
if(updateCurrentTime - timer > 1.0) {
timer++;
while(totalTime>86400) {
totalTime-=86400;
++lapsedDays;
}
float hhT = totalTime / 60 / 60;
hh = floor(hhT);
hhT -= hh;
float mmT = hhT * 60;
mm = floor(mmT);
mmT -= mm;
ss = mmT * 60;
sprintf(timertext, "Localtime: %d:%02d:%02d, Day: %d", hh,mm,ss,lapsedDays);
rot->x=0.0f; rot->y=0.0f; rot->z=0.0f;
pos->x=0.0f; pos->y=0.0f; pos->z=0.0f;
UpdateText(2, pos, rot, 1.0f, Align.topright);
if(saveCount<=0.0f) {
saveGame();
saveCount=saveTime;
printf("Game saved. (Game local time=%d:%02d:%02d\n",hh,mm,ss);
//} else {
// printf("next save in %02f\n",saveCount);
}
}
} else {
timer = glfwGetTime(); // start time
}
updateLastTime = updateCurrentTime;
//continue;
// Release the context
glfwMakeContextCurrent(NULL);
// Release the mutex lock
should_render = 1;
pthread_cond_signal(&ready);
pthread_mutex_unlock(&glock);
}
return NULL;
}
// custom list sorting
int compare(const void *a, const void *b) {
float fa = *(const float*) a;
float fb = *(const float*) b;
return COMPARE(fa, fb);
}
// strcmp default compare ascii values, use custom str_cmp
bool str_cmp(char *str1, char *str2, int len) {
bool match=true;
for(int i=0;i<len;i++) { // matches char to char
if(str1[i]!=str2[i]) { // but require input len
match=false;
break;
}
}
return match;
}
// custom string split
char *str_split(char *str, char *d, int *rows, int *chunk) { // return rows and chunk
int N=1;
int chunks=100; // max input string
char *sub=malloc(sizeof(char)*100*N); // chunk is 100 = 1 line
int splits=0;
int c=0;
bool endofstring=false;
for(int i=0;i<chunks;++i) {
if(str[i]==*d) { // delimiter
sub[(chunks*splits)+c]='\0'; // add null terminator
++splits;
++N;
c=0;
sub=realloc(sub,sizeof(char)*100*N); // increase
//printf("found 1 split, adding N:%d\n",N);
} else {
if(str[i]!='\0') {
sub[(chunks*splits)+c]=str[i]; // add char
//printf("adding char:%c, pos:%d\n",str[i],c);
} else {
endofstring=true;
}
++c;
if(endofstring) break;
}
}
if(N>1) {
sub[(chunks*splits)+c]='\0'; // add null terminator
}
*rows=N;
*chunk=chunks;
//printf("splits:%d, chunk size: %d\n",*rows,*chunk);
return sub;
}
int main(int argc, char **argv)
//int main()
{
totalTime = adjustStartTime;
if(argc>1) { // cmd argument handler
char *data=malloc(sizeof(char)*100);
for(int i=1;i<argc;++i) {
//printf("arg%d: %s\n",i,argv[i]);
if(str_cmp(argv[i],"--server",8)) {
if(i==argc-1) {
printf("correct argument is --server <port>\n");
} else {
//data=argv[i+1];
memcpy(data,argv[i+1],100);
printf("starting as server --server %s\n\n",data);
}
} else if(str_cmp(argv[i],"--connect",9)) {
if(i==argc-1) {
printf("correct argument is --connect <client:port>\n");
} else {
//data=argv[i+1];
memcpy(data,argv[i+1],100);
int chunk;
int rows;
char *list = str_split(data,":",&rows,&chunk);
for(int j=0;j<rows;++j) {
//printf("split string j=%d, str=%s\n",j,list[j]);
printf("split string j=%d, str=%s\n",j,&list[chunk*j]);
}
free(list);
printf("starting as client --client %s\n\n",data);
}
} else if(str_cmp(argv[i],"--help",6)) {
printf("--help: valid arguments are\n --server <port>\n --connect <client:port>\n --help\n\n");
} else {
printf("unknown arg %s, try --help\n",argv[i]);
}
}
free(data);
}
// just some example stuff
unsigned int sizevec3=sizeof(Camera);
printf("size = %d\n",sizevec3);
//FreeImage_Initialise();
time_t mytime = time(NULL);
char *time_str = ctime(&mytime);
time_str[strlen(time_str)-1]='\0';
printf("Current Time: %s\n", time_str);
int xs[] = {420, 69, 1337, 4, 1, 3, 2};
size_t n = sizeof(xs)/sizeof(xs[0]);
qsort(xs, n, sizeof(xs[0]), compare);
for(size_t i = 0; i < n; ++i) printf("%d ",xs[i]);
printf("\n\n");
//--char **words;
//--size_t tlen=0;
//--long unsigned int i;
//--words=split(time_str," ",&tlen);
//--*time_str='\0';
//--for(i=0;i<tlen;++i) {
//-- strcat(time_str,words[i]);
//-- strcat(time_str," ");
//--}
//--strcat(time_str, words[i]);
//--printf("\"%s\"\n",time_str);
//--free4split(words);
// prep main memory things (all malloc must freed
// glGenTex etc has internal malloc, glDelete to clear~
mX = 24; // fixed window coordiates in window mode
mY = 64; // to avoid titlebar out of screen on windows
//
player = malloc(sizeof(Player));
player->transform = malloc(sizeof(Transform));
player->dir = malloc(sizeof(Direction));
player->transform->position = malloc(sizeof(Vec3));
player->transform->rotation = malloc(sizeof(Vec3));
player->transform->scale = malloc(sizeof(Vec3));
player->dir->right = malloc(sizeof(Vec3));
player->dir->forward = malloc(sizeof(Vec3));
player->dir->up = malloc(sizeof(Vec3));
camera = malloc(sizeof(Camera));
camera->eye = malloc(sizeof(Transform));
camera->dir = malloc(sizeof(Direction));
camera->eye->position = malloc(sizeof(Vec3));
camera->eye->rotation = malloc(sizeof(Vec3));
camera->eye->scale = malloc(sizeof(Vec3));
camera->dir->right = malloc(sizeof(Vec3));
camera->dir->forward = malloc(sizeof(Vec3));
camera->dir->up = malloc(sizeof(Vec3));
camera->center = malloc(sizeof(Vec3));
player->camera = camera;
InitializePlayer();
// init save file
FILE *fp = fopen("data.json", "r");
int savemissing=false;
if(fp==NULL) {
printf("error: unable to open the file.\n");
savemissing=true;
} else {
printf("found and loading existing game data\n");
loadGame(fp);
}
if(savemissing) {
printf("creating new initial save file cjson\n");
saveGame();
}
// saving
vec3 ui_eye={camera->eye->position->x,camera->eye->position->y,camera->eye->position->z};
//vec3 ui_center={camera->center->position->x,camera->center->position->y,camera->center->position->z};
vec3 ui_center={camera->center->x,camera->center->y,camera->center->z};
mat4x4_look_at(v2,ui_eye,ui_center,up);
//double pollingDelay = 1000/limitFPS;
if(FOV>=180) invertControl=0;
// live updating texts updates with UpdateText()
// is executed in render loop with RenderText()
fpstext=calloc(1,sizeof(float)*80);
timertext=calloc(1,sizeof(float)*80);
// just a test rounding calculation
float test=0.43254654342358773647365834573;
float test2 = test * 100;
printf("\n---\n%f * 100 = %f\n",test,test2);
float test3=round(test2 * 100) / 100;
printf("round(%f * 100)/100 = %f\n",test2,test3);
char *buffer = (char *)malloc(sizeof(char) * 80);
sprintf(buffer, "with printf rounding = %.2f", test3);
printf("%s\n---\n\n",buffer);
free(buffer);
//output linux:
//0.432547 * 100 = 43.254654
//round(43.254654 * 100)/100 = 43.250000
//printf("early test 2");
//GLint mvp_location, vpos_location, vcol_location;
// moving on to threads~
pthread_t main_thread, render_thread;
pthread_create(&main_thread, NULL, thread_main, NULL);
pthread_create(&render_thread, NULL, thread_render, NULL);
//while(more) { // no need to loop here as join will block/wait
// // keep alive?
// more=!glfwWindowShouldClose(window);
// #if defined(_WIN32)
// Sleep(16); // ~60 fps mcs
// #else
// usleep(16000); // ~60fps ns
// #endif
//}
printf("main closed?\n");
// Wait for the thread to finish
pthread_join(main_thread, NULL);
pthread_join(render_thread, NULL);
// ---------------------------------------------------------------
// Clean up
pthread_mutex_destroy(&glock);
free(fpstext);
free(timertext);
//
// buffers
glDeleteBuffers(1, &skyVBO);
glDeleteBuffers(1, &skyEBO);
glDeleteBuffers(1, &terrainVBO);
glDeleteBuffers(1, &terrainEBO);
glDeleteBuffers(1, &waterVBO);
glDeleteBuffers(1, &waterEBO);
glDeleteBuffers(1, &plane_elements);
glDeleteBuffers(1, &plane_buffer);
glDeleteBuffers(1, &cube_elements);
glDeleteBuffers(1, &cube_buffer);
glDeleteBuffers(1, &quadVBO);
glDeleteBuffers(1, &VBO);
// arrays
//
glDeleteVertexArrays(1, &skyVAO); // sphere/sky
glDeleteVertexArrays(1, &terrainVAO); //terrain
glDeleteVertexArrays(1, &waterVAO); //water
glDeleteVertexArrays(1, &cube_array); // cube/player
glDeleteVertexArrays(1, &plane_array); // spinning quad
glDeleteVertexArrays(1, &quadVAO); // framebuffer quad
glDeleteVertexArrays(1, &VAO); // text quad
//framebuffer
//
if(cft_state == 1) {
glDeleteFramebuffers(1, &textFB);
glDeleteTextures(1, &textFBsample);
//glDeleteRenderbuffers(1, &textFBbuffer);
}
if(cfd_state == 1) {
glDeleteFramebuffers(1, &depthFB);
glDeleteTextures(1, &depthFBsample);
glDeleteTextures(1, &depthFBdepth);
//glDeleteTextures(1, &depthFBstencil);
}
if(cfm_state == 1) {
glDeleteFramebuffers(1, &msaaFB);
glDeleteTextures(1, &msaaSample);
glDeleteTextures(1, &msaaDepth);
}
if(cfa_state == 1) {
glDeleteFramebuffers(1, &mainFB);
glDeleteTextures(1, &mainFBsample);
glDeleteTextures(1, &mainFBdepth);
}
if(cfu_state == 1) {
glDeleteFramebuffers(1, &uiFB);
glDeleteTextures(1, &uiFBsample);
}
if(cfh_state == 1) {
glDeleteFramebuffers(1, &heightFB);
glDeleteTextures(1, &heightFBsample);
}
unloadTerrainTextures();
unloadSkyImages();
cleanupAllShaders(0); // shaders.c
while(highestTidx>0) { // cleanup sentences
Sentences *sts;
if((sts = find_sts(highestTidx))) {
if(sts != NULL) { // rerender(all) or refresh(specific)
glDeleteTextures(1,&sts->textureid);
free(sts->transform->position);
free(sts->transform->rotation);
free(sts->transform->scale);
free(sts->transform);
delete_sts(sts);
}
}
highestTidx--;
}
cleanupFonts(0); // glyph cleanup text.c
if(initStairs==1) {
free(block_colliders);
}
free(terrainCollider);
// mallocs in C, opengl uses it's own malloc behind ~glGenTexture etc, delete with glDeleteTexture
// uthash will free it's own "known" data, but pointer within struct malloced must be freed here
free(keepLines);
free(camera->dir->right);
free(camera->dir->forward);
free(camera->dir->up);
free(camera->dir);
free(camera->eye->position);
free(camera->eye->rotation);
free(camera->eye->scale);
free(camera->eye);
free(camera->center);
free(camera);
free(player->transform->position);
free(player->transform->rotation);
free(player->transform->scale);
free(player->transform);
free(player->dir->right);
free(player->dir->forward);
free(player->dir->up);
free(player->dir);
free(player);
glfwDestroyWindow(window);
glfwTerminate();
pthread_exit(NULL);
exit(EXIT_SUCCESS);
}
Top