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.
 
 
 
 

254 lines
7.3 KiB

#include <vector>
#include <cmath> // trig functions
#include <cstdlib> // calloc
#include <GL/gl3w.h>
#if defined (_WIN32)
#include <SDL.h>
#else
#include <SDL2/SDL.h>
#endif
#include <SDL_image.h>
#include <glm/glm.hpp>
#include <glm/geometric.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include "aixlog.hpp"
#include "hexlib.h"
#include "renderer.h"
#include "render_group.h"
#define DEFAULT_VERTEX_SHADER_FILE "../data/default.vs"
#define DEFAULT_FRAGMENT_SHADER_FILE "../data/default.fs"
#define MAX_LIGHTS 10 // NOTE: needs to match the fragment shader source
struct clear_col
{
real32 R;
real32 G;
real32 B;
real32 A;
};
clear_col g_clear_col { 75.f / 255.f, 135.f / 255.f, 135.f / 255.f, 1.f };
// forward declarations
void openglDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity,
GLsizei length, const GLchar* message, const void* userParam);
// interface
bool
renInit(render_state* rs)
{
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, &rs->handles.currentDisplayMode);
rs->handles.window =
SDL_CreateWindow("hexgame", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
rs->viewport_dims.x, rs->viewport_dims.y, SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE);
if (!rs->handles.window) {
LOG(ERROR) << "Error creating window: " << SDL_GetError() << "\n";
return false;
}
rs->handles.glContext = SDL_GL_CreateContext(rs->handles.window);
if (!rs->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;
}
if (gl3wInit()) {
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);
const char* vs_code = utilDumpTextFile(DEFAULT_VERTEX_SHADER_FILE);
const char* fs_code = utilDumpTextFile(DEFAULT_FRAGMENT_SHADER_FILE);
bool shader_error = !rgInitShaderProgram(rs->default_shader, vs_code, fs_code);
utilSafeFree(vs_code);
utilSafeFree(fs_code);
rs->max_lights = MAX_LIGHTS;
rs->lights = UTIL_ALLOC(rs->max_lights, rg_point_light);
if (shader_error) {
LOG(ERROR) << "Error initializing shader program\n";
return false;
}
return true;
}
void
renFreeBuffers(render_state* rs)
{
utilSafeFree(rs->lights);
rgFree(rs->filled_hex_render_group);
rgFree(rs->hex_line_render_group);
rgFree(rs->debug_render_group);
}
bool
renAddTexture(SDL_Handles &handles, const char * path)
{
// testing
LOG(INFO) << "Loading image: " << path << "\n";
SDL_Surface* image = IMG_Load(path);
if (!image)
{
LOG(ERROR) << "IMG_Load: " << IMG_GetError() << "\n";
return false;
}
GLuint tex_id;
glGenTextures(1, &tex_id);
glBindTexture(GL_TEXTURE_2D, tex_id);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image->w, image->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, image->pixels);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
// store opengl id in SDL_Surface.userdat
image->userdata = (void*)(intptr_t) tex_id;
handles.texSurfaces.push_back(image);
return true;
}
bool
renCreateScene(render_state* rs, Entity* entities, uint32 entity_count)
{
// entities
for (uint i = 0; i < entity_count; i++) {
rgInitEntity(&entities[i]);
entities[i].ren_group->shader = rs->default_shader;
}
// debug draw vertices
uint debug_buf_len = 12; // 4 vertices, 3 floats per vertex
rs->debug_render_group = rgInitSingle(rs->default_shader, debug_buf_len, true, 0, GL_LINE_LOOP);
if (rs->debug_render_group == nullptr)
return false;
gl_buffer& debug_vertex_buf = rs->debug_render_group->render_objects[0]->vertex_buffer;
gl_buffer& debug_color_buf = rs->debug_render_group->render_objects[0]->color_buffer;
gl_buffer& debug_normal_buf = rs->debug_render_group->render_objects[0]->normal_buffer;
for (uint i = 0; i < debug_buf_len; i += 3) {
debug_color_buf.buffer[i] = 1.f;
debug_color_buf.buffer[i + 1] = 0.f;
debug_color_buf.buffer[i + 2] = 0.f;
debug_normal_buf.buffer[i] = 0.f;
debug_normal_buf.buffer[i + 1] = 0.f;
debug_normal_buf.buffer[i + 2] = 1.f;
}
rgBufferData(&debug_vertex_buf, GL_DYNAMIC_DRAW, GL_ARRAY_BUFFER);
rgBufferData(&debug_color_buf, GL_STATIC_DRAW, GL_ARRAY_BUFFER);
rgBufferData(&debug_normal_buf, GL_STATIC_DRAW, GL_ARRAY_BUFFER);
return true;
}
void
renRenderFrame(render_state* rs, std::vector<hex_info> *hexes, Entity* entities, uint32 entity_count)
{
glClearColor(g_clear_col.R, g_clear_col.G, g_clear_col.B, g_clear_col.A);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glm::mat4 m_model = rs->cam.model;
glm::mat4 m_view = rs->cam.view;
glm::mat4 m_projection = rs->cam.projection;
// filled hexes
// get new colors every frame
render_group* rg = rs->filled_hex_render_group;
gl_buffer& color_buf = rg->render_objects[0]->color_buffer;
// TODO: this needs optimization for large grids, very performance intensive
hgUpdateColorBuffer(color_buf, hexes);
rgDraw(rg, m_model, m_view, m_projection,
rs->lights, rs->num_lights, false, true);
// hex lines
rgDraw(rs->hex_line_render_group, m_model, m_view, m_projection,
rs->lights, rs->num_lights);
// entities
for (uint i = 0; i < entity_count; i++) {
rgDraw(entities[i].ren_group, entities[i].world_transform , m_view, m_projection,
rs->lights, rs->num_lights);
}
}
void
renRenderDebug(render_state* rs, std::vector<Point> &vertices)
{
GLfloat* buf = rs->debug_render_group->render_objects[0]->vertex_buffer.buffer;
buf[0] = vertices[0].x; buf[1] = vertices[0].y; buf[2] = 0;
buf[3] = vertices[1].x; buf[4] = vertices[1].y; buf[2] = 0;
buf[6] = vertices[2].x; buf[7] = vertices[2].y; buf[8] = 0;
buf[9] = vertices[3].x; buf[10] = vertices[3].y; buf[11] = 0;
rgDraw(rs->debug_render_group, rs->cam.model, rs->cam.view,
rs->cam.projection, rs->lights, rs->num_lights, true);
}
// 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";
}