aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compute_shader.h41
-rw-r--r--src/graphic_shader.h44
-rw-r--r--src/main.cc229
-rw-r--r--src/shader/compute.glsl2
-rw-r--r--src/texture_buffer.h53
-rw-r--r--src/util.h44
6 files changed, 258 insertions, 155 deletions
diff --git a/src/compute_shader.h b/src/compute_shader.h
new file mode 100644
index 0000000..298a454
--- /dev/null
+++ b/src/compute_shader.h
@@ -0,0 +1,41 @@
+#include "util.h"
+
+class ComputeShader {
+private:
+ const GLuint _id;
+
+public:
+ struct Guard {
+ const GLuint _id;
+
+ Guard(GLuint id): _id(id) {
+ glUseProgram(_id);
+ }
+ ~Guard() {
+ glUseProgram(0);
+ }
+ };
+
+ Guard use() {
+ return Guard(_id);
+ }
+
+ ComputeShader(const std::string& src):
+ _id(glCreateProgram()) {
+ glAttachShader(_id, util::compileShader(src, GL_COMPUTE_SHADER));
+ glLinkProgram(_id);
+ };
+ ~ComputeShader() {
+ glDeleteProgram(_id);
+ }
+
+ GLuint setUniform(const std::string& name, float x, float y) {
+ GLuint id = util::getUniform(_id, name);
+ glUniform2f(id, x, y);
+ return id;
+ }
+
+ void dispatch(std::size_t dimX) {
+ glDispatchCompute(dimX, 1, 1);
+ }
+};
diff --git a/src/graphic_shader.h b/src/graphic_shader.h
new file mode 100644
index 0000000..2dd8c41
--- /dev/null
+++ b/src/graphic_shader.h
@@ -0,0 +1,44 @@
+#include "util.h"
+
+class GraphicShader {
+private:
+ const GLuint _id;
+
+public:
+ struct Guard {
+ const GLuint _id;
+
+ Guard(GLuint id): _id(id) {
+ glUseProgram(_id);
+ }
+ ~Guard() {
+ glUseProgram(0);
+ }
+ };
+
+ Guard use() {
+ return Guard(_id);
+ }
+
+ GraphicShader(const std::string& vertex, const std::string fragment):
+ _id(glCreateProgram()) {
+ glAttachShader(_id, util::compileShader(vertex, GL_VERTEX_SHADER));
+ glAttachShader(_id, util::compileShader(fragment, GL_FRAGMENT_SHADER));
+ glLinkProgram(_id);
+ };
+ ~GraphicShader() {
+ glDeleteProgram(_id);
+ }
+
+ GLuint setUniform(const std::string& name, int value) {
+ GLuint id = util::getUniform(_id, name);
+ glUniform1i(id, value);
+ return id;
+ }
+
+ GLuint setUniform(const std::string& name, glm::mat4& M) {
+ GLuint id = util::getUniform(_id, name);
+ glUniformMatrix4fv(id, 1, GL_FALSE, &M[0][0]);
+ return id;
+ }
+};
diff --git a/src/main.cc b/src/main.cc
index 8a1d6de..c6945fb 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -8,6 +8,11 @@
#include <iostream>
#include <random>
#include <chrono>
+#include <memory>
+
+#include "graphic_shader.h"
+#include "compute_shader.h"
+#include "texture_buffer.h"
#include "shader/vertex.glsl"
#include "shader/fragment.glsl"
@@ -15,92 +20,11 @@
const std::size_t particle_count = 100000;
-GLint getUniform(GLuint program, const std::string& name) {
- const GLint uniform = glGetUniformLocation(program, name.c_str());
- if ( uniform == -1 ) {
- std::cerr << "Could not bind uniform " << name << std::endl;
- }
- return uniform;
-}
-
-GLint compileShader(const std::string& source, GLenum type) {
- GLint shader = glCreateShader(type);
-
- if ( !shader ) {
- std::cerr << "Cannot create a shader of type " << type << std::endl;
- exit(-1);
- }
-
- const char* source_data = source.c_str();
- const int source_length = source.size();
-
- glShaderSource(shader, 1, &source_data, &source_length);
- glCompileShader(shader);
-
- GLint compiled;
- glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
- if ( !compiled ) {
- std::cerr << "Cannot compile shader" << std::endl;
- GLint maxLength = 0;
- glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength);
- std::vector<GLchar> errorLog(maxLength);
- glGetShaderInfoLog(shader, maxLength, &maxLength, &errorLog[0]);
- for( auto c : errorLog ) {
- std::cerr << c;
- }
- std::cerr << std::endl;
- }
-
- return shader;
-}
-
-GLint setupShader() {
- GLint shader = glCreateProgram();
- glAttachShader(shader, compileShader(VERTEX_SHADER_CODE, GL_VERTEX_SHADER));
- glAttachShader(shader, compileShader(FRAGMENT_SHADER_CODE, GL_FRAGMENT_SHADER));
- glLinkProgram(shader);
- return shader;
-}
-
-GLint setupComputeShader() {
- GLint shader = glCreateProgram();
- glAttachShader(shader, compileShader(COMPUTE_SHADER_CODE, GL_COMPUTE_SHADER));
- glLinkProgram(shader);
- return shader;
-}
-
-GLint setupTextureShader() {
- GLint shader = glCreateProgram();
- glAttachShader(shader, compileShader(R"(
- #version 330 core
- layout (location = 0) in vec2 screen_vertex;
- layout (location = 1) in vec2 texture_vertex;
- out vec2 TexCoords;
-
- void main() {
- gl_Position = vec4(screen_vertex, 0.0, 1.0);
- TexCoords = texture_vertex;
- }
- )", GL_VERTEX_SHADER));
- glAttachShader(shader, compileShader(R"(
- #version 330 core
- out vec4 FragColor;
- in vec2 TexCoords;
- uniform sampler2D screen_texture;
-
- void main() {
- FragColor = texture(screen_texture, TexCoords);
- }
- )", GL_FRAGMENT_SHADER));
- glLinkProgram(shader);
- return shader;
-}
-
int window_width = 800;
int window_height = 600;
float world_width, world_height;
glm::mat4 MVP;
-GLuint FramebufferID;
+std::unique_ptr<TextureBuffer> textureBuffer;
void updateMVP() {
world_width = 20.f;
@@ -123,10 +47,7 @@ void window_size_callback(GLFWwindow*, int width, int height) {
window_width = width;
window_height = height;
- glBindFramebuffer(GL_FRAMEBUFFER, FramebufferID);
-
- glViewport(0, 0, width, height);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, window_width, window_height, 0, GL_RGB, GL_UNSIGNED_BYTE, (void*)0);
+ textureBuffer->resize(width, height);
updateMVP();
}
@@ -178,51 +99,43 @@ int main() {
glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);
- glGenFramebuffers(1, &FramebufferID);
- glBindFramebuffer(GL_FRAMEBUFFER, FramebufferID);
-
- GLuint TextureID;
- glGenTextures(1, &TextureID);
- glBindTexture(GL_TEXTURE_2D, TextureID);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, window_width, window_height, 0, GL_RGB, GL_UNSIGNED_BYTE, (void*)0);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, TextureID, 0);
+ updateMVP();
- if ( glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE ) {
- std::cerr << "Texture framebuffer error" << std::endl;
- return -1;
- }
+ textureBuffer = std::make_unique<TextureBuffer>(window_width, window_height);
- glClearColor(0.0f, 0.0f, 0.4f, 0.0f);
+ {
+ auto guard = textureBuffer->use();
- updateMVP();
+ glClearColor(0.0f, 0.0f, 0.4f, 0.0f);
+ }
- GLint ShaderID = setupShader();
- GLuint MatrixID = glGetUniformLocation(ShaderID, "MVP");
+ GraphicShader sceneShader(VERTEX_SHADER_CODE, FRAGMENT_SHADER_CODE);
+ sceneShader.setUniform("MVP", MVP);
- GLint ComputeShaderID = setupComputeShader();
- GLuint WorldID = glGetUniformLocation(ComputeShaderID, "world");
+ ComputeShader computeShader(COMPUTE_SHADER_CODE);
auto vertex_buffer_data = makeInitialParticles(particle_count);
GLuint VertexArrayID;
- glGenVertexArrays(1, &VertexArrayID);
- glBindVertexArray(VertexArrayID);
- glEnableVertexAttribArray(0);
-
GLuint VertexBufferID;
- glGenBuffers(1, &VertexBufferID);
- glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, VertexBufferID);
- glBufferData(
- GL_SHADER_STORAGE_BUFFER,
- vertex_buffer_data.size() * sizeof(GLfloat),
- vertex_buffer_data.data(),
- GL_STATIC_DRAW
- );
+ {
+ auto guard = textureBuffer->use();
- glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ glGenVertexArrays(1, &VertexArrayID);
+ glBindVertexArray(VertexArrayID);
+ glEnableVertexAttribArray(0);
+
+ glGenBuffers(1, &VertexBufferID);
+ glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, VertexBufferID);
+
+ glBufferData(
+ GL_SHADER_STORAGE_BUFFER,
+ vertex_buffer_data.size() * sizeof(GLfloat),
+ vertex_buffer_data.data(),
+ GL_STATIC_DRAW
+ );
+ }
GLuint QuadVertexArrayID;
glGenVertexArrays(1, &QuadVertexArrayID);
@@ -230,7 +143,7 @@ int main() {
GLuint QuadVertexBufferID;
glGenBuffers(1, &QuadVertexBufferID);
glBindBuffer(GL_ARRAY_BUFFER, QuadVertexBufferID);
- std::vector<GLfloat> quad_buffer_data{
+ const std::vector<GLfloat> quad_buffer_data{
-1.f, 1.f, 0.f, 1.f,
-1.f, -1.f, 0.f, 0.f,
1.f, -1.f, 1.f, 0.f,
@@ -246,56 +159,67 @@ int main() {
GL_STATIC_DRAW
);
glEnableVertexAttribArray(0);
- glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4*sizeof(GLfloat), (void*)0);
glEnableVertexAttribArray(1);
- glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4*sizeof(GLfloat), (void*)(2*sizeof(GLfloat)));
- GLuint TextureShaderID = setupTextureShader();
- GLuint ScreenTextureID = glGetUniformLocation(TextureShaderID, "screen_texture");
- glUniform1i(ScreenTextureID, 0);
+ GraphicShader displayShader(R"(
+ #version 330 core
+ layout (location = 0) in vec2 screen_vertex;
+ layout (location = 1) in vec2 texture_vertex;
+ out vec2 TexCoords;
+
+ void main() {
+ gl_Position = vec4(screen_vertex, 0.0, 1.0);
+ TexCoords = texture_vertex;
+ }
+ )", R"(
+ #version 330 core
+ out vec4 FragColor;
+ in vec2 TexCoords;
+ uniform sampler2D screen_texture;
+
+ void main() {
+ FragColor = texture(screen_texture, TexCoords);
+ }
+ )");
+ displayShader.setUniform("screen_texture", 0);
auto lastFrame = std::chrono::high_resolution_clock::now();
do {
- glBindFramebuffer(GL_FRAMEBUFFER, FramebufferID);
-
// update particles at most 50 times per second
if ( std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - lastFrame).count() >= 20 ) {
- glUseProgram(ComputeShaderID);
+ auto guard = computeShader.use();
- glUniform2f(WorldID, world_width, world_height);
- glDispatchCompute(particle_count, 1, 1);
-
- glUseProgram(0);
+ computeShader.setUniform("world", world_width, world_height);
+ computeShader.dispatch(particle_count);
lastFrame = std::chrono::high_resolution_clock::now();
}
- glUseProgram(ShaderID);
-
- glClear(GL_COLOR_BUFFER_BIT);
+ {
+ auto texGuard = textureBuffer->use();
+ auto sdrGuard = sceneShader.use();
- glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]);
+ glClear(GL_COLOR_BUFFER_BIT);
- glBindBuffer(GL_ARRAY_BUFFER, VertexBufferID);
- glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
- glDrawArrays(GL_POINTS, 0, 3*particle_count);
+ sceneShader.setUniform("MVP", MVP);
- glUseProgram(0);
-
- glBindFramebuffer(GL_FRAMEBUFFER, 0);
-
- glUseProgram(TextureShaderID);
+ glBindBuffer(GL_ARRAY_BUFFER, VertexBufferID);
+ glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
+ glDrawArrays(GL_POINTS, 0, 3*particle_count);
+ }
- glBindTexture(GL_TEXTURE_2D, TextureID);
- glBindBuffer(GL_ARRAY_BUFFER, QuadVertexBufferID);
- glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4*sizeof(GLfloat), (void*)0);
- glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4*sizeof(GLfloat), (void*)(2*sizeof(GLfloat)));
+ {
+ auto guard = displayShader.use();
- glClear(GL_COLOR_BUFFER_BIT);
- glDrawArrays(GL_TRIANGLES, 0, 6);
+ glBindTexture(GL_TEXTURE_2D, textureBuffer->getTexture());
+ glBindBuffer(GL_ARRAY_BUFFER, QuadVertexBufferID);
+ glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4*sizeof(GLfloat), (void*)0);
+ glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4*sizeof(GLfloat), (void*)(2*sizeof(GLfloat)));
- glUseProgram(0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glDrawArrays(GL_TRIANGLES, 0, 6);
+ }
glfwSwapBuffers(window);
glfwPollEvents();
@@ -306,9 +230,6 @@ int main() {
glDeleteBuffers(1, &VertexBufferID);
glDisableVertexAttribArray(0);
glDeleteVertexArrays(1, &VertexArrayID);
- glDeleteProgram(ShaderID);
- glDeleteProgram(ComputeShaderID);
- glDeleteFramebuffers(1, &FramebufferID);
glfwTerminate();
diff --git a/src/shader/compute.glsl b/src/shader/compute.glsl
index 8b1deab..58bf08b 100644
--- a/src/shader/compute.glsl
+++ b/src/shader/compute.glsl
@@ -22,7 +22,7 @@ void main() {
vec2 v = vec2(data[idx+0], data[idx+1]);
if ( data[idx+2] < 5. && insideWorld(v) ) {
- data[idx+0] += 0.01 * cos(v.x*cos(v.y));
+ data[idx+0] += 0.01 * cos(v.x*sin(v.y));
data[idx+1] += 0.01 * sin(v.x-v.y);
data[idx+2] += 0.01;
} else {
diff --git a/src/texture_buffer.h b/src/texture_buffer.h
new file mode 100644
index 0000000..851833c
--- /dev/null
+++ b/src/texture_buffer.h
@@ -0,0 +1,53 @@
+class TextureBuffer {
+private:
+ GLuint _id;
+ GLuint _texture;
+
+public:
+ struct Guard {
+ const GLuint _id;
+
+ Guard(GLuint id): _id(id) {
+ glBindFramebuffer(GL_FRAMEBUFFER, _id);
+ }
+ ~Guard() {
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ }
+ };
+
+ Guard use() {
+ return Guard(_id);
+ }
+
+ TextureBuffer(std::size_t width, std::size_t height) {
+ glGenFramebuffers(1, &_id);
+
+ auto guard = use();
+
+ glGenTextures(1, &_texture);
+ glBindTexture(GL_TEXTURE_2D, _texture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, (void*)0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _texture, 0);
+
+ if ( glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE ) {
+ std::cerr << "Texture framebuffer error" << std::endl;
+ }
+ }
+
+ ~TextureBuffer() {
+ glDeleteFramebuffers(1, &_id);
+ }
+
+ void resize(std::size_t width, std::size_t height) {
+ auto guard = use();
+
+ glViewport(0, 0, width, height);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, (void*)0);
+ }
+
+ GLuint getTexture() const {
+ return _texture;
+ }
+};
diff --git a/src/util.h b/src/util.h
new file mode 100644
index 0000000..ce8d012
--- /dev/null
+++ b/src/util.h
@@ -0,0 +1,44 @@
+#pragma once
+
+namespace util {
+
+GLint getUniform(GLuint program, const std::string& name) {
+ const GLint uniform = glGetUniformLocation(program, name.c_str());
+ if ( uniform == -1 ) {
+ std::cerr << "Could not bind uniform " << name << std::endl;
+ }
+ return uniform;
+}
+
+GLint compileShader(const std::string& source, GLenum type) {
+ GLint shader = glCreateShader(type);
+
+ if ( !shader ) {
+ std::cerr << "Cannot create a shader of type " << type << std::endl;
+ exit(-1);
+ }
+
+ const char* source_data = source.c_str();
+ const int source_length = source.size();
+
+ glShaderSource(shader, 1, &source_data, &source_length);
+ glCompileShader(shader);
+
+ GLint compiled;
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
+ if ( !compiled ) {
+ std::cerr << "Cannot compile shader" << std::endl;
+ GLint maxLength = 0;
+ glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength);
+ std::vector<GLchar> errorLog(maxLength);
+ glGetShaderInfoLog(shader, maxLength, &maxLength, &errorLog[0]);
+ for( auto c : errorLog ) {
+ std::cerr << c;
+ }
+ std::cerr << std::endl;
+ }
+
+ return shader;
+}
+
+}