Raycast and edit
This commit is contained in:
parent
f3c706013e
commit
5a0c87cd7a
2
TODO.md
2
TODO.md
|
@ -7,7 +7,7 @@
|
|||
- [ ] Octree world
|
||||
- [ ] Serialize
|
||||
- [ ] In memory RLE
|
||||
- [ ] Edition
|
||||
- [x] Edition
|
||||
- [ ] Entity
|
||||
- [ ] Planet
|
||||
- [ ] CubicSphere
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
#version 330 core
|
||||
|
||||
// Ouput data
|
||||
layout(location = 0) out vec4 color;
|
||||
|
||||
in vec4 Color;
|
||||
|
||||
void main(){
|
||||
color = Color;
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
#version 330 core
|
||||
|
||||
|
||||
layout(location = 0) in vec3 Position_modelspace;
|
||||
layout(location = 1) in vec4 Color_model;
|
||||
|
||||
uniform mat4 MVP;
|
||||
|
||||
out vec4 Color;
|
||||
|
||||
void main(){
|
||||
gl_Position = MVP * vec4(Position_modelspace, 1);
|
||||
Color = Color_model;
|
||||
}
|
||||
|
|
@ -41,9 +41,15 @@ vec3 expand(vec3 v) {
|
|||
vec4 getTexture(sampler2DArray sample, vec2 UV) {
|
||||
#ifdef BLEND
|
||||
vec4 colx = texture(sample, vec3(UV, vs.Materials[0]));
|
||||
vec4 coly = texture(sample, vec3(UV, vs.Materials[1]));
|
||||
vec4 colz = texture(sample, vec3(UV, vs.Materials[2]));
|
||||
return colx * vs.MaterialRatio.x + coly * vs.MaterialRatio.y + colz * vs.MaterialRatio.z;
|
||||
if(vs.Materials[1] == vs.Materials[0]) {
|
||||
return vs.Materials[2] == vs.Materials[0] ? colx :
|
||||
mix(colx, texture(sample, vec3(UV, vs.Materials[2])), vs.MaterialRatio.z);
|
||||
} else {
|
||||
vec4 coly = texture(sample, vec3(UV, vs.Materials[1]));
|
||||
return vs.Materials[2] == vs.Materials[0] ? mix(colx, coly, vs.MaterialRatio.y) : (
|
||||
vs.Materials[2] == vs.Materials[1] ? mix(coly, colx, vs.MaterialRatio.x) :
|
||||
colx * vs.MaterialRatio.x + coly * vs.MaterialRatio.y + texture(sample, vec3(UV, vs.Materials[2])) * vs.MaterialRatio.z);
|
||||
}
|
||||
#else
|
||||
return texture(sample, vec3(UV, vs.Material));
|
||||
#endif
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
namespace contouring {
|
||||
static const std::array<std::string, 3> names = {"FlatDualMC", "FlatBox", "Dummy"};
|
||||
static const char* cnames = "FlatDualMC\0FlatBox\0Dummy\0";
|
||||
|
||||
int idxByName(const std::string &name);
|
||||
std::shared_ptr<Abstract> load(int idx, const std::map<std::string, std::string> &data);
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <GLFW/glfw3.h>
|
||||
#include "../data/glm.hpp"
|
||||
#include "../data/geometry/Frustum.hpp"
|
||||
#include "../data/geometry/Ray.hpp"
|
||||
|
||||
/// Moving perspective camera
|
||||
class Camera {
|
||||
|
@ -34,6 +35,7 @@ public:
|
|||
|
||||
glm::vec3 getDirection() const { return glm::vec3(cos(VerticalAngle) * sin(HorizontalAngle), sin(VerticalAngle), cos(VerticalAngle) * cos(HorizontalAngle)); }
|
||||
inline Frustum getFrustum() const { return Frustum(ViewMatrix, ProjectionMatrix); }
|
||||
inline Ray getRay() const { return Ray(Position, getDirection(), o.far); }
|
||||
|
||||
glm::mat4 getViewMatrix() const { return ViewMatrix; }
|
||||
glm::mat4 getProjectionMatrix() const { return ProjectionMatrix; }
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
#pragma once
|
||||
|
||||
#include "Box.hpp"
|
||||
#include "../glm.hpp"
|
||||
|
||||
/// Raycast with distance
|
||||
struct Ray {
|
||||
glm::vec3 from;
|
||||
glm::vec3 dir;
|
||||
float dist;
|
||||
|
||||
// MAYBE: Ray(const glm::mat4& view_matrix) { }
|
||||
Ray(const glm::vec3& from, const glm::vec3& dir, float dist): from(from), dir(glm::normalize(dir)), dist(dist) { }
|
||||
|
||||
inline Ray operator/(float scale) const noexcept {
|
||||
return Ray(from / scale, dir, dist / scale);
|
||||
}
|
||||
|
||||
/// Get path points in integer grid
|
||||
/// @note not precise enough
|
||||
inline void grid(std::vector<voxel_pos>& points) const {
|
||||
voxel_pos current = from + glm::vec3(.5f);
|
||||
voxel_pos d = dir * dist;
|
||||
voxel_pos inc = voxel_pos((d.x < 0) ? -1 : 1, (d.y < 0) ? -1 : 1, (d.z < 0) ? -1 : 1);
|
||||
voxel_pos size = glm::abs(d);
|
||||
voxel_pos delta = size << 1ll;
|
||||
|
||||
if ((size.x >= size.y) && (size.x >= size.z)) {
|
||||
int err_1 = delta.y - size.x;
|
||||
int err_2 = delta.z - size.x;
|
||||
points.reserve(size.x + 1);
|
||||
for (int i = 0; i < size.x; i++) {
|
||||
points.push_back(current);
|
||||
if (err_1 > 0) {
|
||||
current.y += inc.y;
|
||||
err_1 -= delta.x;
|
||||
}
|
||||
if (err_2 > 0) {
|
||||
current.z += inc.z;
|
||||
err_2 -= delta.x;
|
||||
}
|
||||
err_1 += delta.y;
|
||||
err_2 += delta.z;
|
||||
current.x += inc.x;
|
||||
}
|
||||
} else if ((size.y >= size.x) && (size.y >= size.z)) {
|
||||
int err_1 = delta.x - size.y;
|
||||
int err_2 = delta.z - size.y;
|
||||
points.reserve(size.y + 1);
|
||||
for (int i = 0; i < size.y; i++) {
|
||||
points.push_back(current);
|
||||
if (err_1 > 0) {
|
||||
current.x += inc.x;
|
||||
err_1 -= delta.y;
|
||||
}
|
||||
if (err_2 > 0) {
|
||||
current.z += inc.z;
|
||||
err_2 -= delta.y;
|
||||
}
|
||||
err_1 += delta.x;
|
||||
err_2 += delta.z;
|
||||
current.y += inc.y;
|
||||
}
|
||||
} else {
|
||||
int err_1 = delta.y - size.z;
|
||||
int err_2 = delta.x - size.z;
|
||||
points.reserve(size.z + 1);
|
||||
for (int i = 0; i < size.z; i++) {
|
||||
points.push_back(current);
|
||||
if (err_1 > 0) {
|
||||
current.y += inc.y;
|
||||
err_1 -= delta.z;
|
||||
}
|
||||
if (err_2 > 0) {
|
||||
current.x += inc.x;
|
||||
err_2 -= delta.z;
|
||||
}
|
||||
err_1 += delta.y;
|
||||
err_2 += delta.x;
|
||||
current.z += inc.z;
|
||||
}
|
||||
}
|
||||
points.push_back(current);
|
||||
}
|
||||
};
|
|
@ -71,6 +71,10 @@ struct options {
|
|||
show_debug_world = config["show_debug"]["world"].value_or(false);
|
||||
show_debug_contouring = config["show_debug"]["contouring"].value_or(false);
|
||||
show_debug_controls = config["show_debug"]["controls"].value_or(false);
|
||||
|
||||
editor_show = config["editor"]["visible"].value_or(false);
|
||||
tool.material = config["editor"]["tool"]["material"].value_or<int>(tool.material);
|
||||
tool.radius = config["editor"]["tool"]["radius"].value_or(tool.radius);
|
||||
}
|
||||
void save() {
|
||||
auto config = toml::table();
|
||||
|
@ -123,6 +127,14 @@ struct options {
|
|||
{"controls", show_debug_controls}
|
||||
}));
|
||||
|
||||
config.insert_or_assign("editor", toml::table({
|
||||
{"visible", editor_show},
|
||||
{"tool", toml::table({
|
||||
{"material", (int)tool.material},
|
||||
{"radius", tool.radius}
|
||||
})}
|
||||
}));
|
||||
|
||||
std::ofstream out;
|
||||
out.open(PATH, std::ios::out | std::ios::trunc);
|
||||
out << config << "\n\n";
|
||||
|
@ -148,6 +160,12 @@ struct options {
|
|||
bool show_debug_controls;
|
||||
Camera::options camera;
|
||||
|
||||
bool editor_show;
|
||||
struct tool {
|
||||
int radius = 2;
|
||||
unsigned long long material = 2;
|
||||
} tool;
|
||||
|
||||
bool overlay_show;
|
||||
int overlay_corner;
|
||||
|
||||
|
|
48
src/main.cpp
48
src/main.cpp
|
@ -18,6 +18,8 @@
|
|||
#include "control/Camera.hpp"
|
||||
|
||||
#include "render/Renderer.hpp"
|
||||
#include "render/pass/ColorProgram.hpp"
|
||||
#include "render/buffer/ColorBuffer.hpp"
|
||||
#include "world/World.hpp"
|
||||
|
||||
#include "data/state.h"
|
||||
|
@ -41,11 +43,39 @@ int main(int, char *[]){
|
|||
Camera camera(window, inputs, options.camera);
|
||||
|
||||
Renderer *renderer = new Renderer(options.renderer);
|
||||
renderer->LightInvDir = glm::vec3(-0.5f, 2, -2);
|
||||
UI::setup(window);
|
||||
|
||||
GLuint aimTexture = Program::loadTexture("ui/Aim", false);
|
||||
|
||||
renderer->LightInvDir = glm::vec3(-0.5f, 2, -2);
|
||||
ColorProgram *lookProgram = new ColorProgram();
|
||||
ColorBuffer lookBuffer(GL_LINES, 24, {
|
||||
glm::vec3(0, 0, 0), glm::vec3(0, 0, 1),
|
||||
glm::vec3(0, 0, 1), glm::vec3(0, 1, 1),
|
||||
glm::vec3(0, 1, 1), glm::vec3(0, 1, 0),
|
||||
glm::vec3(0, 1, 0), glm::vec3(0, 0, 0),
|
||||
glm::vec3(1, 0, 0), glm::vec3(1, 0, 1),
|
||||
glm::vec3(1, 0, 1), glm::vec3(1, 1, 1),
|
||||
glm::vec3(1, 1, 1), glm::vec3(1, 1, 0),
|
||||
glm::vec3(1, 1, 0), glm::vec3(1, 0, 0),
|
||||
glm::vec3(0, 0, 0), glm::vec3(1, 0, 0),
|
||||
glm::vec3(0, 0, 1), glm::vec3(1, 0, 1),
|
||||
glm::vec3(0, 1, 1), glm::vec3(1, 1, 1),
|
||||
glm::vec3(0, 1, 0), glm::vec3(1, 1, 0),
|
||||
}, {
|
||||
glm::vec4(1, 1, 1, 1), glm::vec4(1, 1, 1, 1),
|
||||
glm::vec4(1, 1, 1, 1), glm::vec4(1, 1, 1, 1),
|
||||
glm::vec4(1, 1, 1, 1), glm::vec4(1, 1, 1, 1),
|
||||
glm::vec4(1, 1, 1, 1), glm::vec4(1, 1, 1, 1),
|
||||
glm::vec4(1, 1, 1, 1), glm::vec4(1, 1, 1, 1),
|
||||
glm::vec4(1, 1, 1, 1), glm::vec4(1, 1, 1, 1),
|
||||
glm::vec4(1, 1, 1, 1), glm::vec4(1, 1, 1, 1),
|
||||
glm::vec4(1, 1, 1, 1), glm::vec4(1, 1, 1, 1),
|
||||
glm::vec4(1, 1, 1, 1), glm::vec4(1, 1, 1, 1),
|
||||
glm::vec4(1, 1, 1, 1), glm::vec4(1, 1, 1, 1),
|
||||
glm::vec4(1, 1, 1, 1), glm::vec4(1, 1, 1, 1),
|
||||
glm::vec4(1, 1, 1, 1), glm::vec4(1, 1, 1, 1),
|
||||
});
|
||||
|
||||
Remotery *rmt;
|
||||
rmt_CreateGlobalInstance(&rmt);
|
||||
|
@ -70,13 +100,13 @@ int main(int, char *[]){
|
|||
renderer->lookFrom(camera);
|
||||
|
||||
state.position = camera.getPosition();
|
||||
/*look_at = world.raycast(camera.getViewRay() / scale);
|
||||
if (capture_mouse && look_at.has_value()) {
|
||||
state.look_at = world.raycast(camera.getRay() / options.voxel_size);
|
||||
if (state.capture_mouse && state.look_at.has_value()) {
|
||||
if (inputs.isPressing(Mouse::Left))
|
||||
world.setCube(look_at.value().first, 2, Voxel{0, 0});
|
||||
world.setCube(state.look_at.value().first, Voxel{0, 0}, options.tool.radius);
|
||||
else if (inputs.isPressing(Mouse::Right))
|
||||
world.setCube(look_at.value().first, 2, Voxel{2, 1});
|
||||
}*/
|
||||
world.setCube(state.look_at.value().first, Voxel{UCHAR_MAX, options.tool.material}, options.tool.radius);
|
||||
}
|
||||
world.update(state.position / options.voxel_size, reports.world);
|
||||
inputs.saveKeys();
|
||||
reports.main.update.push((glfwGetTime() - partTime) * 1000);
|
||||
|
@ -140,6 +170,12 @@ int main(int, char *[]){
|
|||
reports.main.models_count++;
|
||||
reports.main.tris_count += buffer->draw(pass.setup(model));
|
||||
}
|
||||
if(state.look_at.has_value()) {
|
||||
lookProgram->useIt();
|
||||
lookProgram->start(renderer);
|
||||
const auto model = glm::scale(glm::translate(glm::scale(glm::mat4(1), glm::vec3(options.voxel_size)), glm::vec3(state.look_at.value().first) - glm::vec3(.5 + options.tool.radius)), glm::vec3(1 + options.tool.radius * 2));
|
||||
lookBuffer.draw(lookProgram->setup(renderer, model));
|
||||
}
|
||||
renderer->postProcess();
|
||||
|
||||
UI::render();
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "imgui_impl_opengl3.h"
|
||||
#include "pass/Program.hpp"
|
||||
#include "../contouring/Abstract.hpp"
|
||||
#include "../world/materials.hpp"
|
||||
|
||||
void UI::setup(GLFWwindow* window) {
|
||||
// Setup Dear ImGui context
|
||||
|
@ -39,10 +40,14 @@ UI::Actions UI::draw(options &options, state &state, const reports &reports, GLu
|
|||
|
||||
if (options.show_debug_menu) {
|
||||
ImGui::BeginMainMenuBar();
|
||||
ImGui::Checkbox("Render", &options.show_debug_render);
|
||||
ImGui::Checkbox("World", &options.show_debug_world);
|
||||
ImGui::Checkbox("Contouring", &options.show_debug_contouring);
|
||||
ImGui::Checkbox("Controls", &options.show_debug_controls);
|
||||
if (ImGui::BeginMenu("Debug")) {
|
||||
ImGui::Checkbox("Render", &options.show_debug_render);
|
||||
ImGui::Checkbox("World", &options.show_debug_world);
|
||||
ImGui::Checkbox("Contouring", &options.show_debug_contouring);
|
||||
ImGui::Checkbox("Controls", &options.show_debug_controls);
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
ImGui::Checkbox("Editor", &options.editor_show);
|
||||
|
||||
if(ImGui::MenuItem("Close"))
|
||||
options.show_debug_menu = false;
|
||||
|
@ -116,10 +121,18 @@ UI::Actions UI::draw(options &options, state &state, const reports &reports, GLu
|
|||
|
||||
if (options.show_debug_contouring) {
|
||||
ImGui::Begin("Debug: Contouring", &options.show_debug_contouring, ImGuiWindowFlags_AlwaysAutoResize);
|
||||
const auto prev_idx = options.contouring_idx;
|
||||
if(ImGui::Combo("Contouring", &options.contouring_idx, contouring::cnames)) {
|
||||
actions = actions | Actions::ChangeContouring;
|
||||
contouring::save(prev_idx, state.contouring, options.contouring_data);
|
||||
if (ImGui::BeginCombo("Contouring", contouring::names[options.contouring_idx].c_str())) {
|
||||
for (size_t i = 0; i < contouring::names.size(); i++) {
|
||||
const bool is_selected = (options.contouring_idx == (int)i);
|
||||
if (ImGui::Selectable(contouring::names[i].c_str(), is_selected)) {
|
||||
actions = actions | Actions::ChangeContouring;
|
||||
contouring::save(options.contouring_idx, state.contouring, options.contouring_data);
|
||||
options.contouring_idx = i;
|
||||
}
|
||||
if (is_selected)
|
||||
ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
ImGui::Checkbox("Culling", &options.culling);
|
||||
state.contouring->onGui();
|
||||
|
@ -129,12 +142,6 @@ UI::Actions UI::draw(options &options, state &state, const reports &reports, GLu
|
|||
if (options.show_debug_controls) {
|
||||
ImGui::Begin("Debug: Controls", &options.show_debug_controls, ImGuiWindowFlags_AlwaysAutoResize);
|
||||
ImGui::Text("Position: (%.3f, %.3f, %.3f)", state.position.x, state.position.y, state.position.z);
|
||||
if (state.look_at.has_value()) {
|
||||
ImGui::Text("Look at: (%lld, %lld, %lld) (%d, %.1d)", state.look_at.value().first.x, state.look_at.value().first.y, state.look_at.value().first.z, state.look_at.value().second.Material, state.look_at.value().second.Density / UCHAR_MAX);
|
||||
ImGui::Text("(%.3f, %.3f, %.3f)", state.look_at.value().first.x * options.voxel_size, state.look_at.value().first.y * options.voxel_size, state.look_at.value().first.z * options.voxel_size);
|
||||
} else {
|
||||
ImGui::Text("Look at: none");
|
||||
}
|
||||
ImGui::Separator();
|
||||
{
|
||||
bool changePerspective = false;
|
||||
|
@ -150,6 +157,29 @@ UI::Actions UI::draw(options &options, state &state, const reports &reports, GLu
|
|||
ImGui::End();
|
||||
}
|
||||
|
||||
if (options.editor_show) {
|
||||
ImGui::Begin("Editor", &options.editor_show, ImGuiWindowFlags_AlwaysAutoResize);
|
||||
if (state.look_at.has_value()) {
|
||||
ImGui::Text("Look at: (%lld, %lld, %lld) (%s, %.1f)", state.look_at.value().first.x, state.look_at.value().first.y, state.look_at.value().first.z, materials::textures[state.look_at.value().second.Material].c_str(), state.look_at.value().second.Density * 1. / UCHAR_MAX);
|
||||
ImGui::Text("(%.3f, %.3f, %.3f)", state.look_at.value().first.x * options.voxel_size, state.look_at.value().first.y * options.voxel_size, state.look_at.value().first.z * options.voxel_size);
|
||||
} else {
|
||||
ImGui::Text("Look at: none");
|
||||
}
|
||||
ImGui::Separator();
|
||||
if (ImGui::BeginCombo("Material", materials::textures[options.tool.material].c_str())) {
|
||||
for (size_t i = 0; i < materials::textures.size(); i++) {
|
||||
const bool is_selected = (options.tool.material == i);
|
||||
if (ImGui::Selectable(materials::textures[i].c_str(), is_selected))
|
||||
options.tool.material = i;
|
||||
if (is_selected)
|
||||
ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
ImGui::SliderInt("Radius", &options.tool.radius, 0, 10);
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
/*if (show_console) {
|
||||
ImGui::SetNextWindowPos(ImVec2(UI_MARGIN, 500), ImGuiCond_FirstUseEver);
|
||||
ImGui::SetNextWindowSize(ImVec2(200, 100), ImGuiCond_FirstUseEver);
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
#include "ColorBuffer.hpp"
|
||||
|
||||
ColorBuffer::ColorBuffer(GLenum shape, const unsigned long count, const std::vector<glm::vec3> &vertices, const std::vector<glm::vec4> &colors): Buffer(shape) {
|
||||
glGenBuffers(1, &ColorBufferID);
|
||||
setVertices(vertices.size() * sizeof(glm::vec3), &vertices[0]);
|
||||
setColors(colors.size() * sizeof(glm::vec4), &colors[0]);
|
||||
ElementCount = count;
|
||||
}
|
||||
ColorBuffer::~ColorBuffer() {
|
||||
glDeleteBuffers(1, &ColorBufferID);
|
||||
}
|
||||
|
||||
uint ColorBuffer::draw(params params) {
|
||||
if (params.vertexOnly) {
|
||||
enableVertexAttrib();
|
||||
} else {
|
||||
enableAllAttribs();
|
||||
}
|
||||
glDrawArrays(Shape, 0, ElementCount);
|
||||
|
||||
if (params.vertexOnly) {
|
||||
disableVertexAttrib();
|
||||
} else {
|
||||
disableAllAttribs();
|
||||
}
|
||||
return ElementCount;
|
||||
}
|
||||
|
||||
void ColorBuffer::enableAllAttribs() {
|
||||
enableVertexAttrib();
|
||||
|
||||
glEnableVertexAttribArray(1);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, ColorBufferID);
|
||||
glVertexAttribPointer(
|
||||
1, // attribute
|
||||
4, // size
|
||||
GL_FLOAT, // type
|
||||
GL_FALSE, // normalized?
|
||||
0, // stride
|
||||
(void *)0 // array buffer offset
|
||||
);
|
||||
}
|
||||
void ColorBuffer::disableAllAttribs() {
|
||||
glDisableVertexAttribArray(1);
|
||||
|
||||
disableVertexAttrib();
|
||||
}
|
||||
|
||||
void ColorBuffer::setColors(const unsigned long size, const void *data) {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, ColorBufferID);
|
||||
glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
#pragma once
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <vector>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include "Buffer.hpp"
|
||||
|
||||
/// OpenGL VertexBuffer with Colors
|
||||
class ColorBuffer: public Buffer {
|
||||
public:
|
||||
ColorBuffer(GLenum shape, const unsigned long count, const std::vector<glm::vec3> &vertices, const std::vector<glm::vec4> &colors);
|
||||
virtual ~ColorBuffer();
|
||||
|
||||
void enableAllAttribs();
|
||||
void disableAllAttribs();
|
||||
|
||||
uint draw(params params) override;
|
||||
|
||||
private:
|
||||
unsigned long ElementCount;
|
||||
|
||||
GLuint ColorBufferID;
|
||||
|
||||
void setColors(const unsigned long size, const void *data);
|
||||
};
|
|
@ -0,0 +1,30 @@
|
|||
#include "ColorProgram.hpp"
|
||||
|
||||
#include "../Renderer.hpp"
|
||||
|
||||
ColorProgram::ColorProgram(): Program() {
|
||||
|
||||
std::vector<std::string> flags;
|
||||
std::vector<Shader*> shaders;
|
||||
shaders.push_back(loadShader(GL_VERTEX_SHADER, flags));
|
||||
shaders.push_back(loadShader(GL_FRAGMENT_SHADER, flags));
|
||||
load(shaders);
|
||||
|
||||
MVPMatrixID = glGetUniformLocation(ProgramID, "MVP");
|
||||
}
|
||||
|
||||
ColorProgram::~ColorProgram() { }
|
||||
|
||||
std::string ColorProgram::getName() const {
|
||||
return "Color";
|
||||
}
|
||||
void ColorProgram::start(Renderer *renderer) { }
|
||||
Buffer::params ColorProgram::setup(Renderer *renderer, glm::mat4 modelMatrix) {
|
||||
const auto mvp = renderer->getProjectionMatrix() * renderer->getViewMatrix() * modelMatrix;
|
||||
setMVP(&mvp[0][0]);
|
||||
return Buffer::params{.vertexOnly = false};
|
||||
}
|
||||
|
||||
void ColorProgram::setMVP(const GLfloat *matrix) {
|
||||
glUniformMatrix4fv(MVPMatrixID, 1, GL_FALSE, matrix);
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
#include "Program.hpp"
|
||||
|
||||
/// Final pass
|
||||
class ColorProgram: public Program {
|
||||
public:
|
||||
ColorProgram();
|
||||
~ColorProgram();
|
||||
|
||||
std::string getName() const override;
|
||||
void start(Renderer *) override;
|
||||
Buffer::params setup(Renderer *, glm::mat4 modelMatrix) override;
|
||||
|
||||
void setMVP(const GLfloat *matrix);
|
||||
|
||||
private:
|
||||
GLuint MVPMatrixID;
|
||||
};
|
|
@ -11,20 +11,20 @@ Chunk::Chunk(const chunk_pos& pos, Generator& rnd) {
|
|||
|
||||
for (size_t i = 0; i < CHUNK_SIZE; i++) {
|
||||
voxels[i].Density = std::clamp((densitySet[i] + DENSITY) * GRANULARITY, 0.f, 1.f) * UCHAR_MAX;
|
||||
voxels[i].Material = voxels[i].Density > 0 ? 1 + std::clamp(static_cast<int>(std::lrint((materialSet[i] + 1) / 2 * (materials::count - 1))),
|
||||
0, materials::count - 1) : 0; //NOTE: map (approx -1, 1) to (1, mat_max)
|
||||
voxels[i].Material = voxels[i].Density > 0 ? 1 + std::clamp(static_cast<int>(std::lrint((materialSet[i] + 1) / 2 * (materials::count - 2))),
|
||||
0, materials::count - 2) : 0; //NOTE: map (approx -1, 1) to (1, mat_max)
|
||||
}
|
||||
FastNoiseSIMD::FreeNoiseSet(densitySet);
|
||||
FastNoiseSIMD::FreeNoiseSet(materialSet);
|
||||
}
|
||||
Chunk::~Chunk() { }
|
||||
|
||||
bool Chunk::update() {
|
||||
std::optional<Faces> Chunk::update() {
|
||||
if(upToDate) {
|
||||
return false;
|
||||
return {};
|
||||
} else {
|
||||
upToDate = true;
|
||||
return true;
|
||||
return {toUpdate};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,14 +15,16 @@ public:
|
|||
~Chunk();
|
||||
|
||||
/// Update voxels
|
||||
/// @return true if modified
|
||||
bool update();
|
||||
/// @return if modified neightbors to update
|
||||
std::optional<Faces> update();
|
||||
|
||||
const Voxel* begin() const {
|
||||
return voxels.begin();
|
||||
}
|
||||
inline void invalidate() {
|
||||
inline void invalidate(Faces faces) {
|
||||
upToDate = false;
|
||||
toUpdate = toUpdate | faces;
|
||||
modified = true;
|
||||
}
|
||||
inline const Voxel& get(ushort idx) const {
|
||||
return voxels[idx];
|
||||
|
@ -32,11 +34,23 @@ public:
|
|||
}
|
||||
void set(ushort idx, const Voxel& val) {
|
||||
voxels[idx] = val;
|
||||
invalidate();
|
||||
invalidate(
|
||||
((!getNeighborIdx(idx, Face::Up).has_value()) & Faces::Up) |
|
||||
((!getNeighborIdx(idx, Face::Down).has_value()) & Faces::Down) |
|
||||
((!getNeighborIdx(idx, Face::Left).has_value()) & Faces::Left) |
|
||||
((!getNeighborIdx(idx, Face::Right).has_value()) & Faces::Right) |
|
||||
((!getNeighborIdx(idx, Face::Forward).has_value()) & Faces::Forward) |
|
||||
((!getNeighborIdx(idx, Face::Backward).has_value()) & Faces::Backward));
|
||||
}
|
||||
void setAt(const chunk_voxel_pos& pos, const Voxel& val) {
|
||||
set(getIdx(pos), val);
|
||||
}
|
||||
Item breakAt(const chunk_voxel_pos& pos, const Voxel& val) {
|
||||
const auto idx = getIdx(pos);
|
||||
const auto res = voxels[idx];
|
||||
set(idx, val);
|
||||
return Item{res.Density, res.Material};
|
||||
}
|
||||
|
||||
static inline chunk_voxel_pos getPosition(ushort idx) {
|
||||
return chunk_voxel_pos(idx / CHUNK_LENGTH2, (idx / CHUNK_LENGTH) % CHUNK_LENGTH, idx % CHUNK_LENGTH);
|
||||
|
@ -54,4 +68,8 @@ private:
|
|||
std::array<Voxel, CHUNK_SIZE> voxels;
|
||||
/// Require update
|
||||
bool upToDate = true;
|
||||
/// Neighbors to update
|
||||
Faces toUpdate = Faces::None;
|
||||
/// Modified by player
|
||||
bool modified = false;
|
||||
};
|
||||
|
|
|
@ -1,6 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
#include <map>
|
||||
|
||||
struct Voxel {
|
||||
unsigned char Density;
|
||||
unsigned short Material;
|
||||
};
|
||||
struct Item {
|
||||
unsigned long long Count;
|
||||
unsigned short Material;
|
||||
};
|
||||
struct ItemList: std::map<unsigned short, unsigned long long> {
|
||||
void add(const std::optional<Item>& item) {
|
||||
if(item) {
|
||||
(*this)[item.value().Material] += item.value().Count;
|
||||
}
|
||||
}
|
||||
};
|
|
@ -53,8 +53,8 @@ void World::update(const camera_pos& pos, World::report& rep) {
|
|||
continue;
|
||||
}
|
||||
|
||||
if (chunk->update()) { // MAYBE: also contour joints
|
||||
contouring->onUpdate(chunkPos, chunks, Faces::None); //TODO: get update update_type(simple(pos), complex)
|
||||
if (const auto neighbors = chunk->update()) {
|
||||
contouring->onUpdate(chunkPos, chunks, neighbors.value()); //TODO: get update update_type(simple(pos), complex)
|
||||
} else if (chunkChange) { //NOTE: must be solved before octrees
|
||||
contouring->onNotify(chunkPos, chunks);
|
||||
}
|
||||
|
@ -113,3 +113,44 @@ void World::setContouring(std::shared_ptr<contouring::Abstract> ct) {
|
|||
contouring = ct;
|
||||
last_pos = chunk_pos(INT_MAX); // trigger chunkChange on next update
|
||||
}
|
||||
|
||||
std::optional<std::pair<voxel_pos, Voxel>> World::raycast(const Ray &ray) const {
|
||||
std::vector<voxel_pos> points;
|
||||
ray.grid(points);
|
||||
std::shared_ptr<Chunk> chunk = NULL;
|
||||
chunk_pos chunk_pos(INT_MAX);
|
||||
for(auto point: points) {
|
||||
const auto pos = glm::divide(point, glm::ivec3(CHUNK_LENGTH));
|
||||
if(pos != chunk_pos) {
|
||||
if(const auto& newChunk = at(pos)) {
|
||||
chunk = newChunk.value();
|
||||
chunk_pos = pos;
|
||||
}
|
||||
}
|
||||
if(chunk != NULL) {
|
||||
const auto voxel = chunk->getAt(glm::modulo(point, glm::uvec3(CHUNK_LENGTH)));
|
||||
if(voxel.Density > 0)
|
||||
return {{point, voxel}};
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
std::optional<Item> World::set(const voxel_pos& pos, const Voxel& val) {
|
||||
const auto chunkPos = glm::divide(pos, glm::ivec3(CHUNK_LENGTH));
|
||||
if(const auto& chunk = at(chunkPos)) {
|
||||
return {chunk.value()->breakAt(glm::modulo(pos, glm::ivec3(CHUNK_LENGTH)), val)};
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
ItemList World::setCube(const voxel_pos& pos, const Voxel& val, int radius) {
|
||||
ItemList list;
|
||||
for (int z = -radius; z <= radius; z++) {
|
||||
for (int y = -radius; y <= radius; y++) {
|
||||
for (int x = -radius; x <= radius; x++) {
|
||||
//TODO: list.pop(val)
|
||||
list.add(set(pos + glm::lvec3(x, y, z), val));
|
||||
}}}
|
||||
return list;
|
||||
}
|
|
@ -7,6 +7,8 @@
|
|||
#include "../data/safe_priority_queue.hpp"
|
||||
#include "../data/circular_buffer.hpp"
|
||||
#include "Chunk.hpp"
|
||||
#include "../data/geometry/Ray.hpp"
|
||||
|
||||
#define REPORT_BUFFER_SIZE 128
|
||||
|
||||
namespace contouring {
|
||||
|
@ -37,6 +39,9 @@ public:
|
|||
return {};
|
||||
return {it->second};
|
||||
}
|
||||
std::optional<std::pair<voxel_pos, Voxel>> raycast(const Ray &ray) const;
|
||||
std::optional<Item> set(const voxel_pos &pos, const Voxel &val);
|
||||
ItemList setCube(const voxel_pos &pos, const Voxel &val, int radius);
|
||||
|
||||
/// Change contouring worker
|
||||
void setContouring(std::shared_ptr<contouring::Abstract>);
|
||||
|
|
Loading…
Reference in New Issue