wip: Basic spinning triangle demonstration
This commit is contained in:
parent
487dae631f
commit
d7996a991e
|
@ -1,6 +1,12 @@
|
||||||
add_executable(Exponent
|
add_executable(Exponent
|
||||||
main.cc
|
main.cc
|
||||||
|
GLProgramLoader.cc
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(Exponent PUBLIC glfw glm::glm)
|
target_link_libraries(Exponent PUBLIC glfw glm::glm)
|
||||||
target_include_directories(Exponent PUBLIC ${CMAKE_SOURCE_DIR}/include)
|
target_include_directories(Exponent PUBLIC ${CMAKE_SOURCE_DIR}/include)
|
||||||
|
|
||||||
|
target_compile_definitions(Exponent PRIVATE GLFW_INCLUDE_NONE)
|
||||||
|
|
||||||
|
file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/shaders/shader.frag" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/shaders/")
|
||||||
|
file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/shaders/shader.vert" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/shaders/")
|
|
@ -0,0 +1,81 @@
|
||||||
|
#include "GLProgramLoader.hh"
|
||||||
|
|
||||||
|
#include <exception>
|
||||||
|
#include <format>
|
||||||
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
static GLuint compile_shader(GLenum shader_type, const std::string &path) {
|
||||||
|
if (shader_type != GL_VERTEX_SHADER && shader_type != GL_FRAGMENT_SHADER) {
|
||||||
|
throw GLProgramException(std::format("Unsupported shader type {} provided.", shader_type));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that the path actually exists
|
||||||
|
std::ifstream shader_file_handle;
|
||||||
|
shader_file_handle.open(path);
|
||||||
|
|
||||||
|
if (!shader_file_handle.is_open()) {
|
||||||
|
throw GLProgramException(std::format("Failed to open path {}.", path));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the data in.
|
||||||
|
std::stringstream shader_source_stream;
|
||||||
|
shader_source_stream << shader_file_handle.rdbuf();
|
||||||
|
std::string shader_source_str = shader_source_stream.str();
|
||||||
|
const GLchar *shader_source = shader_source_str.c_str();
|
||||||
|
|
||||||
|
GLuint shader_id = glCreateShader(shader_type);
|
||||||
|
|
||||||
|
if (shader_id == 0) {
|
||||||
|
throw GLProgramException(std::format("Error when creating shader type {}.", shader_type));
|
||||||
|
}
|
||||||
|
|
||||||
|
glShaderSource(shader_id, 1, &shader_source, NULL);
|
||||||
|
glCompileShader(shader_id);
|
||||||
|
GLint did_compile;
|
||||||
|
glGetShaderiv(shader_id, GL_COMPILE_STATUS, &did_compile);
|
||||||
|
if(!did_compile) {
|
||||||
|
GLint len = 0;
|
||||||
|
|
||||||
|
glGetShaderiv(shader_id, GL_INFO_LOG_LENGTH, &len);
|
||||||
|
std::string error_log(len, ' ');
|
||||||
|
|
||||||
|
glGetShaderInfoLog(shader_id, len, &len, error_log.data());
|
||||||
|
|
||||||
|
glDeleteShader(shader_id);
|
||||||
|
throw GLProgramException(std::format("Shader {} compilation failed:\n{}", path, error_log));
|
||||||
|
}
|
||||||
|
|
||||||
|
return shader_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLuint compile_and_link_program(const std::vector<std::pair<GLuint, std::string>> &shaders) {
|
||||||
|
// Firstly, compile all the shaders and get all of their ids.
|
||||||
|
// I would love to use a functional map here, but C++ doesn't really do that.
|
||||||
|
std::vector<GLuint> shader_ids = {};
|
||||||
|
for(auto &s:shaders) {
|
||||||
|
shader_ids.push_back(compile_shader(s.first, s.second));
|
||||||
|
}
|
||||||
|
|
||||||
|
GLuint program_id = glCreateProgram();
|
||||||
|
for (auto &s:shader_ids) {
|
||||||
|
glAttachShader(program_id, s);
|
||||||
|
}
|
||||||
|
glLinkProgram(program_id);
|
||||||
|
|
||||||
|
GLint link_worked;
|
||||||
|
glGetProgramiv(program_id, GL_LINK_STATUS, &link_worked);
|
||||||
|
if (!link_worked) {
|
||||||
|
GLint len = 0;
|
||||||
|
glGetProgramiv(program_id, GL_INFO_LOG_LENGTH, &len);
|
||||||
|
|
||||||
|
std::string error_log(len, ' ');
|
||||||
|
|
||||||
|
glGetProgramInfoLog(program_id, len, &len, error_log.data());
|
||||||
|
|
||||||
|
glDeleteProgram(program_id);
|
||||||
|
throw GLProgramException(std::format("Program {} link failed:\n{}", program_id, error_log));
|
||||||
|
}
|
||||||
|
|
||||||
|
return program_id;
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "glad/gl.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <optional>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class GLProgramException : public std::exception {
|
||||||
|
std::string m_what;
|
||||||
|
public:
|
||||||
|
GLProgramException(const char *str):m_what(str) {
|
||||||
|
}
|
||||||
|
|
||||||
|
GLProgramException(const std::string &str):m_what(str) {
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual const char* what() const throw() {
|
||||||
|
return m_what.c_str();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
GLuint compile_and_link_program(const std::vector<std::pair<GLuint, std::string>> &shaders);
|
97
src/main.cc
97
src/main.cc
|
@ -1,9 +1,20 @@
|
||||||
#define GLAD_GL_IMPLEMENTATION
|
|
||||||
#include "glad/gl.h"
|
|
||||||
#define GLFW_INCLUDE_NONE
|
|
||||||
#include "GLFW/glfw3.h"
|
#include "GLFW/glfw3.h"
|
||||||
|
|
||||||
//http://seshbot.com/blog/2015/05/05/an-introduction-to-opengl-getting-started/
|
#include "GLProgramLoader.hh"
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
// This has to come last.
|
||||||
|
#define GLAD_GL_IMPLEMENTATION
|
||||||
|
#include <glad/gl.h>
|
||||||
|
|
||||||
|
static void dbg_log(const char* str) {
|
||||||
|
std::cout << str << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
static void key_callback(GLFWwindow *w, int key, int scancode, int action, int mods) {
|
static void key_callback(GLFWwindow *w, int key, int scancode, int action, int mods) {
|
||||||
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) {
|
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) {
|
||||||
|
@ -11,14 +22,74 @@ static void key_callback(GLFWwindow *w, int key, int scancode, int action, int m
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define VERTEX_SHADER_LOCATION "shaders/shader.vert"
|
||||||
|
#define FRAGMENT_SHADER_LOCATION "shaders/shader.frag"
|
||||||
|
|
||||||
|
GLuint g_program_id = 0;
|
||||||
|
|
||||||
|
static GLuint time_unif;
|
||||||
|
|
||||||
|
static void init_shaders() {
|
||||||
|
dbg_log("Initialising shaders");
|
||||||
|
|
||||||
|
const std::vector<std::pair<GLuint, std::string>> shaders = {
|
||||||
|
{GL_VERTEX_SHADER, VERTEX_SHADER_LOCATION},
|
||||||
|
{GL_FRAGMENT_SHADER, FRAGMENT_SHADER_LOCATION},
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
g_program_id = compile_and_link_program(shaders);
|
||||||
|
} catch (GLProgramException e) {
|
||||||
|
std::cerr << e.what() << std::endl;
|
||||||
|
} catch (...) {
|
||||||
|
std::cerr << "Unexpected exception while compiling shaders." << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
glUseProgram(g_program_id);
|
||||||
|
|
||||||
|
glGetUniformLocation(g_program_id, "time");
|
||||||
|
}
|
||||||
|
|
||||||
|
static const GLfloat verts[6] = {
|
||||||
|
0.0f, 0.0f, 0.0f, 0.5f, 0.5f, 0.0f
|
||||||
|
};
|
||||||
|
|
||||||
|
static GLuint vertex_buf;
|
||||||
|
static GLuint array_buf;
|
||||||
|
static const GLuint vertex_data_position = 0;
|
||||||
|
|
||||||
|
// Do the work of initialising opengl so we can draw stuff
|
||||||
|
static void init_opengl() {
|
||||||
|
dbg_log("Initialising opengl");
|
||||||
|
// Configure the context's capabilities
|
||||||
|
glClearColor(0.0, 0.0, 0.0, 1.0);
|
||||||
|
|
||||||
|
glGenVertexArrays(1, &array_buf);
|
||||||
|
glBindVertexArray(array_buf);
|
||||||
|
|
||||||
|
glGenBuffers(1, &vertex_buf);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, vertex_buf);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW);
|
||||||
|
|
||||||
|
|
||||||
|
init_shaders();
|
||||||
|
|
||||||
|
glVertexAttribPointer(vertex_data_position, 2, GL_FLOAT, GL_FALSE, 0, NULL);
|
||||||
|
glEnableVertexAttribArray(vertex_data_position);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
|
dbg_log("Initialising glfw");
|
||||||
// Initialise GLFW
|
// Initialise GLFW
|
||||||
if (!glfwInit()) {
|
if (!glfwInit()) {
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
||||||
|
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||||
|
|
||||||
// Create our context
|
// Create our context
|
||||||
GLFWwindow *w = glfwCreateWindow(640, 480, "Test", NULL, NULL);
|
GLFWwindow *w = glfwCreateWindow(640, 480, "Test", NULL, NULL);
|
||||||
if (!w) {
|
if (!w) {
|
||||||
|
@ -32,13 +103,7 @@ int main() {
|
||||||
// Set up the key handler
|
// Set up the key handler
|
||||||
glfwSetKeyCallback(w, key_callback);
|
glfwSetKeyCallback(w, key_callback);
|
||||||
|
|
||||||
// Configure the context's capabilities
|
init_opengl();
|
||||||
glClearColor(1.0, 0.0, 0.0, 1.0);
|
|
||||||
glEnable(GL_DEPTH_TEST);
|
|
||||||
glEnable(GL_BLEND); // Maybe this allows transparency?
|
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
||||||
|
|
||||||
// TODO: Actually make some opengl shit happen
|
|
||||||
|
|
||||||
// Main Loop
|
// Main Loop
|
||||||
while(!glfwWindowShouldClose(w)) {
|
while(!glfwWindowShouldClose(w)) {
|
||||||
|
@ -50,6 +115,14 @@ int main() {
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
float time = glfwGetTime();
|
||||||
|
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
|
glUniform1f(time_unif, time);
|
||||||
|
glBindVertexArray(array_buf);
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||||
|
|
||||||
// TODO Draw primitives
|
// TODO Draw primitives
|
||||||
|
|
||||||
glfwSwapBuffers(w);
|
glfwSwapBuffers(w);
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
#version 430 core
|
||||||
|
|
||||||
|
out vec4 f_color;
|
||||||
|
|
||||||
|
// All fragments are the same colour for now.
|
||||||
|
void main() {
|
||||||
|
f_color = vec4(1.0, 1.0, 1.0, 1.0);
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
#version 430 core
|
||||||
|
|
||||||
|
layout (location = 0) in vec4 v_position;
|
||||||
|
|
||||||
|
uniform float time;
|
||||||
|
|
||||||
|
// Simple passthrough shader for now.
|
||||||
|
void main() {
|
||||||
|
vec2 new_xy = v_position.xy * mat2x2(
|
||||||
|
cos(time), -sin(time),
|
||||||
|
sin(time), cos(time)
|
||||||
|
);
|
||||||
|
|
||||||
|
vec4 new_position = vec4(new_xy.x, new_xy.y, 0.0, 1.0);
|
||||||
|
|
||||||
|
gl_Position = new_position;
|
||||||
|
}
|
Loading…
Reference in New Issue