#include #include // trig functions #include // calloc #if defined (_WIN32) #include #else #include #endif #include #include #include #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 #define DEFAULT_PALETTE_DIR "../data" #define DEFAULT_PALETTE_FILE "palette.png" #define CLEAR_COL_R 75.f / 255.f #define CLEAR_COL_G 135.f / 255.f #define CLEAR_COL_B 135.f / 255.f #define CLEAR_COL_A 1.f // TODO: add this to json scene properties and render_state util_RGBA g_clear_col; // 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); if (shader_error) { LOG(ERROR) << "Error initializing shader program\n"; return false; } rs->max_lights = MAX_LIGHTS; rs->lights = UTIL_ALLOC(rs->max_lights, rg_point_light); rs->palette_image = utilLoadImage(DEFAULT_PALETTE_DIR, DEFAULT_PALETTE_FILE); if (!rgInitGLTexture(rs->palette_id, rs->palette_image)) { LOG(ERROR) << "Error creating texture\n"; return false; } g_clear_col.R = CLEAR_COL_R; g_clear_col.B = CLEAR_COL_B; g_clear_col.G = CLEAR_COL_G; g_clear_col.A = CLEAR_COL_A; return true; } void renFreeBuffers(render_state* rs) { utilSafeFree(rs->lights); utilFreeImage(rs->palette_image); glDeleteTextures(1, &rs->palette_id); rgFree(rs->filled_hex_render_group); rgFree(rs->hex_line_render_group); rgFree(rs->debug_render_group); } 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 *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 &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"; }