307 lines
10 KiB
C
307 lines
10 KiB
C
#include <GL/glew.h>
|
|
#define GLFW_INCLUDE_NONE
|
|
#include <GLFW/glfw3.h>
|
|
|
|
#include <stdio.h>
|
|
#include <assert.h>
|
|
#include <math.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "hex_math.h"
|
|
#include "hex_debug.h"
|
|
|
|
|
|
char *read_entire_file(char *path)
|
|
{
|
|
FILE *f = fopen(path, "rb");
|
|
size_t length = 0;
|
|
char *buf = NULL;
|
|
if (f)
|
|
{
|
|
fseek(f, 0, SEEK_END);
|
|
length = (size_t)ftell(f);
|
|
fseek(f, 0, SEEK_SET);
|
|
if (length)
|
|
{
|
|
buf = malloc(length + 1);
|
|
fread(buf, 1, length, f);
|
|
buf[length] = '\0';
|
|
}
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
static void glfw_error_callback(int errcode, const char *description)
|
|
{
|
|
fprintf(stderr, "[GLFW ERROR][ERRCODE %d] %s\n", errcode, description);
|
|
}
|
|
|
|
void set_uniform4f(GLuint program_id, const char *name, vec4f value)
|
|
{
|
|
GLint location = glGetUniformLocation(program_id, name);
|
|
glUniform4f(location, value.x, value.y, value.z, value.w);
|
|
}
|
|
|
|
void set_uniform2f(GLuint program_id, const char *name, vec2f value)
|
|
{
|
|
GLint location = glGetUniformLocation(program_id, name);
|
|
glUniform2f(location, value.x, value.y);
|
|
}
|
|
|
|
void set_uniform4x4f(GLuint program_id, const char *name, mat4f value)
|
|
{
|
|
GLint location = glGetUniformLocation(program_id, name);
|
|
glUniformMatrix4fv(location, 1, GL_TRUE, &value.a0);
|
|
}
|
|
|
|
#define set_uniform(id, name, value) _Generic((value), \
|
|
vec4f: set_uniform4f, \
|
|
vec2f: set_uniform2f, \
|
|
mat4f: set_uniform4x4f)(id, name, value)
|
|
|
|
|
|
|
|
int main(void)
|
|
{
|
|
GLFWwindow *window;
|
|
|
|
if (!glfwInit()) return -1;
|
|
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
|
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
|
|
|
|
|
window = glfwCreateWindow(800, 800, "Hello Hex", NULL, NULL);
|
|
if (!window) return -1;
|
|
glfwMakeContextCurrent(window);
|
|
if (glewInit() != GLEW_OK) return -1;
|
|
|
|
glfwSetErrorCallback(glfw_error_callback);
|
|
|
|
// build and compile our shader program
|
|
// ------------------------------------
|
|
|
|
char * vertexShaderSource = read_entire_file("shaders/vertex.glsl");
|
|
char *fragmentShaderSource = read_entire_file("shaders/fragment.glsl");
|
|
|
|
// vertex shader
|
|
unsigned int vertex_shader = glCreateShader(GL_VERTEX_SHADER);
|
|
glShaderSource(vertex_shader, 1, &vertexShaderSource, NULL);
|
|
glCompileShader(vertex_shader);
|
|
// check for shader compile errors
|
|
int success;
|
|
char infoLog[512];
|
|
glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success);
|
|
if (!success)
|
|
{
|
|
glGetShaderInfoLog(vertex_shader, 512, NULL, infoLog);
|
|
fprintf(stderr, "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n %s\n", infoLog);
|
|
}
|
|
// fragment shader
|
|
unsigned int fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
|
|
glShaderSource(fragment_shader, 1, &fragmentShaderSource, NULL);
|
|
glCompileShader(fragment_shader);
|
|
// check for shader compile errors
|
|
if (!success)
|
|
{
|
|
glGetShaderInfoLog(fragment_shader, 512, NULL, infoLog);
|
|
fprintf(stderr, "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n %s\n", infoLog);
|
|
}
|
|
// link shaders
|
|
unsigned int shader_program = glCreateProgram();
|
|
glAttachShader(shader_program, vertex_shader);
|
|
glAttachShader(shader_program, fragment_shader);
|
|
glLinkProgram(shader_program);
|
|
// check for linking errors
|
|
glGetProgramiv(shader_program, GL_LINK_STATUS, &success);
|
|
if (!success) {
|
|
glGetShaderInfoLog(shader_program, 512, NULL, infoLog);
|
|
fprintf(stderr, "ERROR::SHADER::PROGRAM::COMPILATION_FAILED\n %s\n", infoLog);
|
|
}
|
|
glDeleteShader(vertex_shader);
|
|
glDeleteShader(fragment_shader);
|
|
|
|
|
|
vec4f background_color;
|
|
background_color.r = 0.1f;
|
|
background_color.g = 0.2f;
|
|
background_color.b = 0.3f;
|
|
background_color.a = 1.0f;
|
|
|
|
hexgrid_t grid;
|
|
grid.rows = 30;
|
|
grid.columns = 30;
|
|
grid.hexes = calloc(1, sizeof(hex_t) * grid.rows * grid.columns);
|
|
|
|
// Scale of hexagon relative to screen. A 1:1 hexagon would reach the entire horizontal space
|
|
float scale = 1.0f / 1.0f;
|
|
|
|
for (size_t i = 0; i < grid.columns; ++i)
|
|
{
|
|
for (size_t j = 0; j < grid.rows; ++j)
|
|
{
|
|
// Offset the X and Y coordinates of adjacent hexagons so they do not cut each other
|
|
float offset = 0.0f;
|
|
if (j % 2)
|
|
offset = (float)sint(1.0f/6);
|
|
|
|
grid.hexes[i*grid.rows+j].position.x = (0.0f + j*(1 + cost(1.0f/6)));
|
|
grid.hexes[i*grid.rows+j].position.y = (0.0f + i*(sint(1.0f/6))*2.0f) + offset;
|
|
grid.hexes[i*grid.rows+j].position.z = 0.0f;
|
|
|
|
grid.hexes[i*grid.rows+j].position.w = 1.0f;
|
|
log_debug("Position of hex %ld %ld is %f %f\n", i, j, grid.hexes[i*grid.rows+j].position.x, grid.hexes[i*grid.rows+j].position.y);
|
|
}
|
|
}
|
|
|
|
// Get OpenGL objects
|
|
for (size_t i = 0; i < grid.rows * grid.columns; ++i)
|
|
{
|
|
hex_t *hex = &grid.hexes[i];
|
|
// VAO setup
|
|
glGenVertexArrays(1, &hex->vao);
|
|
glBindVertexArray(hex->vao);
|
|
|
|
// VBO setup
|
|
float *vertices = hex->vertices;
|
|
vertices[0] = hex->position.x * scale;
|
|
vertices[1] = hex->position.y * scale;
|
|
vertices[2] = hex->position.z;
|
|
log_debug("Adding vertex %f %f %f", vertices[0], vertices[1], vertices[2]);
|
|
for (int j = 1; j < 7; ++j)
|
|
{
|
|
vertices[j*3] = (hex->position.x + cost((j-1)/6.0f)) * scale;
|
|
vertices[j*3+1] = (hex->position.y + sint((j-1)/6.0f)) * scale;
|
|
vertices[j*3+2] = hex->position.z;
|
|
|
|
log_debug("Adding vertex %f %f %f", vertices[j*3], vertices[j*3+1], vertices[j*3+2]);
|
|
|
|
}
|
|
glGenBuffers(1,&hex->vbo);
|
|
glBindBuffer(GL_ARRAY_BUFFER, hex->vbo);
|
|
glBufferData(GL_ARRAY_BUFFER, 7*3*sizeof(float), vertices, GL_STATIC_DRAW);
|
|
|
|
// EBO setup
|
|
unsigned int *indices = hex->indices;
|
|
indices[0] = 0; indices[1] = 1; indices[2] = 2;
|
|
indices[3] = 0; indices[4] = 2; indices[5] = 3;
|
|
indices[6] = 0; indices[7] = 3; indices[8] = 4;
|
|
indices[9] = 0; indices[10] = 4; indices[11] = 5;
|
|
indices[12] = 0; indices[13] = 5; indices[14] = 6;
|
|
indices[15] = 0; indices[16] = 6; indices[17] = 1;
|
|
glGenBuffers(1,&hex->ebo);
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, hex->ebo);
|
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6*3 * sizeof(unsigned int), indices, GL_STATIC_DRAW);
|
|
|
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
|
|
glEnableVertexAttribArray(0);
|
|
}
|
|
|
|
|
|
//glBindVertexArray(0);
|
|
//glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
//glBindVertexArray(0);
|
|
|
|
camera_t camera = {};
|
|
camera.near = -0.1f;
|
|
camera.far = 1.0f;
|
|
camera.left = 0.0f;
|
|
camera.right = 600.0f;
|
|
camera.top = 0.0f;
|
|
camera.bottom = 600.0f;
|
|
|
|
while (!glfwWindowShouldClose(window))
|
|
{
|
|
// Camera logic
|
|
if (glfwGetKey(window, GLFW_KEY_A))
|
|
{
|
|
camera.right -= (camera.right - camera.left) * 0.01f;
|
|
camera.left -= (camera.right - camera.left) * 0.01f;
|
|
}
|
|
if (glfwGetKey(window, GLFW_KEY_D))
|
|
{
|
|
camera.right += (camera.right - camera.left) * 0.01f;
|
|
camera.left += (camera.right - camera.left) * 0.01f;
|
|
}
|
|
if (glfwGetKey(window, GLFW_KEY_W))
|
|
{
|
|
camera.top += (camera.bottom - camera.top) * 0.01f;
|
|
camera.bottom += (camera.bottom - camera.top) * 0.01f;
|
|
}
|
|
if (glfwGetKey(window, GLFW_KEY_S))
|
|
{
|
|
camera.top -= (camera.bottom - camera.top) * 0.01f;
|
|
camera.bottom -= (camera.bottom - camera.top) * 0.01f;
|
|
}
|
|
if (glfwGetKey(window, GLFW_KEY_Q))
|
|
{
|
|
float offset = (camera.right - camera.left)*0.02f;
|
|
camera.right -= offset;
|
|
camera.left += offset;
|
|
camera.top += offset;
|
|
camera.bottom -= offset;
|
|
}
|
|
if (glfwGetKey(window, GLFW_KEY_E))
|
|
{
|
|
float offset = (camera.right - camera.left)*0.05f;
|
|
camera.right += offset;
|
|
camera.left -= offset;
|
|
camera.top -= offset;
|
|
camera.bottom += offset;
|
|
}
|
|
if (glfwGetKey(window, GLFW_KEY_R))
|
|
{
|
|
camera.near = -0.1f;
|
|
camera.far = 1.0f;
|
|
camera.left = 0.0f;
|
|
camera.right = 400.0f;
|
|
camera.top = 0.0f;
|
|
camera.bottom = 400.0f;
|
|
}
|
|
|
|
int width, height;
|
|
glfwGetFramebufferSize(window, &width, &height);
|
|
glViewport(0, 0, width, height);
|
|
|
|
glClearColor(background_color.r, background_color.g, background_color.b, 1.0f);
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
glUseProgram(shader_program);
|
|
|
|
|
|
|
|
mat4f camera_matrix = ortho_matrix(camera.left, camera.right, camera.top, camera.bottom, camera.near, camera.far, width, height);
|
|
set_uniform(shader_program, "camera", camera_matrix);
|
|
|
|
vec2f window_size = { .x = (float)width, .y = (float)height };
|
|
set_uniform(shader_program, "window_size", window_size);
|
|
|
|
// For debugging
|
|
float aux;
|
|
glGetUniformfv(shader_program, glGetUniformLocation(shader_program, "window_size"), &aux);
|
|
|
|
for (size_t i = 0; i < grid.rows * grid.columns; ++i)
|
|
{
|
|
|
|
// Set uniforms
|
|
vec4f hex_color;
|
|
hex_color.r = (float)i / (grid.rows * grid.columns);
|
|
hex_color.g = (float)i / (grid.rows * grid.columns);
|
|
hex_color.b = (float)i / (grid.rows * grid.columns);
|
|
hex_color.a = 1.0f;
|
|
|
|
set_uniform(shader_program, "uniform_color", hex_color);
|
|
glBindVertexArray(grid.hexes[i].vao);
|
|
|
|
//log_debug("Binding VAO %d VBO %d EBO %d", grid.hexes[i].vao, grid.hexes[i].vbo, grid.hexes[i].ebo);
|
|
glBindBuffer(GL_ARRAY_BUFFER, grid.hexes[i].vbo);
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, grid.hexes[i].ebo);
|
|
glDrawElements(GL_TRIANGLES, 3*6, GL_UNSIGNED_INT, 0);
|
|
}
|
|
|
|
glfwPollEvents();
|
|
glfwSwapBuffers(window);
|
|
}
|
|
return 0;
|
|
}
|