diff options
Diffstat (limited to 'graphics/GLbackend.cpp')
-rw-r--r-- | graphics/GLbackend.cpp | 887 |
1 files changed, 887 insertions, 0 deletions
diff --git a/graphics/GLbackend.cpp b/graphics/GLbackend.cpp new file mode 100644 index 0000000..6c03277 --- /dev/null +++ b/graphics/GLbackend.cpp @@ -0,0 +1,887 @@ +#include <cstring> + +#include "GLbackend.h" +#include <iostream> +#include <string> +#include <chrono> +#include <cstdint> +#include "glm/gtc/matrix_transform.hpp" +#include "glm/gtx/transform.hpp" +#include "commonshaders.h" +#include "graphics.h" + +#ifdef __APPLE__ +#define sggBindVertexArray glBindVertexArrayAPPLE +#define sggGenVertexArrays glGenVertexArraysAPPLE +#else +#define sggBindVertexArray glBindVertexArray +#define sggGenVertexArrays glGenVertexArrays +#endif + +namespace graphics +{ + + const uint32_t delay = 5; // update every delay ms. + float delta_time = 0.0f; + + GLBackend::GLBackend(int w, int h, std::string title) : + m_width(w), m_height(h), m_title(title), + m_draw_callback(nullptr), + m_resize_callback(nullptr), + m_idle_callback(nullptr), + m_prev_time_tick() + { + + } + + void GLBackend::cleanup() + { + + SDL_GL_DeleteContext(m_context); + SDL_DestroyWindow(m_window); + if (m_audio) + delete m_audio; + SDL_Quit(); + } + + void GLBackend::swap() + { + SDL_GL_SwapWindow(m_window); + } + + GLBackend::~GLBackend() + { + } + + void GLBackend::makeCurrent() + { + SDL_GL_MakeCurrent(m_window, m_context); + } + + void GLBackend::show(bool s) + { + if (s) + SDL_ShowWindow(m_window); + else + SDL_HideWindow(m_window); + } + + void GLBackend::setBackgroundColor(float r, float g, float b) + { + m_back_color = glm::vec3(r, g, b); + } + + float GLBackend::getDeltaTime() + { + return m_delta_time; + } + + float GLBackend::getGlobalTime() + { + return m_global_time; + } + + void GLBackend::getMouseButtonPressed(bool * button_array) + { + button_array[0] = m_button_pressed[0]; + button_array[1] = m_button_pressed[1]; + button_array[2] = m_button_pressed[2]; + } + + void GLBackend::getMouseButtonReleased(bool * button_array) + { + button_array[0] = m_button_released[0]; + button_array[1] = m_button_released[1]; + button_array[2] = m_button_released[2]; + } + + void GLBackend::getMouseButtonState(bool * button_array) + { + button_array[0] = m_button_state[0]; + button_array[1] = m_button_state[1]; + button_array[2] = m_button_state[2]; + } + + void GLBackend::getMousePosition(int * x, int * y) + { + *x = m_mouse_pos.x; + *y = m_mouse_pos.y; + } + + void GLBackend::getPrevMousePosition(int * x, int * y) + { + *x = m_prev_mouse_pos.x; + *y = m_prev_mouse_pos.y; + } + + bool GLBackend::isMouseDragging() + { + return m_mouse_dragging; + } + + void GLBackend::setCanvasMode(int m) + { + m_canvas_mode = m; + if (m == CANVAS_SCALE_WINDOW) + m_requested_canvas = glm::vec4(0.0f); + } + + void GLBackend::setCanvasSize(float w, float h) + { + m_requested_canvas.z = w; + m_requested_canvas.w = h; + } + + void GLBackend::setFullscreen(bool fs) + { + if (fs) + { + SDL_SetWindowFullscreen(m_window, SDL_WINDOW_FULLSCREEN_DESKTOP); + } + else + { + SDL_SetWindowFullscreen(m_window, 0); + } + SDL_GetWindowSize(m_window, &m_width, &m_height); + resize(m_width, m_height); + } + + void GLBackend::playSound(std::string soundfile, float volume, bool looping) + { + m_audio->playSound(soundfile, volume, looping); + } + + void GLBackend::playMusic(std::string soundfile, float volume, bool looping, int fade_time) + { + m_audio->playMusic(soundfile, volume, looping, fade_time); + } + + void GLBackend::stopMusic(int fade_time) + { + m_audio->stopMusic(fade_time); + } + + + bool GLBackend::processEvent(SDL_Event event) + { + if (event.type == SDL_MOUSEMOTION) + { + m_prev_mouse_pos = m_mouse_pos; + m_mouse_pos.x = event.motion.x; + m_mouse_pos.y = event.motion.y; + m_mouse_dragging = (m_button_state[0] || m_button_state[1] || m_button_state[2]); + } + else if (event.type == SDL_MOUSEBUTTONDOWN || event.type == SDL_MOUSEBUTTONUP) + { + bool new_state = (event.type == SDL_MOUSEBUTTONDOWN); + switch (event.button.button) + { + case SDL_BUTTON_LEFT: m_button_state[0] = new_state; + case SDL_BUTTON_MIDDLE: m_button_state[1] = new_state; + case SDL_BUTTON_RIGHT: m_button_state[2] = new_state; + } + + } + else if (event.type == SDL_KEYDOWN) + { + switch (event.key.keysym.sym) + { + case SDLK_ESCAPE: + return false; + + default: + break; + } + } + else if (event.type == SDL_WINDOWEVENT) + { + if (event.window.windowID == m_windowID) + { + if (event.window.event == SDL_WINDOWEVENT_RESIZED || event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED + || event.window.event == SDL_WINDOWEVENT_MAXIMIZED) + { + if (event.window.data1 != 0 && event.window.data2 != 0) + resize(event.window.data1, event.window.data2); + } + } + } + + return true; + } + + void GLBackend::advanceTime() + { + auto now = std::chrono::steady_clock::now(); + std::chrono::duration<float> elapsed_seconds = now - m_prev_time_tick; + m_delta_time = elapsed_seconds.count()*1000.0f; + m_global_time += m_delta_time; + m_prev_time_tick = now; + } + + void GLBackend::computeProjection() + { + float w, h; + float n = -1.0f, f = 1.0f; + float true_aspect = m_width / (float)m_height; + float req_aspect = m_requested_canvas.z / m_requested_canvas.w; + + switch (m_canvas_mode) + { + case CANVAS_SCALE_STRETCH: + m_canvas = m_requested_canvas; + m_projection = glm::scale(glm::vec3(1, -1, 1)) * glm::ortho(0.0f, m_canvas.z, 0.0f, m_canvas.w, n, f); + break; + case CANVAS_SCALE_FIT: + + if (true_aspect > req_aspect) + { + m_canvas.z = (true_aspect / req_aspect) * m_requested_canvas.z; + m_canvas.w = m_requested_canvas.w; + m_canvas.x = -m_requested_canvas.z * (true_aspect / req_aspect-1.0f) / 2; + m_canvas.y = 0.0f; + m_canvas.z += m_canvas.x; + } + else + { + m_canvas.z = m_requested_canvas.z; + m_canvas.w = (req_aspect / true_aspect) * m_requested_canvas.w; + m_canvas.y = 0.0f; + m_canvas.x = 0.0f; + m_canvas.y = -m_requested_canvas.w * (req_aspect / true_aspect - 1.0f) / 2; + m_canvas.w += m_canvas.y; + } + m_projection = glm::scale(glm::vec3(1, -1, 1)) * glm::ortho(m_canvas.x, m_canvas.z, m_canvas.y, m_canvas.w, n, f); + + break; + default: + m_canvas = glm::vec4(0.0f, 0.0f, (float)m_width, (float)m_height); + m_projection = glm::scale(glm::vec3(1, -1, 1)) * glm::ortho(0.0f, m_canvas.z, 0.0f, m_canvas.w, n, f); + } + + + } + + void GLBackend::initPrimitives() + { + glGetError(); + const GLubyte * s = glewGetErrorString(glGetError()); + + m_flat_shader = Shader(__PrimitivesVertexShader, __SolidFragmentShader); + + if (!m_flat_shader.init()) + return; + + GLfloat box[4][4] = { + { -0.5f, 0.5f, 0, 1 }, + { 0.5f, 0.5f, 1, 1 }, + { -0.5f, -0.5f, 0, 0 }, + { 0.5f, -0.5f, 1, 0 } + }; + + GLfloat box_outline[4][4] = { + { -0.5f, 0.5f, 0, 0 }, + { 0.5f, 0.5f, 1, 0 }, + { 0.5f, -0.5f, 1, 1 }, + { -0.5f, -0.5f, 0, 1 } + }; + + GLfloat line[2][4] = + { + {0,0,0,1}, + {1,1,1,1} + }; + + float sector_vertices[2 * CURVE_SUBDIVS][4]; + float sector_outline_vertices[2 * CURVE_SUBDIVS][4]; + float r1 = 0.0f, r2 = 1.0f; + for (int i = 0; i < CURVE_SUBDIVS; i++) + { + float s = i / (float)CURVE_SUBDIVS; + sector_vertices[i*2+0][0] = r1*sin(3.1415936f*s); + sector_vertices[i*2+0][1] = r1*cos(3.1415936f*s); + sector_vertices[i*2+0][2] = s; + sector_vertices[i*2+0][3] = 0.0f; + sector_vertices[i * 2 + 1][0] = r2 * sin(3.1415936f*s); + sector_vertices[i * 2 + 1][1] = r2 * cos(3.1415936f*s); + sector_vertices[i * 2 + 1][2] = s; + sector_vertices[i * 2 + 1][3] = 1.0f; + } + for (int i = 0; i < CURVE_SUBDIVS; i++) + { + float s = i / (float)CURVE_SUBDIVS; + sector_vertices[i][0] = r1 * sin(3.1415936f*s); + sector_vertices[i][1] = r1 * cos(3.1415936f*s); + sector_vertices[i][2] = s; + sector_vertices[i][3] = 0.0f; + sector_vertices[2 * CURVE_SUBDIVS - i - 1][0] = r2 * sin(3.1415936f*s); + sector_vertices[2 * CURVE_SUBDIVS - i - 1][1] = r2 * cos(3.1415936f*s); + sector_vertices[2 * CURVE_SUBDIVS - i - 1][2] = s; + sector_vertices[2 * CURVE_SUBDIVS - i - 1][3] = 1.0f; + } + + sggGenVertexArrays(1, &m_sector_vao); + sggBindVertexArray(m_sector_vao); + glGenBuffers(1, &m_sector_vbo); + glBindBuffer(GL_ARRAY_BUFFER, m_sector_vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof sector_vertices, sector_vertices, GL_DYNAMIC_DRAW); + + sggGenVertexArrays(1, &m_sector_outline_vao); + sggBindVertexArray(m_sector_outline_vao); + glGenBuffers(1, &m_sector_outline_vbo); + glBindBuffer(GL_ARRAY_BUFFER, m_sector_outline_vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof sector_outline_vertices, sector_outline_vertices, GL_DYNAMIC_DRAW); + + sggGenVertexArrays(1, &m_line_vao); + sggBindVertexArray(m_line_vao); + glGenBuffers(1, &m_line_vbo); + glBindBuffer(GL_ARRAY_BUFFER, m_line_vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof line, line, GL_DYNAMIC_DRAW); + + sggGenVertexArrays(1, &m_rect_vao); + sggBindVertexArray(m_rect_vao); + glGenBuffers(1, &m_rect_vbo); + glBindBuffer(GL_ARRAY_BUFFER, m_rect_vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof box, box, GL_STATIC_DRAW); + + sggGenVertexArrays(1, &m_rect_outline_vao); + sggBindVertexArray(m_rect_outline_vao); + glGenBuffers(1, &m_rect_outline_vbo); + glBindBuffer(GL_ARRAY_BUFFER, m_rect_outline_vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof box_outline, box_outline, GL_STATIC_DRAW); + + unsigned int attrib_flat_position = m_flat_shader.getAttributeLocation("coord"); + glEnableVertexAttribArray(attrib_flat_position); + glVertexAttribPointer(attrib_flat_position, 4, GL_FLOAT, GL_FALSE, 0, 0); + + } + + void GLBackend::computeTransformation() + { + // note: rotation is CW, due to mirroring after projection. + m_transformation = glm::rotate(-3.1415936f*m_orientation / 180.0f, glm::vec3(0.f, 0.f, 1.f)) * glm::scale(m_scale); + } + + void GLBackend::drawRect(float cx, float cy, float w, float h, const Brush & brush) + { + + glEnable(GL_TEXTURE_2D); + glFrontFace(GL_CCW); + glPolygonMode(GL_FRONT, GL_FILL); + glm::mat4 mat = glm::translate(glm::vec3(cx, cy, 0.0f)) * + m_transformation * glm::scale(glm::vec3(w, h, 1.0f)); + m_flat_shader["gradient"] = glm::vec2(brush.gradient_dir_u, brush.gradient_dir_v); + + // fill + if (brush.fill_opacity != 0.0f || brush.fill_secondary_opacity != 0.0f ) + { + int tid = textures.getTexture(brush.texture); + if (tid > 0) + { + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, tid); + + } + + m_flat_shader["color1"] = glm::vec4(brush.fill_color[0], brush.fill_color[1], brush.fill_color[2], brush.fill_opacity); + + if (brush.gradient) + { + m_flat_shader["color2"] = glm::vec4(brush.fill_secondary_color[0], brush.fill_secondary_color[1], + brush.fill_secondary_color[2], brush.fill_secondary_opacity); + } + else + { + m_flat_shader["color2"] = glm::vec4(brush.fill_color[0], brush.fill_color[1], brush.fill_color[2], brush.fill_opacity); + } + + m_flat_shader["MV"] = mat; + m_flat_shader["tex"] = 0; + if (tid>0) + m_flat_shader["has_texture"] = 1; + else + m_flat_shader["has_texture"] = 0; + + unsigned int attrib_flat_position = m_flat_shader.getAttributeLocation("coord"); + sggBindVertexArray(m_rect_vao); + glBindBuffer(GL_ARRAY_BUFFER, m_rect_vbo); + glEnableVertexAttribArray(attrib_flat_position); + glVertexAttribPointer(attrib_flat_position, 4, GL_FLOAT, GL_FALSE, 0, 0); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + } + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, 0); + + if (brush.outline_opacity>0.0f) + { + m_flat_shader.use(); + m_flat_shader["color1"] = glm::vec4(brush.outline_color[0], brush.outline_color[1], brush.outline_color[2], brush.outline_opacity); + m_flat_shader["color2"] = glm::vec4(brush.outline_color[0], brush.outline_color[1], brush.outline_color[2], brush.outline_opacity); + m_flat_shader["MV"] = mat; + m_flat_shader["has_texture"] = 0; + glLineWidth(brush.outline_width); + sggBindVertexArray(m_rect_outline_vao); + glBindBuffer(GL_ARRAY_BUFFER, m_rect_outline_vbo); + unsigned int attrib_flat_position = m_flat_shader.getAttributeLocation("coord"); + glEnableVertexAttribArray(attrib_flat_position); + glVertexAttribPointer(attrib_flat_position, 4, GL_FLOAT, GL_FALSE, 0, 0); + glDrawArrays(GL_LINE_LOOP, 0, 4); + glLineWidth(1); + + } + + } + + void GLBackend::drawLine(float x_1, float y_1, float x_2, float y_2, const Brush & brush) + { + m_flat_shader["color1"] = glm::vec4(brush.outline_color[0], brush.outline_color[1], brush.outline_color[2], brush.outline_opacity); + m_flat_shader["MV"] = glm::mat4(1.0f); + m_flat_shader["gradient"] = glm::vec2(1.0f, 0.0f); + GLfloat line[2][4] = + { + { x_1, y_1, 0.0f, 1.0f}, + { x_2, y_2, 0.1f, 1.0f}, + }; + + sggBindVertexArray(m_line_vao); + glBindBuffer(GL_ARRAY_BUFFER, m_line_vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof line, line, GL_DYNAMIC_DRAW); + unsigned int attrib_flat_position = m_flat_shader.getAttributeLocation("coord"); + glEnableVertexAttribArray(attrib_flat_position); + glVertexAttribPointer(attrib_flat_position, 4, GL_FLOAT, GL_FALSE, 0, 0); + glDrawArrays(GL_LINES, 0, 2); + } + + void GLBackend::drawSector(float cx, float cy, float start_angle, float end_angle, float radius1, float radius2, const Brush & brush) + { + glEnable(GL_TEXTURE_2D); + glFrontFace(GL_CCW); + glPolygonMode(GL_FRONT, GL_FILL); + m_flat_shader["MV"] = glm::translate(glm::vec3(cx, cy, 0.0f)) * m_transformation; + m_flat_shader["gradient"] = glm::vec2(brush.gradient_dir_u,brush.gradient_dir_v); + + float sector_vertices[2 * CURVE_SUBDIVS+2][4]; + float sector_outline_vertices[2 * CURVE_SUBDIVS+2][4]; + float r1 = radius1, r2 = radius2; + float arc_inc = 3.1415936f*(end_angle - start_angle) / (180.0f*CURVE_SUBDIVS); + for (int i = 0; i <= CURVE_SUBDIVS; i++) + { + float s = i / (float)CURVE_SUBDIVS; + sector_vertices[i * 2 + 0][0] = r1 * cos(3.1415936f*start_angle / 180.f + i * arc_inc); + sector_vertices[i * 2 + 0][1] = r1 * -sin(3.1415936f*start_angle / 180.f + i * arc_inc); + sector_vertices[i * 2 + 0][2] = s; + sector_vertices[i * 2 + 0][3] = 0.0f; + sector_vertices[i * 2 + 1][0] = r2 * cos(3.1415936f*start_angle / 180.f + i * arc_inc); + sector_vertices[i * 2 + 1][1] = r2 * -sin(3.1415936f*start_angle / 180.f + i * arc_inc); + sector_vertices[i * 2 + 1][2] = s; + sector_vertices[i * 2 + 1][3] = 1.0f; + } + for (int i = 0; i <= CURVE_SUBDIVS; i++) + { + float s = i / (float)CURVE_SUBDIVS; + sector_outline_vertices[i][0] = r1 * cos(3.1415936f*start_angle / 180.f + i * arc_inc); + sector_outline_vertices[i][1] = r1 * -sin(3.1415936f*start_angle / 180.f + i * arc_inc); + sector_outline_vertices[i][2] = s; + sector_outline_vertices[i][3] = 0.0f; + } + for (int i = CURVE_SUBDIVS; i >= 0; i--) + { + float s = (i) / (float)CURVE_SUBDIVS; + sector_outline_vertices[2*CURVE_SUBDIVS-i+1][0] = r2 * cos(3.1415936f*start_angle / 180.f + i * arc_inc); + sector_outline_vertices[2*CURVE_SUBDIVS-i+1][1] = r2 * -sin(3.1415936f*start_angle / 180.f + i * arc_inc); + sector_outline_vertices[2*CURVE_SUBDIVS-i+1][2] = s; + sector_outline_vertices[2*CURVE_SUBDIVS-i+1][3] = 1.0f; + } + + + // fill + if (brush.fill_opacity != 0.0f || brush.fill_secondary_opacity != 0.0f) + { + int tid = textures.getTexture(brush.texture); + if (tid > 0) + { + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, tid); + + } + + m_flat_shader["color1"] = glm::vec4(brush.fill_color[0], brush.fill_color[1], brush.fill_color[2], brush.fill_opacity); + + if (brush.gradient) + { + m_flat_shader["color2"] = glm::vec4(brush.fill_secondary_color[0], brush.fill_secondary_color[1], + brush.fill_secondary_color[2], brush.fill_secondary_opacity); + } + else + { + m_flat_shader["color2"] = glm::vec4(brush.fill_color[0], brush.fill_color[1], brush.fill_color[2], brush.fill_opacity); + } + + m_flat_shader["tex"] = 0; + if (tid > 0) + m_flat_shader["has_texture"] = 1; + else + m_flat_shader["has_texture"] = 0; + + sggBindVertexArray(m_sector_vao); + glBindBuffer(GL_ARRAY_BUFFER, m_sector_vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof sector_vertices, sector_vertices, GL_DYNAMIC_DRAW); + unsigned int attrib_flat_position = m_flat_shader.getAttributeLocation("coord"); + glEnableVertexAttribArray(attrib_flat_position); + glVertexAttribPointer(attrib_flat_position, 4, GL_FLOAT, GL_FALSE, 0, 0); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 2 * CURVE_SUBDIVS+2); + + } + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, 0); + + if (brush.outline_opacity > 0.0f) + { + m_flat_shader.use(); + m_flat_shader["color1"] = glm::vec4(brush.outline_color[0], brush.outline_color[1], brush.outline_color[2], brush.outline_opacity); + m_flat_shader["color2"] = glm::vec4(brush.outline_color[0], brush.outline_color[1], brush.outline_color[2], brush.outline_opacity); + m_flat_shader["has_texture"] = 0; + glLineWidth(brush.outline_width); + + sggBindVertexArray(m_sector_outline_vao); + glBindBuffer(GL_ARRAY_BUFFER, m_sector_outline_vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof sector_outline_vertices, sector_outline_vertices, GL_DYNAMIC_DRAW); + unsigned int attrib_flat_position = m_flat_shader.getAttributeLocation("coord"); + glEnableVertexAttribArray(attrib_flat_position); + glVertexAttribPointer(attrib_flat_position, 4, GL_FLOAT, GL_FALSE, 0, 0); + if (fabs(end_angle-start_angle-360.0f)>0.000f) + glDrawArrays(GL_LINE_LOOP, 0, 2 * CURVE_SUBDIVS+2); + else + glDrawArrays(GL_LINE_LOOP, CURVE_SUBDIVS + 1, CURVE_SUBDIVS ); + + glLineWidth(1); + + } + + + + } + + void GLBackend::drawText(float pos_x, float pos_y, float size, const std::string & text, const Brush & brush) + { + TextRecord entry; + entry.text = text; + entry.pos = glm::vec2(pos_x, pos_y); + entry.size = glm::vec2(size, size); + entry.color1 = glm::vec4(brush.fill_color[0], brush.fill_color[1], brush.fill_color[2], brush.fill_opacity); + entry.color2 = glm::vec4(brush.fill_secondary_color[0], brush.fill_secondary_color[1], brush.fill_secondary_color[2], brush.fill_secondary_opacity); + entry.gradient = glm::vec2(brush.gradient_dir_u, brush.gradient_dir_v); + entry.use_gradient = brush.gradient; + entry.mv = m_transformation; + entry.proj = m_projection; + m_fontlib.submitText(entry); + } + + void GLBackend::setUserData(const void * user_data) { + m_user_data = user_data; + } + + void* GLBackend::getUserData() { + /* Safely cast const away */ + return const_cast<void*>(m_user_data); + } + + void GLBackend::setScale(float sx, float sy, float sz) + { + m_scale = glm::vec3(sx,sy,sz); + computeTransformation(); + } + + void GLBackend::setOrientation(float degrees) + { + m_orientation = degrees; + computeTransformation(); + } + + void GLBackend::resetPose() + { + m_transformation = glm::mat4(1.0f); + m_scale = glm::vec3(1.0f); + m_orientation = 0.0f; + } + + bool GLBackend::setFont(std::string fontname) + { + return m_fontlib.setCurrentFont(fontname); + } + + bool GLBackend::getKeyState(scancode_t key) + { + int numkeys; + const uint8_t * keymap = SDL_GetKeyboardState(&numkeys); + return keymap[key]; + } + + + bool GLBackend::processMessages() + { + SDL_Event event; + bool loop = true; + while (SDL_PollEvent(&event)) + { + if (event.type == SDL_WINDOWEVENT_CLOSE || event.type == SDL_QUIT) + { + return false; + } + else + { + loop = processEvent(event); + } + } + update(); + m_idle_callback(getDeltaTime()); + draw(); + advanceTime(); + SDL_Delay(5); + + return loop; + } + + void GLBackend::update(float delta_time) + { + static bool prev_mouse_state[3] = { 0,0,0 }; + + m_button_pressed[0] = (m_button_state[0] && !prev_mouse_state[0]); + m_button_pressed[1] = (m_button_state[1] && !prev_mouse_state[1]); + m_button_pressed[2] = (m_button_state[2] && !prev_mouse_state[2]); + + m_button_released[0] = (!m_button_state[0] && prev_mouse_state[0]); + m_button_released[1] = (!m_button_state[1] && prev_mouse_state[1]); + m_button_released[2] = (!m_button_state[2] && prev_mouse_state[2]); + + prev_mouse_state[0] = m_button_state[0]; + prev_mouse_state[1] = m_button_state[1]; + prev_mouse_state[2] = m_button_state[2]; + + } + + void GLBackend::resize(int w, int h) + { + m_width = w; + m_height = h; + + if (m_resize_callback != nullptr) + m_resize_callback(w, h); + + if (m_requested_canvas.z == 0 || m_requested_canvas.w == 0) + // default canvas is window-sized, in pixel units. + m_canvas = glm::vec4(0, 0, m_width, m_height); + else + m_canvas = m_requested_canvas; + + float c_w = m_canvas.z; + float c_h = m_canvas.w; + float cr = c_w / c_h; + float wr = m_width / (float)m_height; + + // calculate window to canvas unit conversion ratios + if (m_canvas_mode == CANVAS_SCALE_FIT) + { + if (cr > wr) + { + m_window_to_canvas_factors.x = c_w / m_width; + m_window_to_canvas_factors.y = 0.0f; + m_window_to_canvas_factors.z = c_w / m_width; + m_window_to_canvas_factors.w = c_h / 2.0f - 0.5 * m_height * c_w / m_width; + } + else + { + m_window_to_canvas_factors.z = c_h / m_height; + m_window_to_canvas_factors.w = 0.0f; + m_window_to_canvas_factors.x = c_h / m_height; + m_window_to_canvas_factors.y = c_w / 2.0f - 0.5 * m_width * c_h / m_height; + } + } + else + { + m_window_to_canvas_factors.x = c_w / m_width; + m_window_to_canvas_factors.y = 0.0f; + m_window_to_canvas_factors.z = c_h / m_height; + m_window_to_canvas_factors.w = 0.0f; + } + + computeProjection(); + glViewport(0, 0, m_width, m_height); + //SDL_Delay(100); + draw(); + } + + float GLBackend::WindowToCanvasX(float x, bool clamped) + { + float coord = m_window_to_canvas_factors.x*x + m_window_to_canvas_factors.y; + return clamped?glm::clamp(coord, 0.0f, m_canvas.z) : coord; + } + + float GLBackend::WindowToCanvasY(float y, bool clamped) + { + float coord = m_window_to_canvas_factors.z*y + m_window_to_canvas_factors.w; + return clamped?glm::clamp(coord, 0.0f, m_canvas.w) : coord; + } + + void GLBackend::draw() + { + m_flat_shader.use(); + + // reset timers on first run + static bool first_time = true; + if (first_time) + { + advanceTime(); + m_global_time = 0.0f; + m_delta_time = 0.0f; + first_time = false; + + //force a call to resize to take canvas parameters set by the user. + resize(m_width, m_height); + return; + } + + resetPose(); + + glDepthMask(0.0f); + glDisable(GL_DEPTH_TEST); + glClearColor(0.0f, 0.0f, 0.f, 1.0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + if (m_canvas_mode == CANVAS_SCALE_FIT) + { + float true_aspect = m_width / (float)m_height; + float req_aspect = m_requested_canvas.z / m_requested_canvas.w; + glEnable(GL_SCISSOR_TEST); + glm::vec4 rect; + rect.x = (true_aspect > req_aspect ? (m_width - m_height * req_aspect) / 2.0f : 0.0f); + rect.y = (req_aspect > true_aspect ? (m_height - m_width / req_aspect)/2.0f : 0.0f); + rect.z = (true_aspect > req_aspect ? m_height * req_aspect : m_width); + rect.w = (req_aspect > true_aspect ? m_width / req_aspect : m_height); + glScissor(rect.x, rect.y, rect.z, rect.w); + } + + Brush bck; + bck.fill_color[0] = m_back_color.r, bck.fill_color[1] = m_back_color.g, bck.fill_color[2] = m_back_color.b; + bck.outline_opacity = 0.0f; + drawRect(m_requested_canvas.z / 2, m_requested_canvas.w / 2, m_requested_canvas.z, m_requested_canvas.w, bck); + + glEnable(GL_BLEND); + glBlendEquation(GL_ADD); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + + m_flat_shader["P"] = m_projection; + glGetError(); + if (m_draw_callback != nullptr) + m_draw_callback(); + + m_fontlib.setCanvas(glm::vec2(m_requested_canvas.z, m_requested_canvas.w)); + m_fontlib.commitText(); + + glDisable(GL_SCISSOR_TEST); + swap(); + } + + + + void GLBackend::setDrawCallback(std::function<void()> drf) + { + m_draw_callback = drf; + } + + void GLBackend::setIdleCallback(std::function<void(float)> idf) + { + m_idle_callback = idf; + } + + void GLBackend::setResizeCallback(std::function<void(int, int)> rsf) + { + m_resize_callback = rsf; + } + + bool GLBackend::init() + { + m_initialized = false; + + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_EVENTS | SDL_INIT_AUDIO) < 0) + { + std::cout << "Failed to init SDL\n"; + return false; + } + + m_window = SDL_CreateWindow(m_title.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, + m_width, m_height, SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE ); + m_windowID = SDL_GetWindowID(m_window); + m_audio = new AudioManager(); + + if (!m_window) + { + std::cout << "Unable to create window\n"; + CheckSDLError(__LINE__); + return false; + } + + m_context = SDL_GL_CreateContext(m_window); + + + //SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); + SDL_GL_SetSwapInterval(0); + + glewExperimental = GL_TRUE; + glewInit(); + glGetError(); + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LEQUAL); + glClearDepth(1.0f); + glDisable(GL_CULL_FACE); + glCullFace(GL_BACK); + + if (!m_fontlib.init()) + { + std::cout << "Unable to initialize font library\n"; + CheckSDLError(__LINE__); + return false; + } + + initPrimitives(); + computeProjection(); + glViewport(0, 0, m_width, m_height); + + m_initialized = true; + return true; + } + + + + void CheckSDLError(int line = -1) + { + std::string error = SDL_GetError(); + + if (error != "") + { + std::cout << "SLD Error : " << error << std::endl; + + if (line != -1) + std::cout << "\nLine : " << line << std::endl; + + SDL_ClearError(); + } + } + + void PrintSDL_GL_Attributes() + { + int value = 0; + SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &value); + std::cout << "SDL_GL_CONTEXT_MAJOR_VERSION : " << value << std::endl; + + SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &value); + std::cout << "SDL_GL_CONTEXT_MINOR_VERSION: " << value << std::endl; + } +}
\ No newline at end of file |