|
|
|
|
@ -2,8 +2,7 @@
|
|
|
|
|
#ifndef RENDERER_H |
|
|
|
|
#define RENDERER_H |
|
|
|
|
|
|
|
|
|
#include <cstdlib> // rand, srand, RAND_MAX |
|
|
|
|
#include <ctime> // time |
|
|
|
|
#include <vector> |
|
|
|
|
// TODO: remove for better logging
|
|
|
|
|
#include <iostream> // std::cout |
|
|
|
|
|
|
|
|
|
@ -21,20 +20,21 @@
|
|
|
|
|
bool initRenderer(SDL_Handles &handles, v2i vpDims); |
|
|
|
|
// TODO: re-implement debug erender
|
|
|
|
|
void debugRender(HexDrawMode mode, hex_info *startHex, hex_info *currentHex); |
|
|
|
|
void renderFrame(const vector<hex_info> *hexes); |
|
|
|
|
void renderFrame(const std::vector<hex_info> *hexes); |
|
|
|
|
void freeBuffers(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// forward declarations
|
|
|
|
|
|
|
|
|
|
GLuint initShaders(); |
|
|
|
|
bool initShaders(GLuint &programID1, GLuint &programID2); |
|
|
|
|
// enable debug output https://www.khronos.org/opengl/wiki/OpenGL_Error
|
|
|
|
|
void openglDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, |
|
|
|
|
GLsizei length, const GLchar* message, const void* userParam); |
|
|
|
|
void createScene(vector<hex_info>* hexes); |
|
|
|
|
void createScene(std::vector<hex_info>* hexes); |
|
|
|
|
void parseHexToGLBuffer(GLfloat buf[], int idx, const hex_info &hex); |
|
|
|
|
void fillColorBuffer(GLfloat* buf, int len); |
|
|
|
|
bool fillColorBuffer(GLfloat* buf, int len, std::vector<hex_info> *hexes); |
|
|
|
|
|
|
|
|
|
// TODO: organize these into a struct/structs since we're using at least 2 now
|
|
|
|
|
glm::mat4 g_projection_matrix; |
|
|
|
|
glm::mat4 g_view_matrix; |
|
|
|
|
glm::mat4 g_model_matrix; |
|
|
|
|
@ -44,9 +44,14 @@ GLuint g_vertex_buffer_triangle_count;
|
|
|
|
|
GLuint g_color_buffer; |
|
|
|
|
size_t g_buf_size; |
|
|
|
|
GLfloat *g_color_buf_data; |
|
|
|
|
GLuint g_programID; |
|
|
|
|
GLuint g_hex_programID; |
|
|
|
|
GLuint g_matrixID; |
|
|
|
|
|
|
|
|
|
GLuint g_hex_line_vertexbuffer; |
|
|
|
|
size_t g_line_buf_size; |
|
|
|
|
GLuint g_line_programID; |
|
|
|
|
GLuint g_line_matrixID; |
|
|
|
|
|
|
|
|
|
bool |
|
|
|
|
initRenderer(SDL_Handles &handles, v2i vpDims) |
|
|
|
|
{ |
|
|
|
|
@ -97,17 +102,24 @@ initRenderer(SDL_Handles &handles, v2i vpDims)
|
|
|
|
|
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); |
|
|
|
|
#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); |
|
|
|
|
g_programID = initShaders(); |
|
|
|
|
g_matrixID = glGetUniformLocation(g_programID, "g_MVP"); // shader variable for mvp xform
|
|
|
|
|
// hide VRAM debug messages
|
|
|
|
|
glDebugMessageControl(GL_DONT_CARE, 33361, GL_DONT_CARE, 0, 0, GL_FALSE); |
|
|
|
|
|
|
|
|
|
initShaders(g_hex_programID, g_line_programID); |
|
|
|
|
g_matrixID = glGetUniformLocation(g_hex_programID, "g_MVP"); // shader variables for mvp xform
|
|
|
|
|
g_line_matrixID = glGetUniformLocation(g_line_programID, "g_MVP"); |
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// TODO: figure out how to keep track of shader state, and pass in struct here
|
|
|
|
|
GLuint |
|
|
|
|
initShaders() |
|
|
|
|
// TODO: make reusable by creating 1 program at a time
|
|
|
|
|
bool |
|
|
|
|
initShaders(GLuint &programID1, GLuint &programID2) |
|
|
|
|
{ |
|
|
|
|
GLuint VertexArrayID; |
|
|
|
|
glGenVertexArrays(1, &VertexArrayID); |
|
|
|
|
@ -131,44 +143,57 @@ initShaders()
|
|
|
|
|
"out vec3 color;\n" |
|
|
|
|
"void main()\n" |
|
|
|
|
"{\n" |
|
|
|
|
//" color = vec3(0.5,0,0);\n"
|
|
|
|
|
" color = fragmentColor;\n" |
|
|
|
|
"}"; |
|
|
|
|
|
|
|
|
|
#if 1 |
|
|
|
|
const char * LineFragmentShaderCode = |
|
|
|
|
"#version 330 core\n" |
|
|
|
|
"out vec3 color;\n" |
|
|
|
|
"void main()\n" |
|
|
|
|
"{\n" |
|
|
|
|
" color = vec3(0,0,0);\n" |
|
|
|
|
"}"; |
|
|
|
|
#endif |
|
|
|
|
GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER); |
|
|
|
|
GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER); |
|
|
|
|
GLuint LineFragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER); |
|
|
|
|
glShaderSource(VertexShaderID, 1, &VertexShaderCode, NULL); |
|
|
|
|
glShaderSource(FragmentShaderID, 1, &FragmentShaderCode, NULL); |
|
|
|
|
glShaderSource(LineFragmentShaderID, 1, &LineFragmentShaderCode, NULL); |
|
|
|
|
glCompileShader(VertexShaderID); |
|
|
|
|
glCompileShader(FragmentShaderID); |
|
|
|
|
|
|
|
|
|
GLuint programID = glCreateProgram(); |
|
|
|
|
glAttachShader(programID, VertexShaderID); |
|
|
|
|
glAttachShader(programID, FragmentShaderID); |
|
|
|
|
glLinkProgram(programID); |
|
|
|
|
|
|
|
|
|
glDetachShader(programID, VertexShaderID); |
|
|
|
|
glDetachShader(programID, FragmentShaderID); |
|
|
|
|
glCompileShader(LineFragmentShaderID); |
|
|
|
|
|
|
|
|
|
programID1 = glCreateProgram(); |
|
|
|
|
glAttachShader(programID1, VertexShaderID); |
|
|
|
|
glAttachShader(programID1, FragmentShaderID); |
|
|
|
|
glLinkProgram(programID1); |
|
|
|
|
|
|
|
|
|
programID2 = glCreateProgram(); |
|
|
|
|
glAttachShader(programID2, VertexShaderID); |
|
|
|
|
glAttachShader(programID2, LineFragmentShaderID); |
|
|
|
|
glLinkProgram(programID2); |
|
|
|
|
|
|
|
|
|
glDetachShader(programID1, VertexShaderID); |
|
|
|
|
glDetachShader(programID1, FragmentShaderID); |
|
|
|
|
glDetachShader(programID2, LineFragmentShaderID); |
|
|
|
|
glDetachShader(programID2, FragmentShaderID); |
|
|
|
|
glDeleteShader(VertexShaderID); |
|
|
|
|
glDeleteShader(FragmentShaderID); |
|
|
|
|
|
|
|
|
|
return programID; |
|
|
|
|
glDeleteShader(LineFragmentShaderID); |
|
|
|
|
|
|
|
|
|
// TODO: what kind of errors can happen here?
|
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void |
|
|
|
|
createScene(vector<hex_info>* hexes) |
|
|
|
|
createScene(std::vector<hex_info>* hexes) |
|
|
|
|
{ |
|
|
|
|
////////////////////
|
|
|
|
|
// Model, View, Projection Matrices
|
|
|
|
|
|
|
|
|
|
g_projection_matrix = glm::ortho( |
|
|
|
|
0.f, // left
|
|
|
|
|
1280.0f, // right
|
|
|
|
|
0.f, // bottom
|
|
|
|
|
720.0f, // top
|
|
|
|
|
0.1f, // zNear
|
|
|
|
|
100.0f // zFar
|
|
|
|
|
); |
|
|
|
|
// left, right, bottom, top, zNear, zFar
|
|
|
|
|
g_projection_matrix = glm::ortho(0.f, 1280.0f, 0.f, 720.0f, 0.1f, 100.0f); |
|
|
|
|
|
|
|
|
|
g_view_matrix = glm::lookAt( |
|
|
|
|
glm::vec3(0.0f, 0.0f, 2.0f), // camera position
|
|
|
|
|
@ -186,7 +211,7 @@ createScene(vector<hex_info>* hexes)
|
|
|
|
|
// TODO: index duplicate vertices
|
|
|
|
|
// http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-9-vbo-indexing/
|
|
|
|
|
|
|
|
|
|
// 6 triangles * 3 vertices per triange * 3 floats per vertex = 54
|
|
|
|
|
// 6 triangles * 3 vertices per triangle * 3 floats per vertex = 54
|
|
|
|
|
int buf_index = 54; |
|
|
|
|
size_t hex_count = hexes->size(); |
|
|
|
|
g_buf_size = 6 * 9 * hex_count; |
|
|
|
|
@ -202,14 +227,64 @@ createScene(vector<hex_info>* hexes)
|
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, g_vertexbuffer); |
|
|
|
|
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * g_buf_size, vbuf_data, GL_STATIC_DRAW); |
|
|
|
|
|
|
|
|
|
// make some pretty colors
|
|
|
|
|
|
|
|
|
|
// color data for hex vertices
|
|
|
|
|
|
|
|
|
|
srand(time(0)); // seed c library rng
|
|
|
|
|
g_color_buf_data = (GLfloat*) std::malloc(sizeof(GLfloat) * g_buf_size); |
|
|
|
|
fillColorBuffer(g_color_buf_data, int(g_buf_size)); |
|
|
|
|
g_color_buf_data = (GLfloat*) std::calloc( g_buf_size, sizeof(GLfloat)); |
|
|
|
|
|
|
|
|
|
if (!fillColorBuffer(g_color_buf_data, (int) g_buf_size, hexes)) |
|
|
|
|
{ |
|
|
|
|
// TODO: log fatal error
|
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
glGenBuffers(1, &g_color_buffer); |
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, g_color_buffer); |
|
|
|
|
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * g_buf_size, g_color_buf_data, GL_DYNAMIC_DRAW); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Hex Line Vertex Data
|
|
|
|
|
|
|
|
|
|
// TODO: surely there's a way to use indexed drawing for line vertices eg) LINE_LOOP
|
|
|
|
|
// and still use one buffer for multiple shapes/paths glDrawArraysIntanced?, glDrawElements?
|
|
|
|
|
// https://gamedev.stackexchange.com/questions/104310/opengl-4-5-primitive-restart-vs-base-index
|
|
|
|
|
int line_vertices_per_hex = 6 * 2; // 12 vertices since we're using line segments atm
|
|
|
|
|
g_line_buf_size = hex_count * line_vertices_per_hex * 3; // 3 floats per vertex
|
|
|
|
|
GLfloat line_buf_data[g_line_buf_size] = { 0 }; |
|
|
|
|
|
|
|
|
|
int line_buf_idx = 0; |
|
|
|
|
for (int i = 0; i < (int) hex_count; i++) |
|
|
|
|
{ |
|
|
|
|
hex_info hxi = (*hexes)[i]; |
|
|
|
|
for (int j = 0; j < 6; j ++) |
|
|
|
|
{ |
|
|
|
|
Point p1, p2; |
|
|
|
|
|
|
|
|
|
if (j == 5) // wrap
|
|
|
|
|
{ |
|
|
|
|
p1 = hxi.vertices[j]; |
|
|
|
|
p2 = hxi.vertices[0]; |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
p1 = hxi.vertices[j]; |
|
|
|
|
p2 = hxi.vertices[j + 1]; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
line_buf_data[line_buf_idx + 0] = p1.x; |
|
|
|
|
line_buf_data[line_buf_idx + 1] = p1.y; |
|
|
|
|
line_buf_data[line_buf_idx + 2] = 0.f; |
|
|
|
|
line_buf_data[line_buf_idx + 3] = p2.x; |
|
|
|
|
line_buf_data[line_buf_idx + 4] = p2.y; |
|
|
|
|
line_buf_data[line_buf_idx + 5] = 0.f; |
|
|
|
|
|
|
|
|
|
line_buf_idx += 6; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
glGenBuffers(1, &g_hex_line_vertexbuffer); |
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, g_hex_line_vertexbuffer); |
|
|
|
|
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * g_line_buf_size, line_buf_data, GL_STATIC_DRAW); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void |
|
|
|
|
@ -218,7 +293,7 @@ parseHexToGLBuffer(GLfloat buf[], int idx, const hex_info &hex)
|
|
|
|
|
// triangles
|
|
|
|
|
for (int i = 0; i < 6; i++) |
|
|
|
|
{ |
|
|
|
|
if (i == 5) // wrap
|
|
|
|
|
if (i == 5) // re-use the first point for the last triangle
|
|
|
|
|
{ |
|
|
|
|
// vertex 0
|
|
|
|
|
buf[idx + 0] = (GLfloat) hex.XPos; |
|
|
|
|
@ -258,23 +333,53 @@ parseHexToGLBuffer(GLfloat buf[], int idx, const hex_info &hex)
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void |
|
|
|
|
fillColorBuffer(GLfloat* buf, int len) |
|
|
|
|
bool |
|
|
|
|
fillColorBuffer(GLfloat buf[], int len, std::vector<hex_info> *hexes) |
|
|
|
|
{ |
|
|
|
|
for (int i = 0; i < len; i++) |
|
|
|
|
if (!buf || len < 1) |
|
|
|
|
{ |
|
|
|
|
// should be normalized between 0 and 1
|
|
|
|
|
buf[i] = GLfloat((GLfloat) rand() / (GLfloat) RAND_MAX); |
|
|
|
|
// TODO: log fatal error
|
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!hexes || hexes->size() == 0) |
|
|
|
|
{ |
|
|
|
|
// TODO: log fatal error
|
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 3 floats per vertex, 3 vertexes per triangle, 6 triangles per hex
|
|
|
|
|
if (len != (int) hexes->size() * 3 * 3 * 6) |
|
|
|
|
{ |
|
|
|
|
// TODO: log fatal error
|
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int buf_idx; |
|
|
|
|
int buf_len_per_hex = 54; // NOTE: 3 * 3 * 6
|
|
|
|
|
for (int i = 0; i < (int) hexes->size(); i++) |
|
|
|
|
{ |
|
|
|
|
buf_idx = i * buf_len_per_hex; |
|
|
|
|
hex_info hxi = (*hexes)[i]; |
|
|
|
|
GLfloat color = (GLfloat) hxi.current_color / (GLfloat) UINT32_MAX; |
|
|
|
|
|
|
|
|
|
for (int j = 0; j < buf_len_per_hex; j++) |
|
|
|
|
{ |
|
|
|
|
buf[buf_idx + j] = color; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
struct
|
|
|
|
|
typedef struct clear_col |
|
|
|
|
{ |
|
|
|
|
real32 R = 75.0f / 255.0f; |
|
|
|
|
real32 G = 135.0f / 255.0f; |
|
|
|
|
real32 B = 135.0f / 255.0f; |
|
|
|
|
real32 A = 1; |
|
|
|
|
} gl_clear_color; |
|
|
|
|
real32 R; |
|
|
|
|
real32 G; |
|
|
|
|
real32 B; |
|
|
|
|
real32 A; |
|
|
|
|
} clear_col; |
|
|
|
|
clear_col g_clear_col { 75.f / 255.f, 135.f / 255.f, 135.f / 255.f, 1.f }; |
|
|
|
|
|
|
|
|
|
void |
|
|
|
|
openglDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, |
|
|
|
|
@ -289,56 +394,56 @@ openglDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity,
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void |
|
|
|
|
renderFrame(const vector<hex_info> *hexes) |
|
|
|
|
renderFrame(std::vector<hex_info> *hexes) |
|
|
|
|
{ |
|
|
|
|
glClearColor(gl_clear_color.R, gl_clear_color.G, gl_clear_color.B, |
|
|
|
|
gl_clear_color.A); |
|
|
|
|
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); |
|
|
|
|
|
|
|
|
|
glUseProgram(g_programID); |
|
|
|
|
|
|
|
|
|
// Send our transformation to the currently bound shader,
|
|
|
|
|
// in the "g_MVP" uniform
|
|
|
|
|
#if 1 |
|
|
|
|
glUseProgram(g_hex_programID); |
|
|
|
|
// Send our transformation to the currently bound shader, in the "g_MVP" uniform
|
|
|
|
|
glUniformMatrix4fv(g_matrixID, 1, GL_FALSE, &g_MVP[0][0]); |
|
|
|
|
|
|
|
|
|
// 1st attribute buffer : vertices
|
|
|
|
|
glEnableVertexAttribArray(0); |
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, g_vertexbuffer); |
|
|
|
|
glVertexAttribPointer( |
|
|
|
|
0, // attribute 0. No particular reason for 0, but must match the layout in the shader.
|
|
|
|
|
3, // size
|
|
|
|
|
GL_FLOAT, // type
|
|
|
|
|
GL_FALSE, // normalized?
|
|
|
|
|
0, // stride
|
|
|
|
|
(void*)0 // array buffer offset
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*) 0); |
|
|
|
|
|
|
|
|
|
// 2nd attribute buffer : colors
|
|
|
|
|
glEnableVertexAttribArray(1); |
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, g_color_buffer); |
|
|
|
|
glVertexAttribPointer( |
|
|
|
|
1, |
|
|
|
|
3, |
|
|
|
|
GL_FLOAT, |
|
|
|
|
GL_FALSE, |
|
|
|
|
0, |
|
|
|
|
(void*)0 |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (void*) 0); |
|
|
|
|
// get new colors every frame
|
|
|
|
|
fillColorBuffer(g_color_buf_data, int(g_buf_size)); |
|
|
|
|
fillColorBuffer(g_color_buf_data, (int) g_buf_size, hexes); |
|
|
|
|
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(GLfloat) * g_buf_size, g_color_buf_data); |
|
|
|
|
|
|
|
|
|
glDrawArrays(GL_TRIANGLES, 0, g_vertex_buffer_triangle_count); |
|
|
|
|
glDisableVertexAttribArray(0); |
|
|
|
|
glDisableVertexAttribArray(1); |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
#if 1 |
|
|
|
|
glUseProgram(g_line_programID); |
|
|
|
|
// Send our transformation to the currently bound shader, in the "g_MVP" uniform
|
|
|
|
|
glUniformMatrix4fv(g_matrixID, 1, GL_FALSE, &g_MVP[0][0]); |
|
|
|
|
|
|
|
|
|
// 1st attribute buffer : vertices
|
|
|
|
|
GLuint attrib_index = 0; // TODO: line buffer doesn't render if this is anything other than 0
|
|
|
|
|
glEnableVertexAttribArray(attrib_index); |
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, g_hex_line_vertexbuffer); |
|
|
|
|
glVertexAttribPointer(attrib_index, 3, GL_FLOAT, GL_FALSE, 0, (void*) 0); |
|
|
|
|
|
|
|
|
|
glDrawArrays(GL_LINES, 0, g_line_buf_size / 3); |
|
|
|
|
#endif |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void |
|
|
|
|
freeBuffers() |
|
|
|
|
{ |
|
|
|
|
free(g_color_buf_data); |
|
|
|
|
g_color_buf_data = 0; |
|
|
|
|
if (g_color_buf_data) |
|
|
|
|
{ |
|
|
|
|
free(g_color_buf_data); |
|
|
|
|
g_color_buf_data = 0; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#endif // RENDERER_H
|
|
|
|
|
|