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_PARTICLES_IN 2
#define SSBO_PARTICLES_OUT 3
#define UBO_PARTICLES_INFO 4
#define SSBO_PARTICLES_LOOKUP 4
#define UBO_PARTICLES_INFO 5
#define TEX_ATLAS 1

View File

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

View File

@ -2,22 +2,28 @@
#include "header.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 {
vec4 pos;
vec4 colour;
vec2 screen_offset;
vec2 uv;
float texid;
int texid;
};
struct ParticleType {
vec4 pos; // xyz: pos, w: vel random scale
vec4 velocity; // xyz: vel, w: colour random scale
vec4 pos;
vec4 vel;
vec4 acc;
vec4 colour;
float random_pos;
float random_vel;
float random_time;
float time_start;
float duration;
float size;
int texid;
int seed;
};
@ -29,34 +35,47 @@ layout (binding = SSBO_PARTICLES_OUT) writeonly buffer ParticleBufferOut {
VertType vertices_out[];
};
layout (binding = SSBO_PARTICLES_LOOKUP) readonly buffer ParticleLookupIn {
int lookup_in[];
};
layout (binding = UBO_PARTICLES_INFO) uniform ParticleInfo {
float p_time;
int p_size;
};
const vec2 QUADS[4] = {
vec2(0, 0),
vec2(1, 0),
vec2(0, 1),
vec2(1, 1)
};
void main() {
ParticleType particle = particles_in[gl_WorkGroupID.x];
int seed = particle.seed;
rand_mix(seed, int(gl_LocalInvocationID.x));
ParticleType p = particles_in[lookup_in[gl_GlobalInvocationID.x]];
float duration = clamp((p_time - particle.time_start) / particle.duration, 0, 1);
vec3 velocity = normalize(vec3(
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);
int n = p.seed;
rand_mix(n, int(gl_GlobalInvocationID.y));
uint v_id = gl_GlobalInvocationID.x;
vertices_out[v_id].pos = vec4(pos, 1);
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);
}
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) {
n = rand_gen(n ^ v);
}

View File

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

View File

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

View File

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

View File

@ -7,36 +7,51 @@
#include <glm/matrix.hpp>
namespace Graphics {
struct Pipeline;
struct Particles {
struct Type {
glm::vec3 m_pos;
float m_random_velocity_scale;
glm::vec3 m_velocity;
float m_random_colour_scale;
glm::vec4 m_colour;
int _padding_1;
glm::vec3 m_vel;
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_duration;
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::ArrayBuffer m_ssbo_particles;
GL::ArrayBuffer m_ssbo_vertices;
GL::ArrayBuffer m_ubo_info;
GL::ArrayBuffer m_buff_particles;
GL::ArrayBuffer m_buff_lookup;
GL::ArrayBuffer m_buff_vertices;
GL::ArrayBuffer m_buff_indices;
GL::ArrayBuffer m_buff_info;
Type* m_particles_mapping;
int m_particles_mapping_size = 0;
int* m_lookup_mapping;
int m_mapping_size = 0;
double m_time_started;
Particles();
void add(const Type& type);
double get_time_diff();
void update(const Pipeline& pipeline);
void update();
void add(Type type);
double get_time_diff() const;
void render(const Context& ctx) const;
};
};

View File

@ -7,6 +7,8 @@
#include "shader/compile.hpp"
#include "shader/link.hpp"
#include "texture/generate_atlas.hpp"
#include "../world/state.hpp"
#include "../util/debug.hpp"
using Graphics::Pipeline;
@ -19,6 +21,9 @@ Pipeline::Pipeline() {
Graphics::Shader::link(m_program_model, {model_vert, model_frag});
Graphics::Shader::link(m_program_particles, {particles_comp});
CHECK_DEBUG(CURRENT == nullptr);
CURRENT = this;
}
bool Pipeline::should_close() const {
@ -27,7 +32,6 @@ bool Pipeline::should_close() const {
void Pipeline::update() {
m_window.update();
m_particles.update(*this);
}
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);
state.render(ctx);
m_particles.render(ctx);
m_window.swap_buffers();
}

View File

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

View File

@ -5,7 +5,8 @@ namespace Graphics::Shader {
constexpr int SSBO_ATLAS_BUFFER = 1;
constexpr int SSBO_PARTICLES_IN = 2;
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;
};

View File

@ -6,12 +6,20 @@
namespace Graphics::Texture {
inline Image MISSING {"missing.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_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[] {
&MISSING,
&WHITE,
&CROSS,
&YELLOW_BRICK_WALL,
&YELLOW_BRICK_FLOOR,
&WHITE_BRICK_WALL,
&WHITE_BRICK_FLOOR,
};
};

View File

@ -5,6 +5,7 @@
#include "atlas.hpp"
#include "image.hpp"
#include "uv.hpp"
#include <iostream>
#include <iterator>
#include <stb/stb_rect_pack.h>
#include <GL/glew.h>
@ -60,8 +61,8 @@ void Graphics::Texture::generate_atlas(GeneratedAtlas& ga) {
src->clear_host();
uvs[it->id] = {
.uv0={(it->x + offset + 0.5f) / size, (it->y + offset + 0.5f) / size},
.uv1={(it->x + offset + src->m_size.x - 0.5f) / size, (it->y + offset + src->m_size.y - 0.5f) / size},
.uv0={float(it->x + offset) / size, float(it->y + offset) / size},
.uv1={float(it->x + offset + src->m_size.x) / size, float(it->y + offset + src->m_size.y) / size},
.zpos=zpos,
.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);
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));
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, 2, 2, GL_FLOAT, false, Util::pointer_diff(&v, &v.m_uv));
glVertexArrayAttribIFormat(vao, 3, 1, GL_UNSIGNED_INT, Util::pointer_diff(&v, &v.m_texid));
glVertexArrayAttribFormat(vao, 2, 2, GL_FLOAT, false, Util::pointer_diff(&v, &v.m_screen_offset));
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);
glVertexArrayAttribBinding(vao, i, 0);
}

View File

@ -7,13 +7,14 @@ namespace Graphics {
struct Vertex {
glm::vec4 m_pos;
glm::vec4 m_colour = {1, 1, 1, 1};
glm::vec2 m_screen_offset = {0, 0};
glm::vec2 m_uv;
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_assert(sizeof(Vertex) == 48);
static_assert(sizeof(Vertex) == 64);
};

View File

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

View File

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

View File

@ -4,6 +4,8 @@
#include "../graphics/texture.hpp"
#include "chunk.hpp"
#include "map.hpp"
#include "player.hpp"
#include "state.hpp"
#include "tile/empty.hpp"
#include "tile/tile_base.hpp"
#include <GL/glew.h>
@ -18,7 +20,7 @@ using World::Builder;
Builder::Builder() {
Graphics::Mesh mesh;
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);
for(int i = 0; i < 4; i++) {
@ -30,17 +32,20 @@ Builder::Builder() {
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;
if(Graphics::Window::mouse_locked) {
return;
}
Player& player = state.m_player;
Map& map = state.m_map;
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;
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> 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> 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), player.m_view, player.m_projection, glm::vec4(0, 0, Graphics::Window::size));
glm::vec<3, double> direction = far - near;
const glm::vec<2, double> CHECK_TILES[] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
bool found = false;
@ -49,7 +54,7 @@ void Builder::update(Map& map, const Graphics::Context& ctx) {
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;
if(map.get_tile(m_intersect)) {
@ -71,6 +76,16 @@ void Builder::update(Map& map, const Graphics::Context& ctx) {
tile = nullptr;
}
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 {

View File

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

View File

@ -79,7 +79,7 @@ void Chunk::update(Map& map) {
auto prim = PRIMITIVE_B;
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);
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 = {
.m_vertices={
{.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, 1}, .m_uv={2, 2}},
{.m_pos={+0.5, -0.5, 0, 1}, .m_uv={2, 1.5}},
},
.m_indices={
0, 2, 3,

View File

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

View File

@ -1,7 +1,6 @@
#include "player.hpp"
#include "../graphics/window.hpp"
#include "../util/math/mod.hpp"
#include <GLFW/glfw3.h>
#include <algorithm>
#include <cmath>
@ -64,13 +63,13 @@ void Player::update() {
m_vel += m_accel;
m_pos += m_vel;
m_accel = -m_vel * 0.125;
}
glm::mat4 Player::get_view_matrix() const {
glm::mat4 mat(1);
mat = glm::translate(mat, {0, 0, -m_distance});
mat = glm::rotate(mat, (float)m_yaw, {-1, 0, 0});
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_accel = {0, 0};
glm::vec<2, double> m_cursor_last;
glm::mat4 m_view;
glm::mat4 m_projection;
double m_distance = 2;
double m_pitch = 0;
double m_yaw = glm::pi<double>() * 5.0 / 16.0;
Player();
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>());
}
void State::update(const Graphics::Context& ctx) {
m_builder.update(m_map, ctx);
void State::update() {
m_player.update();
m_builder.update(*this);
m_map.update();
m_particles.update();
}
void State::render(const Graphics::Context& ctx) const {
m_map.render(ctx);
m_builder.render(ctx);
m_particles.render(ctx);
}

View File

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