You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
204 lines
5.0 KiB
204 lines
5.0 KiB
|
|
#include <vector> |
|
#include <cmath> // trig functions |
|
|
|
#if defined (_WIN32) |
|
#include <SDL.h> |
|
#else |
|
#include <SDL2/SDL.h> |
|
#endif |
|
#include <glm/glm.hpp> |
|
#include <glm/geometric.hpp> |
|
#include <glm/gtc/matrix_transform.hpp> |
|
|
|
#include "dumbLog.h" |
|
#include "renderer.h" |
|
#include "default_shaders.cpp" |
|
|
|
#define MAX_LIGHTS 10 // NOTE: needs to match the fragment shader source |
|
#define CLEAR_COL_R 55.f / 255.f |
|
#define CLEAR_COL_G 55.f / 255.f |
|
#define CLEAR_COL_B 55.f / 255.f |
|
#define CLEAR_COL_A 1.f |
|
#define DEFAULT_WIDTH 1280 |
|
#define DEFAULT_HEIGHT 720 |
|
#define USE_SECOND_MONITOR 0 |
|
|
|
|
|
// forward declarations |
|
void openglDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, |
|
GLsizei length, const GLchar* message, const void* userParam); |
|
bool initSDL(SDL_Handles& handles); |
|
bool createWindow(SDL_Handles& handles, v2i& viewport_dims); |
|
bool initContext(SDL_Handles& handles); |
|
bool initGlOptions(); |
|
void setDefaults(render_state* rs); |
|
|
|
|
|
// interface |
|
|
|
render_state* |
|
renInit() |
|
{ |
|
render_state* rs = UTIL_ALLOC(1, render_state); |
|
setDefaults(rs); |
|
|
|
if (initSDL(rs->handles) && |
|
createWindow(rs->handles, rs->viewport_dims) && |
|
initContext(rs->handles) && |
|
initGlOptions() && |
|
rgInitShaderProgram(rs->default_shader, DEFAULT_VERTEX_SHADER, DEFAULT_FRAGMENT_SHADER)) |
|
{ |
|
return rs; |
|
} else { |
|
LOG(Error) << "renderer initialization failed, aborting\n"; |
|
return nullptr; |
|
} |
|
} |
|
|
|
void |
|
renShutdown(render_state* rs) |
|
{ |
|
utilSafeFree(rs->lights); |
|
SDL_GL_DeleteContext(rs->handles.glContext); |
|
SDL_DestroyWindow(rs->handles.window); |
|
SDL_Quit(); |
|
} |
|
|
|
void |
|
renRenderFrame(render_state* rs, Entity* entities, uint32 entity_count) |
|
{ |
|
glClearColor(rs->clear_col.R, rs->clear_col.G, rs->clear_col.B, rs->clear_col.A); |
|
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); |
|
|
|
// entities |
|
for (uint i = 0; i < entity_count; i++) { |
|
rgDraw(entities[i].ren_group, |
|
entities[i].world_transform, |
|
rs->cam.view, |
|
rs->cam.projection, |
|
rs->lights, |
|
rs->num_lights |
|
); |
|
} |
|
} |
|
|
|
|
|
// internal |
|
|
|
void |
|
openglDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, |
|
GLsizei length, const GLchar* message, const void* userParam) |
|
{ |
|
LOG((type == GL_DEBUG_TYPE_ERROR) ? Error : Debug) |
|
<< (type == GL_DEBUG_TYPE_ERROR ? "** GL Error **" : "") |
|
<< ", type: " << type |
|
<< ", severity: " << severity |
|
<< ", message: " << message << "\n"; |
|
} |
|
|
|
bool |
|
initSDL(SDL_Handles& handles) |
|
{ |
|
if (SDL_Init(SDL_INIT_VIDEO) != 0) { |
|
LOG(Error) << "Error, SDL_Init: " << SDL_GetError() << "\n"; |
|
return false; |
|
} |
|
|
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG); |
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); |
|
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); |
|
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); |
|
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); |
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); |
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); |
|
SDL_GetCurrentDisplayMode(0, &handles.currentDisplayMode); |
|
|
|
return true; |
|
} |
|
|
|
bool |
|
createWindow(SDL_Handles& handles, v2i& viewport_dims) |
|
{ |
|
uint display_id = 0; |
|
if (USE_SECOND_MONITOR && SDL_GetNumVideoDisplays() > 1) |
|
display_id = 1; |
|
|
|
handles.window = SDL_CreateWindow( |
|
"hexgame", |
|
SDL_WINDOWPOS_CENTERED_DISPLAY(display_id), |
|
SDL_WINDOWPOS_CENTERED_DISPLAY(display_id), |
|
viewport_dims.x, |
|
viewport_dims.y, |
|
SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE |
|
); |
|
|
|
if (!handles.window) { |
|
LOG(Error) << "Error creating window: " << SDL_GetError() << "\n"; |
|
return false; |
|
} |
|
|
|
return true; |
|
} |
|
|
|
bool |
|
initContext(SDL_Handles& handles) |
|
{ |
|
handles.glContext = SDL_GL_CreateContext(handles.window); |
|
|
|
if (!handles.glContext) { |
|
LOG(Error) << "Error creating glContext: " << SDL_GetError() << "\n"; |
|
return false; |
|
} |
|
|
|
if (SDL_GL_SetSwapInterval(1) != 0) { // vsync |
|
LOG(Error) << "SDL Errors: " << SDL_GetError() << "\n"; |
|
return false; |
|
} |
|
|
|
return true; |
|
} |
|
|
|
bool |
|
initGlOptions() |
|
{ |
|
if (glewInit()) { |
|
LOG(Error) << "failed to initialize OpenGL\n"; |
|
return false; |
|
} |
|
|
|
LOG(Info) << "opengl vendor: " << glGetString(GL_VENDOR) << "\n"; |
|
LOG(Info)<< "opengl renderer: " << glGetString(GL_RENDERER) << "\n"; |
|
LOG(Info) << "opengl version: " << glGetString(GL_VERSION) << "\n"; |
|
|
|
glEnable(GL_DEPTH_TEST); |
|
glEnable(GL_LINE_SMOOTH); |
|
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); |
|
#if 0 |
|
// TODO: blending messes up rendering with mesa on intel graphics 4000 |
|
glEnable(GL_BLEND); |
|
glBlendEquation(GL_FUNC_ADD); |
|
glBlendFunc(GL_ONE, GL_SRC_ALPHA); |
|
#endif |
|
|
|
// TODO: glDebugMessageCallback is only availabe from >v4.3 |
|
// check and warn if context doesn't support this function here |
|
glEnable (GL_DEBUG_OUTPUT); |
|
glDebugMessageCallback((GLDEBUGPROC) openglDebugCallback, 0); |
|
// hide VRAM debug messages |
|
glDebugMessageControl(GL_DONT_CARE, 33361, GL_DONT_CARE, 0, 0, GL_FALSE); |
|
|
|
return true; |
|
} |
|
|
|
void |
|
setDefaults(render_state* rs) |
|
{ |
|
rs->viewport_dims = v2i(DEFAULT_WIDTH, DEFAULT_HEIGHT); |
|
rs->max_lights = MAX_LIGHTS; |
|
rs->lights = UTIL_ALLOC(rs->max_lights, rg_point_light); |
|
rs->clear_col.R = CLEAR_COL_R; |
|
rs->clear_col.B = CLEAR_COL_B; |
|
rs->clear_col.G = CLEAR_COL_G; |
|
rs->clear_col.A = CLEAR_COL_A; |
|
}
|
|
|