You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
631 lines
18 KiB
631 lines
18 KiB
|
|
#include <vector> |
|
#include <cmath> // trig functions |
|
#include <cstdlib> // calloc |
|
|
|
#include <GL/gl3w.h> |
|
#if defined (_WIN32) |
|
#include <SDL.h> |
|
#else |
|
#include <SDL2/SDL.h> |
|
#endif |
|
#include <SDL_image.h> |
|
#include <glm/glm.hpp> |
|
#include <glm/geometric.hpp> |
|
#include <glm/gtc/matrix_transform.hpp> |
|
|
|
#include "aixlog.hpp" |
|
|
|
#include "hexlib.h" |
|
#include "renderer.h" |
|
#include "render_group.h" |
|
|
|
#define MOVE_SPEED 5.f |
|
#define ROTATE_SPEED 0.005f |
|
#define CAMERA_Z_CLAMP_ANGLE 85.f |
|
//#define PROJ_TYPE ORTHOGRAPHIC |
|
#define PROJ_TYPE PERSPECTIVE |
|
#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 |
|
|
|
typedef struct clear_col |
|
{ |
|
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 }; |
|
|
|
typedef struct gl_matrix_info |
|
{ |
|
glm::mat4 projection; |
|
glm::mat4 view; |
|
glm::mat4 model; |
|
glm::mat4 MVP; |
|
} gl_matrix_info; |
|
|
|
|
|
// forward declarations |
|
void initMatrices(projection_type p); |
|
void openglDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, |
|
GLsizei length, const GLchar* message, const void* userParam); |
|
// TODO: move hex logic to new file |
|
bool initHexGridBuffers(std::vector<hex_info>* hexes); |
|
void fillTriangleBufferFromHex(GLfloat buf[], int idx, const hex_info &hex); |
|
void fillColorBuffer(GLfloat buf[], int len, std::vector<hex_info>* hexes); |
|
void fillHexLineBuffer(GLfloat buf[], int len, std::vector<hex_info>* hexes); |
|
|
|
|
|
// globals |
|
// TODO: store scene_matrices on camera object |
|
static gl_matrix_info g_scene_matrices; |
|
static render_group* g_filled_hex_render_group; |
|
static render_group* g_hex_line_render_group; |
|
static render_group* g_debug_render_group; |
|
static rg_shader_program g_default_shader; |
|
// NOTE: entity render_group pointers are kept in the entity struct |
|
static camera g_camera; |
|
// TODO: maybe keep all these globals in the render_state object? |
|
|
|
|
|
// interface |
|
|
|
// TODO: maybe make this a contructor for render_state? |
|
bool |
|
initRenderer(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(g_default_shader, vs_code, fs_code); |
|
|
|
utilSafeFree(vs_code); |
|
utilSafeFree(fs_code); |
|
|
|
rs->max_lights = MAX_LIGHTS; |
|
rs->lights = UTIL_ALLOC(rs->max_lights, rg_point_light); |
|
|
|
if (shader_error) { |
|
LOG(ERROR) << "Error initializing shader program\n"; |
|
return false; |
|
} |
|
|
|
return true; |
|
} |
|
|
|
void |
|
freeBuffers(render_state* rs) |
|
{ |
|
utilSafeFree(rs->lights); |
|
|
|
std::vector<render_group*> groups = { |
|
g_filled_hex_render_group, |
|
g_hex_line_render_group, |
|
g_debug_render_group, |
|
}; |
|
|
|
for (render_group* group : groups) |
|
rgFree(group); |
|
} |
|
|
|
bool |
|
addTexture(SDL_Handles &handles, const char * path) |
|
{ |
|
// testing |
|
LOG(INFO) << "Loading image: " << path << "\n"; |
|
SDL_Surface* image = IMG_Load(path); |
|
|
|
if (!image) |
|
{ |
|
LOG(ERROR) << "IMG_Load: " << IMG_GetError() << "\n"; |
|
return false; |
|
} |
|
|
|
GLuint tex_id; |
|
glGenTextures(1, &tex_id); |
|
glBindTexture(GL_TEXTURE_2D, tex_id); |
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); |
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image->w, image->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, image->pixels); |
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
|
|
|
// store opengl id in SDL_Surface.userdat |
|
image->userdata = (void*)(intptr_t) tex_id; |
|
handles.texSurfaces.push_back(image); |
|
|
|
return true; |
|
} |
|
|
|
camera& |
|
renGetCamera() |
|
{ |
|
return g_camera; |
|
} |
|
|
|
v2f |
|
getUnprojectedCoords(int32 x, int32 y, int32 vp_width, int32 vp_height) |
|
{ |
|
// NOTE: using depth buffer may not be as accurate as doing ray-cast |
|
GLfloat depth; |
|
glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth); |
|
glm::vec4 viewport = glm::vec4(0, 0, vp_width, vp_height); |
|
glm::vec3 wincoord = glm::vec3(x, y, depth); |
|
glm::vec3 vU = glm::unProject(wincoord, g_scene_matrices.view, g_scene_matrices.projection, viewport); |
|
v2f v(vU.x, vU.y); |
|
|
|
return v; |
|
} |
|
|
|
v3f |
|
getCameraPosition() |
|
{ |
|
return v3f(g_camera.position.x, g_camera.position.y, g_camera.position.z); |
|
} |
|
|
|
bool |
|
createScene(render_state* rs, std::vector<hex_info>* hexes, Entity* entities, uint32 entity_count) |
|
{ |
|
// entities |
|
|
|
for (uint i = 0; i < entity_count; i++) { |
|
rgInitEntity(&entities[i]); |
|
entities[i].ren_group->shader = g_default_shader; |
|
} |
|
|
|
// TODO: rename/alter this now that we init camera in sceneloader |
|
initMatrices(PROJ_TYPE); |
|
|
|
if (!initHexGridBuffers(hexes)) |
|
return false; |
|
|
|
// debug draw vertices |
|
|
|
uint debug_buf_len = 12; // 4 vertices, 3 floats per vertex |
|
g_debug_render_group = rgInitSingle(g_default_shader, debug_buf_len, true, 0, GL_LINE_LOOP); |
|
|
|
if (g_debug_render_group == nullptr) |
|
return false; |
|
|
|
gl_buffer& debug_vertex_buf = g_debug_render_group->render_objects[0]->vertex_buffer; |
|
gl_buffer& debug_color_buf = g_debug_render_group->render_objects[0]->color_buffer; |
|
gl_buffer& debug_normal_buf = g_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 |
|
moveCamera(bool up, bool left, bool down, bool right, bool forward, bool backward) |
|
{ |
|
if (!up && !left && !down && !right && !forward && !backward) |
|
return; |
|
|
|
glm::vec3 f = g_camera.forward; |
|
glm::vec3 u = g_camera.up; |
|
glm::vec3 old = g_camera.position; |
|
glm::vec3 &p = g_camera.position; |
|
glm::vec3 v(0.f); // normalized direction |
|
|
|
// TODO: still seems like we're adding magnitude when moving in 2 directions |
|
#if 0 |
|
if (forward) v = glm::normalize(v + f); |
|
if (backward) v = glm::normalize(v - f); |
|
if (up) v = glm::normalize(v + u); |
|
if (down) v = glm::normalize(v - u); |
|
if (left) v -= glm::normalize(glm::cross(f, u)); |
|
if (right) v -= glm::normalize(glm::cross(u, f)); |
|
#else |
|
if (forward) v += f; |
|
if (backward) v -= f; |
|
if (up) v += u; |
|
if (down) v -= u; |
|
if (left) v -= glm::cross(f, u); |
|
if (right) v -= glm::cross(u, f); |
|
#endif |
|
|
|
p += (v * MOVE_SPEED); |
|
glm::vec3 diff = old - p; |
|
g_scene_matrices.view = glm::translate(g_scene_matrices.view, diff); |
|
g_scene_matrices.MVP = g_scene_matrices.projection * g_scene_matrices.view * g_scene_matrices.model; |
|
} |
|
|
|
void |
|
rotateCamera(int32 xrel, int32 yrel) |
|
{ |
|
camera &c = g_camera; |
|
float &h = c.hAngle; |
|
float &v = c.vAngle; |
|
h += ROTATE_SPEED * xrel; |
|
v -= ROTATE_SPEED * yrel; |
|
|
|
// clamp vAngle to prevent gimbal lock |
|
float a = glm::radians(CAMERA_Z_CLAMP_ANGLE); |
|
if (v < (-1 * a)) v = (-1 * a); |
|
if (v > a) v = a; |
|
|
|
c.forward = glm::vec3( |
|
glm::cos(v) * glm::sin(h), |
|
glm::cos(v) * glm::cos(h), |
|
glm::sin(v) |
|
); |
|
|
|
glm::normalize(c.forward); |
|
c.up = glm::vec3(0,0,1); |
|
c.left = glm::normalize(glm::cross(c.forward, c.up)); |
|
c.up = glm::normalize(glm::cross(c.left, c.forward)); |
|
|
|
g_scene_matrices.view = glm::lookAt(c.position, c.position + c.forward, c.up); |
|
g_scene_matrices.MVP = g_scene_matrices.projection * g_scene_matrices.view * g_scene_matrices.model; |
|
} |
|
|
|
// NOTE: don't need this yet |
|
void |
|
rollCamera(bool CW, bool CCW) |
|
{ |
|
#if 0 |
|
if ((!CW && !CCW) || (CW && CCW)) |
|
return; |
|
|
|
float a = 0.005f; |
|
if (CW) a *= 1; |
|
if (CCW) a *= -1; |
|
camera &c = g_camera; |
|
glm::mat4 m = glm::rotate(glm::mat4(1.f), a, c.forward); |
|
glm::vec4 v(c.up.x, c.up.y, c.up.z, 0); |
|
v = v * m; |
|
g_camera.up = glm::vec3(v.x, v.y, v.z); |
|
g_scene_matrices.view *= m; |
|
g_scene_matrices.MVP = g_scene_matrices.projection * g_scene_matrices.view * g_scene_matrices.model; |
|
#endif |
|
} |
|
|
|
void |
|
renderFrame(render_state* rs, std::vector<hex_info> *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 = g_scene_matrices.model; |
|
glm::mat4 m_view = g_scene_matrices.view; |
|
glm::mat4 m_projection = g_scene_matrices.projection; |
|
|
|
// filled hexes |
|
|
|
// get new colors every frame |
|
render_group* rg = g_filled_hex_render_group; |
|
gl_buffer& color_buf = rg->render_objects[0]->color_buffer; |
|
// TODO: this needs optimization for large grids, very performance intensive |
|
fillColorBuffer(color_buf.buffer, color_buf.buffer_len, hexes); |
|
rgDraw(rg, m_model, m_view, m_projection, |
|
rs->lights, rs->num_lights, false, true); |
|
|
|
// hex lines |
|
rgDraw(g_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 |
|
renderDebug(render_state* rs, std::vector<Point> &vertices) |
|
{ |
|
GLfloat* buf = g_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(g_debug_render_group, g_scene_matrices.model, g_scene_matrices.view, |
|
g_scene_matrices.projection, rs->lights, rs->num_lights, true); |
|
} |
|
|
|
|
|
// internal |
|
|
|
void |
|
initMatrices(projection_type p) |
|
{ |
|
// TODO: many constants used here should be passed as args |
|
|
|
if (p == PERSPECTIVE) |
|
{ |
|
// TODO: replace referernces to g_scene_matrices with camera.matrix_name |
|
g_scene_matrices.projection = g_camera.projection; |
|
g_scene_matrices.view = g_camera.view; |
|
//g_scene_matrices.model = g_camera.model; |
|
//g_scene_matrices.MVP = g_camera.MVP; |
|
#if 0 |
|
g_scene_matrices.projection = glm::infinitePerspective( |
|
glm::radians(60.f), // FoV |
|
16.f / 9.f, // ascpect ratio |
|
0.1f // near clip plane |
|
); |
|
|
|
g_camera.position = glm::vec3(640,0,100); |
|
g_camera.target = glm::vec3(640,500,0); |
|
//g_camera.target = glm::vec3(0,0,0); |
|
// inital rotation should match target direction |
|
glm::vec3 &p = g_camera.position; |
|
glm::vec3 &t = g_camera.target; |
|
g_camera.hAngle = 0; |
|
g_camera.vAngle = glm::atan((t.z - p.z) / (t.y - p.y)); |
|
|
|
////// |
|
// TODO: add call to rotate camera here to remove duplicate code |
|
camera &c = g_camera; |
|
float &h = c.hAngle; |
|
float &v = c.vAngle; |
|
c.forward = glm::vec3( |
|
glm::cos(v) * glm::sin(h), |
|
glm::cos(v) * glm::cos(h), |
|
glm::sin(v) |
|
); |
|
|
|
glm::normalize(c.forward); |
|
////// |
|
|
|
g_camera.up = glm::vec3(0,1,0); |
|
g_camera.left = glm::normalize(glm::cross(g_camera.up, g_camera.forward)); |
|
g_camera.up = glm::normalize(glm::cross(g_camera.forward, g_camera.left)); |
|
|
|
g_scene_matrices.view = glm::lookAt( |
|
g_camera.position, // camera position |
|
g_camera.position + g_camera.forward, |
|
g_camera.up // "up" vector |
|
); |
|
#endif |
|
} |
|
else // ORTHO |
|
{ |
|
// left, right, bottom, top, zNear, zFar |
|
g_scene_matrices.projection = glm::ortho(0.f, 1280.0f, 0.f, 720.0f, 0.1f, 100.0f); |
|
g_scene_matrices.view = glm::lookAt( |
|
glm::vec3(0.0f, 0.0f, 1.0f), // camera position |
|
glm::vec3(0.0f, 0.0f, 0.0f), // look at position |
|
glm::vec3(0,1,0) // "up" vector |
|
); |
|
} |
|
|
|
g_scene_matrices.model = glm::mat4(1.0f); |
|
g_scene_matrices.MVP = g_scene_matrices.projection * g_scene_matrices.view * g_scene_matrices.model; |
|
} |
|
|
|
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"; |
|
} |
|
|
|
// TODO: move hex logic to new file |
|
bool |
|
initHexGridBuffers(std::vector<hex_info>* hexes) |
|
{ |
|
// TODO: index duplicate vertices |
|
// 6 triangles * 3 vertices per triangle * 3 floats per vertex = 54 |
|
uint line_vertices_per_hex = 6 * 2; // 12 vertices since we're using line segments atm |
|
uint line_buf_len = hexes->size() * line_vertices_per_hex * 3; // 3 floats per vertex |
|
uint vbuf_len = hexes->size() * 6 * 3 * 3; |
|
|
|
g_filled_hex_render_group = rgInitSingle(g_default_shader, vbuf_len, true); |
|
|
|
if (g_filled_hex_render_group == nullptr) |
|
return false; |
|
|
|
gl_buffer& vbuf = g_filled_hex_render_group->render_objects[0]->vertex_buffer; |
|
gl_buffer& cbuf = g_filled_hex_render_group->render_objects[0]->color_buffer; |
|
gl_buffer& normal_buf = g_filled_hex_render_group->render_objects[0]->normal_buffer; |
|
|
|
for (uint i = 0; i < hexes->size(); i++) |
|
fillTriangleBufferFromHex(vbuf.buffer, i * 54, (*hexes)[i]); |
|
|
|
rgBufferData(&vbuf, GL_DYNAMIC_DRAW, GL_ARRAY_BUFFER); |
|
fillColorBuffer(cbuf.buffer, vbuf_len, hexes); |
|
rgBufferData(&cbuf, GL_DYNAMIC_DRAW, GL_ARRAY_BUFFER); |
|
|
|
// cheat at vertex normals since all hexes lay flat on z-axis |
|
|
|
for (uint i = 0; i < vbuf_len; i += 3) { |
|
normal_buf.buffer[i] = 0.f; |
|
normal_buf.buffer[i + 1] = 0.f; |
|
normal_buf.buffer[i + 2] = 1.f; |
|
} |
|
rgBufferData(&normal_buf, GL_STATIC_DRAW, GL_ARRAY_BUFFER); |
|
|
|
// hex lines |
|
|
|
g_hex_line_render_group = rgInitSingle(g_default_shader, line_buf_len, true, 0, GL_LINES); |
|
|
|
if (g_hex_line_render_group == nullptr) |
|
return false; |
|
|
|
gl_buffer& line_buf = g_hex_line_render_group->render_objects[0]->vertex_buffer; |
|
gl_buffer& line_color_buf = g_hex_line_render_group->render_objects[0]->color_buffer; |
|
gl_buffer& line_normal_buf = g_hex_line_render_group->render_objects[0]->normal_buffer; |
|
fillHexLineBuffer(line_buf.buffer, line_buf_len, hexes); |
|
rgBufferData(&line_buf, GL_STATIC_DRAW, GL_ARRAY_BUFFER); |
|
|
|
for (uint i = 0; i < line_buf_len; i++) |
|
line_color_buf.buffer[i] = 0.f; |
|
|
|
rgBufferData(&line_color_buf, GL_STATIC_DRAW, GL_ARRAY_BUFFER); |
|
|
|
for (uint i = 0; i < line_buf_len; i += 3) { |
|
line_normal_buf.buffer[i] = 0.f; |
|
line_normal_buf.buffer[i + 1] = 0.f; |
|
line_normal_buf.buffer[i + 2] = 1.f; |
|
} |
|
|
|
rgBufferData(&line_normal_buf, GL_STATIC_DRAW, GL_ARRAY_BUFFER); |
|
|
|
return true; |
|
} |
|
|
|
void |
|
fillTriangleBufferFromHex(GLfloat buf[], int idx, const hex_info &hex) |
|
{ |
|
// triangles |
|
for (int i = 0; i < 6; i++) |
|
{ |
|
// vertex 0 |
|
buf[idx + 0] = (GLfloat) hex.XPos; |
|
buf[idx + 1] = (GLfloat) hex.YPos; |
|
buf[idx + 2] = (GLfloat) 0.f; |
|
|
|
// vertex 1 |
|
buf[idx + 3] = (GLfloat) hex.vertices[i].x; |
|
buf[idx + 4] = (GLfloat) hex.vertices[i].y; |
|
buf[idx + 5] = (GLfloat) 0.f; |
|
|
|
if (i == 5) // re-use the first point for the last triangle |
|
{ |
|
// vertex 2 |
|
buf[idx + 6] = (GLfloat) hex.vertices[0].x; |
|
buf[idx + 7] = (GLfloat) hex.vertices[0].y; |
|
buf[idx + 8] = (GLfloat) 0.f; |
|
} |
|
else |
|
{ |
|
// vertex 2 |
|
buf[idx + 6] = (GLfloat) hex.vertices[i + 1].x; |
|
buf[idx + 7] = (GLfloat) hex.vertices[i + 1].y; |
|
buf[idx + 8] = (GLfloat) 0.f; |
|
} |
|
|
|
// we've added 9 GLfloats per loop |
|
idx += 9; |
|
} |
|
} |
|
|
|
void |
|
fillColorBuffer(GLfloat buf[], int len, std::vector<hex_info>* hexes) |
|
{ |
|
int buf_idx; |
|
int buf_len_per_hex = 54; // NOTE: 3 * 3 * 6 |
|
GLfloat color_buf[3]; |
|
for (int i = 0; i < (int) hexes->size(); i++) |
|
{ |
|
buf_idx = i * buf_len_per_hex; |
|
hex_info hxi = (*hexes)[i]; |
|
// TODO: check performance of this since we call multiple times per frame |
|
// maybe can cache glfloat triplets somewhere |
|
utilConvertColor(color_buf, hxi.current_color); |
|
|
|
for (int j = 0; j < buf_len_per_hex; j+=3) |
|
{ |
|
buf[buf_idx + j] = color_buf[0]; |
|
buf[buf_idx + j + 1] = color_buf[1]; |
|
buf[buf_idx + j + 2] = color_buf[2]; |
|
} |
|
} |
|
} |
|
|
|
void |
|
fillHexLineBuffer(GLfloat buf[], int len, std::vector<hex_info>* hexes) |
|
{ |
|
Point p1, p2; |
|
int idx = 0; |
|
for (int i = 0; i < (int) hexes->size(); i++) |
|
{ |
|
hex_info hxi = (*hexes)[i]; |
|
for (int j = 0; j < 6; j ++) |
|
{ |
|
if (j == 5) // wrap |
|
{ |
|
p1 = hxi.vertices[j]; |
|
p2 = hxi.vertices[0]; |
|
} |
|
else |
|
{ |
|
p1 = hxi.vertices[j]; |
|
p2 = hxi.vertices[j + 1]; |
|
} |
|
|
|
buf[idx + 0] = p1.x; |
|
buf[idx + 1] = p1.y; |
|
buf[idx + 2] = 0.f; |
|
buf[idx + 3] = p2.x; |
|
buf[idx + 4] = p2.y; |
|
buf[idx + 5] = 0.f; |
|
idx += 6; |
|
} |
|
} |
|
}
|
|
|