working particle system

This commit is contained in:
Jay Robson 2024-07-10 23:11:00 +10:00
parent 82146468f3
commit 3d18ccf04e
32 changed files with 246 additions and 126 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 804 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

BIN
assets/image/cross.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 775 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 780 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 808 B

View File

@ -4,7 +4,8 @@
#define SSBO_ATLAS_BUFFER 1 #define SSBO_ATLAS_BUFFER 1
#define SSBO_PARTICLES_IN 2 #define SSBO_PARTICLES_IN 2
#define SSBO_PARTICLES_OUT 3 #define SSBO_PARTICLES_OUT 3
#define UBO_PARTICLES_INFO 4 #define SSBO_PARTICLES_LOOKUP 4
#define UBO_PARTICLES_INFO 5
#define TEX_ATLAS 1 #define TEX_ATLAS 1

View File

@ -3,8 +3,9 @@
layout (location = 0) in vec4 v_pos; layout (location = 0) in vec4 v_pos;
layout (location = 1) in vec4 v_colour; layout (location = 1) in vec4 v_colour;
layout (location = 2) in vec2 v_uv; layout (location = 2) in vec2 v_screen_offset;
layout (location = 3) in uint v_texid; layout (location = 3) in vec2 v_uv;
layout (location = 4) in uint v_texid;
out VS_OUT { out VS_OUT {
vec4 pos; vec4 pos;
@ -23,7 +24,6 @@ void main() {
vout.colour = v_colour; vout.colour = v_colour;
vout.uv = v_uv; vout.uv = v_uv;
vout.texid = v_texid; vout.texid = v_texid;
vec4 p = u_projection * vout.pos; gl_Position = u_projection * (vout.pos + vec4(v_screen_offset, 0, 0));
gl_Position = vec4(p.xy, 2 / (p.z + 2) - 1, p.w);
} }

View File

@ -2,22 +2,28 @@
#include "header.glsl" #include "header.glsl"
#include "random.glsl" #include "random.glsl"
layout (local_size_x = 32, local_size_y = 1, local_size_z = 1) in; layout (local_size_x = 1, local_size_y = 64, local_size_z = 1) in;
struct VertType { struct VertType {
vec4 pos; vec4 pos;
vec4 colour; vec4 colour;
vec2 screen_offset;
vec2 uv; vec2 uv;
float texid; int texid;
}; };
struct ParticleType { struct ParticleType {
vec4 pos; // xyz: pos, w: vel random scale vec4 pos;
vec4 velocity; // xyz: vel, w: colour random scale vec4 vel;
vec4 acc;
vec4 colour; vec4 colour;
float random_pos;
float random_vel;
float random_time;
float time_start; float time_start;
float duration; float duration;
float size; float size;
int texid;
int seed; int seed;
}; };
@ -29,34 +35,47 @@ layout (binding = SSBO_PARTICLES_OUT) writeonly buffer ParticleBufferOut {
VertType vertices_out[]; VertType vertices_out[];
}; };
layout (binding = SSBO_PARTICLES_LOOKUP) readonly buffer ParticleLookupIn {
int lookup_in[];
};
layout (binding = UBO_PARTICLES_INFO) uniform ParticleInfo { layout (binding = UBO_PARTICLES_INFO) uniform ParticleInfo {
float p_time; float p_time;
int p_size; int p_size;
}; };
void main() { const vec2 QUADS[4] = {
ParticleType particle = particles_in[gl_WorkGroupID.x]; vec2(0, 0),
int seed = particle.seed; vec2(1, 0),
rand_mix(seed, int(gl_LocalInvocationID.x)); vec2(0, 1),
vec2(1, 1)
};
float duration = clamp((p_time - particle.time_start) / particle.duration, 0, 1); void main() {
vec3 velocity = normalize(vec3( ParticleType p = particles_in[lookup_in[gl_GlobalInvocationID.x]];
rand_float(seed) * 2 - 1,
rand_float(seed) * 2 - 1,
rand_float(seed) * 2 - 1
)) * particle.pos.w + particle.velocity.xyz;
vec4 colour = normalize(vec4(
rand_float(seed) * 2 - 1,
rand_float(seed) * 2 - 1,
rand_float(seed) * 2 - 1,
rand_float(seed) * 2 - 1
)) * particle.velocity.w + particle.colour;
vec3 pos = particle.pos.xyz + velocity * duration;
colour.a *= (1 - duration);
uint v_id = gl_GlobalInvocationID.x; int n = p.seed;
vertices_out[v_id].pos = vec4(pos, 1); rand_mix(n, int(gl_GlobalInvocationID.y));
vertices_out[v_id].colour = colour;
vertices_out[v_id].texid = TEXID_WHITE; float t_total = p.duration + p.random_time * (rand_float(n)*2-1);
float t = clamp(p_time - p.time_start, 0, t_total);
float t_ratio = t / t_total;
vec3 vel = p.vel.xyz + normalize(rand_vec3(n)*2-1) * p.random_vel;
vec4 pos = vec4(p.pos.xyz + normalize(rand_vec3(n)*2-1) * p.random_pos + (vel + 0.5 * p.acc.xyz * t) * t, 1);
vec4 colour = vec4(p.colour.rgb, p.colour.a * (1 - t_ratio));
pos.z *= (pos.z > 0 ? 1 : 0);
mat2 uv = mat2(rand_vec2(n), rand_vec2(n));
uv = mat2(min(uv[0], uv[1]), max(uv[0], uv[1]));
uint v_id = (gl_GlobalInvocationID.x * gl_WorkGroupSize.y * p_size + gl_GlobalInvocationID.y) * 4;
for(int i = 0; i < 4; i++) {
vertices_out[v_id+i].pos = pos;
vertices_out[v_id+i].colour = colour;
vertices_out[v_id+i].screen_offset = (QUADS[i]*2-1) * p.size;
vertices_out[v_id+i].uv = QUADS[i] * (uv[1] - uv[0]) + uv[0];
vertices_out[v_id+i].texid = p.texid;
}
} }

View File

@ -9,6 +9,18 @@ float rand_float(inout int n) {
return float(n) / float(0x7fffffff); return float(n) / float(0x7fffffff);
} }
vec2 rand_vec2(inout int n) {
return vec2(rand_float(n), rand_float(n));
}
vec3 rand_vec3(inout int n) {
return vec3(rand_float(n), rand_float(n), rand_float(n));
}
vec4 rand_vec4(inout int n) {
return vec4(rand_float(n), rand_float(n), rand_float(n), rand_float(n));
}
void rand_mix(inout int n, int v) { void rand_mix(inout int n, int v) {
n = rand_gen(n ^ v); n = rand_gen(n ^ v);
} }

View File

@ -1,7 +1,7 @@
#include "context.hpp" #include "context.hpp"
#include "../world/state.hpp"
#include "gl/uniform.hpp" #include "gl/uniform.hpp"
#include "window.hpp"
#include <GL/glew.h> #include <GL/glew.h>
#include <glm/ext/matrix_clip_space.hpp> #include <glm/ext/matrix_clip_space.hpp>
#include <glm/ext/matrix_float4x4.hpp> #include <glm/ext/matrix_float4x4.hpp>
@ -9,15 +9,13 @@
using Graphics::Context; using Graphics::Context;
Context::Context(GLFWwindow* window, unsigned int program) { Context::Context(unsigned int program) {
assert(window);
glUseProgram(program); glUseProgram(program);
m_u_model = glGetUniformLocation(program, "u_model"); m_u_model = glGetUniformLocation(program, "u_model");
m_u_view = glGetUniformLocation(program, "u_view"); m_u_view = glGetUniformLocation(program, "u_view");
m_u_projection = glGetUniformLocation(program, "u_projection"); m_u_projection = glGetUniformLocation(program, "u_projection");
m_u_colour = glGetUniformLocation(program, "u_colour"); m_u_colour = glGetUniformLocation(program, "u_colour");
m_program = program; m_program = program;
m_window = window;
} }
void Context::set_model_matrix(glm::mat4 mat) const { void Context::set_model_matrix(glm::mat4 mat) const {
@ -38,9 +36,10 @@ void Context::set_projection_matrix(glm::mat4 mat) {
m_projection = mat; m_projection = mat;
} }
void Context::set_player(const World::Player& player) { void Context::set_from_state(const World::State& state) {
set_projection_matrix(glm::perspective(glm::radians(90.0f), Graphics::Window::get_aspect(), 0.01f, 10.f)); const World::Player& player = state.m_player;
set_view_matrix(player.get_view_matrix()); set_projection_matrix(player.m_projection);
set_view_matrix(player.m_view);
m_transform = player.m_pos; m_transform = player.m_pos;
} }

View File

@ -3,12 +3,13 @@
#include <glm/ext/matrix_float4x4.hpp> #include <glm/ext/matrix_float4x4.hpp>
#include <glm/matrix.hpp> #include <glm/matrix.hpp>
#include "../world/player.hpp"
#include "window.hpp" namespace World {
struct State;
};
namespace Graphics { namespace Graphics {
struct Context { struct Context {
GLFWwindow* m_window;
unsigned int m_program; unsigned int m_program;
unsigned int m_u_model; unsigned int m_u_model;
unsigned int m_u_view; unsigned int m_u_view;
@ -18,13 +19,13 @@ namespace Graphics {
glm::mat4 m_view; glm::mat4 m_view;
glm::mat4 m_projection; glm::mat4 m_projection;
Context(GLFWwindow* window, unsigned int program); Context(unsigned int program);
void set_model_matrix(glm::mat4 mat) const; void set_model_matrix(glm::mat4 mat) const;
void set_view_matrix(glm::mat4 mat); void set_view_matrix(glm::mat4 mat);
void set_projection_matrix(glm::mat4 mat); void set_projection_matrix(glm::mat4 mat);
void set_colour_matrix(glm::mat4 mat) const; void set_colour_matrix(glm::mat4 mat) const;
void set_player(const World::Player& player); void set_from_state(const World::State& state);
glm::mat4 get_vp() const; glm::mat4 get_vp() const;
}; };

View File

@ -1,15 +1,15 @@
#include "particles.hpp" #include "particles.hpp"
#include "context.hpp"
#include "pipeline.hpp" #include "pipeline.hpp"
#include "shader.hpp" #include "shader.hpp"
#include "vertex.hpp" #include "vertex.hpp"
#include <GL/glew.h> #include <GL/glew.h>
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#include <utility>
#include <vector>
using Graphics::Particles; using Graphics::Particles;
struct InfoType { struct InfoType {
float m_time; float m_time;
int m_size; int m_size;
@ -18,60 +18,86 @@ struct InfoType {
Particles::Particles() { Particles::Particles() {
m_time_started = glfwGetTime(); m_time_started = glfwGetTime();
glNamedBufferStorage(m_ssbo_particles, sizeof(Type) * MAX_PARTICLES, nullptr, GL_MAP_PERSISTENT_BIT | GL_MAP_READ_BIT | GL_MAP_WRITE_BIT); std::vector<int> indices(MAX_PARTICLES*6);
glNamedBufferData(m_ssbo_vertices, sizeof(Vertex) * MAX_PARTICLES, nullptr, GL_DYNAMIC_COPY); std::vector<int> lookup(MAX_PARTICLE_GROUPS);
glNamedBufferData(m_ubo_info, sizeof(InfoType), nullptr, GL_DYNAMIC_DRAW);
m_particles_mapping = (Type*)glMapNamedBuffer(m_ssbo_particles, GL_READ_WRITE);
glBindVertexArray(m_vao); for(int i = 0; i < MAX_PARTICLES; i++) {
glBindBuffer(GL_ARRAY_BUFFER, m_ssbo_vertices); int i4 = i*4;
glBindVertexArray(0); int i6 = i*6;
indices[i6+0] = i4+0;
indices[i6+1] = i4+1;
indices[i6+2] = i4+3;
indices[i6+3] = i4+0;
indices[i6+4] = i4+3;
indices[i6+5] = i4+2;
}
for(int i = 0; i < MAX_PARTICLE_GROUPS; i++) {
lookup[i] = i;
}
glNamedBufferStorage(m_buff_particles, sizeof(Type) * MAX_PARTICLE_GROUPS, nullptr, GL_MAP_PERSISTENT_BIT | GL_MAP_READ_BIT | GL_MAP_WRITE_BIT);
glNamedBufferStorage(m_buff_lookup, sizeof(int) * MAX_PARTICLE_GROUPS, lookup.data(), GL_MAP_PERSISTENT_BIT | GL_MAP_READ_BIT | GL_MAP_WRITE_BIT);
glNamedBufferData(m_buff_vertices, sizeof(Vertex) * MAX_PARTICLES * 4, nullptr, GL_DYNAMIC_COPY);
glNamedBufferData(m_buff_indices, sizeof(int) * MAX_PARTICLES * 6, indices.data(), GL_STATIC_COPY);
glNamedBufferData(m_buff_info, sizeof(InfoType), nullptr, GL_DYNAMIC_DRAW);
m_particles_mapping = (Type*)glMapNamedBuffer(m_buff_particles, GL_READ_WRITE);
m_lookup_mapping = (int*)glMapNamedBuffer(m_buff_lookup, GL_READ_WRITE);
Vertex::set_vertex_attribs(m_vao, m_buff_vertices);
glVertexArrayElementBuffer(m_vao, m_buff_indices);
} }
void Particles::update(const Pipeline& pipeline) { void Particles::update() {
double now = get_time_diff(); double now = get_time_diff();
int j = 0; int j = 0;
for(int i = 0; i < m_particles_mapping_size; i++) { for(int i = 0; i < m_mapping_size; i++) {
Type& p = m_particles_mapping[i]; Type& p = m_particles_mapping[m_lookup_mapping[i]];
if(p.m_time_start + p.m_duration < now) { if(p.m_time_start + p.m_duration > now) {
if(i > j) { if(i > j) {
m_particles_mapping[j] = m_particles_mapping[i]; std::swap(m_lookup_mapping[j], m_lookup_mapping[i]);
} }
j++; j++;
} }
} }
m_particles_mapping_size = j; m_mapping_size = j;
InfoType info { InfoType info {
.m_time = (float)now, .m_time = (float)now,
.m_size = m_particles_mapping_size, .m_size = 1,
}; };
glNamedBufferSubData(m_ubo_info, 0, sizeof(InfoType), &info); glNamedBufferSubData(m_buff_info, 0, sizeof(InfoType), &info);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, Shader::SSBO_PARTICLES_IN, m_ssbo_particles); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, Shader::SSBO_PARTICLES_IN, m_buff_particles);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, Shader::SSBO_PARTICLES_OUT, m_ssbo_vertices); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, Shader::SSBO_PARTICLES_OUT, m_buff_vertices);
glBindBufferBase(GL_UNIFORM_BUFFER, Shader::UBO_PARTICLES_INFO, m_ubo_info); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, Shader::SSBO_PARTICLES_LOOKUP, m_buff_lookup);
glUseProgram(pipeline.m_program_particles); glBindBufferBase(GL_UNIFORM_BUFFER, Shader::UBO_PARTICLES_INFO, m_buff_info);
glDispatchCompute(m_particles_mapping_size, 1, 1); glUseProgram(Graphics::Pipeline::CURRENT->m_program_particles);
glDispatchCompute(m_mapping_size, info.m_size, 1);
} }
void Particles::render(const Context& ctx) const { void Particles::render(const Context& ctx) const {
if(m_mapping_size == 0) {
return;
}
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT); glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
ctx.set_colour_matrix(glm::mat4(1));
ctx.set_model_matrix(glm::mat4(1)); ctx.set_model_matrix(glm::mat4(1));
ctx.set_colour_matrix(glm::mat4(1));
glBindVertexArray(m_vao); glBindVertexArray(m_vao);
glDrawArrays(GL_POINTS, 0, m_particles_mapping_size); glDrawElements(GL_TRIANGLES, m_mapping_size * PARTICLES_PER_GROUP * 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
} }
void Particles::add(const Type& type) { void Particles::add(Type type) {
if(m_particles_mapping_size < MAX_PARTICLES) { if(m_mapping_size < MAX_PARTICLE_GROUPS) {
m_particles_mapping[m_particles_mapping_size++] = type; type.m_time_start = (float)get_time_diff();
type.m_seed = random();
m_particles_mapping[m_lookup_mapping[m_mapping_size++]] = type;
} }
} }
double Particles::get_time_diff() { double Particles::get_time_diff() const {
return m_time_started - glfwGetTime(); return glfwGetTime() - m_time_started;
} }

View File

@ -7,36 +7,51 @@
#include <glm/matrix.hpp> #include <glm/matrix.hpp>
namespace Graphics { namespace Graphics {
struct Pipeline;
struct Particles { struct Particles {
struct Type { struct Type {
glm::vec3 m_pos; glm::vec3 m_pos;
float m_random_velocity_scale; int _padding_1;
glm::vec3 m_velocity;
float m_random_colour_scale; glm::vec3 m_vel;
glm::vec4 m_colour; int _padding_2;
glm::vec3 m_acc;
int _padding_3;
glm::vec4 m_colour = {1, 1, 1, 1};
float m_random_pos;
float m_random_vel;
float m_random_time;
float m_time_start; float m_time_start;
float m_duration; float m_duration;
float m_size; float m_size;
int m_seed; unsigned int m_texid;
unsigned int m_seed;
}; };
static_assert(sizeof(Type) == 64); static_assert(sizeof(Type) == 96);
static constexpr int MAX_PARTICLES = 1024; static constexpr int MAX_PARTICLE_GROUPS = 1024;
static constexpr int PARTICLES_PER_GROUP = 64;
static constexpr int MAX_PARTICLES = MAX_PARTICLE_GROUPS * PARTICLES_PER_GROUP;
GL::VertexArray m_vao; GL::VertexArray m_vao;
GL::ArrayBuffer m_ssbo_particles; GL::ArrayBuffer m_buff_particles;
GL::ArrayBuffer m_ssbo_vertices; GL::ArrayBuffer m_buff_lookup;
GL::ArrayBuffer m_ubo_info; GL::ArrayBuffer m_buff_vertices;
GL::ArrayBuffer m_buff_indices;
GL::ArrayBuffer m_buff_info;
Type* m_particles_mapping; Type* m_particles_mapping;
int m_particles_mapping_size = 0; int* m_lookup_mapping;
int m_mapping_size = 0;
double m_time_started; double m_time_started;
Particles(); Particles();
void add(const Type& type); void update();
double get_time_diff(); void add(Type type);
void update(const Pipeline& pipeline); double get_time_diff() const;
void render(const Context& ctx) const; void render(const Context& ctx) const;
}; };
}; };

View File

@ -7,6 +7,8 @@
#include "shader/compile.hpp" #include "shader/compile.hpp"
#include "shader/link.hpp" #include "shader/link.hpp"
#include "texture/generate_atlas.hpp" #include "texture/generate_atlas.hpp"
#include "../world/state.hpp"
#include "../util/debug.hpp"
using Graphics::Pipeline; using Graphics::Pipeline;
@ -19,6 +21,9 @@ Pipeline::Pipeline() {
Graphics::Shader::link(m_program_model, {model_vert, model_frag}); Graphics::Shader::link(m_program_model, {model_vert, model_frag});
Graphics::Shader::link(m_program_particles, {particles_comp}); Graphics::Shader::link(m_program_particles, {particles_comp});
CHECK_DEBUG(CURRENT == nullptr);
CURRENT = this;
} }
bool Pipeline::should_close() const { bool Pipeline::should_close() const {
@ -27,7 +32,6 @@ bool Pipeline::should_close() const {
void Pipeline::update() { void Pipeline::update() {
m_window.update(); m_window.update();
m_particles.update(*this);
} }
void Pipeline::render(const World::State& state, const Context& ctx) const { void Pipeline::render(const World::State& state, const Context& ctx) const {
@ -36,7 +40,6 @@ void Pipeline::render(const World::State& state, const Context& ctx) const {
glClearColor(0.1, 0.1, 0.12, 1); glClearColor(0.1, 0.1, 0.12, 1);
state.render(ctx); state.render(ctx);
m_particles.render(ctx);
m_window.swap_buffers(); m_window.swap_buffers();
} }

View File

@ -1,18 +1,21 @@
#pragma once #pragma once
#include "context.hpp"
#include "gl/program.hpp" #include "gl/program.hpp"
#include "particles.hpp"
#include "texture/generate_atlas.hpp" #include "texture/generate_atlas.hpp"
#include "context.hpp"
#include "window.hpp" #include "window.hpp"
#include "../world/state.hpp"
namespace World {
struct State;
};
namespace Graphics { namespace Graphics {
struct Pipeline { struct Pipeline {
static inline Pipeline* CURRENT = nullptr;
Window m_window; Window m_window;
Texture::GeneratedAtlas m_generated_atlas; Texture::GeneratedAtlas m_generated_atlas;
Particles m_particles;
GL::Program m_program_model; GL::Program m_program_model;
GL::Program m_program_particles; GL::Program m_program_particles;

View File

@ -5,7 +5,8 @@ namespace Graphics::Shader {
constexpr int SSBO_ATLAS_BUFFER = 1; constexpr int SSBO_ATLAS_BUFFER = 1;
constexpr int SSBO_PARTICLES_IN = 2; constexpr int SSBO_PARTICLES_IN = 2;
constexpr int SSBO_PARTICLES_OUT = 3; constexpr int SSBO_PARTICLES_OUT = 3;
constexpr int UBO_PARTICLES_INFO = 4; constexpr int SSBO_PARTICLES_LOOKUP = 4;
constexpr int UBO_PARTICLES_INFO = 5;
constexpr int TEX_ATLAS = 1; constexpr int TEX_ATLAS = 1;
}; };

View File

@ -6,12 +6,20 @@
namespace Graphics::Texture { namespace Graphics::Texture {
inline Image MISSING {"missing.png", Image::Edge::REPEATING}; inline Image MISSING {"missing.png", Image::Edge::REPEATING};
inline Image WHITE {"white.png", Image::Edge::REPEATING}; inline Image WHITE {"white.png", Image::Edge::REPEATING};
inline Image CROSS {"cross.png", Image::Edge::CLAMP};
inline Image YELLOW_BRICK_WALL {"yellow_brick_wall.png", Image::Edge::REPEATING}; inline Image YELLOW_BRICK_WALL {"yellow_brick_wall.png", Image::Edge::REPEATING};
inline Image YELLOW_BRICK_FLOOR {"yellow_brick_floor.png", Image::Edge::REPEATING};
inline Image WHITE_BRICK_WALL {"white_brick_wall.png", Image::Edge::REPEATING};
inline Image WHITE_BRICK_FLOOR {"white_brick_floor.png", Image::Edge::REPEATING};
inline Image* const IMAGES[] { inline Image* const IMAGES[] {
&MISSING, &MISSING,
&WHITE, &WHITE,
&CROSS,
&YELLOW_BRICK_WALL, &YELLOW_BRICK_WALL,
&YELLOW_BRICK_FLOOR,
&WHITE_BRICK_WALL,
&WHITE_BRICK_FLOOR,
}; };
}; };

View File

@ -5,6 +5,7 @@
#include "atlas.hpp" #include "atlas.hpp"
#include "image.hpp" #include "image.hpp"
#include "uv.hpp" #include "uv.hpp"
#include <iostream>
#include <iterator> #include <iterator>
#include <stb/stb_rect_pack.h> #include <stb/stb_rect_pack.h>
#include <GL/glew.h> #include <GL/glew.h>
@ -60,8 +61,8 @@ void Graphics::Texture::generate_atlas(GeneratedAtlas& ga) {
src->clear_host(); src->clear_host();
uvs[it->id] = { uvs[it->id] = {
.uv0={(it->x + offset + 0.5f) / size, (it->y + offset + 0.5f) / size}, .uv0={float(it->x + offset) / size, float(it->y + offset) / size},
.uv1={(it->x + offset + src->m_size.x - 0.5f) / size, (it->y + offset + src->m_size.y - 0.5f) / size}, .uv1={float(it->x + offset + src->m_size.x) / size, float(it->y + offset + src->m_size.y) / size},
.zpos=zpos, .zpos=zpos,
.edges=src->m_edges, .edges=src->m_edges,
}; };
@ -70,6 +71,8 @@ void Graphics::Texture::generate_atlas(GeneratedAtlas& ga) {
} }
} }
std::cout << "Finished stitching " << size << "x" << size << "x" << atlas.m_size.z << " atlas" << std::endl;
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, Graphics::Shader::SSBO_ATLAS_BUFFER, ga.m_ssbo_id); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, Graphics::Shader::SSBO_ATLAS_BUFFER, ga.m_ssbo_id);
glNamedBufferData(ga.m_ssbo_id, sizeof(UV) * uvs.size(), uvs.data(), GL_STATIC_DRAW); glNamedBufferData(ga.m_ssbo_id, sizeof(UV) * uvs.size(), uvs.data(), GL_STATIC_DRAW);

View File

@ -11,10 +11,11 @@ void Vertex::set_vertex_attribs(unsigned int vao, unsigned int vbo) {
glVertexArrayVertexBuffer(vao, 0, vbo, 0, sizeof(v)); glVertexArrayVertexBuffer(vao, 0, vbo, 0, sizeof(v));
glVertexArrayAttribFormat(vao, 0, 4, GL_FLOAT, false, Util::pointer_diff(&v, &v.m_pos)); glVertexArrayAttribFormat(vao, 0, 4, GL_FLOAT, false, Util::pointer_diff(&v, &v.m_pos));
glVertexArrayAttribFormat(vao, 1, 4, GL_FLOAT, false, Util::pointer_diff(&v, &v.m_colour)); glVertexArrayAttribFormat(vao, 1, 4, GL_FLOAT, false, Util::pointer_diff(&v, &v.m_colour));
glVertexArrayAttribFormat(vao, 2, 2, GL_FLOAT, false, Util::pointer_diff(&v, &v.m_uv)); glVertexArrayAttribFormat(vao, 2, 2, GL_FLOAT, false, Util::pointer_diff(&v, &v.m_screen_offset));
glVertexArrayAttribIFormat(vao, 3, 1, GL_UNSIGNED_INT, Util::pointer_diff(&v, &v.m_texid)); glVertexArrayAttribFormat(vao, 3, 2, GL_FLOAT, false, Util::pointer_diff(&v, &v.m_uv));
glVertexArrayAttribIFormat(vao, 4, 1, GL_UNSIGNED_INT, Util::pointer_diff(&v, &v.m_texid));
for(int i = 0; i < 4; i++) { for(int i = 0; i < 5; i++) {
glEnableVertexArrayAttrib(vao, i); glEnableVertexArrayAttrib(vao, i);
glVertexArrayAttribBinding(vao, i, 0); glVertexArrayAttribBinding(vao, i, 0);
} }

View File

@ -7,13 +7,14 @@ namespace Graphics {
struct Vertex { struct Vertex {
glm::vec4 m_pos; glm::vec4 m_pos;
glm::vec4 m_colour = {1, 1, 1, 1}; glm::vec4 m_colour = {1, 1, 1, 1};
glm::vec2 m_screen_offset = {0, 0};
glm::vec2 m_uv; glm::vec2 m_uv;
unsigned int m_texid = 0; unsigned int m_texid = 0;
int _padding_1 = 0; int _padding_1[3] = {0};
static void set_vertex_attribs(unsigned int vao, unsigned int vbo); static void set_vertex_attribs(unsigned int vao, unsigned int vbo);
}; };
static_assert(sizeof(Vertex) == 48); static_assert(sizeof(Vertex) == 64);
}; };

View File

@ -76,6 +76,7 @@ Window::Window() {
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE); glEnable(GL_CULL_FACE);
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
} }
Window::Window(Window&& o) { Window::Window(Window&& o) {

View File

@ -9,11 +9,11 @@ int main() {
World::State state; World::State state;
while(!pipeline.should_close()) { while(!pipeline.should_close()) {
Graphics::Context ctx(pipeline.m_window, pipeline.m_program_model);
ctx.set_player(state.m_player);
pipeline.update(); pipeline.update();
state.update(ctx); state.update();
Graphics::Context ctx(pipeline.m_program_model);
ctx.set_from_state(state);
pipeline.render(state, ctx); pipeline.render(state, ctx);
} }
} }

View File

@ -4,6 +4,8 @@
#include "../graphics/texture.hpp" #include "../graphics/texture.hpp"
#include "chunk.hpp" #include "chunk.hpp"
#include "map.hpp" #include "map.hpp"
#include "player.hpp"
#include "state.hpp"
#include "tile/empty.hpp" #include "tile/empty.hpp"
#include "tile/tile_base.hpp" #include "tile/tile_base.hpp"
#include <GL/glew.h> #include <GL/glew.h>
@ -18,7 +20,7 @@ using World::Builder;
Builder::Builder() { Builder::Builder() {
Graphics::Mesh mesh; Graphics::Mesh mesh;
auto prim = Chunk::PRIMITIVE_B; auto prim = Chunk::PRIMITIVE_B;
prim.m_texid = Graphics::Texture::YELLOW_BRICK_WALL; prim.m_texid = Graphics::Texture::YELLOW_BRICK_FLOOR;
mesh.add_primitive(prim); mesh.add_primitive(prim);
for(int i = 0; i < 4; i++) { for(int i = 0; i < 4; i++) {
@ -30,17 +32,20 @@ Builder::Builder() {
m_model.set(mesh, GL_STATIC_DRAW); m_model.set(mesh, GL_STATIC_DRAW);
} }
void Builder::update(Map& map, const Graphics::Context& ctx) { void Builder::update(State& state) {
m_has_intersect = false; m_has_intersect = false;
if(Graphics::Window::mouse_locked) { if(Graphics::Window::mouse_locked) {
return; return;
} }
Player& player = state.m_player;
Map& map = state.m_map;
glm::vec<2, double> mpos; glm::vec<2, double> mpos;
glfwGetCursorPos(ctx.m_window, &mpos.x, &mpos.y); glfwGetCursorPos(glfwGetCurrentContext(), &mpos.x, &mpos.y);
mpos.y = Graphics::Window::size.y - mpos.y; mpos.y = Graphics::Window::size.y - mpos.y;
glm::vec<3, double> near = glm::unProject<float>(glm::vec3(mpos, -1), ctx.m_view, ctx.m_projection, glm::vec4(0, 0, Graphics::Window::size)); glm::vec<3, double> near = glm::unProject<float>(glm::vec3(mpos, -1), player.m_view, player.m_projection, glm::vec4(0, 0, Graphics::Window::size));
glm::vec<3, double> far = glm::unProject<float>(glm::vec3(mpos, 1), ctx.m_view, ctx.m_projection, glm::vec4(0, 0, Graphics::Window::size)); glm::vec<3, double> far = glm::unProject<float>(glm::vec3(mpos, 1), player.m_view, player.m_projection, glm::vec4(0, 0, Graphics::Window::size));
glm::vec<3, double> direction = far - near; glm::vec<3, double> direction = far - near;
const glm::vec<2, double> CHECK_TILES[] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}}; const glm::vec<2, double> CHECK_TILES[] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
bool found = false; bool found = false;
@ -49,7 +54,7 @@ void Builder::update(Map& map, const Graphics::Context& ctx) {
return; return;
} }
m_intersect = glm::round(glm::vec<2, double>(near - direction / direction.z * near.z) + ctx.m_transform); m_intersect = glm::round(glm::vec<2, double>(near - direction / direction.z * near.z) + player.m_pos);
m_has_intersect = true; m_has_intersect = true;
if(map.get_tile(m_intersect)) { if(map.get_tile(m_intersect)) {
@ -71,6 +76,16 @@ void Builder::update(Map& map, const Graphics::Context& ctx) {
tile = nullptr; tile = nullptr;
} }
map.set_tile(m_intersect, std::move(tile)); map.set_tile(m_intersect, std::move(tile));
state.m_particles.add({
.m_pos = {m_intersect, 0.75/2},
.m_acc = {0, 0, -0.98},
.m_random_pos = 0.5,
.m_random_vel = 0.05,
.m_duration = 1,
.m_size = 0.025,
.m_texid = Graphics::Texture::YELLOW_BRICK_WALL,
});
} }
void Builder::render(const Graphics::Context& ctx) const { void Builder::render(const Graphics::Context& ctx) const {

View File

@ -3,9 +3,9 @@
#include "../graphics/context.hpp" #include "../graphics/context.hpp"
#include "../graphics/gl/model.hpp" #include "../graphics/gl/model.hpp"
#include "map.hpp"
namespace World { namespace World {
struct State;
struct Builder { struct Builder {
enum Mode { enum Mode {
SET, SET,
@ -19,7 +19,7 @@ namespace World {
Builder(); Builder();
void update(Map& map, const Graphics::Context& ctx); void update(State& state);
void render(const Graphics::Context& ctx) const; void render(const Graphics::Context& ctx) const;
}; };
}; };

View File

@ -79,7 +79,7 @@ void Chunk::update(Map& map) {
auto prim = PRIMITIVE_B; auto prim = PRIMITIVE_B;
prim.m_offset = {t_off, 0, 0}; prim.m_offset = {t_off, 0, 0};
prim.m_texid = Graphics::Texture::MISSING; prim.m_texid = Graphics::Texture::YELLOW_BRICK_FLOOR;
mesh.add_primitive(prim); mesh.add_primitive(prim);
for(int i = 0; i < std::size(neighbours); i++) { for(int i = 0; i < std::size(neighbours); i++) {

View File

@ -32,9 +32,9 @@ namespace World {
static const inline Graphics::Primitive<4, 6> PRIMITIVE_0 = { static const inline Graphics::Primitive<4, 6> PRIMITIVE_0 = {
.m_vertices={ .m_vertices={
{.m_pos={-0.5, -0.5, 0.75, 1}, .m_uv={0, 0}}, {.m_pos={-0.5, -0.5, 0.75, 1}, .m_uv={0, 0}},
{.m_pos={-0.5, -0.5, 0, 1}, .m_uv={0, 2}}, {.m_pos={-0.5, -0.5, 0, 1}, .m_uv={0, 1.5}},
{.m_pos={+0.5, -0.5, 0.75, 1}, .m_uv={2, 0}}, {.m_pos={+0.5, -0.5, 0.75, 1}, .m_uv={2, 0}},
{.m_pos={+0.5, -0.5, 0, 1}, .m_uv={2, 2}}, {.m_pos={+0.5, -0.5, 0, 1}, .m_uv={2, 1.5}},
}, },
.m_indices={ .m_indices={
0, 2, 3, 0, 2, 3,

View File

@ -14,6 +14,7 @@ namespace World {
#include <memory> #include <memory>
namespace World { namespace World {
struct State;
struct Map { struct Map {
static constexpr int N = 16; static constexpr int N = 16;
std::map<uint64_t, Chunk> m_chunks; std::map<uint64_t, Chunk> m_chunks;

View File

@ -1,7 +1,6 @@
#include "player.hpp" #include "player.hpp"
#include "../graphics/window.hpp" #include "../graphics/window.hpp"
#include "../util/math/mod.hpp"
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#include <algorithm> #include <algorithm>
#include <cmath> #include <cmath>
@ -64,13 +63,13 @@ void Player::update() {
m_vel += m_accel; m_vel += m_accel;
m_pos += m_vel; m_pos += m_vel;
m_accel = -m_vel * 0.125; m_accel = -m_vel * 0.125;
}
glm::mat4 Player::get_view_matrix() const {
glm::mat4 mat(1); glm::mat4 mat(1);
mat = glm::translate(mat, {0, 0, -m_distance}); mat = glm::translate(mat, {0, 0, -m_distance});
mat = glm::rotate(mat, (float)m_yaw, {-1, 0, 0}); mat = glm::rotate(mat, (float)m_yaw, {-1, 0, 0});
mat = glm::rotate(mat, (float)m_pitch, {0, 0, 1}); mat = glm::rotate(mat, (float)m_pitch, {0, 0, 1});
return mat;
m_view = mat;
m_projection = glm::perspective(glm::radians(90.0f), Graphics::Window::get_aspect(), 0.01f, 10.f);
} }

View File

@ -11,13 +11,16 @@ namespace World {
glm::vec<2, double> m_vel = {0.01, 0}; glm::vec<2, double> m_vel = {0.01, 0};
glm::vec<2, double> m_accel = {0, 0}; glm::vec<2, double> m_accel = {0, 0};
glm::vec<2, double> m_cursor_last; glm::vec<2, double> m_cursor_last;
glm::mat4 m_view;
glm::mat4 m_projection;
double m_distance = 2; double m_distance = 2;
double m_pitch = 0; double m_pitch = 0;
double m_yaw = glm::pi<double>() * 5.0 / 16.0; double m_yaw = glm::pi<double>() * 5.0 / 16.0;
Player(); Player();
void update(); void update();
glm::mat4 get_view_matrix() const;
}; };
}; };

View File

@ -9,14 +9,16 @@ State::State() {
m_map.set_tile({0, 0}, std::make_unique<Tile::Empty>()); m_map.set_tile({0, 0}, std::make_unique<Tile::Empty>());
} }
void State::update(const Graphics::Context& ctx) { void State::update() {
m_builder.update(m_map, ctx);
m_player.update(); m_player.update();
m_builder.update(*this);
m_map.update(); m_map.update();
m_particles.update();
} }
void State::render(const Graphics::Context& ctx) const { void State::render(const Graphics::Context& ctx) const {
m_map.render(ctx); m_map.render(ctx);
m_builder.render(ctx); m_builder.render(ctx);
m_particles.render(ctx);
} }

View File

@ -1,20 +1,26 @@
#pragma once #pragma once
#include "../graphics/context.hpp" namespace World {
struct State;
};
#include <glm/matrix.hpp>
#include "../graphics/particles.hpp"
#include "builder.hpp" #include "builder.hpp"
#include "player.hpp" #include "player.hpp"
#include "map.hpp" #include "map.hpp"
namespace World { namespace World {
struct State { struct State {
Graphics::Particles m_particles;
Builder m_builder; Builder m_builder;
Player m_player; Player m_player;
Map m_map; Map m_map;
State(); State();
void update(const Graphics::Context& ctx); void update();
void render(const Graphics::Context& ctx) const; void render(const Graphics::Context& ctx) const;
}; };
}; };