Browse Source

new renderer for opengl programmable pipeline

master
dummy 9 years ago
parent
commit
5447534963
  1. 3
      src/Makefile
  2. 177
      src/hexgame.cpp
  3. 1
      src/hexgame.h
  4. 296
      src/renderer.h

3
src/Makefile

@ -1,6 +1,8 @@
CXXFLAGS = -std=c++11 -g -Wall
INCLUDES =
# libGLEW needs to be >= 2.0.0 to use opengl core context
# don't know a good way to require this in make without forcing a specific version
LDFLAGS = -lSDL2 -lGLEW -lGL
all:
@ -10,4 +12,3 @@ all:
clean:
rm ../bin/hexgame

177
src/hexgame.cpp

@ -34,12 +34,13 @@
#include <Winuser.h>
#endif
#include <SDL2/SDL.h>
#include <GL/glew.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_opengl.h>
#include "hexgame.h"
#include "hexlib.h"
#include "renderer.h"
//#include "gooey.h"
using std::string;
@ -68,127 +69,8 @@ uint32 line_color = 0xFFFFFFFF;
uint32 selected_fill_color = 0xF46000FF;
uint32 fill_color = 0x5C5C5CFF;
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
renderHexagon(vector<Point> &vertices, uint32 fillColor, uint32 lineColor)
{
glColor4ub(
uint8((fillColor & 0xFF000000) >> 24),
uint8((fillColor & 0x00FF0000) >> 16),
uint8((fillColor & 0x0000FF00) >> 8),
uint8((fillColor & 0x000000FF))
);
glBegin(GL_POLYGON);
glVertex3d(vertices[0].x, vertices[0].y, 0);
glVertex3d(vertices[1].x, vertices[1].y, 0);
glVertex3d(vertices[2].x, vertices[2].y, 0);
glVertex3d(vertices[3].x, vertices[3].y, 0);
glVertex3d(vertices[4].x, vertices[4].y, 0);
glVertex3d(vertices[5].x, vertices[5].y, 0);
glEnd();
glColor4ub(
uint8((lineColor & 0xFF000000) >> 24),
uint8((lineColor & 0x00FF0000) >> 16),
uint8((lineColor & 0x0000FF00) >> 8),
uint8((lineColor & 0x000000FF))
);
glLineWidth(1.0f);
glBegin(GL_LINE_LOOP);
glVertex3d(vertices[0].x, vertices[0].y, 0);
glVertex3d(vertices[1].x, vertices[1].y, 0);
glVertex3d(vertices[2].x, vertices[2].y, 0);
glVertex3d(vertices[3].x, vertices[3].y, 0);
glVertex3d(vertices[4].x, vertices[4].y, 0);
glVertex3d(vertices[5].x, vertices[5].y, 0);
glEnd();
}
void
setProjectionMatrix(int w, int h)
{
w = (w == 0) ? 1 : w; // don't divide by zero
h = (h == 0) ? 1 : h;
glMatrixMode(GL_PROJECTION);
real32 a = 2.0f / (real32) w;
real32 b = 2.0f / (real32) h;
real32 matrix[16] = {
a, 0, 0, 0,
0, b, 0, 0,
0, 0, 1, 0,
-1, -1, 0, 1,
};
glLoadMatrixf(matrix);
// TODO: Make helper function for glGetError(), also map codes to
// error strings
GLenum e = glGetError();
if (e != GL_NO_ERROR)
{
stringstream ss;
ss << "setProjectionMatrix(), GLerror: " << e;
debugLog(ss.str());
}
}
uint32
createRandomColor(uint8 alpha = 205)
{
// http://en.cppreference.com/w/cpp/numeric/random/uniform_int_distribution
// NOTE: gcc on mingw-w54 produces the same results every time without a
// non-deterministic source
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<int> uniI(0, 255);
uint32 color = (
(uniI(gen) << 24) // red
| (uniI(gen) << 16) // green
| (uniI(gen) << 8) // blue
| alpha // alpha
);
return color;
}
bool
InitGraphics(SDL_Handles &handles)
{
// TODO: pretty much all of these calls need error handling :(
SDL_Init(SDL_INIT_VIDEO);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
SDL_Window *window = SDL_CreateWindow("hexgame", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
viewportDims.x, viewportDims.y, SDL_WINDOW_OPENGL);
if (window == NULL) {
stringstream e;
e << "Could not create window: " << SDL_GetError();
debugLog(e.str());
return false;
}
handles.window = window;
handles.glContext = SDL_GL_CreateContext(window);
SDL_GL_SetSwapInterval(1); // vsync
// enable blending
glEnable (GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// init opengl projection/model matrices
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
setProjectionMatrix(viewportDims.x, viewportDims.y);
// TODO: Check for errors and return false
return true;
}
void
createScene()
createHexes(vector<hex_info> *hxi_array)
{
// create a hexagonal grid of hexagons
int map_radius = 7;
@ -209,7 +91,7 @@ createScene()
hxi.stored_color = hxi.current_color;
hxi.vertices = polygon_corners(global_layout, hxi.hex);
hxi.vertices.shrink_to_fit();
hexInfoArray->push_back(hxi);
hxi_array->push_back(hxi);
}
}
}
@ -221,7 +103,7 @@ hex_info *currentHex;
vector<hex_info> selectedHexes;
HexDrawMode globalDrawMode = NONE;
/*
// TODO: many globals used here
void
debugRender()
@ -264,34 +146,7 @@ debugRender()
}
}
}
void
render()
{
glClearColor(gl_clear_color.R, gl_clear_color.G, gl_clear_color.B,
gl_clear_color.A);
glClear(GL_COLOR_BUFFER_BIT);
// hexagons
for (hex_info hxi : *hexInfoArray)
{
renderHexagon(hxi.vertices, hxi.current_color,
(hxi.selected) ? selected_line_color : line_color);
}
debugRender();
//renderGooey(viewportDims);
// TODO: Make helper function for glGetError(), also map codes to
// error strings
GLenum e = glGetError();
if (e != GL_NO_ERROR)
{
stringstream ss;
ss << "render(), GLerror: " << e;
debugLog(ss.str());
}
}
*/
v2i
mapMouseToViewport(int32 x, int32 y)
@ -620,7 +475,7 @@ enterLoop(SDL_Handles &handles)
}
}
render();
render(hexInfoArray);
SDL_GL_SwapWindow(handles.window);
}
@ -648,8 +503,18 @@ int main(int argc, char* argv[])
#endif
{
hexInfoArray = new vector<hex_info>;
createHexes(hexInfoArray);
SDL_Handles handles;
if (InitGraphics(handles) == false)
if (SDL_Init(SDL_INIT_VIDEO) != 0)
{
stringstream ss;
ss << "Error, SDL_Init: " << SDL_GetError();
debugLog(ss.str());
return 1;
}
if (!initRenderer(handles, viewportDims))
{
stringstream ss;
ss << "Unable to initialize graphics, exiting";
@ -657,7 +522,8 @@ int main(int argc, char* argv[])
return 1;
}
/*
createScene(hexInfoArray);
#if 0
if (InitGooey(viewportDims) == false)
{
stringstream ss;
@ -665,9 +531,8 @@ int main(int argc, char* argv[])
debugLog(ss.str());
return 1;
}
*/
#endif
createScene();
enterLoop(handles);
cleanUp(handles);
delete hexInfoArray;

1
src/hexgame.h

@ -43,6 +43,7 @@ struct SDL_Handles
{
SDL_Window *window;
SDL_GLContext glContext;
SDL_DisplayMode currentDisplayMode;
std::vector<SDL_Surface*> texSurfaces;
};

296
src/renderer.h

@ -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…
Cancel
Save