4 changed files with 322 additions and 159 deletions
@ -0,0 +1,296 @@ |
|||||||
|
|
||||||
|
#ifndef RENDERER_H |
||||||
|
#define RENDERER_H |
||||||
|
|
||||||
|
#include <cstdlib> // malloc/calloc |
||||||
|
// TODO: remove for better logging
|
||||||
|
#include <iostream> // std::cout |
||||||
|
|
||||||
|
#include <GL/glew.h> |
||||||
|
#include <SDL2/SDL.h> |
||||||
|
#include <glm/glm.hpp> |
||||||
|
#include <glm/gtc/matrix_transform.hpp> |
||||||
|
|
||||||
|
#include "hexlib.h" |
||||||
|
#include "hexgame.h" |
||||||
|
|
||||||
|
|
||||||
|
// Interface
|
||||||
|
|
||||||
|
bool initRenderer(SDL_Handles &handles, v2i vpDims); |
||||||
|
void debugRender(HexDrawMode mode, hex_info *startHex, hex_info *currentHex); |
||||||
|
void render(const vector<hex_info> *hexes); |
||||||
|
|
||||||
|
|
||||||
|
// Implementation
|
||||||
|
|
||||||
|
GLuint initShaders(); |
||||||
|
// 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 parseHexToGLBuffer(GLfloat* buf, int idx, Point origin, vector<Point> &verts); |
||||||
|
|
||||||
|
GLuint g_vertexbuffer; |
||||||
|
GLuint g_vertex_buffer_triangle_count; |
||||||
|
GLuint g_programID; |
||||||
|
GLuint g_matrixID; |
||||||
|
glm::mat4 g_projection_matrix; |
||||||
|
glm::mat4 g_view_matrix; |
||||||
|
glm::mat4 g_model_matrix; |
||||||
|
glm::mat4 MVP; |
||||||
|
|
||||||
|
// TODO: could break this up into initGL(), initShaders(), initVertices(), initMatrices() ?
|
||||||
|
bool |
||||||
|
initRenderer(SDL_Handles &handles, v2i vpDims) |
||||||
|
{ |
||||||
|
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_GL_SetSwapInterval(1); // vsync
|
||||||
|
SDL_GetCurrentDisplayMode(0, &handles.currentDisplayMode); |
||||||
|
handles.window =
|
||||||
|
SDL_CreateWindow("hexgame", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, |
||||||
|
vpDims.x, vpDims.y, SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE); |
||||||
|
|
||||||
|
if (handles.window == NULL) |
||||||
|
{ |
||||||
|
// TODO: log error SDL_GetError()
|
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
handles.glContext = SDL_GL_CreateContext(handles.window); |
||||||
|
|
||||||
|
// Initialize GLEW
|
||||||
|
// glewExperimental is only needed in GLEW <= 1.13.0
|
||||||
|
// we can require version 2.0.0+
|
||||||
|
//glewExperimental = true; // Needed for core profile
|
||||||
|
GLenum err = glewInit(); |
||||||
|
if (err != GLEW_OK) { |
||||||
|
// TODO: better logging
|
||||||
|
std::cout << "Failed to initilize GLEW" << glewGetErrorString(err) << "\n"; |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
// TODO: better logging
|
||||||
|
// see what kind of context we got
|
||||||
|
std::cout << "opengl vendor: " << glGetString(GL_VENDOR) << "\n"; |
||||||
|
std::cout << "opengl renderer: " << glGetString(GL_RENDERER) << "\n"; |
||||||
|
std::cout << "opengl version: " << glGetString(GL_VERSION) << "\n"; |
||||||
|
|
||||||
|
// TODO: blending, these options break the http://www.opengl-tutorial.org tutorials atm
|
||||||
|
// Setup render state: alpha-blending enabled, polygon fill
|
||||||
|
#if 0 |
||||||
|
glEnable(GL_BLEND); |
||||||
|
glBlendEquation(GL_FUNC_ADD); |
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); |
||||||
|
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); |
||||||
|
#endif |
||||||
|
|
||||||
|
glEnable (GL_DEBUG_OUTPUT); |
||||||
|
glDebugMessageCallback((GLDEBUGPROC) openglDebugCallback, 0); |
||||||
|
g_programID = initShaders(); |
||||||
|
g_matrixID = glGetUniformLocation(g_programID, "MVP"); // shader variable for mvp xform
|
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
// TODO: figure out how to keep track of shader state, and pass in struct here
|
||||||
|
GLuint |
||||||
|
initShaders() |
||||||
|
{ |
||||||
|
GLuint VertexArrayID; |
||||||
|
glGenVertexArrays(1, &VertexArrayID); |
||||||
|
glBindVertexArray(VertexArrayID); |
||||||
|
|
||||||
|
const char * VertexShaderCode = |
||||||
|
"#version 330 core\n" |
||||||
|
"in vec3 vertexPosition_modelspace;\n" |
||||||
|
"uniform mat4 MVP;\n" |
||||||
|
"void main()\n" |
||||||
|
"{\n" |
||||||
|
" gl_Position = MVP * vec4(vertexPosition_modelspace, 1);\n" |
||||||
|
"}"; |
||||||
|
|
||||||
|
const char * FragmentShaderCode = |
||||||
|
"#version 330 core\n" |
||||||
|
"out vec3 color;\n" |
||||||
|
"void main()\n" |
||||||
|
"{\n" |
||||||
|
" color = vec3(0.5,0,0);\n" |
||||||
|
"}"; |
||||||
|
|
||||||
|
GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER); |
||||||
|
GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER); |
||||||
|
glShaderSource(VertexShaderID, 1, &VertexShaderCode, NULL); |
||||||
|
glShaderSource(FragmentShaderID, 1, &FragmentShaderCode, NULL); |
||||||
|
glCompileShader(VertexShaderID); |
||||||
|
glCompileShader(FragmentShaderID); |
||||||
|
|
||||||
|
GLuint programID = glCreateProgram(); |
||||||
|
glAttachShader(programID, VertexShaderID); |
||||||
|
glAttachShader(programID, FragmentShaderID); |
||||||
|
glLinkProgram(programID); |
||||||
|
|
||||||
|
glDetachShader(programID, VertexShaderID); |
||||||
|
glDetachShader(programID, FragmentShaderID); |
||||||
|
glDeleteShader(VertexShaderID); |
||||||
|
glDeleteShader(FragmentShaderID); |
||||||
|
|
||||||
|
return programID; |
||||||
|
} |
||||||
|
|
||||||
|
void |
||||||
|
createScene(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
|
||||||
|
); |
||||||
|
|
||||||
|
g_view_matrix = glm::lookAt( |
||||||
|
glm::vec3(0.0f, 0.0f, 2.0f), // camera position
|
||||||
|
glm::vec3(0.0f, 0.0f, 0.0f), // look at position
|
||||||
|
glm::vec3(0,1,0) // "up" vector
|
||||||
|
); |
||||||
|
|
||||||
|
g_model_matrix = glm::mat4(1.0f); |
||||||
|
MVP = g_projection_matrix * g_view_matrix * g_model_matrix;
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////
|
||||||
|
// Vertex Data
|
||||||
|
|
||||||
|
// 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
|
||||||
|
int buf_index = 54; |
||||||
|
size_t hex_count = hexes->size(); |
||||||
|
size_t buf_size = 6 * 9 * hex_count; |
||||||
|
GLfloat vbuf_data[buf_size] = { 0 }; |
||||||
|
|
||||||
|
for (int i = 0; i < (int) hex_count; i++) |
||||||
|
{ |
||||||
|
hex_info hxi = (*hexes)[i]; |
||||||
|
Point p(hxi.XPos, hxi.YPos); |
||||||
|
vector<Point> verts = hxi.vertices; |
||||||
|
parseHexToGLBuffer(vbuf_data, buf_index * i, p, verts); |
||||||
|
} |
||||||
|
|
||||||
|
g_vertex_buffer_triangle_count = buf_size / 3; |
||||||
|
|
||||||
|
glGenBuffers(1, &g_vertexbuffer); |
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, g_vertexbuffer); |
||||||
|
glBufferData(GL_ARRAY_BUFFER, sizeof(vbuf_data), vbuf_data, GL_STATIC_DRAW); |
||||||
|
} |
||||||
|
|
||||||
|
void |
||||||
|
parseHexToGLBuffer(GLfloat buf[], int idx, Point origin, vector<Point> &verts) |
||||||
|
{ |
||||||
|
int buf_idx = idx; |
||||||
|
// triangles
|
||||||
|
for (int i = 0; i < 6; i++) |
||||||
|
{ |
||||||
|
if (i == 5) // wrap
|
||||||
|
{ |
||||||
|
// vertex 0
|
||||||
|
buf[buf_idx + 0] = (GLfloat) origin.x; |
||||||
|
buf[buf_idx + 1] = (GLfloat) origin.y; |
||||||
|
buf[buf_idx + 2] = (GLfloat) 0.f; |
||||||
|
|
||||||
|
// vertex 1
|
||||||
|
buf[buf_idx + 3] = (GLfloat) verts[i].x; |
||||||
|
buf[buf_idx + 4] = (GLfloat) verts[i].y; |
||||||
|
buf[buf_idx + 5] = (GLfloat) 0.f; |
||||||
|
|
||||||
|
// vertex 1
|
||||||
|
buf[buf_idx + 6] = (GLfloat) verts[0].x; |
||||||
|
buf[buf_idx + 7] = (GLfloat) verts[0].y; |
||||||
|
buf[buf_idx + 8] = (GLfloat) 0.f; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
// vertex 0
|
||||||
|
buf[buf_idx + 0] = (GLfloat) origin.x; |
||||||
|
buf[buf_idx + 1] = (GLfloat) origin.y; |
||||||
|
buf[buf_idx + 2] = (GLfloat) 0.f; |
||||||
|
|
||||||
|
// vertex 1
|
||||||
|
buf[buf_idx + 3] = (GLfloat) verts[i].x; |
||||||
|
buf[buf_idx + 4] = (GLfloat) verts[i].y; |
||||||
|
buf[buf_idx + 5] = (GLfloat) 0.f; |
||||||
|
|
||||||
|
// vertex 1
|
||||||
|
buf[buf_idx + 6] = (GLfloat) verts[i + 1].x; |
||||||
|
buf[buf_idx + 7] = (GLfloat) verts[i + 1].y; |
||||||
|
buf[buf_idx + 8] = (GLfloat) 0.f; |
||||||
|
} |
||||||
|
|
||||||
|
// we've added 9 GLfloats per loop
|
||||||
|
buf_idx += 9; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
struct
|
||||||
|
{ |
||||||
|
real32 R = 75.0f / 255.0f; |
||||||
|
real32 G = 135.0f / 255.0f; |
||||||
|
real32 B = 135.0f / 255.0f; |
||||||
|
real32 A = 1; |
||||||
|
} gl_clear_color; |
||||||
|
|
||||||
|
void |
||||||
|
openglDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, |
||||||
|
GLsizei length, const GLchar* message, const void* userParam) |
||||||
|
{ |
||||||
|
// TODO: update error logging
|
||||||
|
std::cout << "openGLDebugCallback: "
|
||||||
|
<< (type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : "") |
||||||
|
<< ", type: " << type |
||||||
|
<< ", severity: " << severity |
||||||
|
<< ", message: " << message << "\n"; |
||||||
|
} |
||||||
|
|
||||||
|
void |
||||||
|
render(const vector<hex_info> *hexes) |
||||||
|
{ |
||||||
|
glClearColor(gl_clear_color.R, gl_clear_color.G, gl_clear_color.B, |
||||||
|
gl_clear_color.A); |
||||||
|
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); |
||||||
|
|
||||||
|
glUseProgram(g_programID); |
||||||
|
|
||||||
|
// Send our transformation to the currently bound shader,
|
||||||
|
// in the "MVP" uniform
|
||||||
|
glUniformMatrix4fv(g_matrixID, 1, GL_FALSE, &MVP[0][0]); |
||||||
|
|
||||||
|
// 1rst 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
|
||||||
|
); |
||||||
|
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, g_vertex_buffer_triangle_count); |
||||||
|
glDisableVertexAttribArray(0); |
||||||
|
} |
||||||
|
|
||||||
|
#endif // RENDERER_H
|
||||||
|
|
||||||
Loading…
Reference in new issue