Added glm, fbo, shader, texture and texture generator

This commit is contained in:
2022-04-23 16:41:33 +03:00
parent 38af8d7336
commit 8290c32cda
17 changed files with 676 additions and 25 deletions
+3
View File
@@ -0,0 +1,3 @@
[submodule "lib/glm"]
path = lib/glm
url = git@github.com:g-truc/glm.git
+1
View File
@@ -9,6 +9,7 @@ find_package(OpenGL REQUIRED)
include_directories("src/")
include_directories("gl/include")
add_subdirectory(lib/glm EXCLUDE_FROM_ALL)
add_subdirectory(src)
add_executable(demo main.cpp gl/src/glad.c ${SOURCE})
Submodule
+1
Submodule lib/glm added at cc98465e35
-3
View File
@@ -1,6 +1,5 @@
#include "peripherals_glfw.h"
int main() {
acidrain::peripherals_glfw peripherals;
peripherals.init();
@@ -8,7 +7,6 @@ int main() {
glDisable(GL_DEPTH_TEST);
double alpha = 0.0;
// while (!glfwWindowShouldClose(window)) {
while (!peripherals.should_close()) {
alpha += 0.01;
if (alpha > 1.0) alpha = 0.0;
@@ -19,5 +17,4 @@ int main() {
peripherals.swap_buffers();
peripherals.poll_events();
}
}
+9
View File
@@ -1,11 +1,20 @@
set(HEADERS
${HEADERS}
${CMAKE_CURRENT_SOURCE_DIR}/colour.h
${CMAKE_CURRENT_SOURCE_DIR}/fbo.h
${CMAKE_CURRENT_SOURCE_DIR}/peripherals.h
${CMAKE_CURRENT_SOURCE_DIR}/peripherals_glfw.h
${CMAKE_CURRENT_SOURCE_DIR}/shader.h
${CMAKE_CURRENT_SOURCE_DIR}/texture.h
${CMAKE_CURRENT_SOURCE_DIR}/texture_generator.h
PARENT_SCOPE
)
set(SOURCE
${SOURCE}
${CMAKE_CURRENT_SOURCE_DIR}/fbo.cpp
${CMAKE_CURRENT_SOURCE_DIR}/peripherals_glfw.cpp
${CMAKE_CURRENT_SOURCE_DIR}/shader.cpp
${CMAKE_CURRENT_SOURCE_DIR}/texture.cpp
${CMAKE_CURRENT_SOURCE_DIR}/texture_generator.cpp
PARENT_SCOPE
)
+14
View File
@@ -0,0 +1,14 @@
#pragma once
#include <cstdint>
#include "glm/vec4.hpp"
typedef glm::vec4 colour;
inline uint32_t as_int(const glm::vec4 &col) {
unsigned char rr = static_cast<unsigned char>(col.r * 255);
unsigned char gg = static_cast<unsigned char>(col.g * 255);
unsigned char bb = static_cast<unsigned char>(col.b * 255);
unsigned char aa = static_cast<unsigned char>(col.a * 255);
return rr + (gg << 8) + (bb << 16) + (aa << 24);
}
+3
View File
@@ -1,5 +1,8 @@
#pragma once
#include <glad/glad.h>
#define BEGIN_NAMESPACE namespace acidrain {
#define END_NAMESPACE };
static int SCREEN_WIDTH = 800;
static int SCREEN_HEIGHT = 600;
+73
View File
@@ -0,0 +1,73 @@
#include "fbo.h"
#include <memory>
BEGIN_NAMESPACE
fbo::fbo(int w, int h)
: width(w),
height(h) {
glGenFramebuffers(1, &frame_buffer_id);
glGenTextures(1, &color_buffer_id);
glGenRenderbuffers(1, &depth_buffer_id);
glBindFramebuffer(GL_FRAMEBUFFER, frame_buffer_id);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, color_buffer_id);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE,
4, // number of samples for multisampling
GL_RGBA8,
width, height,
false);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, color_buffer_id,
0);
glBindRenderbuffer(GL_RENDERBUFFER, depth_buffer_id);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height);
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth_buffer_id);
}
int fbo::get_width() const {
return width;
}
int fbo::get_height() const {
return height;
}
GLuint fbo::get_color_buffer_id() const {
return color_buffer_id;
}
GLuint fbo::get_depth_buffer_id() const {
return depth_buffer_id;
}
void fbo::use() {
old_width = SCREEN_WIDTH;
old_height = SCREEN_HEIGHT;
SCREEN_WIDTH = width;
SCREEN_HEIGHT = height;
glBindFramebuffer(GL_FRAMEBUFFER, frame_buffer_id);
glViewport(0, 0, width, height);
}
void fbo::unuse() {
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0, 0, old_width, old_height);
SCREEN_WIDTH = old_width;
SCREEN_HEIGHT = old_height;
}
std::shared_ptr<texture> fbo::get_texture() {
return std::make_shared<texture>(color_buffer_id, width, height);
}
END_NAMESPACE
+36
View File
@@ -0,0 +1,36 @@
#pragma once
#include "texture.h"
#include <memory>
BEGIN_NAMESPACE
class fbo {
public:
explicit fbo(int width, int height);
~fbo() = default;
void use();
void unuse();
int get_width() const;
int get_height() const;
GLuint get_color_buffer_id() const;
GLuint get_depth_buffer_id() const;
std::shared_ptr<texture> get_texture();
private:
int width;
int height;
int old_width;
int old_height;
GLuint frame_buffer_id;
GLuint color_buffer_id;
GLuint depth_buffer_id;
};
END_NAMESPACE
-1
View File
@@ -1,6 +1,5 @@
#pragma once
#include "peripherals.h"
#include <glad/glad.h>
// forward declares
class GLFWwindow;
+114
View File
@@ -0,0 +1,114 @@
#include "shader.h"
#include <string>
#include <iostream>
#include <vector>
BEGIN_NAMESPACE
void check_compile_error(GLuint shaderId) {
GLint isCompiled = 0;
glGetShaderiv(shaderId, GL_COMPILE_STATUS, &isCompiled);
if (isCompiled == GL_FALSE) {
GLint maxLength = 0;
glGetShaderiv(shaderId, GL_INFO_LOG_LENGTH, &maxLength);
//The maxLength includes the NULL character
char errorLog[maxLength];
glGetShaderInfoLog(shaderId, maxLength, &maxLength, &errorLog[0]);
std::cout << "Shader error: " << errorLog << std::endl;
//Provide the infolog in whatever manor you deem best.
//Exit with failure.
glDeleteShader(shaderId); //Don't leak the shader.
}
}
shader::shader(const char *vs_content, const char *ps_content) {
shader_ids[0] = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(shader_ids[0], 1, &vs_content, nullptr);
glCompileShader(shader_ids[0]);
check_compile_error(shader_ids[0]);
shader_ids[1] = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(shader_ids[1], 1, &ps_content, nullptr);
glCompileShader(shader_ids[1]);
check_compile_error(shader_ids[1]);
program_id = glCreateProgram();
glAttachShader(program_id, shader_ids[0]);
glAttachShader(program_id, shader_ids[1]);
// TODO Adrian: these should come from an external enumeration
glBindAttribLocation(program_id, 0, "position");
glBindAttribLocation(program_id, 1, "normal");
glBindAttribLocation(program_id, 2, "texCoords");
glLinkProgram(program_id);
glUseProgram(program_id);
}
shader::~shader() {
glDetachShader(program_id, shader_ids[0]);
glDetachShader(program_id, shader_ids[1]);
glDeleteShader(shader_ids[0]);
glDeleteShader(shader_ids[1]);
glDeleteProgram(program_id);
}
void shader::use() const {
glUseProgram(program_id);
}
void shader::unuse() const {
glUseProgram(0);
}
int shader::getUniform(const char *uniformName) {
if (uniformCache.count(uniformName) == 0) {
uniformCache[uniformName] = glGetUniformLocation(program_id, uniformName);
}
return uniformCache[uniformName];
}
void shader::setMatrix3Uniform(float *matrix, const char *uniformName) {
GLint location = getUniform(uniformName);
if (location != -1)
glUniformMatrix3fv(location, 1, false, matrix);
}
void shader::setMatrix4Uniform(float *matrix, const char *uniformName) {
GLint location = getUniform(uniformName);
if (location != -1)
glUniformMatrix4fv(location, 1, false, matrix);
}
void shader::setVec3Uniform(float *value, const char *uniformName) {
GLint location = getUniform(uniformName);
if (location != -1)
glUniform3fv(location, 1, value);
}
void shader::setVec4Uniform(float *value, const char *uniformName) {
GLint location = getUniform(uniformName);
if (location != -1)
glUniform4fv(location, 1, value);
}
void shader::setIntUniform(int value, const char *uniformName) {
GLint location = getUniform(uniformName);
if (location != -1)
glUniform1i(location, value);
}
void shader::setFloatUniform(float value, const char *uniformName) {
GLint location = getUniform(uniformName);
if (location != -1)
glUniform1f(location, value);
}
END_NAMESPACE
+34
View File
@@ -0,0 +1,34 @@
#pragma once
#include "defines.h"
#include <map>
BEGIN_NAMESPACE
class shader {
public:
shader(const char *vs_content, const char *ps_content);
virtual ~shader();
void use() const;
void unuse() const;
GLuint getId() const { return program_id; }
int getUniform(const char *uniformName);
void setMatrix3Uniform(float *value, const char *uniformName);
void setMatrix4Uniform(float *value, const char *uniformName);
void setVec3Uniform(float *value, const char *uniformName);
void setVec4Uniform(float *value, const char *uniformName);
void setFloatUniform(float value, const char *uniformName);
void setIntUniform(int value, const char *uniformName);
private:
GLuint program_id;
GLuint shader_ids[2];
std::map<const char *, int> uniformCache;
};
END_NAMESPACE
+62
View File
@@ -0,0 +1,62 @@
#include "texture.h"
BEGIN_NAMESPACE
texture::texture(int w, int h, uint8_t *buffer)
: width(w),
height(h),
destroyable(true) {
glGenTextures(1, &id);
glBindTexture(GL_TEXTURE_2D, id);
// select modulate to mix texture with color for shading
// glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
// // only set this when we do have mipmaps
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// for versions up to 3
// glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
width, height,
0, GL_RGBA, GL_UNSIGNED_BYTE,
buffer);
}
texture::texture(GLuint id, int w, int h)
: id(id),
width(w),
height(h),
destroyable(false) {
}
texture::~texture() {
if (destroyable)
glDeleteTextures(1, &id);
}
int texture::get_width() const {
return width;
}
int texture::get_height() const {
return height;
}
void texture::use() const {
glBindTexture(GL_TEXTURE_2D, id);
}
void texture::unuse() const {
glBindTexture(GL_TEXTURE_2D, 0);
}
END_NAMESPACE
+27
View File
@@ -0,0 +1,27 @@
#pragma once
#include "peripherals.h"
BEGIN_NAMESPACE
class texture {
public:
texture(int width, int height, uint8_t *buffer);
texture(GLuint id, int width, int height);
virtual ~texture();
int get_width() const;
int get_height() const;
GLuint get_id() const { return id; }
void use() const;
void unuse() const;
private:
int width;
int height;
bool destroyable;
GLuint id = 0;
};
END_NAMESPACE
+232
View File
@@ -0,0 +1,232 @@
#include "texture_generator.h"
#include <cmath>
#include <memory>
BEGIN_NAMESPACE
texture_generator::texture_generator(uint16_t w, uint16_t h)
: width(w), height(h) {
for (auto &layer: layers)
layer = new uint8_t[width * height * 4];
}
texture_generator::~texture_generator() {
for (auto &layer: layers)
delete[] layer;
}
texture_generator &texture_generator::checker_board(uint8_t layer,
uint8_t block_size,
colour on,
colour off) {
auto *input = reinterpret_cast<uint32_t *>(layers[layer]);
uint32_t on_color = as_int(on);
uint32_t off_color = as_int(off);
for (auto y = 0; y < height; y++) {
for (auto x = 0; x < width; x++) {
bool in_block = (
((x % (2 * block_size)) < block_size) &&
((y % (2 * block_size)) < block_size)
);
*input++ = in_block ? on_color : off_color;
// *input++ = 0xffffffff;
}
}
return *this;
}
texture_generator &texture_generator::env_map(uint8_t layer, uint8_t size) {
auto *input = reinterpret_cast<uint32_t *>(layers[layer]);
colour col{1};
float size_squared = size * size;
for (uint16_t y = 0; y < height; y++) {
for (uint16_t x = 0; x < width; x++) {
int32_t rx = x - width / 2;
int32_t ry = y - height / 2;
float r_square = static_cast<float>(rx * rx + ry * ry);
if (r_square <= size_squared) {
float a = 1.0f - (r_square / size_squared);
col.r = col.g = col.b = a;
// col.a = 1;
} else {
col.r = col.g = col.b = 0;
// col.a = 1;
}
*input++ = as_int(col);
}
}
return *this;
}
texture_generator &texture_generator::lens(uint8_t layer, uint8_t size) {
auto *input = reinterpret_cast<uint32_t *>(layers[layer]);
colour col{0};
float size_squared = size * size;
float c;
for (uint16_t y = 0; y < height; y++) {
for (uint16_t x = 0; x < width; x++) {
int32_t rx = x - width / 2;
int32_t ry = y - height / 2;
auto r_squared = static_cast<float>(rx * rx + ry * ry);
if (r_squared <= size_squared) {
// double r = sqrt(static_cast<double>rsquare) / static_cast<double>(size);
float r = 0;
c = 1.0f - r;
c = c * c;
if (r > 1.0f)
c = 0.0f;
col = glm::vec4(c);
} else {
col = glm::vec4(0);
}
*input++ = as_int(col);
}
}
return *this;
}
texture_generator &texture_generator::roll(uint8_t layer, uint8_t x, uint8_t y) {
uint8_t *input = layers[layer];
auto *output = new uint8_t[width * height * 4];
uint8_t *out_ptr = output;
for (uint16_t j = 0; j < height; j++) {
for (uint16_t i = 0; i < width; i++) {
uint32_t index = ((j + y) % height) * width + ((i + x) % width);
*out_ptr++ = input[index * 4 + 0];
*out_ptr++ = input[index * 4 + 1];
*out_ptr++ = input[index * 4 + 2];
*out_ptr++ = input[index * 4 + 3];
}
}
memcpy(input, output, width * height * 4);
delete[] output;
return *this;
}
uint8_t *texture_generator::get(uint8_t layer) {
return layers[layer];
}
std::shared_ptr<texture> texture_generator::get_texture(uint8_t layer) {
return std::make_shared<texture>(width, height, get(layer));
}
texture_generator &texture_generator::white_noise(uint8_t layer) {
auto *input = reinterpret_cast<uint32_t *>(layers[layer]);
for (uint16_t y = 0; y < height; y++) {
for (uint16_t x = 0; x < width; x++) {
*input++ = rand();
}
}
return *this;
}
texture_generator &texture_generator::polar_grid(uint8_t layer) {
uint8_t *input = layers[layer];
auto *output = new uint8_t[width * height * 4];
uint8_t *out_ptr = output;
for (int j = 0; j < height; j++) {
double theta = M_PI * (j - (height - 1) / 2.0) / static_cast<double>(height - 1);
for (int i = 0; i < width; i++) {
double phi = 2 * M_PI * (i - width / 2.0) / static_cast<double>(width);
double phi2 = phi * cos(theta);
int i2 = phi2 * width / (2 * M_PI) + width / 2;
if (i2 < 0 || i2 > width - 1) {
*out_ptr++ = 255;
*out_ptr++ = 0;
*out_ptr++ = 0;
*out_ptr++ = 1;
} else {
*out_ptr++ = input[(j * width + i2) * 4 + 0];
*out_ptr++ = input[(j * width + i2) * 4 + 1];
*out_ptr++ = input[(j * width + i2) * 4 + 2];
*out_ptr++ = input[(j * width + i2) * 4 + 3];
}
}
}
memcpy(input, output, width * height * 4);
delete[] output;
return *this;
}
texture_generator &texture_generator::brick(uint8_t layer,
uint8_t brick_width,
uint8_t brick_height,
uint8_t gap_size,
colour mortar_col,
colour brick_col) {
auto *input = reinterpret_cast<uint32_t *>(layers[layer]);
uint32_t mortar = as_int(mortar_col);
uint32_t brick = as_int(brick_col);
for (int i = 0; i < width * height; i++) {
input[i] = brick;
}
int y = 0;
while (y < height) {
for (int i = 0; i < gap_size; i++) {
if ((y + i) < height) {
for (int x = 0; x < width; x++) {
input[x + (y + i) * width] = mortar;
}
}
}
y += brick_height + gap_size;
}
int offset = 0;
bool is_odd_row = false;
y = gap_size;
while (y < height) {
int x = is_odd_row ? 0 : brick_width / 2;
while (x < width) {
for (int i = 0; i < gap_size; i++) {
for (int current_brick_y = 0; current_brick_y < brick_height; current_brick_y++) {
input[x + i + (current_brick_y + y) * width] = mortar;
}
}
x += gap_size + brick_width;
}
y += brick_height + gap_size;
is_odd_row = !is_odd_row;
}
return *this;
}
END_NAMESPACE
+43
View File
@@ -0,0 +1,43 @@
#pragma once
#include "texture.h"
#include "colour.h"
#include <memory>
BEGIN_NAMESPACE
class texture_generator {
public:
texture_generator(uint16_t width, uint16_t height);
virtual ~texture_generator();
texture_generator &checker_board(uint8_t layer,
uint8_t block_size,
colour on,
colour off);
texture_generator &brick(uint8_t layer,
uint8_t brick_width,
uint8_t brick_height,
uint8_t gap_size,
colour mortar_col,
colour brick_col);
texture_generator &white_noise(uint8_t layer);
texture_generator &env_map(uint8_t layer, uint8_t size);
texture_generator &lens(uint8_t layer, uint8_t size);
texture_generator &roll(uint8_t layer, uint8_t x, uint8_t y);
texture_generator &polar_grid(uint8_t layer);
uint8_t *get(uint8_t layer);
std::shared_ptr<texture> get_texture(uint8_t layer);
uint16_t width;
uint16_t height;
private:
static const int NUM_LAYERS = 4;
uint8_t *layers[NUM_LAYERS] = {nullptr};
};
END_NAMESPACE
+3
View File
@@ -0,0 +1,3 @@
TODO:
- add random generator (maybe mersene twister)
-