prosperon/source/engine/openglrender.c

680 lines
18 KiB
C
Executable file

#include "openglrender.h"
#include <SDL2/SDL.h>
#include "sprite.h"
#include "shader.h"
#include "font.h"
#include "config.h"
#include "static_actor.h"
#include "gameobject.h"
#include "camera.h"
#include "window.h"
#include "debugdraw.h"
#include "log.h"
int renderMode = 0;
static GLuint UBO;
static GLuint UBOBind = 0;
static GLuint gridVBO = 0;
static GLuint gridVAO = 0;
static GLuint quadVAO = 0;
static GLuint quadVBO = 0;
static GLuint depthMapFBO = 0;
static GLuint depthMap = 0;
const unsigned int SHADOW_WIDTH = 2048, SHADOW_HEIGHT = 2048;
static struct mShader *outlineShader;
static struct mShader *modelShader;
static struct mShader *shadowShader;
struct mShader *spriteShader = NULL;
struct mShader *animSpriteShader = NULL;
static struct mShader *textShader;
static struct mShader *diffuseShader;
struct sFont *stdFont;
static struct mShader *debugDepthQuad;
static struct mShader *debugColorPickShader;
static struct mShader *debugGridShader;
static struct mShader *debugGizmoShader;
struct mStaticActor *gizmo;
float editorFOV = 45.f;
float editorClose = 0.1f;
float editorFar = 1000.f;
mfloat_t editorClearColor[4] = { 0.2f, 0.4f, 0.3f, 1.f };
float shadowLookahead = 8.5f;
mfloat_t gridSmallColor[3] = { 0.35f, 1.f, 0.9f };
mfloat_t gridBigColor[3] = { 0.92f, 0.92f, 0.68f };
float gridScale = 500.f;
float smallGridUnit = 1.f;
float bigGridUnit = 10.f;
float gridSmallThickness = 2.f;
float gridBigThickness = 7.f;
float gridOpacity = 0.3f;
mfloat_t proj[16];
float near_plane = -100.f, far_plane = 10.f, plane_size = 60.f;
// Debug render modes
bool renderGizmos = false;
bool showGrid = true;
bool debugDrawPhysics = false;
bool renderNav = false;
// Lighting effect flags
bool renderAO = true;
bool renderDynamicShadows = true;
bool renderRefraction = true;
bool renderReflection = true;
///// for editing
struct mGameObject *selectedobject = NULL;
char objectName[200] = { '\0' }; // object name buffer
uint16_t debugColorPickBO = 0;
uint16_t debugColorPickTEX = 0;
struct mSprite *tsprite = NULL;
static struct mSprite *tanim = NULL;
static unsigned int projUBO;
void openglInit()
{
if (SDL_GL_SetSwapInterval(1)) {
YughLog(0, SDL_LOG_PRIORITY_WARN,
"Unable to set VSync! SDL Error: %s", SDL_GetError());
}
sprite_initialize();
////// MAKE SHADERS
outlineShader = MakeShader("outlinevert.glsl", "outline.glsl");
spriteShader = MakeShader("spritevert.glsl", "spritefrag.glsl");
animSpriteShader =
MakeShader("animspritevert.glsl", "animspritefrag.glsl");
debugdraw_init();
stdFont = MakeFont("notosans.ttf", 300);
text_settype(stdFont);
//glEnable(GL_STENCIL_TEST);
glClearColor(editorClearColor[0], editorClearColor[1],
editorClearColor[2], editorClearColor[3]);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glLineWidth(1.3f);
/*
glEnable(GL_TEXTURE_3D);
glEnable(GL_MULTISAMPLE);
glLineWidth(2);
*/
glGenBuffers(1, &projUBO);
glBindBuffer(GL_UNIFORM_BUFFER, projUBO);
glBufferData(GL_UNIFORM_BUFFER, 64, NULL, GL_DYNAMIC_DRAW);
glBindBufferRange(GL_UNIFORM_BUFFER, 0, projUBO, 0,
sizeof(float) * 16);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
shader_setUBO(spriteShader, "Projection", 0);
/* shader_setUBO(textShader, "Projection", 0);*/
shader_setUBO(animSpriteShader, "Projection", 0);
}
void openglRender(struct mSDLWindow *window, struct mCamera *mcamera)
{
//////////// 2D projection
mfloat_t projection[16] = { 0.f };
mat4_ortho(projection, mcamera->transform.position[0],
window->width + mcamera->transform.position[0],
mcamera->transform.position[1],
window->height + mcamera->transform.position[1], -1.f, 1.f);
glBindBuffer(GL_UNIFORM_BUFFER, projUBO);
glBufferSubData(GL_UNIFORM_BUFFER, 0, 64, projection);
/*
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glCullFace(GL_BACK);
*/
// Clear color and depth
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |
GL_STENCIL_BUFFER_BIT);
////// TEXT && GUI
/*
glDepthFunc(GL_ALWAYS);
shader_use(textShader);
shader_setmat4(textShader, "projection", window->projection);
*/
/*
mfloat_t fontpos[2] = { 25.f, 25.f };
mfloat_t fontcolor[3] = { 0.5f, 0.8f, 0.2f };
renderText(stdFont, textShader, "Sample text", fontpos, 0.4f, fontcolor, -1.f);
*/
/*
for (int i = 0; i < numSprites; i++) {
sprite_draw(sprites[i]);
}
*/
//glDepthFunc(GL_LESS);
}
void openglInit3d(struct mSDLWindow *window)
{
//Initialize SDL
if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
YughLog(0, SDL_LOG_PRIORITY_ERROR,
"SDL could not initialize! SDL Error: %s", SDL_GetError());
}
//Use OpenGL 3.3
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK,
SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 2); /* How many x MSAA */
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 1);
// TODO: Add non starter initializtion return here for some reason?
MakeSDLWindow("Untitled Game", 1280, 720,
SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN |
SDL_WINDOW_RESIZABLE);
//Use Vsync
if (!SDL_GL_SetSwapInterval(1)) {
YughLog(0, SDL_LOG_PRIORITY_WARN,
"Unable to set VSync! SDL Error: %s", SDL_GetError());
}
/* TODO: IMG init doesn't work in C+
int init =(0x00000001 | 0x00000002);
int initted =IMG_Init(init);
YughLog(0, SDL_LOG_PRIORITY_ERROR, "Init flags: %d\nInitted values: %d ", init, initted);
if ((initted & (IMG_INIT_JPG | IMG_INIT_PNG)) != (IMG_INIT_JPG | IMG_INIT_PNG)) {
YughLog(0, SDL_LOG_PRIORITY_ERROR,
"IMG_Init: Failed to init required jpg and png support! SDL_IMG error: %s",
IMG_GetError());
}
*/
////// MAKE SHADERS
outlineShader = MakeShader("outlinevert.glsl", "outline.glsl");
diffuseShader = MakeShader("simplevert.glsl", "albedofrag.glsl");
modelShader = MakeShader("modelvert.glsl", "modelfrag.glsl");
shadowShader = MakeShader("shadowvert.glsl", "shadowfrag.glsl");
textShader = MakeShader("textvert.glsl", "textfrag.glsl");
spriteShader = MakeShader("spritevert.glsl", "spritefrag.glsl");
debugDepthQuad = MakeShader("postvert.glsl", "debugdepthfrag.glsl");
debugColorPickShader =
MakeShader("simplevert.glsl", "debugcolorfrag.glsl");
debugGridShader = MakeShader("gridvert.glsl", "gridfrag.glsl");
debugGizmoShader = MakeShader("gizmovert.glsl", "gizmofrag.glsl");
stdFont = MakeFont("notosans.ttf", 300);
shader_compile_all();
mat4_perspective_fov(proj, editorFOV * DEG2RADS, window->width,
window->height, editorClose, editorFar);
glEnable(GL_STENCIL_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_TEXTURE_3D);
glEnable(GL_MULTISAMPLE);
glLineWidth(2);
////
// Shadow mapping buffers
////
glGenFramebuffers(1, &depthMapFBO);
glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO);
glGenTextures(1, &depthMap);
glBindTexture(GL_TEXTURE_2D, depthMap);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, SHADOW_WIDTH,
SHADOW_HEIGHT, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_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);
float borderColor[] = { 1.0f, 1.0f, 1.0f, 1.0f };
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
GL_TEXTURE_2D, depthMap, 0);
glDrawBuffer(GL_NONE);
//glReadBuffer(GL_NONE);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
//// Universal buffer to hold projection and light coordinates
glGenBuffers(1, &UBO);
glBindBuffer(GL_UNIFORM_BUFFER, UBO);
glBufferData(GL_UNIFORM_BUFFER, 2 * sizeof(proj), NULL,
GL_STATIC_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
glBindBufferRange(GL_UNIFORM_BUFFER, 0, UBO, 0, 2 * sizeof(proj));
glBindBuffer(GL_UNIFORM_BUFFER, UBO);
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(proj), proj);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
////// debug color pick buffer
glGenFramebuffers(1, &debugColorPickBO);
glBindFramebuffer(GL_FRAMEBUFFER, debugColorPickBO);
glGenTextures(1, &debugColorPickTEX);
glBindTexture(GL_TEXTURE_2D, debugColorPickTEX);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, SCREEN_WIDTH, SCREEN_HEIGHT, 0,
GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, debugColorPickTEX, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
//////// Create grid
float gridVertices[] = {
-1.f, 0.f, 1.f, 0.f, 1.f,
-1.f, 0.f, -1.f, 0.f, 0.f,
1.f, 0.f, 1.f, 1.f, 1.f,
1.f, 0.f, -1.f, 1.f, 0.f,
};
glGenVertexArrays(1, &gridVAO);
glGenBuffers(1, &gridVBO);
glBindVertexArray(gridVAO);
glBindBuffer(GL_ARRAY_BUFFER, gridVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(gridVertices), &gridVertices,
GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float),
(void *) 0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float),
(void *) (3 * sizeof(float)));
//////// Create post quad
float quadVertices[] = {
// positions // texture Coords
-1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
};
// setup plane VAO
glGenVertexArrays(1, &quadVAO);
glGenBuffers(1, &quadVBO);
glBindVertexArray(quadVAO);
glBindBuffer(GL_ARRAY_BUFFER, quadVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices,
GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float),
(void *) 0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float),
(void *) (3 * sizeof(float)));
//////
// skybox = new Skybox("skybox");
BindUniformBlock(modelShader->id, "Matrices", 0);
BindUniformBlock(outlineShader->id, "Matrices", 0);
// BindUniformBlock(skybox->shader->id, "Matrices", 0);
BindUniformBlock(diffuseShader->id, "Matrices", 0);
BindUniformBlock(debugGridShader->id, "Matrices", 0);
BindUniformBlock(debugGizmoShader->id, "Matrices", 0);
shader_use(debugDepthQuad);
shader_setint(debugDepthQuad, "depthMap", 0);
glBindTexture(GL_TEXTURE_2D, 0);
//////////// 2D projection
mfloat_t projection[16] = { 0.f };
mat4_ortho(projection, 0.f, SCREEN_WIDTH, SCREEN_HEIGHT, 1.f, -1.f,
1.f);
shader_setmat4(textShader, "projection", projection);
shader_setmat4(spriteShader, "projection", projection);
shader_setmat4(debugGizmoShader, "proj", projection);
}
void openglRender3d(struct mSDLWindow *window, struct mCamera *mcamera)
{
//////// SET NEW PROJECTION
// TODO: Make this not happen every frame
mat4_perspective_fov(proj, editorFOV * DEG2RADS, window->width,
window->height, editorClose, editorFar);
glBindBuffer(GL_UNIFORM_BUFFER, UBO);
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(proj), proj);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
////////// Render a depthmap from the perspective of the directional light
glViewport(0, 0, SHADOW_WIDTH, SHADOW_HEIGHT);
glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO);
glCullFace(GL_BACK);
glClear(GL_DEPTH_BUFFER_BIT);
// Configure matrices with an orthogonal
mfloat_t lightView[16] = { 0.f };
mfloat_t lightSpaceMatrix[16] = { 0.f };
/*
if (dLight) {
mfloat_t lightProjection[16] = { 0.f };
mat4_ortho(lightProjection, -plane_size, plane_size, -plane_size,
plane_size, near_plane, far_plane);
mfloat_t lookPos[3] = { 0.f };
mfloat_t cam_fwd[3] = { 0.f };
vec3_add(lookPos, mcamera->transform.position,
vec3_multiply_f(lookPos,
trans_forward(cam_fwd,
&mcamera->transform),
shadowLookahead));
lookPos[1] = 0.f;
mfloat_t lightLookPos[3] = { 0.f };
mfloat_t light_fwd[3] = { 0.f };
mat4_look_at(lightView,
vec3_subtract(lightLookPos, lookPos,
trans_forward(light_fwd,
&dLight->light.obj.
transform)), lookPos, UP);
mat4_multiply(lightSpaceMatrix, lightProjection, lightView);
//lightSpaceMatrix = lightProjection * lightView;
if (renderDynamicShadows) {
shader_use(shadowShader);
shader_setmat4(shadowShader, "lightSpaceMatrix",
lightSpaceMatrix);
staticactor_draw_shadowcasters(shadowShader);
}
}
*/
//////////////////////////
// Back to the normal render
window_makecurrent(window);
glCullFace(GL_BACK);
// Render the color thing for debug picking
glBindFramebuffer(GL_FRAMEBUFFER, debugColorPickBO);
glClearColor(editorClearColor[0], editorClearColor[1],
editorClearColor[2], editorClearColor[3]);
glClear(GL_COLOR_BUFFER_BIT);
shader_use(debugColorPickShader);
staticactor_draw_dbg_color_pick(debugColorPickShader);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// Clear color and depth
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |
GL_STENCIL_BUFFER_BIT);
if (renderMode == DIRSHADOWMAP) {
// render Depth map to quad for visual debugging
// ---------------------------------------------
shader_use(debugDepthQuad);
shader_setfloat(debugDepthQuad, "near_plane", near_plane);
shader_setfloat(debugDepthQuad, "far_plane", far_plane);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, depthMap);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glBindVertexArray(quadVAO);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glBindVertexArray(0);
} else if (renderMode == OBJECTPICKER) {
// TODO: This rendering mode
shader_use(debugColorPickShader);
} else {
glClearColor(editorClearColor[0], editorClearColor[1],
editorClearColor[2], editorClearColor[3]);
glDepthMask(GL_TRUE);
mfloat_t view[16] = { 0.f };
getviewmatrix(view, mcamera);
glBindBuffer(GL_UNIFORM_BUFFER, UBO);
glBufferSubData(GL_UNIFORM_BUFFER, sizeof(view), sizeof(view),
view);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
switch (renderMode) {
case LIT:
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
shader_use(modelShader);
/*
if (dLight)
dlight_prepshader(dLight, modelShader);
pointlights_prepshader(modelShader);
spotlights_prepshader(modelShader);
*/
shader_setvec3(modelShader, "viewPos",
mcamera->transform.position);
shader_setmat4(modelShader, "lightSpaceMatrix",
lightSpaceMatrix);
shader_setint(modelShader, "shadowMap", 12);
glActiveTexture(GL_TEXTURE);
glBindTexture(GL_TEXTURE_2D, depthMap);
staticactor_draw_models(modelShader);
break;
case UNLIT:
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
shader_use(diffuseShader);
staticactor_draw_models(diffuseShader);
break;
case WIREFRAME:
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
shader_use(diffuseShader);
staticactor_draw_models(diffuseShader);
break;
}
//// skybox
// draw skybox as last
glDepthFunc(GL_LEQUAL);
// skybox->Draw(mcamera);
glDepthFunc(GL_LESS);
if (debugDrawPhysics) {
// Render physics world
//dynamicsWorld->debugDrawWorld();
}
// Draw outline
if (selectedobject != NULL) {
// Draw the selected object outlined
glClearStencil(0);
glClear(GL_STENCIL_BUFFER_BIT);
glStencilFunc(GL_ALWAYS, 1, 0xFF);
glDepthFunc(GL_ALWAYS);
glDepthMask(false);
glColorMask(false, false, false, false);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
glStencilMask(0xFF);
shader_use(diffuseShader);
setup_model_transform(&selectedobject->transform,
diffuseShader, 1.f);
//selectedobject->draw(diffuseShader);
glStencilFunc(GL_NOTEQUAL, 1, 0xFF);
glDepthMask(true);
glColorMask(true, true, true, true);
glStencilMask(0x00);
shader_use(outlineShader);
setup_model_transform(&selectedobject->transform,
outlineShader, 1.f);
//selectedobject->draw(outlineShader);
}
glDepthFunc(GL_LESS);
glStencilMask(0xFF);
glStencilFunc(GL_ALWAYS, 0, 0xFF);
}
////// TEXT && GUI
// glCullFace(GL_FRONT);
glDepthFunc(GL_ALWAYS);
shader_use(textShader);
shader_setmat4(textShader, "projection", window->projection);
mfloat_t fontpos[2] = { 25.f, 25.f };
mfloat_t fontcolor[3] = { 0.5f, 0.8f, 0.2f };
text_settype(stdFont);
renderText("Sample text", fontpos, 0.4f,
fontcolor, -1.f);
sprite_draw(tsprite);
glDepthFunc(GL_LESS);
////// Render grid
if (showGrid) {
glDisable(GL_CULL_FACE);
shader_use(debugGridShader);
mfloat_t gmodel[16] = { 0.f };
mfloat_t gridscale[3] = { 0.f };
vec3(gridscale, gridScale, gridScale, gridScale);
mat4_multiply_f(gmodel, gmodel, gridScale);
// TODO: Hook into here to make the grid scalable
shader_setmat4(debugGridShader, "model", gmodel);
shader_setvec3(debugGridShader, "smallColor", gridSmallColor);
shader_setvec3(debugGridShader, "bigColor", gridBigColor);
shader_setfloat(debugGridShader, "gridScale", gridScale);
shader_setfloat(debugGridShader, "smallUnit", smallGridUnit);
shader_setfloat(debugGridShader, "bigUnit", bigGridUnit);
shader_setfloat(debugGridShader, "smallThickness",
gridSmallThickness);
shader_setfloat(debugGridShader, "largeThickness",
gridBigThickness);
shader_setfloat(debugGridShader, "opacity", gridOpacity);
glBindVertexArray(gridVAO);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glBindVertexArray(0);
}
///// Render gizmos
// These are things that are overlaid on everything else
// glBindFramebuffer(GL_FRAMEBUFFER, 0); // back to default
// glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
// glClear(GL_COLOR_BUFFER_BIT);
// postShader.use();
// glBindVertexArray(quadVAO);
// glBindTexture(GL_TEXTURE_2D, fboTexture);
// glDrawArrays(GL_TRIANGLES, 0, 6);
}
void BindUniformBlock(GLuint shaderID, const char *bufferName,
GLuint bufferBind)
{
glUniformBlockBinding(shaderID,
glGetUniformBlockIndex(shaderID, bufferName),
bufferBind);
}