Merge pull request #521 from MihailRis/render-update

Render update
This commit is contained in:
MihailRis 2025-04-30 18:37:56 +03:00 committed by GitHub
commit 76fb2e42d3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
54 changed files with 926 additions and 802 deletions

View File

@ -45,6 +45,16 @@
} }
], ],
"buildPresets": [ "buildPresets": [
{
"name": "Debug build",
"configurePreset": "default-vs-msvc-windows",
"configuration": "Debug"
},
{
"name": "Release build",
"configurePreset": "default-vs-msvc-windows",
"configuration": "Release"
},
{ {
"name": "default-vs-msvc-windows", "name": "default-vs-msvc-windows",
"configurePreset": "default-vs-msvc-windows", "configurePreset": "default-vs-msvc-windows",

View File

@ -3,7 +3,7 @@
layout (location = 0) in vec3 v_position; layout (location = 0) in vec3 v_position;
layout (location = 1) in vec2 v_texCoord; layout (location = 1) in vec2 v_texCoord;
layout (location = 2) in vec3 v_color; layout (location = 2) in vec3 v_color;
layout (location = 3) in float v_light; layout (location = 3) in vec4 v_light;
out vec4 a_color; out vec4 a_color;
out vec2 a_texCoord; out vec2 a_texCoord;
@ -31,8 +31,7 @@ void main() {
vec3 pos3d = modelpos.xyz - u_cameraPos; vec3 pos3d = modelpos.xyz - u_cameraPos;
modelpos.xyz = apply_planet_curvature(modelpos.xyz, pos3d); modelpos.xyz = apply_planet_curvature(modelpos.xyz, pos3d);
vec4 decomp_light = decompress_light(v_light); vec3 light = v_light.rgb;
vec3 light = decomp_light.rgb;
float torchlight = max(0.0, 1.0-distance(u_cameraPos, modelpos.xyz) / float torchlight = max(0.0, 1.0-distance(u_cameraPos, modelpos.xyz) /
u_torchlightDistance); u_torchlightDistance);
light += torchlight * u_torchlightColor; light += torchlight * u_torchlightColor;
@ -41,7 +40,7 @@ void main() {
a_dir = modelpos.xyz - u_cameraPos; a_dir = modelpos.xyz - u_cameraPos;
vec3 skyLightColor = pick_sky_color(u_cubemap); vec3 skyLightColor = pick_sky_color(u_cubemap);
a_color.rgb = max(a_color.rgb, skyLightColor.rgb*decomp_light.a) * v_color; a_color.rgb = max(a_color.rgb, skyLightColor.rgb*v_light.a) * v_color;
a_color.a = u_opacity; a_color.a = u_opacity;
float dist = length(u_view * u_model * vec4(pos3d * FOG_POS_SCALE, 0.0)); float dist = length(u_view * u_model * vec4(pos3d * FOG_POS_SCALE, 0.0));

View File

@ -1,28 +1,17 @@
#ifndef COMMONS_GLSL_ #ifndef COMMONS_GLSL_
#define COMMONS_GLSL_ #define COMMONS_GLSL_
#include <constants> #include <constants>
vec4 decompress_light(float compressed_light) {
vec4 result;
int compressed = floatBitsToInt(compressed_light);
result.r = ((compressed >> 24) & 0xFF) / 255.f;
result.g = ((compressed >> 16) & 0xFF) / 255.f;
result.b = ((compressed >> 8) & 0xFF) / 255.f;
result.a = (compressed & 0xFF) / 255.f;
return result;
}
vec3 pick_sky_color(samplerCube cubemap) { vec3 pick_sky_color(samplerCube cubemap) {
vec3 skyLightColor = texture(cubemap, vec3(0.4f, 0.0f, 0.4f)).rgb; vec3 skyLightColor = texture(cubemap, vec3(0.4f, 0.0f, 0.4f)).rgb;
skyLightColor *= SKY_LIGHT_TINT; skyLightColor *= SKY_LIGHT_TINT;
skyLightColor = min(vec3(1.0), skyLightColor*SKY_LIGHT_MUL); skyLightColor = min(vec3(1.0f), skyLightColor * SKY_LIGHT_MUL);
skyLightColor = max(MIN_SKY_LIGHT, skyLightColor); skyLightColor = max(MIN_SKY_LIGHT, skyLightColor);
return skyLightColor; return skyLightColor;
} }
vec3 apply_planet_curvature(vec3 modelPos, vec3 pos3d) { vec3 apply_planet_curvature(vec3 modelPos, vec3 pos3d) {
modelPos.y -= pow(length(pos3d.xz)*CURVATURE_FACTOR, 3.0); modelPos.y -= pow(length(pos3d.xz) * CURVATURE_FACTOR, 3.0f);
return modelPos; return modelPos;
} }

View File

@ -7,10 +7,13 @@ out vec4 f_color;
uniform sampler2D u_texture0; uniform sampler2D u_texture0;
uniform samplerCube u_cubemap; uniform samplerCube u_cubemap;
uniform bool u_alphaClip; uniform bool u_alphaClip;
uniform bool u_debugLights;
void main() { void main() {
vec3 fogColor = texture(u_cubemap, a_dir).rgb; vec3 fogColor = texture(u_cubemap, a_dir).rgb;
vec4 tex_color = texture(u_texture0, a_texCoord); vec4 tex_color = texture(u_texture0, a_texCoord);
if (u_debugLights)
tex_color.rgb = vec3(1.0);
float alpha = a_color.a * tex_color.a; float alpha = a_color.a * tex_color.a;
if (u_alphaClip) { if (u_alphaClip) {
if (alpha < 0.2f) if (alpha < 0.2f)

View File

@ -2,7 +2,7 @@
layout (location = 0) in vec3 v_position; layout (location = 0) in vec3 v_position;
layout (location = 1) in vec2 v_texCoord; layout (location = 1) in vec2 v_texCoord;
layout (location = 2) in float v_light; layout (location = 2) in vec4 v_light;
out vec4 a_color; out vec4 a_color;
out vec2 a_texCoord; out vec2 a_texCoord;
@ -27,13 +27,12 @@ uniform vec3 u_torchlightColor;
uniform float u_torchlightDistance; uniform float u_torchlightDistance;
void main() { void main() {
vec4 modelpos = u_model * vec4(v_position, 1.0); vec4 modelpos = u_model * vec4(v_position, 1.0f);
vec3 pos3d = modelpos.xyz-u_cameraPos; vec3 pos3d = modelpos.xyz-u_cameraPos;
modelpos.xyz = apply_planet_curvature(modelpos.xyz, pos3d); modelpos.xyz = apply_planet_curvature(modelpos.xyz, pos3d);
vec4 decomp_light = decompress_light(v_light); vec3 light = v_light.rgb;
vec3 light = decomp_light.rgb; float torchlight = max(0.0, 1.0-distance(u_cameraPos, modelpos.xyz) /
float torchlight = max(0.0, 1.0-distance(u_cameraPos, modelpos.xyz) /
u_torchlightDistance); u_torchlightDistance);
light += torchlight * u_torchlightColor; light += torchlight * u_torchlightColor;
a_color = vec4(pow(light, vec3(u_gamma)),1.0f); a_color = vec4(pow(light, vec3(u_gamma)),1.0f);
@ -41,7 +40,7 @@ void main() {
a_dir = modelpos.xyz - u_cameraPos; a_dir = modelpos.xyz - u_cameraPos;
vec3 skyLightColor = pick_sky_color(u_cubemap); vec3 skyLightColor = pick_sky_color(u_cubemap);
a_color.rgb = max(a_color.rgb, skyLightColor.rgb*decomp_light.a); a_color.rgb = max(a_color.rgb, skyLightColor.rgb*v_light.a);
a_distance = length(u_view * u_model * vec4(pos3d * FOG_POS_SCALE, 0.0)); a_distance = length(u_view * u_model * vec4(pos3d * FOG_POS_SCALE, 0.0));
float depth = (a_distance / 256.0); float depth = (a_distance / 256.0);

View File

@ -257,12 +257,12 @@ void AssetsLoader::addDefaults(AssetsLoader& loader, const Content* content) {
} }
} }
for (const auto& [_, def] : content->blocks.getDefs()) { for (const auto& [_, def] : content->blocks.getDefs()) {
if (!def->modelName.empty() && if (!def->model.name.empty() &&
def->modelName.find(':') == std::string::npos) { def->model.name.find(':') == std::string::npos) {
loader.add( loader.add(
AssetType::MODEL, AssetType::MODEL,
MODELS_FOLDER + "/" + def->modelName, MODELS_FOLDER + "/" + def->model.name,
def->modelName def->model.name
); );
} }
} }

View File

@ -1,13 +1,12 @@
#include "png.hpp" #include "png.hpp"
#include <png.h> #include <png.h>
#include <GL/glew.h>
#include <iostream> #include <iostream>
#include "debug/Logger.hpp" #include "debug/Logger.hpp"
#include "io/io.hpp" #include "io/io.hpp"
#include "graphics/core/GLTexture.hpp" #include "graphics/core/Texture.hpp"
#include "graphics/core/ImageData.hpp" #include "graphics/core/ImageData.hpp"
static debug::Logger logger("png-coder"); static debug::Logger logger("png-coder");
@ -206,7 +205,7 @@ std::unique_ptr<ImageData> png::load_image(const ubyte* bytes, size_t size) {
std::unique_ptr<Texture> png::load_texture(const ubyte* bytes, size_t size) { std::unique_ptr<Texture> png::load_texture(const ubyte* bytes, size_t size) {
auto image = load_image(bytes, size); auto image = load_image(bytes, size);
auto texture = GLTexture::from(image.get()); auto texture = Texture::from(image.get());
texture->setNearestFilter(); texture->setNearestFilter();
return texture; return texture;
} }

View File

@ -28,7 +28,7 @@ std::unique_ptr<Content> ContentBuilder::build() {
// Generating runtime info // Generating runtime info
def.rt.id = blockDefsIndices.size(); def.rt.id = blockDefsIndices.size();
def.rt.emissive = *reinterpret_cast<uint32_t*>(def.emission); def.rt.emissive = *reinterpret_cast<uint32_t*>(def.emission);
def.rt.solid = def.model == BlockModel::block; def.rt.solid = def.model.type == BlockModelType::BLOCK;
def.rt.extended = def.size.x > 1 || def.size.y > 1 || def.size.z > 1; def.rt.extended = def.size.x > 1 || def.size.y > 1 || def.size.z > 1;
const float EPSILON = 0.01f; const float EPSILON = 0.01f;

View File

@ -86,20 +86,23 @@ template<> void ContentUnitLoader<Block>::loadUnit(
} }
// block model // block model
std::string modelTypeName = BlockModelMeta.getNameString(def.model); auto& model = def.model;
std::string modelTypeName = BlockModelTypeMeta.getNameString(model.type);
root.at("model").get(modelTypeName); root.at("model").get(modelTypeName);
root.at("model-name").get(def.modelName); root.at("model-name").get(def.model.name);
if (BlockModelMeta.getItem(modelTypeName, def.model)) { if (BlockModelTypeMeta.getItem(modelTypeName, model.type)) {
if (def.model == BlockModel::custom && def.customModelRaw == nullptr) { if (model.type == BlockModelType::CUSTOM && def.model.customRaw == nullptr) {
if (root.has("model-primitives")) { if (root.has("model-primitives")) {
def.customModelRaw = root["model-primitives"]; def.model.customRaw = root["model-primitives"];
} else if (def.modelName.empty()) { } else if (def.model.name.empty()) {
throw std::runtime_error(name + ": no 'model-primitives' or 'model-name' found"); throw std::runtime_error(
name + ": no 'model-primitives' or 'model-name' found"
);
} }
} }
} else if (!modelTypeName.empty()) { } else if (!modelTypeName.empty()) {
logger.error() << "unknown model: " << modelTypeName; logger.error() << "unknown model: " << modelTypeName;
def.model = BlockModel::none; model.type = BlockModelType::NONE;
} }
std::string cullingModeName = CullingModeMeta.getNameString(def.culling); std::string cullingModeName = CullingModeMeta.getNameString(def.culling);
@ -171,9 +174,9 @@ template<> void ContentUnitLoader<Block>::loadUnit(
"block " + util::quote(def.name) + ": invalid block size" "block " + util::quote(def.name) + ": invalid block size"
); );
} }
if (def.model == BlockModel::block && if (model.type == BlockModelType::BLOCK &&
(def.size.x != 1 || def.size.y != 1 || def.size.z != 1)) { (def.size.x != 1 || def.size.y != 1 || def.size.z != 1)) {
def.model = BlockModel::aabb; model.type = BlockModelType::AABB;
def.hitboxes = {AABB(def.size)}; def.hitboxes = {AABB(def.size)};
} }
} }

View File

@ -19,7 +19,7 @@ void corecontent::setup(Input& input, ContentBuilder& builder) {
block.skyLightPassing = true; block.skyLightPassing = true;
block.obstacle = false; block.obstacle = false;
block.selectable = false; block.selectable = false;
block.model = BlockModel::none; block.model.type = BlockModelType::NONE;
block.pickingItem = CORE_EMPTY; block.pickingItem = CORE_EMPTY;
} }
{ {

View File

@ -203,7 +203,8 @@ void Engine::updateHotkeys() {
if (input->jpressed(Keycode::F2)) { if (input->jpressed(Keycode::F2)) {
saveScreenshot(); saveScreenshot();
} }
if (input->jpressed(Keycode::F8)) { if (input->pressed(Keycode::LEFT_CONTROL) && input->pressed(Keycode::F3) &&
input->jpressed(Keycode::U)) {
gui->toggleDebug(); gui->toggleDebug();
} }
if (input->jpressed(Keycode::F11)) { if (input->jpressed(Keycode::F11)) {

View File

@ -35,10 +35,10 @@ void ContentGfxCache::refresh(const Block& def, const Atlas& atlas) {
sideregions[def.rt.id * 6 + side] = atlas.get(TEXTURE_NOTFOUND); sideregions[def.rt.id * 6 + side] = atlas.get(TEXTURE_NOTFOUND);
} }
} }
if (def.model == BlockModel::custom) { if (def.model.type == BlockModelType::CUSTOM) {
auto model = assets.require<model::Model>(def.modelName); auto model = assets.require<model::Model>(def.model.name);
// temporary dirty fix tbh // temporary dirty fix tbh
if (def.modelName.find(':') == std::string::npos) { if (def.model.name.find(':') == std::string::npos) {
for (auto& mesh : model.meshes) { for (auto& mesh : model.meshes) {
size_t pos = mesh.texture.find(':'); size_t pos = mesh.texture.find(':');
if (pos == std::string::npos) { if (pos == std::string::npos) {

View File

@ -93,11 +93,11 @@ std::shared_ptr<UINode> create_debug_panel(
panel->add(create_label(gui, []() { return L"fps: "+fpsString;})); panel->add(create_label(gui, []() { return L"fps: "+fpsString;}));
panel->add(create_label(gui, []() { panel->add(create_label(gui, []() {
return L"meshes: " + std::to_wstring(Mesh::meshesCount); return L"meshes: " + std::to_wstring(MeshStats::meshesCount);
})); }));
panel->add(create_label(gui, []() { panel->add(create_label(gui, []() {
int drawCalls = Mesh::drawCalls; int drawCalls = MeshStats::drawCalls;
Mesh::drawCalls = 0; MeshStats::drawCalls = 0;
return L"draw-calls: " + std::to_wstring(drawCalls); return L"draw-calls: " + std::to_wstring(drawCalls);
})); }));
panel->add(create_label(gui, []() { panel->add(create_label(gui, []() {

View File

@ -184,16 +184,21 @@ void LevelScreen::saveWorldPreview() {
void LevelScreen::updateHotkeys() { void LevelScreen::updateHotkeys() {
auto& settings = engine.getSettings(); auto& settings = engine.getSettings();
if (input.jpressed(Keycode::O)) {
settings.graphics.frustumCulling.toggle();
}
if (input.jpressed(Keycode::F1)) { if (input.jpressed(Keycode::F1)) {
hudVisible = !hudVisible; hudVisible = !hudVisible;
} }
if (input.jpressed(Keycode::F3)) { if (!input.pressed(Keycode::LEFT_CONTROL)) {
debug = !debug; if (input.jpressed(Keycode::F3)) {
hud->setDebug(debug); debug = !debug;
renderer->setDebug(debug); hud->setDebug(debug);
renderer->setDebug(debug);
}
} else if (input.pressed(Keycode::F3)) {
if (input.jpressed(Keycode::L)) {
renderer->toggleLightsDebug();
} else if (input.jpressed(Keycode::O)) {
settings.graphics.frustumCulling.toggle();
}
} }
} }

View File

@ -4,19 +4,12 @@
#include "gl_util.hpp" #include "gl_util.hpp"
#include "maths/UVRegion.hpp" #include "maths/UVRegion.hpp"
#include <GL/glew.h>
#include <cmath> #include <cmath>
inline constexpr uint B2D_VERTEX_SIZE = 8;
Batch2D::Batch2D(size_t capacity) : capacity(capacity), color(1.0f){ Batch2D::Batch2D(size_t capacity) : capacity(capacity), color(1.0f){
const VertexAttribute attrs[] = { buffer = std::make_unique<Batch2DVertex[]>(capacity );
{2}, {2}, {4}, {0} mesh = std::make_unique<Mesh<Batch2DVertex>>(buffer.get(), 0);
};
buffer = std::make_unique<float[]>(capacity * B2D_VERTEX_SIZE);
mesh = std::make_unique<Mesh>(buffer.get(), 0, attrs);
index = 0; index = 0;
const ubyte pixels[] = { const ubyte pixels[] = {
@ -51,28 +44,20 @@ void Batch2D::vertex(
float u, float v, float u, float v,
float r, float g, float b, float a float r, float g, float b, float a
) { ) {
buffer[index++] = x; buffer[index].position = {x, y};
buffer[index++] = y; buffer[index].uv = {u * region.getWidth() + region.u1, v * region.getHeight() + region.v1};
buffer[index++] = u * region.getWidth() + region.u1; buffer[index].color = {r, g, b, a};
buffer[index++] = v * region.getHeight() + region.v1; index++;
buffer[index++] = r;
buffer[index++] = g;
buffer[index++] = b;
buffer[index++] = a;
} }
void Batch2D::vertex( void Batch2D::vertex(
glm::vec2 point, glm::vec2 point,
glm::vec2 uvpoint, glm::vec2 uvpoint,
float r, float g, float b, float a float r, float g, float b, float a
) { ) {
buffer[index++] = point.x; buffer[index].position = point;
buffer[index++] = point.y; buffer[index].uv = {uvpoint.x * region.getWidth() + region.u1, uvpoint.y * region.getHeight() + region.v1};
buffer[index++] = uvpoint.x * region.getWidth() + region.u1; buffer[index].color = {r, g, b, a};
buffer[index++] = uvpoint.y * region.getHeight() + region.v1; index++;
buffer[index++] = r;
buffer[index++] = g;
buffer[index++] = b;
buffer[index++] = a;
} }
void Batch2D::texture(const Texture* new_texture){ void Batch2D::texture(const Texture* new_texture){
@ -99,14 +84,14 @@ void Batch2D::setRegion(UVRegion region) {
} }
void Batch2D::point(float x, float y, float r, float g, float b, float a){ void Batch2D::point(float x, float y, float r, float g, float b, float a){
if (index + 6*B2D_VERTEX_SIZE >= capacity) if (index + 6 >= capacity)
flush(); flush();
setPrimitive(DrawPrimitive::point); setPrimitive(DrawPrimitive::point);
vertex(x, y, 0, 0, r,g,b,a); vertex(x, y, 0, 0, r,g,b,a);
} }
void Batch2D::line(float x1, float y1, float x2, float y2, float r, float g, float b, float a){ void Batch2D::line(float x1, float y1, float x2, float y2, float r, float g, float b, float a){
if (index + 6*B2D_VERTEX_SIZE >= capacity) { if (index + 6 >= capacity) {
flush(); flush();
} }
setPrimitive(DrawPrimitive::line); setPrimitive(DrawPrimitive::line);
@ -119,7 +104,7 @@ void Batch2D::rect(float x, float y, float w, float h){
const float g = color.g; const float g = color.g;
const float b = color.b; const float b = color.b;
const float a = color.a; const float a = color.a;
if (index + 6*B2D_VERTEX_SIZE >= capacity) { if (index + 6 >= capacity) {
flush(); flush();
} }
setPrimitive(DrawPrimitive::triangle); setPrimitive(DrawPrimitive::triangle);
@ -142,7 +127,7 @@ void Batch2D::rect(
bool flippedY, bool flippedY,
glm::vec4 tint glm::vec4 tint
) { ) {
if (index + 6 * B2D_VERTEX_SIZE >= capacity) { if (index + 6 >= capacity) {
flush(); flush();
} }
setPrimitive(DrawPrimitive::triangle); setPrimitive(DrawPrimitive::triangle);
@ -230,14 +215,14 @@ void Batch2D::rect(
} }
void Batch2D::lineRect(float x, float y, float w, float h) { void Batch2D::lineRect(float x, float y, float w, float h) {
if (index + 8 * B2D_VERTEX_SIZE >= capacity) { if (index + 8 >= capacity) {
flush(); flush();
} }
setPrimitive(DrawPrimitive::line); setPrimitive(DrawPrimitive::line);
vertex(x, y, 0.0f, 0.0f, color.r, color.g, color.b, color.a); vertex(x, y, 0.0f, 0.0f, color.r, color.g, color.b, color.a);
vertex(x, y+h, 0.0f, 1.0f, color.r, color.g, color.b, color.a); vertex(x, y+h, 0.0f, 1.0f, color.r, color.g, color.b, color.a);
vertex(x, y+h, 0.0f, 1.0f, color.r, color.g, color.b, color.a); vertex(x, y+h, 0.0f, 1.0f, color.r, color.g, color.b, color.a);
vertex(x+w, y+h, 1.0f, 1.0f, color.r, color.g, color.b, color.a); vertex(x+w, y+h, 1.0f, 1.0f, color.r, color.g, color.b, color.a);
@ -253,7 +238,7 @@ void Batch2D::rect(
float u, float v, float tx, float ty, float u, float v, float tx, float ty,
float r, float g, float b, float a float r, float g, float b, float a
){ ){
if (index + 6*B2D_VERTEX_SIZE >= capacity) { if (index + 6 >= capacity) {
flush(); flush();
} }
setPrimitive(DrawPrimitive::triangle); setPrimitive(DrawPrimitive::triangle);
@ -271,7 +256,7 @@ void Batch2D::parallelogram(
float u, float v, float tx, float ty, float u, float v, float tx, float ty,
float r, float g, float b, float a float r, float g, float b, float a
){ ){
if (index + 6*B2D_VERTEX_SIZE >= capacity) { if (index + 6 >= capacity) {
flush(); flush();
} }
setPrimitive(DrawPrimitive::triangle); setPrimitive(DrawPrimitive::triangle);
@ -292,7 +277,7 @@ void Batch2D::rect(
float r3, float g3, float b3, float r3, float g3, float b3,
float r4, float g4, float b4, int sh float r4, float g4, float b4, int sh
){ ){
if (index + 30*B2D_VERTEX_SIZE >= capacity) { if (index + 30 >= capacity) {
flush(); flush();
} }
setPrimitive(DrawPrimitive::triangle); setPrimitive(DrawPrimitive::triangle);
@ -378,7 +363,7 @@ void Batch2D::sprite(
void Batch2D::flush() { void Batch2D::flush() {
if (index == 0) if (index == 0)
return; return;
mesh->reload(buffer.get(), index / B2D_VERTEX_SIZE); mesh->reload(buffer.get(), index);
mesh->draw(gl::to_glenum(primitive)); mesh->draw(gl::to_glenum(primitive));
index = 0; index = 0;
} }

View File

@ -1,19 +1,32 @@
#pragma once #pragma once
#include <memory> #include <memory>
#include <stdlib.h>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include "commons.hpp" #include "commons.hpp"
#include "maths/UVRegion.hpp" #include "maths/UVRegion.hpp"
#include "MeshData.hpp"
template<typename VertexStructure>
class Mesh; class Mesh;
class Texture; class Texture;
struct Batch2DVertex {
glm::vec2 position;
glm::vec2 uv;
glm::vec4 color;
static constexpr VertexAttribute ATTRIBUTES[] {
{VertexAttribute::Type::FLOAT, false, 2},
{VertexAttribute::Type::FLOAT, false, 2},
{VertexAttribute::Type::FLOAT, false, 4},
{{}, 0}};
};
class Batch2D : public Flushable { class Batch2D : public Flushable {
std::unique_ptr<float[]> buffer; std::unique_ptr<Batch2DVertex[]> buffer;
size_t capacity; size_t capacity;
std::unique_ptr<Mesh> mesh; std::unique_ptr<Mesh<Batch2DVertex>> mesh;
std::unique_ptr<Texture> blank; std::unique_ptr<Texture> blank;
size_t index; size_t index;
glm::vec4 color; glm::vec4 color;

View File

@ -3,21 +3,15 @@
#include "Mesh.hpp" #include "Mesh.hpp"
#include "Texture.hpp" #include "Texture.hpp"
#include <GL/glew.h>
#include "typedefs.hpp" #include "typedefs.hpp"
#include "maths/UVRegion.hpp" #include "maths/UVRegion.hpp"
/// xyz, uv, rgba Batch3D::Batch3D(size_t capacity)
inline constexpr uint B3D_VERTEX_SIZE = 9;
Batch3D::Batch3D(size_t capacity)
: capacity(capacity) { : capacity(capacity) {
const VertexAttribute attrs[] = {
{3}, {2}, {4}, {0}
};
buffer = std::make_unique<float[]>(capacity * B3D_VERTEX_SIZE);
mesh = std::make_unique<Mesh>(buffer.get(), 0, attrs); buffer = std::make_unique<Batch3DVertex[]>(capacity);
mesh = std::make_unique<Mesh<Batch3DVertex>>(buffer.get(), 0);
index = 0; index = 0;
const ubyte pixels[] = { const ubyte pixels[] = {
@ -40,69 +34,54 @@ void Batch3D::vertex(
float x, float y, float z, float u, float v, float x, float y, float z, float u, float v,
float r, float g, float b, float a float r, float g, float b, float a
) { ) {
buffer[index++] = x; buffer[index].position = {x, y, z};
buffer[index++] = y; buffer[index].uv = {u, v};
buffer[index++] = z; buffer[index].color = {r, g, b, a};
buffer[index++] = u; index++;
buffer[index++] = v;
buffer[index++] = r;
buffer[index++] = g;
buffer[index++] = b;
buffer[index++] = a;
} }
void Batch3D::vertex( void Batch3D::vertex(
glm::vec3 coord, float u, float v, glm::vec3 coord, float u, float v,
float r, float g, float b, float a float r, float g, float b, float a
) { ) {
buffer[index++] = coord.x; buffer[index].position = coord;
buffer[index++] = coord.y; buffer[index].uv = {u, v};
buffer[index++] = coord.z; buffer[index].color = {r, g, b, a};
buffer[index++] = u; index++;
buffer[index++] = v;
buffer[index++] = r;
buffer[index++] = g;
buffer[index++] = b;
buffer[index++] = a;
} }
void Batch3D::vertex( void Batch3D::vertex(
glm::vec3 point, glm::vec3 point,
glm::vec2 uvpoint, glm::vec2 uvpoint,
float r, float g, float b, float a float r, float g, float b, float a
) { ) {
buffer[index++] = point.x; buffer[index].position = point;
buffer[index++] = point.y; buffer[index].uv = uvpoint;
buffer[index++] = point.z; buffer[index].color = {r, g, b, a};
buffer[index++] = uvpoint.x; index++;
buffer[index++] = uvpoint.y;
buffer[index++] = r;
buffer[index++] = g;
buffer[index++] = b;
buffer[index++] = a;
} }
void Batch3D::face( void Batch3D::face(
const glm::vec3& coord, const glm::vec3& coord,
float w, float h, float w, float h,
const glm::vec3& axisX, const glm::vec3& axisX,
const glm::vec3& axisY, const glm::vec3& axisY,
const UVRegion& region, const UVRegion& region,
const glm::vec4& tint const glm::vec4& tint
) { ) {
if (index + B3D_VERTEX_SIZE * 6 > capacity) { if (index + 6 >= capacity) {
flush(); flush();
} }
vertex(coord, region.u1, region.v1, vertex(coord, region.u1, region.v1,
tint.r, tint.g, tint.b, tint.a); tint.r, tint.g, tint.b, tint.a);
vertex(coord + axisX * w, region.u2, region.v1, vertex(coord + axisX * w, region.u2, region.v1,
tint.r, tint.g, tint.b, tint.a); tint.r, tint.g, tint.b, tint.a);
vertex(coord + axisX * w + axisY * h, region.u2, region.v2, vertex(coord + axisX * w + axisY * h, region.u2, region.v2,
tint.r, tint.g, tint.b, tint.a); tint.r, tint.g, tint.b, tint.a);
vertex(coord, region.u1, region.v1, vertex(coord, region.u1, region.v1,
tint.r, tint.g, tint.b, tint.a); tint.r, tint.g, tint.b, tint.a);
vertex(coord + axisX * w + axisY * h, region.u2, region.v2, vertex(coord + axisX * w + axisY * h, region.u2, region.v2,
tint.r, tint.g, tint.b, tint.a); tint.r, tint.g, tint.b, tint.a);
vertex(coord + axisY * h, region.u1, region.v2, vertex(coord + axisY * h, region.u1, region.v2,
tint.r, tint.g, tint.b, tint.a); tint.r, tint.g, tint.b, tint.a);
} }
@ -134,18 +113,18 @@ void Batch3D::sprite(
} }
void Batch3D::sprite( void Batch3D::sprite(
const glm::vec3& pos, const glm::vec3& pos,
const glm::vec3& up, const glm::vec3& up,
const glm::vec3& right, const glm::vec3& right,
float w, float h, float w, float h,
const UVRegion& uv, const UVRegion& uv,
const glm::vec4& color const glm::vec4& color
){ ){
const float r = color.r; const float r = color.r;
const float g = color.g; const float g = color.g;
const float b = color.b; const float b = color.b;
const float a = color.a; const float a = color.a;
if (index + 6*B3D_VERTEX_SIZE >= capacity) { if (index + 6 >= capacity) {
flush(); flush();
} }
@ -194,17 +173,17 @@ void Batch3D::xSprite(
float w, float h, const UVRegion& uv, const glm::vec4& tint, bool shading float w, float h, const UVRegion& uv, const glm::vec4& tint, bool shading
) { ) {
face( face(
glm::vec3(-w * 0.25f, 0.0f, -w * 0.25f), glm::vec3(-w * 0.25f, 0.0f, -w * 0.25f),
w, h, w, h,
glm::vec3(1, 0, 0), glm::vec3(1, 0, 0),
glm::vec3(0, 1, 0), glm::vec3(0, 1, 0),
uv, (shading ? do_tint(1.0f)*tint : tint) uv, (shading ? do_tint(1.0f)*tint : tint)
); );
face( face(
glm::vec3(w * 0.25f, 0.0f, w * 0.5f - w * 0.25f), glm::vec3(w * 0.25f, 0.0f, w * 0.5f - w * 0.25f),
w, h, w, h,
glm::vec3(0, 0, -1), glm::vec3(0, 0, -1),
glm::vec3(0, 1, 0), glm::vec3(0, 1, 0),
uv, (shading ? do_tint(0.9f)*tint : tint) uv, (shading ? do_tint(0.9f)*tint : tint)
); );
} }
@ -221,41 +200,41 @@ void Batch3D::cube(
const glm::vec3 Z(0.0f, 0.0f, 1.0f); const glm::vec3 Z(0.0f, 0.0f, 1.0f);
face( face(
coord+glm::vec3(0.0f, 0.0f, 0.0f), coord+glm::vec3(0.0f, 0.0f, 0.0f),
size.x, size.y, X, Y, texfaces[5], size.x, size.y, X, Y, texfaces[5],
(shading ? do_tint(0.8)*tint : tint) (shading ? do_tint(0.8)*tint : tint)
); );
face( face(
coord+glm::vec3(size.x, 0.0f, -size.z), coord+glm::vec3(size.x, 0.0f, -size.z),
size.x, size.y, -X, Y, texfaces[4], size.x, size.y, -X, Y, texfaces[4],
(shading ? do_tint(0.8f)*tint : tint) (shading ? do_tint(0.8f)*tint : tint)
); );
face( face(
coord+glm::vec3(0.0f, size.y, 0.0f), coord+glm::vec3(0.0f, size.y, 0.0f),
size.x, size.z, X, -Z, texfaces[3], size.x, size.z, X, -Z, texfaces[3],
(shading ? do_tint(1.0f)*tint : tint) (shading ? do_tint(1.0f)*tint : tint)
); );
face( face(
coord+glm::vec3(0.0f, 0.0f, -size.z), coord+glm::vec3(0.0f, 0.0f, -size.z),
size.x, size.z, X, Z, texfaces[2], size.x, size.z, X, Z, texfaces[2],
(shading ? do_tint(0.7f)*tint : tint) (shading ? do_tint(0.7f)*tint : tint)
); );
face( face(
coord+glm::vec3(0.0f, 0.0f, -size.z), coord+glm::vec3(0.0f, 0.0f, -size.z),
size.z, size.y, Z, Y, texfaces[0], size.z, size.y, Z, Y, texfaces[0],
(shading ? do_tint(0.9f)*tint : tint) (shading ? do_tint(0.9f)*tint : tint)
); );
face( face(
coord+glm::vec3(size.x, 0.0f, 0.0f), coord+glm::vec3(size.x, 0.0f, 0.0f),
size.z, size.y, -Z, Y, texfaces[1], size.z, size.y, -Z, Y, texfaces[1],
(shading ? do_tint(0.9f)*tint : tint) (shading ? do_tint(0.9f)*tint : tint)
); );
} }
void Batch3D::blockCube( void Batch3D::blockCube(
const glm::vec3& size, const glm::vec3& size,
const UVRegion(&texfaces)[6], const UVRegion(&texfaces)[6],
const glm::vec4& tint, const glm::vec4& tint,
bool shading bool shading
) { ) {
cube((1.0f - size) * -0.5f, size, texfaces, tint, shading); cube((1.0f - size) * -0.5f, size, texfaces, tint, shading);
@ -264,27 +243,27 @@ void Batch3D::blockCube(
void Batch3D::vertex( void Batch3D::vertex(
const glm::vec3& coord, const glm::vec2& uv, const glm::vec4& tint const glm::vec3& coord, const glm::vec2& uv, const glm::vec4& tint
) { ) {
if (index + B3D_VERTEX_SIZE >= capacity) { if (index + 1 >= capacity) {
flush(); flush();
} }
vertex(coord, uv, tint.r, tint.g, tint.b, tint.a); vertex(coord, uv, tint.r, tint.g, tint.b, tint.a);
} }
void Batch3D::point(const glm::vec3& coord, const glm::vec4& tint) { void Batch3D::point(const glm::vec3& coord, const glm::vec4& tint) {
if (index + B3D_VERTEX_SIZE >= capacity) { if (index + 1 >= capacity) {
flushPoints(); flushPoints();
} }
vertex(coord, {}, tint.r, tint.g, tint.b, tint.a); vertex(coord, {}, tint.r, tint.g, tint.b, tint.a);
} }
void Batch3D::flush() { void Batch3D::flush() {
mesh->reload(buffer.get(), index / B3D_VERTEX_SIZE); mesh->reload(buffer.get(), index);
mesh->draw(); mesh->draw();
index = 0; index = 0;
} }
void Batch3D::flushPoints() { void Batch3D::flushPoints() {
mesh->reload(buffer.get(), index / B3D_VERTEX_SIZE); mesh->reload(buffer.get(), index);
mesh->draw(GL_POINTS); mesh->draw(GL_POINTS);
index = 0; index = 0;
} }

View File

@ -2,19 +2,33 @@
#include "typedefs.hpp" #include "typedefs.hpp"
#include "commons.hpp" #include "commons.hpp"
#include "MeshData.hpp"
#include <memory> #include <memory>
#include <stdlib.h> #include <cstdlib>
#include <glm/glm.hpp> #include <glm/glm.hpp>
class Mesh; template<typename VertexStructure> class Mesh;
class Texture; class Texture;
struct UVRegion; struct UVRegion;
struct Batch3DVertex {
glm::vec3 position;
glm::vec2 uv;
glm::vec4 color;
static constexpr VertexAttribute ATTRIBUTES[] {
{VertexAttribute::Type::FLOAT, false, 3},
{VertexAttribute::Type::FLOAT, false, 2},
{VertexAttribute::Type::FLOAT, false, 4},
{{}, 0}};
};
class Batch3D : public Flushable { class Batch3D : public Flushable {
std::unique_ptr<float[]> buffer; std::unique_ptr<Batch3DVertex[]> buffer;
size_t capacity; size_t capacity;
std::unique_ptr<Mesh> mesh; std::unique_ptr<Mesh<Batch3DVertex>> mesh;
std::unique_ptr<Texture> blank; std::unique_ptr<Texture> blank;
size_t index; size_t index;
glm::vec4 tint {1.0f}; glm::vec4 tint {1.0f};

View File

@ -4,7 +4,7 @@
#include <GL/glew.h> #include <GL/glew.h>
Cubemap::Cubemap(uint width, uint height, ImageFormat imageFormat) Cubemap::Cubemap(uint width, uint height, ImageFormat imageFormat)
: GLTexture(0, width, height) : Texture(0, width, height)
{ {
glGenTextures(1, &id); glGenTextures(1, &id);
glBindTexture(GL_TEXTURE_CUBE_MAP, id); glBindTexture(GL_TEXTURE_CUBE_MAP, id);

View File

@ -1,9 +1,9 @@
#pragma once #pragma once
#include "GLTexture.hpp" #include "Texture.hpp"
/// @brief Cubemap texture /// @brief Cubemap texture
class Cubemap : public GLTexture { class Cubemap : public Texture {
public: public:
Cubemap(uint width, uint height, ImageFormat format); Cubemap(uint width, uint height, ImageFormat format);

View File

@ -1,7 +1,7 @@
#include "Framebuffer.hpp" #include "Framebuffer.hpp"
#include <GL/glew.h> #include <GL/glew.h>
#include "GLTexture.hpp" #include "Texture.hpp"
Framebuffer::Framebuffer(uint fbo, uint depth, std::unique_ptr<Texture> texture) Framebuffer::Framebuffer(uint fbo, uint depth, std::unique_ptr<Texture> texture)
: fbo(fbo), depth(depth), texture(std::move(texture)) : fbo(fbo), depth(depth), texture(std::move(texture))
@ -25,7 +25,7 @@ static std::unique_ptr<Texture> create_texture(int width, int height, int format
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
return std::make_unique<GLTexture>(tex, width, height); return std::make_unique<Texture>(tex, width, height);
} }
Framebuffer::Framebuffer(uint width, uint height, bool alpha) Framebuffer::Framebuffer(uint width, uint height, bool alpha)

View File

@ -1,101 +0,0 @@
#include "GLTexture.hpp"
#include "gl_util.hpp"
#include <GL/glew.h>
#include <stdexcept>
#include <memory>
uint Texture::MAX_RESOLUTION = 1024; // Window.initialize overrides it
GLTexture::GLTexture(uint id, uint width, uint height)
: Texture(width, height), id(id) {
}
GLTexture::GLTexture(const ubyte* data, uint width, uint height, ImageFormat imageFormat)
: Texture(width, height) {
glGenTextures(1, &id);
glBindTexture(GL_TEXTURE_2D, id);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
GLenum format = gl::to_glenum(imageFormat);
glTexImage2D(
GL_TEXTURE_2D, 0, format, width, height, 0,
format, GL_UNSIGNED_BYTE, static_cast<const GLvoid*>(data)
);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
glBindTexture(GL_TEXTURE_2D, 0);
}
GLTexture::~GLTexture() {
glDeleteTextures(1, &id);
}
void GLTexture::bind() const {
glBindTexture(GL_TEXTURE_2D, id);
}
void GLTexture::unbind() const {
glBindTexture(GL_TEXTURE_2D, 0);
}
void GLTexture::reload(const ImageData& image) {
width = image.getWidth();
height = image.getHeight();
reload(image.getData());
}
void GLTexture::reload(const ubyte* data) {
glBindTexture(GL_TEXTURE_2D, id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, static_cast<const GLvoid*>(data));
glBindTexture(GL_TEXTURE_2D, 0);
}
std::unique_ptr<ImageData> GLTexture::readData() {
auto data = std::make_unique<ubyte[]>(width * height * 4);
glBindTexture(GL_TEXTURE_2D, id);
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, data.get());
glBindTexture(GL_TEXTURE_2D, 0);
return std::make_unique<ImageData>(
ImageFormat::rgba8888, width, height, std::move(data)
);
}
void GLTexture::setNearestFilter() {
bind();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glBindTexture(GL_TEXTURE_2D, 0);
}
void GLTexture::setMipMapping(bool flag, bool pixelated) {
bind();
if (flag) {
glTexParameteri(
GL_TEXTURE_2D,
GL_TEXTURE_MIN_FILTER,
pixelated ? GL_NEAREST : GL_LINEAR_MIPMAP_NEAREST
);
} else {
glTexParameteri(
GL_TEXTURE_2D,
GL_TEXTURE_MIN_FILTER,
pixelated ? GL_NEAREST : GL_LINEAR
);
}
glBindTexture(GL_TEXTURE_2D, 0);
}
std::unique_ptr<GLTexture> GLTexture::from(const ImageData* image) {
uint width = image->getWidth();
uint height = image->getHeight();
void* data = image->getData();
return std::make_unique<GLTexture>(static_cast<ubyte*>(data), width, height, image->getFormat());
}
uint GLTexture::getId() const {
return id;
}

View File

@ -1,31 +0,0 @@
#pragma once
#include "Texture.hpp"
class GLTexture : public Texture {
protected:
uint id;
public:
GLTexture(uint id, uint width, uint height);
GLTexture(const ubyte* data, uint width, uint height, ImageFormat format);
virtual ~GLTexture();
virtual void bind() const override;
virtual void unbind() const override;
virtual void reload(const ubyte* data);
void setNearestFilter();
virtual void reload(const ImageData& image) override;
virtual void setMipMapping(bool flag, bool pixelated) override;
virtual std::unique_ptr<ImageData> readData() override;
virtual uint getId() const override;
virtual UVRegion getUVRegion() const override {
return UVRegion(0.0f, 0.0f, 1.0f, 1.0f);
}
static std::unique_ptr<GLTexture> from(const ImageData* image);
};

View File

@ -3,12 +3,11 @@
#include <GL/glew.h> #include <GL/glew.h>
inline constexpr uint LB_VERTEX_SIZE = (3+4);
LineBatch::LineBatch(size_t capacity) : capacity(capacity) { LineBatch::LineBatch(size_t capacity) : capacity(capacity) {
const VertexAttribute attrs[] = { {3},{4}, {0} };
buffer = std::make_unique<float[]>(capacity * LB_VERTEX_SIZE * 2); buffer = std::make_unique<LineVertex[]>(capacity * 2);
mesh = std::make_unique<Mesh>(buffer.get(), 0, attrs); mesh = std::make_unique<Mesh<LineVertex>>(buffer.get(), 0);
index = 0; index = 0;
} }
@ -16,31 +15,21 @@ LineBatch::~LineBatch(){
} }
void LineBatch::line( void LineBatch::line(
float x1, float y1, float x1, float y1,
float z1, float x2, float z1, float x2,
float y2, float z2, float y2, float z2,
float r, float g, float b, float a float r, float g, float b, float a
) { ) {
if (index + LB_VERTEX_SIZE * 2 >= capacity) { if (index + 2 >= capacity) {
flush(); flush();
} }
buffer[index] = x1; buffer[index].position = {x1,y1,z1};
buffer[index+1] = y1; buffer[index].color = {r,g,b,a};
buffer[index+2] = z1; index++;
buffer[index+3] = r;
buffer[index+4] = g;
buffer[index+5] = b;
buffer[index+6] = a;
index += LB_VERTEX_SIZE;
buffer[index] = x2; buffer[index].position = {x2,y2,z2};
buffer[index+1] = y2; buffer[index].color = {r,g,b,a};
buffer[index+2] = z2; index++;
buffer[index+3] = r;
buffer[index+4] = g;
buffer[index+5] = b;
buffer[index+6] = a;
index += LB_VERTEX_SIZE;
} }
void LineBatch::box(float x, float y, float z, float w, float h, float d, void LineBatch::box(float x, float y, float z, float w, float h, float d,
@ -68,7 +57,7 @@ void LineBatch::box(float x, float y, float z, float w, float h, float d,
void LineBatch::flush(){ void LineBatch::flush(){
if (index == 0) if (index == 0)
return; return;
mesh->reload(buffer.get(), index / LB_VERTEX_SIZE); mesh->reload(buffer.get(), index);
mesh->draw(GL_LINES); mesh->draw(GL_LINES);
index = 0; index = 0;
} }

View File

@ -5,12 +5,24 @@
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include "commons.hpp" #include "commons.hpp"
#include "MeshData.hpp"
template<typename VertexStructure>
class Mesh; class Mesh;
struct LineVertex {
glm::vec3 position;
glm::vec4 color;
static constexpr VertexAttribute ATTRIBUTES[] {
{VertexAttribute::Type::FLOAT, false, 3},
{VertexAttribute::Type::FLOAT, false, 4},
{{}, 0}};
};
class LineBatch : public Flushable { class LineBatch : public Flushable {
std::unique_ptr<Mesh> mesh; std::unique_ptr<Mesh<LineVertex>> mesh;
std::unique_ptr<float[]> buffer; std::unique_ptr<LineVertex[]> buffer;
size_t index; size_t index;
size_t capacity; size_t capacity;
public: public:

View File

@ -1,93 +1,4 @@
#include "Mesh.hpp" #include "graphics/core/Mesh.hpp"
#include <assert.h>
#include <GL/glew.h>
int Mesh::meshesCount = 0; int MeshStats::meshesCount = 0;
int Mesh::drawCalls = 0; int MeshStats::drawCalls = 0;
inline size_t calc_vertex_size(const VertexAttribute* attrs) {
size_t vertexSize = 0;
for (int i = 0; attrs[i].size; i++) {
vertexSize += attrs[i].size;
}
assert(vertexSize != 0);
return vertexSize;
}
Mesh::Mesh(const MeshData& data)
: Mesh(data.vertices.data(),
data.vertices.size() / calc_vertex_size(data.attrs.data()),
data.indices.data(),
data.indices.size(),
data.attrs.data()) {}
Mesh::Mesh(const float* vertexBuffer, size_t vertices, const int* indexBuffer, size_t indices, const VertexAttribute* attrs) :
ibo(0),
vertices(0),
indices(0)
{
meshesCount++;
vertexSize = 0;
for (int i = 0; attrs[i].size; i++) {
vertexSize += attrs[i].size;
}
glGenVertexArrays(1, &vao);
glGenBuffers(1, &vbo);
reload(vertexBuffer, vertices, indexBuffer, indices);
// attributes
int offset = 0;
for (int i = 0; attrs[i].size; i++) {
int size = attrs[i].size;
glVertexAttribPointer(i, size, GL_FLOAT, GL_FALSE, vertexSize * sizeof(float), (GLvoid*)(offset * sizeof(float)));
glEnableVertexAttribArray(i);
offset += size;
}
glBindVertexArray(0);
}
Mesh::~Mesh(){
meshesCount--;
glDeleteVertexArrays(1, &vao);
glDeleteBuffers(1, &vbo);
if (ibo != 0) glDeleteBuffers(1, &ibo);
}
void Mesh::reload(const float* vertexBuffer, size_t vertices, const int* indexBuffer, size_t indices){
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
if (vertexBuffer != nullptr && vertices != 0) {
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * vertexSize * vertices, vertexBuffer, GL_STREAM_DRAW);
} else {
glBufferData(GL_ARRAY_BUFFER, 0, {}, GL_STREAM_DRAW);
}
if (indexBuffer != nullptr && indices != 0) {
if (ibo == 0) glGenBuffers(1, &ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int) * indices, indexBuffer, GL_STATIC_DRAW);
}
else if (ibo != 0) {
glDeleteBuffers(1, &ibo);
}
this->vertices = vertices;
this->indices = indices;
}
void Mesh::draw(unsigned int primitive) const {
drawCalls++;
glBindVertexArray(vao);
if (ibo != 0) {
glDrawElements(primitive, indices, GL_UNSIGNED_INT, 0);
}
else {
glDrawArrays(primitive, 0, vertices);
}
glBindVertexArray(0);
}
void Mesh::draw() const {
draw(GL_TRIANGLES);
}

View File

@ -1,39 +1,54 @@
#pragma once #pragma once
#include <stdlib.h>
#include "typedefs.hpp"
#include "MeshData.hpp" #include "MeshData.hpp"
struct MeshStats {
static int meshesCount;
static int drawCalls;
};
template <typename VertexStructure>
class Mesh { class Mesh {
unsigned int vao; unsigned int vao;
unsigned int vbo; unsigned int vbo;
unsigned int ibo; unsigned int ibo;
size_t vertices; size_t vertexCount;
size_t indices; size_t indexCount;
size_t vertexSize;
public: public:
Mesh(const MeshData& data); explicit Mesh(const MeshData<VertexStructure>& data);
Mesh(const float* vertexBuffer, size_t vertices, const int* indexBuffer, size_t indices, const VertexAttribute* attrs);
Mesh(const float* vertexBuffer, size_t vertices, const VertexAttribute* attrs) : Mesh(
Mesh(vertexBuffer, vertices, nullptr, 0, attrs) {}; const VertexStructure* vertexBuffer,
size_t vertices,
const uint32_t* indexBuffer,
size_t indices
);
Mesh(const VertexStructure* vertexBuffer, size_t vertices)
: Mesh<VertexStructure>(vertexBuffer, vertices, nullptr, 0) {};
~Mesh(); ~Mesh();
/// @brief Update GL vertex and index buffers data without changing VAO attributes /// @brief Update GL vertex and index buffers data without changing VAO
/// attributes
/// @param vertexBuffer vertex data buffer /// @param vertexBuffer vertex data buffer
/// @param vertices number of vertices in new buffer /// @param vertexCount number of vertices in new buffer
/// @param indexBuffer indices buffer /// @param indexBuffer indices buffer
/// @param indices number of values in indices buffer /// @param indexCount number of values in indices buffer
void reload(const float* vertexBuffer, size_t vertices, const int* indexBuffer = nullptr, size_t indices = 0); void reload(
const VertexStructure* vertexBuffer,
size_t vertexCount,
const uint32_t* indexBuffer = nullptr,
size_t indexCount = 0
);
/// @brief Draw mesh with specified primitives type /// @brief Draw mesh with specified primitives type
/// @param primitive primitives type /// @param primitive primitives type
void draw(unsigned int primitive) const; void draw(unsigned int primitive) const;
/// @brief Draw mesh as triangles /// @brief Draw mesh as triangles
void draw() const; void draw() const;
/// @brief Total numbers of alive mesh objects
static int meshesCount;
static int drawCalls;
}; };
#include "graphics/core/Mesh.inl"

124
src/graphics/core/Mesh.inl Normal file
View File

@ -0,0 +1,124 @@
#pragma once
#include "MeshData.hpp"
#include "gl_util.hpp"
inline constexpr size_t calc_size(const VertexAttribute attrs[]) {
size_t vertexSize = 0;
for (int i = 0; attrs[i].count; i++) {
vertexSize += attrs[i].size();
}
return vertexSize;
}
template <typename VertexStructure>
Mesh<VertexStructure>::Mesh(const MeshData<VertexStructure>& data)
: Mesh(
data.vertices.data(),
data.vertices.size(),
data.indices.data(),
data.indices.size()
) {
}
template <typename VertexStructure>
Mesh<VertexStructure>::Mesh(
const VertexStructure* vertexBuffer,
size_t vertices,
const uint32_t* indexBuffer,
size_t indices
)
: vao(0), vbo(0), ibo(0), vertexCount(0), indexCount(0) {
static_assert(
calc_size(VertexStructure::ATTRIBUTES) == sizeof(VertexStructure)
);
const auto& attrs = VertexStructure::ATTRIBUTES;
MeshStats::meshesCount++;
glGenVertexArrays(1, &vao);
glGenBuffers(1, &vbo);
reload(vertexBuffer, vertices, indexBuffer, indices);
// attributes
int offset = 0;
for (int i = 0; attrs[i].count; i++) {
const VertexAttribute& attr = attrs[i];
glVertexAttribPointer(
i,
attr.count,
gl::to_glenum(attr.type),
attr.normalized,
sizeof(VertexStructure),
(GLvoid*)(size_t)offset
);
glEnableVertexAttribArray(i);
offset += attr.size();
}
glBindVertexArray(0);
}
template <typename VertexStructure>
Mesh<VertexStructure>::~Mesh() {
MeshStats::meshesCount--;
glDeleteVertexArrays(1, &vao);
glDeleteBuffers(1, &vbo);
if (ibo != 0) {
glDeleteBuffers(1, &ibo);
}
}
template <typename VertexStructure>
void Mesh<VertexStructure>::reload(
const VertexStructure* vertexBuffer,
size_t vertexCount,
const uint32_t* indexBuffer,
size_t indexCount
) {
this->vertexCount = vertexCount;
this->indexCount = indexCount;
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
if (vertexBuffer != nullptr && vertexCount != 0) {
glBufferData(
GL_ARRAY_BUFFER,
vertexCount * sizeof(VertexStructure),
vertexBuffer,
GL_STREAM_DRAW
);
} else {
glBufferData(GL_ARRAY_BUFFER, 0, {}, GL_STREAM_DRAW);
}
if (indexBuffer != nullptr && indexCount != 0) {
if (ibo == 0) glGenBuffers(1, &ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(
GL_ELEMENT_ARRAY_BUFFER,
sizeof(uint32_t) * indexCount,
indexBuffer,
GL_STATIC_DRAW
);
} else if (ibo != 0) {
glDeleteBuffers(1, &ibo);
}
}
template <typename VertexStructure>
void Mesh<VertexStructure>::draw(unsigned int primitive) const {
MeshStats::drawCalls++;
glBindVertexArray(vao);
if (ibo != 0) {
glDrawElements(primitive, indexCount, GL_UNSIGNED_INT, nullptr);
} else {
glDrawArrays(primitive, 0, vertexCount);
}
glBindVertexArray(0);
}
template <typename VertexStructure>
void Mesh<VertexStructure>::draw() const {
draw(GL_TRIANGLES);
}

View File

@ -1,19 +1,46 @@
#pragma once #pragma once
#include <vector> #include <stdexcept>
#include "typedefs.hpp" #include "typedefs.hpp"
#include "util/Buffer.hpp" #include "util/Buffer.hpp"
/// @brief Vertex attribute info /// @brief Vertex attribute info
struct VertexAttribute { struct VertexAttribute {
ubyte size; enum class Type {
FLOAT,
INT, UNSIGNED_INT,
SHORT, UNSIGNED_SHORT,
BYTE, UNSIGNED_BYTE
};
Type type = Type::FLOAT;
bool normalized = false;
ubyte count = 0;
[[nodiscard]] constexpr uint32_t size() const {
switch (type) {
case Type::FLOAT:
return count * sizeof(float);
case Type::UNSIGNED_INT:
case Type::INT:
return count * sizeof(int32_t);
case Type::UNSIGNED_SHORT:
case Type::SHORT:
return count * sizeof(int16_t);
case Type::UNSIGNED_BYTE:
case Type::BYTE:
return count * sizeof(int8_t);
}
return 0;
}
}; };
/// @brief Raw mesh data structure /// @brief Raw mesh data structure
template<typename VertexStructure>
struct MeshData { struct MeshData {
util::Buffer<float> vertices; util::Buffer<VertexStructure> vertices;
util::Buffer<int> indices; util::Buffer<uint32_t> indices;
util::Buffer<VertexAttribute> attrs; util::Buffer<VertexAttribute> attrs;
MeshData() = default; MeshData() = default;
@ -22,8 +49,8 @@ struct MeshData {
/// @param indices nullable indices buffer /// @param indices nullable indices buffer
/// @param attrs vertex attribute sizes (must be null-terminated) /// @param attrs vertex attribute sizes (must be null-terminated)
MeshData( MeshData(
util::Buffer<float> vertices, util::Buffer<VertexStructure> vertices,
util::Buffer<int> indices, util::Buffer<uint32_t> indices,
util::Buffer<VertexAttribute> attrs util::Buffer<VertexAttribute> attrs
) : vertices(std::move(vertices)), ) : vertices(std::move(vertices)),
indices(std::move(indices)), indices(std::move(indices)),

View File

@ -12,12 +12,16 @@
PostProcessing::PostProcessing(size_t effectSlotsCount) PostProcessing::PostProcessing(size_t effectSlotsCount)
: effectSlots(effectSlotsCount) { : effectSlots(effectSlotsCount) {
// Fullscreen quad mesh bulding // Fullscreen quad mesh bulding
float vertices[] { PostProcessingVertex meshData[]{
-1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, {{-1.0f, -1.0f}},
-1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f {{-1.0f, 1.0f}},
{{1.0f, 1.0f}},
{{-1.0f, -1.0f}},
{{1.0f, 1.0f}},
{{1.0f, -1.0f}},
}; };
VertexAttribute attrs[] {{2}, {0}};
quadMesh = std::make_unique<Mesh>(vertices, 6, attrs); quadMesh = std::make_unique<Mesh<PostProcessingVertex>>(meshData, 6);
} }
PostProcessing::~PostProcessing() = default; PostProcessing::~PostProcessing() = default;

View File

@ -2,14 +2,24 @@
#include <vector> #include <vector>
#include <memory> #include <memory>
#include <glm/glm.hpp>
#include "MeshData.hpp"
class Mesh; template<typename VertexStructure> class Mesh;
class Assets; class Assets;
class Framebuffer; class Framebuffer;
class DrawContext; class DrawContext;
class ImageData; class ImageData;
class PostEffect; class PostEffect;
struct PostProcessingVertex {
glm::vec2 position;
static constexpr VertexAttribute ATTRIBUTES[] {
{VertexAttribute::Type::FLOAT, false, 2},
{{}, 0}};
};
/// @brief Framebuffer with blitting with shaders. /// @brief Framebuffer with blitting with shaders.
/// @attention Current implementation does not support multiple render passes /// @attention Current implementation does not support multiple render passes
/// for multiple effects. Will be implemented in v0.21 /// for multiple effects. Will be implemented in v0.21
@ -18,7 +28,7 @@ class PostProcessing {
std::unique_ptr<Framebuffer> fbo; std::unique_ptr<Framebuffer> fbo;
std::unique_ptr<Framebuffer> fboSecond; std::unique_ptr<Framebuffer> fboSecond;
/// @brief Fullscreen quad mesh as the post-processing canvas /// @brief Fullscreen quad mesh as the post-processing canvas
std::unique_ptr<Mesh> quadMesh; std::unique_ptr<Mesh<PostProcessingVertex>> quadMesh;
std::vector<std::shared_ptr<PostEffect>> effectSlots; std::vector<std::shared_ptr<PostEffect>> effectSlots;
public: public:
PostProcessing(size_t effectSlotsCount); PostProcessing(size_t effectSlotsCount);

View File

@ -1,6 +1,103 @@
#include "Texture.hpp" #include "Texture.hpp"
#include "GLTexture.hpp" #include "gl_util.hpp"
#include <GL/glew.h>
#include <stdexcept>
#include <memory>
uint Texture::MAX_RESOLUTION = 1024; // Window.initialize overrides it
Texture::Texture(uint id, uint width, uint height)
: id(id), width(width), height(height) {
}
Texture::Texture(const ubyte* data, uint width, uint height, ImageFormat imageFormat)
: width(width), height(height) {
glGenTextures(1, &id);
glBindTexture(GL_TEXTURE_2D, id);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
GLenum format = gl::to_glenum(imageFormat);
glTexImage2D(
GL_TEXTURE_2D, 0, format, width, height, 0,
format, GL_UNSIGNED_BYTE, static_cast<const GLvoid*>(data)
);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
glBindTexture(GL_TEXTURE_2D, 0);
}
Texture::~Texture() {
glDeleteTextures(1, &id);
}
void Texture::bind() const {
glBindTexture(GL_TEXTURE_2D, id);
}
void Texture::unbind() const {
glBindTexture(GL_TEXTURE_2D, 0);
}
void Texture::reload(const ImageData& image) {
width = image.getWidth();
height = image.getHeight();
reload(image.getData());
}
void Texture::reload(const ubyte* data) {
glBindTexture(GL_TEXTURE_2D, id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, static_cast<const GLvoid*>(data));
glBindTexture(GL_TEXTURE_2D, 0);
}
std::unique_ptr<ImageData> Texture::readData() {
auto data = std::make_unique<ubyte[]>(width * height * 4);
glBindTexture(GL_TEXTURE_2D, id);
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, data.get());
glBindTexture(GL_TEXTURE_2D, 0);
return std::make_unique<ImageData>(
ImageFormat::rgba8888, width, height, std::move(data)
);
}
void Texture::setNearestFilter() {
bind();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glBindTexture(GL_TEXTURE_2D, 0);
}
void Texture::setMipMapping(bool flag, bool pixelated) {
bind();
if (flag) {
glTexParameteri(
GL_TEXTURE_2D,
GL_TEXTURE_MIN_FILTER,
pixelated ? GL_NEAREST : GL_LINEAR_MIPMAP_NEAREST
);
} else {
glTexParameteri(
GL_TEXTURE_2D,
GL_TEXTURE_MIN_FILTER,
pixelated ? GL_NEAREST : GL_LINEAR
);
}
glBindTexture(GL_TEXTURE_2D, 0);
}
std::unique_ptr<Texture> Texture::from(const ImageData* image) { std::unique_ptr<Texture> Texture::from(const ImageData* image) {
return GLTexture::from(image); uint width = image->getWidth();
uint height = image->getHeight();
void* data = image->getData();
return std::make_unique<Texture>(
static_cast<ubyte*>(data), width, height, image->getFormat()
);
}
uint Texture::getId() const {
return id;
} }

View File

@ -8,33 +8,39 @@
class Texture { class Texture {
protected: protected:
uint id;
uint width; uint width;
uint height; uint height;
Texture(uint width, uint height) : width(width), height(height) {}
public: public:
static uint MAX_RESOLUTION; Texture(uint id, uint width, uint height);
Texture(const ubyte* data, uint width, uint height, ImageFormat format);
virtual ~Texture();
virtual ~Texture() {} virtual void bind() const;
virtual void unbind() const;
void reload(const ubyte* data);
virtual void bind() const = 0; void setNearestFilter();
virtual void unbind() const = 0;
virtual void reload(const ImageData& image) = 0; void reload(const ImageData& image);
virtual std::unique_ptr<ImageData> readData() = 0; void setMipMapping(bool flag, bool pixelated);
virtual uint getWidth() const { std::unique_ptr<ImageData> readData();
uint getId() const;
UVRegion getUVRegion() const {
return UVRegion(0.0f, 0.0f, 1.0f, 1.0f);
}
uint getWidth() const {
return width; return width;
} }
virtual uint getHeight() const {
uint getHeight() const {
return height; return height;
} }
virtual UVRegion getUVRegion() const = 0;
virtual uint getId() const = 0;
virtual void setMipMapping(bool flag, bool pixelated) = 0;
static std::unique_ptr<Texture> from(const ImageData* image); static std::unique_ptr<Texture> from(const ImageData* image);
static uint MAX_RESOLUTION;
}; };

View File

@ -1,5 +1,5 @@
#include "TextureAnimation.hpp" #include "TextureAnimation.hpp"
#include "GLTexture.hpp" #include "Texture.hpp"
#include "Framebuffer.hpp" #include "Framebuffer.hpp"
#include <GL/glew.h> #include <GL/glew.h>

View File

@ -2,6 +2,7 @@
#include "commons.hpp" #include "commons.hpp"
#include "ImageData.hpp" #include "ImageData.hpp"
#include "MeshData.hpp"
#include <GL/glew.h> #include <GL/glew.h>
@ -23,4 +24,25 @@ namespace gl {
}; };
return primitives[static_cast<int>(primitive)]; return primitives[static_cast<int>(primitive)];
} }
inline GLenum to_glenum(VertexAttribute::Type type) {
using Type = VertexAttribute::Type;
switch (type) {
case Type::FLOAT:
return GL_FLOAT;
case Type::UNSIGNED_INT:
return GL_UNSIGNED_INT;
case Type::INT:
return GL_INT;
case Type::UNSIGNED_SHORT:
return GL_UNSIGNED_SHORT;
case Type::SHORT:
return GL_SHORT;
case Type::UNSIGNED_BYTE:
return GL_UNSIGNED_BYTE;
case Type::BYTE:
return GL_BYTE;
}
return 0;
}
} }

View File

@ -44,8 +44,8 @@ void BlockWrapsRenderer::draw(const BlockWrapper& wrapper) {
} }
if (vox->id != BLOCK_VOID) { if (vox->id != BLOCK_VOID) {
const auto& def = level.content.getIndices()->blocks.require(vox->id); const auto& def = level.content.getIndices()->blocks.require(vox->id);
switch (def.model) { switch (def.model.type) {
case BlockModel::block: case BlockModelType::BLOCK:
batch->cube( batch->cube(
glm::vec3(wrapper.position) + glm::vec3(0.5f), glm::vec3(wrapper.position) + glm::vec3(0.5f),
glm::vec3(1.01f), glm::vec3(1.01f),
@ -54,7 +54,7 @@ void BlockWrapsRenderer::draw(const BlockWrapper& wrapper) {
false false
); );
break; break;
case BlockModel::aabb: { case BlockModelType::AABB: {
const auto& aabb = const auto& aabb =
(def.rotatable ? def.rt.hitboxes[vox->state.rotation] (def.rotatable ? def.rt.hitboxes[vox->state.rotation]
: def.hitboxes) : def.hitboxes)

View File

@ -32,17 +32,17 @@ std::unique_ptr<ImageData> BlocksPreview::draw(
cache.getRegion(id, 4), cache.getRegion(id, 5)}; cache.getRegion(id, 4), cache.getRegion(id, 5)};
glm::vec3 offset(0.1f, 0.5f, 0.1f); glm::vec3 offset(0.1f, 0.5f, 0.1f);
switch (def.model) { switch (def.model.type) {
case BlockModel::none: case BlockModelType::NONE:
// something went wrong... // something went wrong...
break; break;
case BlockModel::block: case BlockModelType::BLOCK:
shader.uniformMatrix("u_apply", glm::translate(glm::mat4(1.0f), offset)); shader.uniformMatrix("u_apply", glm::translate(glm::mat4(1.0f), offset));
batch.blockCube(glm::vec3(size * 0.63f), texfaces, batch.blockCube(glm::vec3(size * 0.63f), texfaces,
glm::vec4(1.0f), !def.rt.emissive); glm::vec4(1.0f), !def.rt.emissive);
batch.flush(); batch.flush();
break; break;
case BlockModel::aabb: case BlockModelType::AABB:
{ {
glm::vec3 hitbox {}; glm::vec3 hitbox {};
for (const auto& box : def.hitboxes) { for (const auto& box : def.hitboxes) {
@ -60,7 +60,7 @@ std::unique_ptr<ImageData> BlocksPreview::draw(
} }
batch.flush(); batch.flush();
break; break;
case BlockModel::custom:{ case BlockModelType::CUSTOM:{
glm::vec3 pmul = glm::vec3(size * 0.63f); glm::vec3 pmul = glm::vec3(size * 0.63f);
glm::vec3 hitbox = glm::vec3(1.0f); glm::vec3 hitbox = glm::vec3(1.0f);
glm::vec3 poff = glm::vec3(0.0f, 0.0f, 1.0f); glm::vec3 poff = glm::vec3(0.0f, 0.0f, 1.0f);
@ -78,7 +78,7 @@ std::unique_ptr<ImageData> BlocksPreview::draw(
} }
break; break;
} }
case BlockModel::xsprite: { case BlockModelType::XSPRITE: {
shader.uniformMatrix("u_apply", glm::translate(glm::mat4(1.0f), offset)); shader.uniformMatrix("u_apply", glm::translate(glm::mat4(1.0f), offset));
glm::vec3 right = glm::normalize(glm::vec3(1.f, 0.f, -1.f)); glm::vec3 right = glm::normalize(glm::vec3(1.f, 0.f, -1.f));
batch.sprite( batch.sprite(

View File

@ -9,7 +9,8 @@
#include "lighting/Lightmap.hpp" #include "lighting/Lightmap.hpp"
#include "frontend/ContentGfxCache.hpp" #include "frontend/ContentGfxCache.hpp"
const glm::vec3 BlocksRenderer::SUN_VECTOR (0.2275f,0.9388f,-0.1005f); const glm::vec3 BlocksRenderer::SUN_VECTOR(0.528265f, 0.833149f, -0.163704f);
const float DIRECTIONAL_LIGHT_FACTOR = 0.3f;
BlocksRenderer::BlocksRenderer( BlocksRenderer::BlocksRenderer(
size_t capacity, size_t capacity,
@ -17,18 +18,18 @@ BlocksRenderer::BlocksRenderer(
const ContentGfxCache& cache, const ContentGfxCache& cache,
const EngineSettings& settings const EngineSettings& settings
) : content(content), ) : content(content),
vertexBuffer(std::make_unique<float[]>(capacity * CHUNK_VERTEX_SIZE)), vertexBuffer(std::make_unique<ChunkVertex[]>(capacity)),
indexBuffer(std::make_unique<int[]>(capacity)), indexBuffer(std::make_unique<uint32_t[]>(capacity)),
vertexCount(0),
vertexOffset(0), vertexOffset(0),
indexOffset(0), indexCount(0),
indexSize(0),
capacity(capacity), capacity(capacity),
cache(cache), cache(cache),
settings(settings) settings(settings)
{ {
voxelsBuffer = std::make_unique<VoxelsVolume>( voxelsBuffer = std::make_unique<VoxelsVolume>(
CHUNK_W + voxelBufferPadding*2, CHUNK_W + voxelBufferPadding*2,
CHUNK_H, CHUNK_H,
CHUNK_D + voxelBufferPadding*2); CHUNK_D + voxelBufferPadding*2);
blockDefsCache = content.getIndices()->blocks.getDefs(); blockDefsCache = content.getIndices()->blocks.getDefs();
} }
@ -40,39 +41,31 @@ BlocksRenderer::~BlocksRenderer() {
void BlocksRenderer::vertex( void BlocksRenderer::vertex(
const glm::vec3& coord, float u, float v, const glm::vec4& light const glm::vec3& coord, float u, float v, const glm::vec4& light
) { ) {
vertexBuffer[vertexOffset++] = coord.x;
vertexBuffer[vertexOffset++] = coord.y;
vertexBuffer[vertexOffset++] = coord.z;
vertexBuffer[vertexOffset++] = u; vertexBuffer[vertexCount].position = coord;
vertexBuffer[vertexOffset++] = v;
union { vertexBuffer[vertexCount].uv = {u,v};
float floating;
uint32_t integer;
} compressed;
compressed.integer = (static_cast<uint32_t>(light.r * 255) & 0xff) << 24; vertexBuffer[vertexCount].color[0] = static_cast<uint8_t>(light.r * 255);
compressed.integer |= (static_cast<uint32_t>(light.g * 255) & 0xff) << 16; vertexBuffer[vertexCount].color[1] = static_cast<uint8_t>(light.g * 255);
compressed.integer |= (static_cast<uint32_t>(light.b * 255) & 0xff) << 8; vertexBuffer[vertexCount].color[2] = static_cast<uint8_t>(light.b * 255);
compressed.integer |= (static_cast<uint32_t>(light.a * 255) & 0xff); vertexBuffer[vertexCount].color[3] = static_cast<uint8_t>(light.a * 255);
vertexCount++;
vertexBuffer[vertexOffset++] = compressed.floating;
} }
void BlocksRenderer::index(int a, int b, int c, int d, int e, int f) { void BlocksRenderer::index(uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_t e, uint32_t f) {
indexBuffer[indexSize++] = indexOffset + a; indexBuffer[indexCount++] = static_cast<uint32_t>(vertexOffset + a);
indexBuffer[indexSize++] = indexOffset + b; indexBuffer[indexCount++] = static_cast<uint32_t>(vertexOffset + b);
indexBuffer[indexSize++] = indexOffset + c; indexBuffer[indexCount++] = static_cast<uint32_t>(vertexOffset + c);
indexBuffer[indexSize++] = indexOffset + d; indexBuffer[indexCount++] = static_cast<uint32_t>(vertexOffset + d);
indexBuffer[indexSize++] = indexOffset + e; indexBuffer[indexCount++] = static_cast<uint32_t>(vertexOffset + e);
indexBuffer[indexSize++] = indexOffset + f; indexBuffer[indexCount++] = static_cast<uint32_t>(vertexOffset + f);
indexOffset += 4; vertexOffset += 4;
} }
/// @brief Add face with precalculated lights /// @brief Add face with precalculated lights
void BlocksRenderer::face( void BlocksRenderer::face(
const glm::vec3& coord, const glm::vec3& coord,
float w, float h, float d, float w, float h, float d,
const glm::vec3& axisX, const glm::vec3& axisX,
const glm::vec3& axisY, const glm::vec3& axisY,
@ -81,7 +74,7 @@ void BlocksRenderer::face(
const glm::vec4(&lights)[4], const glm::vec4(&lights)[4],
const glm::vec4& tint const glm::vec4& tint
) { ) {
if (vertexOffset + CHUNK_VERTEX_SIZE * 4 > capacity) { if (vertexCount + 4 >= capacity) {
overflow = true; overflow = true;
return; return;
} }
@ -97,7 +90,7 @@ void BlocksRenderer::face(
} }
void BlocksRenderer::vertexAO( void BlocksRenderer::vertexAO(
const glm::vec3& coord, const glm::vec3& coord,
float u, float v, float u, float v,
const glm::vec4& tint, const glm::vec4& tint,
const glm::vec3& axisX, const glm::vec3& axisX,
@ -121,7 +114,7 @@ void BlocksRenderer::faceAO(
const UVRegion& region, const UVRegion& region,
bool lights bool lights
) { ) {
if (vertexOffset + CHUNK_VERTEX_SIZE * 4 > capacity) { if (vertexCount + 4 >= capacity) {
overflow = true; overflow = true;
return; return;
} }
@ -129,7 +122,7 @@ void BlocksRenderer::faceAO(
float s = 0.5f; float s = 0.5f;
if (lights) { if (lights) {
float d = glm::dot(glm::normalize(Z), SUN_VECTOR); float d = glm::dot(glm::normalize(Z), SUN_VECTOR);
d = 0.7f + d * 0.3f; d = (1.0f - DIRECTIONAL_LIGHT_FACTOR) + d * DIRECTIONAL_LIGHT_FACTOR;
auto axisX = glm::normalize(X); auto axisX = glm::normalize(X);
auto axisY = glm::normalize(Y); auto axisY = glm::normalize(Y);
@ -159,7 +152,7 @@ void BlocksRenderer::face(
glm::vec4 tint, glm::vec4 tint,
bool lights bool lights
) { ) {
if (vertexOffset + CHUNK_VERTEX_SIZE * 4 > capacity) { if (vertexCount + 4 >= capacity) {
overflow = true; overflow = true;
return; return;
} }
@ -167,7 +160,7 @@ void BlocksRenderer::face(
float s = 0.5f; float s = 0.5f;
if (lights) { if (lights) {
float d = glm::dot(glm::normalize(Z), SUN_VECTOR); float d = glm::dot(glm::normalize(Z), SUN_VECTOR);
d = 0.7f + d * 0.3f; d = (1.0f - DIRECTIONAL_LIGHT_FACTOR) + d * DIRECTIONAL_LIGHT_FACTOR;
tint *= d; tint *= d;
} }
vertex(coord + (-X - Y + Z) * s, region.u1, region.v1, tint); vertex(coord + (-X - Y + Z) * s, region.u1, region.v1, tint);
@ -178,10 +171,10 @@ void BlocksRenderer::face(
} }
void BlocksRenderer::blockXSprite( void BlocksRenderer::blockXSprite(
int x, int y, int z, int x, int y, int z,
const glm::vec3& size, const glm::vec3& size,
const UVRegion& texface1, const UVRegion& texface1,
const UVRegion& texface2, const UVRegion& texface2,
float spread float spread
) { ) {
glm::vec4 lights1[] { glm::vec4 lights1[] {
@ -207,12 +200,12 @@ void BlocksRenderer::blockXSprite(
face({x + xs, y, z + zs}, w, size.y, 0, {-1, 0, 1}, {0, 1, 0}, glm::vec3(), face({x + xs, y, z + zs}, w, size.y, 0, {-1, 0, 1}, {0, 1, 0}, glm::vec3(),
texface1, lights2, tint); texface1, lights2, tint);
face({x + xs, y, z + zs}, w, size.y, 0, {1, 0, 1}, {0, 1, 0}, glm::vec3(), face({x + xs, y, z + zs}, w, size.y, 0, {1, 0, 1}, {0, 1, 0}, glm::vec3(),
texface1, lights1, tint); texface1, lights1, tint);
face({x + xs, y, z + zs}, w, size.y, 0, {-1, 0, -1}, {0, 1, 0}, glm::vec3(), face({x + xs, y, z + zs}, w, size.y, 0, {-1, 0, -1}, {0, 1, 0}, glm::vec3(),
texface2, lights2, tint); texface2, lights2, tint);
face({x + xs, y, z + zs}, w, size.y, 0, {1, 0, -1}, {0, 1, 0}, glm::vec3(), face({x + xs, y, z + zs}, w, size.y, 0, {1, 0, -1}, {0, 1, 0}, glm::vec3(),
texface2, lights1, tint); texface2, lights1, tint);
} }
@ -221,8 +214,8 @@ void BlocksRenderer::blockXSprite(
/// @brief AABB blocks render method /// @brief AABB blocks render method
void BlocksRenderer::blockAABB( void BlocksRenderer::blockAABB(
const glm::ivec3& icoord, const glm::ivec3& icoord,
const UVRegion(&texfaces)[6], const UVRegion(&texfaces)[6],
const Block* block, const Block* block,
ubyte rotation, ubyte rotation,
bool lights, bool lights,
bool ao bool ao
@ -249,7 +242,7 @@ void BlocksRenderer::blockAABB(
orient.transform(hitbox); orient.transform(hitbox);
} }
coord -= glm::vec3(0.5f) - hitbox.center(); coord -= glm::vec3(0.5f) - hitbox.center();
if (ao) { if (ao) {
faceAO(coord, X*size.x, Y*size.y, Z*size.z, texfaces[5], lights); // north faceAO(coord, X*size.x, Y*size.y, Z*size.z, texfaces[5], lights); // north
faceAO(coord, -X*size.x, Y*size.y, -Z*size.z, texfaces[4], lights); // south faceAO(coord, -X*size.x, Y*size.y, -Z*size.z, texfaces[4], lights); // south
@ -272,6 +265,19 @@ void BlocksRenderer::blockAABB(
} }
} }
static bool is_aligned(const glm::vec3& v, float e = 1e-6f) {
if (std::abs(v.y) < e && std::abs(v.z) < e && std::abs(v.x) > e) {
return true;
}
if (std::abs(v.x) < e && std::abs(v.z) < e && std::abs(v.y) > e) {
return true;
}
if (std::abs(v.x) < e && std::abs(v.y) < e && std::abs(v.z) > e) {
return true;
}
return false;
}
void BlocksRenderer::blockCustomModel( void BlocksRenderer::blockCustomModel(
const glm::ivec3& icoord, const Block* block, ubyte rotation, bool lights, bool ao const glm::ivec3& icoord, const Block* block, ubyte rotation, bool lights, bool ao
) { ) {
@ -289,32 +295,44 @@ void BlocksRenderer::blockCustomModel(
const auto& model = cache.getModel(block->rt.id); const auto& model = cache.getModel(block->rt.id);
for (const auto& mesh : model.meshes) { for (const auto& mesh : model.meshes) {
if (vertexOffset + CHUNK_VERTEX_SIZE * mesh.vertices.size() > capacity) { if (vertexCount + mesh.vertices.size() >= capacity) {
overflow = true; overflow = true;
return; return;
} }
for (int triangle = 0; triangle < mesh.vertices.size() / 3; triangle++) { for (int triangle = 0; triangle < mesh.vertices.size() / 3; triangle++) {
auto r = mesh.vertices[triangle * 3 + (triangle % 2) * 2].coord - auto r = mesh.vertices[triangle * 3 + (triangle % 2) * 2].coord -
mesh.vertices[triangle * 3 + 1].coord; mesh.vertices[triangle * 3 + 1].coord;
r = r.x * X + r.y * Y + r.z * Z;
r = glm::normalize(r); r = glm::normalize(r);
const auto& v0 = mesh.vertices[triangle * 3];
auto n = v0.normal.x * X + v0.normal.y * Y + v0.normal.z * Z;
if (!isOpen(glm::floor(coord + n * 1e-4f), *block) && is_aligned(n)) {
continue;
}
float d = glm::dot(n, SUN_VECTOR);
d = (1.0f - DIRECTIONAL_LIGHT_FACTOR) + d * DIRECTIONAL_LIGHT_FACTOR;
glm::vec3 t = glm::cross(r, n);
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
const auto& vertex = mesh.vertices[triangle * 3 + i]; const auto& vertex = mesh.vertices[triangle * 3 + i];
auto n = vertex.normal.x * X + vertex.normal.y * Y +
vertex.normal.z * Z;
float d = glm::dot(n, SUN_VECTOR);
d = 0.8f + d * 0.2f;
const auto& vcoord = vertex.coord - 0.5f; const auto& vcoord = vertex.coord - 0.5f;
vertexAO(
glm::vec4 aoColor {1.0f, 1.0f, 1.0f, 1.0f};
if (ao) {
auto p = coord + vcoord.x * X + vcoord.y * Y +
vcoord.z * Z + r * 0.5f + t * 0.5f + n * 0.5f;
aoColor = pickSoftLight(p.x, p.y, p.z, glm::ivec3(r), glm::ivec3(t));
}
this->vertex(
coord + vcoord.x * X + vcoord.y * Y + vcoord.z * Z, coord + vcoord.x * X + vcoord.y * Y + vcoord.z * Z,
vertex.uv.x, vertex.uv.x,
vertex.uv.y, vertex.uv.y,
glm::vec4(d, d, d, d), glm::vec4(d, d, d, d) * aoColor
glm::cross(r, n),
r,
n
); );
indexBuffer[indexSize++] = indexOffset++; indexBuffer[indexCount++] = vertexOffset++;
} }
} }
} }
@ -322,9 +340,9 @@ void BlocksRenderer::blockCustomModel(
/* Fastest solid shaded blocks render method */ /* Fastest solid shaded blocks render method */
void BlocksRenderer::blockCube( void BlocksRenderer::blockCube(
const glm::ivec3& coord, const glm::ivec3& coord,
const UVRegion(&texfaces)[6], const UVRegion(&texfaces)[6],
const Block& block, const Block& block,
blockstate states, blockstate states,
bool lights, bool lights,
bool ao bool ao
@ -340,7 +358,7 @@ void BlocksRenderer::blockCube(
Y = orient.axes[1]; Y = orient.axes[1];
Z = orient.axes[2]; Z = orient.axes[2];
} }
if (ao) { if (ao) {
if (isOpen(coord + Z, block)) { if (isOpen(coord + Z, block)) {
faceAO(coord, X, Y, Z, texfaces[5], lights); faceAO(coord, X, Y, Z, texfaces[5], lights);
@ -383,8 +401,8 @@ void BlocksRenderer::blockCube(
} }
bool BlocksRenderer::isOpenForLight(int x, int y, int z) const { bool BlocksRenderer::isOpenForLight(int x, int y, int z) const {
blockid_t id = voxelsBuffer->pickBlockId(chunk->x * CHUNK_W + x, blockid_t id = voxelsBuffer->pickBlockId(chunk->x * CHUNK_W + x,
y, y,
chunk->z * CHUNK_D + z); chunk->z * CHUNK_D + z);
if (id == BLOCK_VOID) { if (id == BLOCK_VOID) {
return false; return false;
@ -398,7 +416,7 @@ bool BlocksRenderer::isOpenForLight(int x, int y, int z) const {
glm::vec4 BlocksRenderer::pickLight(int x, int y, int z) const { glm::vec4 BlocksRenderer::pickLight(int x, int y, int z) const {
if (isOpenForLight(x, y, z)) { if (isOpenForLight(x, y, z)) {
light_t light = voxelsBuffer->pickLight(chunk->x * CHUNK_W + x, y, light_t light = voxelsBuffer->pickLight(chunk->x * CHUNK_W + x, y,
chunk->z * CHUNK_D + z); chunk->z * CHUNK_D + z);
return glm::vec4(Lightmap::extract(light, 0), return glm::vec4(Lightmap::extract(light, 0),
Lightmap::extract(light, 1), Lightmap::extract(light, 1),
@ -426,8 +444,8 @@ glm::vec4 BlocksRenderer::pickSoftLight(
float x, float y, float z, const glm::ivec3& right, const glm::ivec3& up float x, float y, float z, const glm::ivec3& right, const glm::ivec3& up
) const { ) const {
return pickSoftLight({ return pickSoftLight({
static_cast<int>(std::round(x)), static_cast<int>(std::round(x)),
static_cast<int>(std::round(y)), static_cast<int>(std::round(y)),
static_cast<int>(std::round(z))}, static_cast<int>(std::round(z))},
right, up); right, up);
} }
@ -460,23 +478,23 @@ void BlocksRenderer::render(
int x = i % CHUNK_W; int x = i % CHUNK_W;
int y = i / (CHUNK_D * CHUNK_W); int y = i / (CHUNK_D * CHUNK_W);
int z = (i / CHUNK_D) % CHUNK_W; int z = (i / CHUNK_D) % CHUNK_W;
switch (def.model) { switch (def.model.type) {
case BlockModel::block: case BlockModelType::BLOCK:
blockCube({x, y, z}, texfaces, def, vox.state, !def.shadeless, blockCube({x, y, z}, texfaces, def, vox.state, !def.shadeless,
def.ambientOcclusion); def.ambientOcclusion);
break; break;
case BlockModel::xsprite: { case BlockModelType::XSPRITE: {
blockXSprite(x, y, z, glm::vec3(1.0f), blockXSprite(x, y, z, glm::vec3(1.0f),
texfaces[FACE_MX], texfaces[FACE_MZ], 1.0f); texfaces[FACE_MX], texfaces[FACE_MZ], 1.0f);
break; break;
} }
case BlockModel::aabb: { case BlockModelType::AABB: {
blockAABB({x, y, z}, texfaces, &def, vox.state.rotation, blockAABB({x, y, z}, texfaces, &def, vox.state.rotation,
!def.shadeless, def.ambientOcclusion); !def.shadeless, def.ambientOcclusion);
break; break;
} }
case BlockModel::custom: { case BlockModelType::CUSTOM: {
blockCustomModel({x, y, z}, &def, vox.state.rotation, blockCustomModel({x, y, z}, &def, vox.state.rotation,
!def.shadeless, def.ambientOcclusion); !def.shadeless, def.ambientOcclusion);
break; break;
} }
@ -523,30 +541,30 @@ SortingMeshData BlocksRenderer::renderTranslucent(
int x = i % CHUNK_W; int x = i % CHUNK_W;
int y = i / (CHUNK_D * CHUNK_W); int y = i / (CHUNK_D * CHUNK_W);
int z = (i / CHUNK_D) % CHUNK_W; int z = (i / CHUNK_D) % CHUNK_W;
switch (def.model) { switch (def.model.type) {
case BlockModel::block: case BlockModelType::BLOCK:
blockCube({x, y, z}, texfaces, def, vox.state, !def.shadeless, blockCube({x, y, z}, texfaces, def, vox.state, !def.shadeless,
def.ambientOcclusion); def.ambientOcclusion);
break; break;
case BlockModel::xsprite: { case BlockModelType::XSPRITE: {
blockXSprite(x, y, z, glm::vec3(1.0f), blockXSprite(x, y, z, glm::vec3(1.0f),
texfaces[FACE_MX], texfaces[FACE_MZ], 1.0f); texfaces[FACE_MX], texfaces[FACE_MZ], 1.0f);
break; break;
} }
case BlockModel::aabb: { case BlockModelType::AABB: {
blockAABB({x, y, z}, texfaces, &def, vox.state.rotation, blockAABB({x, y, z}, texfaces, &def, vox.state.rotation,
!def.shadeless, def.ambientOcclusion); !def.shadeless, def.ambientOcclusion);
break; break;
} }
case BlockModel::custom: { case BlockModelType::CUSTOM: {
blockCustomModel({x, y, z}, &def, vox.state.rotation, blockCustomModel({x, y, z}, &def, vox.state.rotation,
!def.shadeless, def.ambientOcclusion); !def.shadeless, def.ambientOcclusion);
break; break;
} }
default: default:
break; break;
} }
if (vertexOffset == 0) { if (vertexCount == 0) {
continue; continue;
} }
SortingMeshEntry entry { SortingMeshEntry entry {
@ -555,50 +573,50 @@ SortingMeshData BlocksRenderer::renderTranslucent(
y + 0.5f, y + 0.5f,
z + chunk->z * CHUNK_D + 0.5f z + chunk->z * CHUNK_D + 0.5f
), ),
util::Buffer<float>(indexSize * CHUNK_VERTEX_SIZE), 0}; util::Buffer<ChunkVertex>(indexCount), 0};
totalSize += entry.vertexData.size(); totalSize += entry.vertexData.size();
for (int j = 0; j < indexSize; j++) { for (int j = 0; j < indexCount; j++) {
std::memcpy( std::memcpy(
entry.vertexData.data() + j * CHUNK_VERTEX_SIZE, entry.vertexData.data() + j,
vertexBuffer.get() + indexBuffer[j] * CHUNK_VERTEX_SIZE, vertexBuffer.get() + indexBuffer[j],
sizeof(float) * CHUNK_VERTEX_SIZE sizeof(ChunkVertex)
); );
float& vx = entry.vertexData[j * CHUNK_VERTEX_SIZE + 0]; ChunkVertex& vertex = entry.vertexData[j];
float& vy = entry.vertexData[j * CHUNK_VERTEX_SIZE + 1];
float& vz = entry.vertexData[j * CHUNK_VERTEX_SIZE + 2];
if (!aabbInit) { if (!aabbInit) {
aabbInit = true; aabbInit = true;
aabb.a = aabb.b = {vx, vy, vz}; aabb.a = aabb.b = vertex.position;
} else { } else {
aabb.addPoint(glm::vec3(vx, vy, vz)); aabb.addPoint(vertex.position);
} }
vx += chunk->x * CHUNK_W + 0.5f;
vy += 0.5f; vertex.position.x += chunk->x * CHUNK_W + 0.5f;
vz += chunk->z * CHUNK_D + 0.5f; vertex.position.y += 0.5f;
vertex.position.z += chunk->z * CHUNK_D + 0.5f;
} }
sortingMesh.entries.push_back(std::move(entry)); sortingMesh.entries.push_back(std::move(entry));
vertexOffset = 0; vertexCount = 0;
indexOffset = indexSize = 0; vertexOffset = indexCount = 0;
} }
} }
// additional powerful optimization // additional powerful optimization
auto size = aabb.size(); auto size = aabb.size();
if ((size.y < 0.01f || size.x < 0.01f || size.z < 0.01f) && if ((size.y < 0.01f || size.x < 0.01f || size.z < 0.01f) &&
sortingMesh.entries.size() > 1) { sortingMesh.entries.size() > 1) {
SortingMeshEntry newEntry { SortingMeshEntry newEntry {
sortingMesh.entries[0].position, sortingMesh.entries[0].position,
util::Buffer<float>(totalSize), util::Buffer<ChunkVertex>(totalSize),
0 0
}; };
size_t offset = 0; size_t offset = 0;
for (const auto& entry : sortingMesh.entries) { for (const auto& entry : sortingMesh.entries) {
std::memcpy( std::memcpy(
newEntry.vertexData.data() + offset, newEntry.vertexData.data() + offset,
entry.vertexData.data(), entry.vertexData.size() * sizeof(float) entry.vertexData.data(),
entry.vertexData.size() * sizeof(ChunkVertex)
); );
offset += entry.vertexData.size(); offset += entry.vertexData.size();
} }
@ -630,7 +648,7 @@ void BlocksRenderer::build(const Chunk* chunk, const Chunks* chunks) {
const voxel& vox = voxels[i]; const voxel& vox = voxels[i];
blockid_t id = vox.id; blockid_t id = vox.id;
const auto& def = *blockDefsCache[id]; const auto& def = *blockDefsCache[id];
if (beginEnds[def.drawGroup][0] == 0) { if (beginEnds[def.drawGroup][0] == 0) {
beginEnds[def.drawGroup][0] = i+1; beginEnds[def.drawGroup][0] = i+1;
} }
@ -639,36 +657,37 @@ void BlocksRenderer::build(const Chunk* chunk, const Chunks* chunks) {
cancelled = false; cancelled = false;
overflow = false; overflow = false;
vertexOffset = 0; vertexCount = 0;
indexOffset = indexSize = 0; vertexOffset = indexCount = 0;
sortingMesh = renderTranslucent(voxels, beginEnds); sortingMesh = renderTranslucent(voxels, beginEnds);
overflow = false; overflow = false;
vertexCount = 0;
vertexOffset = 0; vertexOffset = 0;
indexOffset = indexSize = 0; indexCount = 0;
render(voxels, beginEnds); render(voxels, beginEnds);
} }
ChunkMeshData BlocksRenderer::createMesh() { ChunkMeshData BlocksRenderer::createMesh() {
return ChunkMeshData { return ChunkMeshData{
MeshData( MeshData(
util::Buffer<float>(vertexBuffer.get(), vertexOffset), util::Buffer(vertexBuffer.get(), vertexCount),
util::Buffer<int>(indexBuffer.get(), indexSize), util::Buffer(indexBuffer.get(), indexCount),
util::Buffer<VertexAttribute>( util::Buffer(
CHUNK_VATTRS, sizeof(CHUNK_VATTRS) / sizeof(VertexAttribute) ChunkVertex::ATTRIBUTES, sizeof(ChunkVertex::ATTRIBUTES) / sizeof(VertexAttribute)
) )
), ),
std::move(sortingMesh)}; std::move(sortingMesh)
};
} }
ChunkMesh BlocksRenderer::render(const Chunk* chunk, const Chunks* chunks) { ChunkMesh BlocksRenderer::render(const Chunk *chunk, const Chunks *chunks) {
build(chunk, chunks); build(chunk, chunks);
size_t vcount = vertexOffset / CHUNK_VERTEX_SIZE; return ChunkMesh{std::make_unique<Mesh<ChunkVertex>>(
return ChunkMesh{std::make_unique<Mesh>( vertexBuffer.get(), vertexCount, indexBuffer.get(), indexCount
vertexBuffer.get(), vcount, indexBuffer.get(), indexSize, CHUNK_VATTRS
), std::move(sortingMesh)}; ), std::move(sortingMesh)};
} }

View File

@ -1,7 +1,5 @@
#pragma once #pragma once
#include <stdlib.h>
#include <vector>
#include <memory> #include <memory>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include "voxels/voxel.hpp" #include "voxels/voxel.hpp"
@ -10,28 +8,27 @@
#include "voxels/Block.hpp" #include "voxels/Block.hpp"
#include "voxels/Chunk.hpp" #include "voxels/Chunk.hpp"
#include "voxels/VoxelsVolume.hpp" #include "voxels/VoxelsVolume.hpp"
#include "graphics/core/MeshData.hpp"
#include "maths/util.hpp" #include "maths/util.hpp"
#include "commons.hpp" #include "commons.hpp"
#include "settings.hpp" #include "settings.hpp"
template<typename VertexStructure> class Mesh;
class Content; class Content;
class Mesh;
class Block; class Block;
class Chunk; class Chunk;
class Chunks; class Chunks;
class VoxelsVolume; class VoxelsVolume;
class Chunks;
class ContentGfxCache; class ContentGfxCache;
struct UVRegion; struct UVRegion;
class BlocksRenderer { class BlocksRenderer {
static const glm::vec3 SUN_VECTOR; static const glm::vec3 SUN_VECTOR;
const Content& content; const Content& content;
std::unique_ptr<float[]> vertexBuffer; std::unique_ptr<ChunkVertex[]> vertexBuffer;
std::unique_ptr<int[]> indexBuffer; std::unique_ptr<uint32_t[]> indexBuffer;
size_t vertexCount;
size_t vertexOffset; size_t vertexOffset;
size_t indexOffset, indexSize; size_t indexCount;
size_t capacity; size_t capacity;
int voxelBufferPadding = 2; int voxelBufferPadding = 2;
bool overflow = false; bool overflow = false;
@ -48,7 +45,7 @@ class BlocksRenderer {
SortingMeshData sortingMesh; SortingMeshData sortingMesh;
void vertex(const glm::vec3& coord, float u, float v, const glm::vec4& light); void vertex(const glm::vec3& coord, float u, float v, const glm::vec4& light);
void index(int a, int b, int c, int d, int e, int f); void index(uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_t e, uint32_t f);
void vertexAO( void vertexAO(
const glm::vec3& coord, float u, float v, const glm::vec3& coord, float u, float v,

View File

@ -74,7 +74,7 @@ ChunksRenderer::ChunksRenderer(
if (!result.cancelled) { if (!result.cancelled) {
auto meshData = std::move(result.meshData); auto meshData = std::move(result.meshData);
meshes[result.key] = ChunkMesh { meshes[result.key] = ChunkMesh {
std::make_unique<Mesh>(meshData.mesh), std::make_unique<Mesh<ChunkVertex>>(meshData.mesh),
std::move(meshData.sortingMesh)}; std::move(meshData.sortingMesh)};
} }
inwork.erase(result.key); inwork.erase(result.key);
@ -92,7 +92,7 @@ ChunksRenderer::ChunksRenderer(
ChunksRenderer::~ChunksRenderer() { ChunksRenderer::~ChunksRenderer() {
} }
const Mesh* ChunksRenderer::render( const Mesh<ChunkVertex>* ChunksRenderer::render(
const std::shared_ptr<Chunk>& chunk, bool important const std::shared_ptr<Chunk>& chunk, bool important
) { ) {
chunk->flags.modified = false; chunk->flags.modified = false;
@ -125,7 +125,7 @@ void ChunksRenderer::clear() {
threadPool.clearQueue(); threadPool.clearQueue();
} }
const Mesh* ChunksRenderer::getOrRender( const Mesh<ChunkVertex>* ChunksRenderer::getOrRender(
const std::shared_ptr<Chunk>& chunk, bool important const std::shared_ptr<Chunk>& chunk, bool important
) { ) {
auto found = meshes.find(glm::ivec2(chunk->x, chunk->z)); auto found = meshes.find(glm::ivec2(chunk->x, chunk->z));
@ -142,7 +142,7 @@ void ChunksRenderer::update() {
threadPool.update(); threadPool.update();
} }
const Mesh* ChunksRenderer::retrieveChunk( const Mesh<ChunkVertex>* ChunksRenderer::retrieveChunk(
size_t index, const Camera& camera, Shader& shader, bool culling size_t index, const Camera& camera, Shader& shader, bool culling
) { ) {
auto chunk = chunks.getChunks()[index]; auto chunk = chunks.getChunks()[index];
@ -234,14 +234,14 @@ void ChunksRenderer::drawChunks(
} }
static inline void write_sorting_mesh_entries( static inline void write_sorting_mesh_entries(
float* buffer, const std::vector<SortingMeshEntry>& chunkEntries ChunkVertex* buffer, const std::vector<SortingMeshEntry>& chunkEntries
) { ) {
for (const auto& entry : chunkEntries) { for (const auto& entry : chunkEntries) {
const auto& vertexData = entry.vertexData; const auto& vertexData = entry.vertexData;
std::memcpy( std::memcpy(
buffer, buffer,
vertexData.data(), vertexData.data(),
vertexData.size() * sizeof(float) vertexData.size() * sizeof(ChunkVertex)
); );
buffer += vertexData.size(); buffer += vertexData.size();
} }
@ -288,10 +288,8 @@ void ChunksRenderer::drawSortedMeshes(const Camera& camera, Shader& shader) {
if (chunkEntries.size() == 1) { if (chunkEntries.size() == 1) {
auto& entry = chunkEntries.at(0); auto& entry = chunkEntries.at(0);
if (found->second.sortedMesh == nullptr) { if (found->second.sortedMesh == nullptr) {
found->second.sortedMesh = std::make_unique<Mesh>( found->second.sortedMesh = std::make_unique<Mesh<ChunkVertex>>(
entry.vertexData.data(), entry.vertexData.data(), entry.vertexData.size()
entry.vertexData.size() / CHUNK_VERTEX_SIZE,
CHUNK_VATTRS
); );
} }
found->second.sortedMesh->draw(); found->second.sortedMesh->draw();
@ -310,13 +308,13 @@ void ChunksRenderer::drawSortedMeshes(const Camera& camera, Shader& shader) {
size += entry.vertexData.size(); size += entry.vertexData.size();
} }
static util::Buffer<float> buffer; static util::Buffer<ChunkVertex> buffer;
if (buffer.size() < size) { if (buffer.size() < size) {
buffer = util::Buffer<float>(size); buffer = util::Buffer<ChunkVertex>(size);
} }
write_sorting_mesh_entries(buffer.data(), chunkEntries); write_sorting_mesh_entries(buffer.data(), chunkEntries);
found->second.sortedMesh = std::make_unique<Mesh>( found->second.sortedMesh = std::make_unique<Mesh<ChunkVertex>>(
buffer.data(), size / CHUNK_VERTEX_SIZE, CHUNK_VATTRS buffer.data(), size
); );
} }
found->second.sortedMesh->draw(); found->second.sortedMesh->draw();

View File

@ -1,6 +1,5 @@
#pragma once #pragma once
#include <queue>
#include <memory> #include <memory>
#include <vector> #include <vector>
#include <unordered_map> #include <unordered_map>
@ -9,12 +8,10 @@
#define GLM_ENABLE_EXPERIMENTAL #define GLM_ENABLE_EXPERIMENTAL
#include <glm/gtx/hash.hpp> #include <glm/gtx/hash.hpp>
#include "voxels/Block.hpp"
#include "util/ThreadPool.hpp" #include "util/ThreadPool.hpp"
#include "graphics/core/MeshData.hpp"
#include "commons.hpp" #include "commons.hpp"
class Mesh; template<typename VertexStructure> class Mesh;
class Chunk; class Chunk;
class Level; class Level;
class Camera; class Camera;
@ -52,7 +49,7 @@ class ChunksRenderer {
std::unordered_map<glm::ivec2, bool> inwork; std::unordered_map<glm::ivec2, bool> inwork;
std::vector<ChunksSortEntry> indices; std::vector<ChunksSortEntry> indices;
util::ThreadPool<std::shared_ptr<Chunk>, RendererResult> threadPool; util::ThreadPool<std::shared_ptr<Chunk>, RendererResult> threadPool;
const Mesh* retrieveChunk( const Mesh<ChunkVertex>* retrieveChunk(
size_t index, const Camera& camera, Shader& shader, bool culling size_t index, const Camera& camera, Shader& shader, bool culling
); );
public: public:
@ -66,13 +63,13 @@ public:
); );
virtual ~ChunksRenderer(); virtual ~ChunksRenderer();
const Mesh* render( const Mesh<ChunkVertex>* render(
const std::shared_ptr<Chunk>& chunk, bool important const std::shared_ptr<Chunk>& chunk, bool important
); );
void unload(const Chunk* chunk); void unload(const Chunk* chunk);
void clear(); void clear();
const Mesh* getOrRender( const Mesh<ChunkVertex>* getOrRender(
const std::shared_ptr<Chunk>& chunk, bool important const std::shared_ptr<Chunk>& chunk, bool important
); );
void drawChunks(const Camera& camera, Shader& shader); void drawChunks(const Camera& camera, Shader& shader);

View File

@ -6,18 +6,15 @@
#include "voxels/Chunks.hpp" #include "voxels/Chunks.hpp"
#include "voxels/Chunk.hpp" #include "voxels/Chunk.hpp"
static const VertexAttribute attrs[] = {
{3}, {2}, {3}, {1}, {0}
};
MainBatch::MainBatch(size_t capacity) MainBatch::MainBatch(size_t capacity)
: buffer(std::make_unique<float[]>(capacity * VERTEX_SIZE)), : buffer(std::make_unique<MainBatchVertex[]>(capacity)),
capacity(capacity), capacity(capacity),
index(0), index(0),
mesh(std::make_unique<Mesh>(buffer.get(), 0, attrs)) { mesh(std::make_unique<Mesh<MainBatchVertex>>(buffer.get(), 0)) {
const ubyte pixels[] = { const ubyte pixels[] = {
255, 255, 255, 255, 255, 255, 255, 255,
}; };
ImageData image(ImageFormat::rgba8888, 1, 1, pixels); ImageData image(ImageFormat::rgba8888, 1, 1, pixels);
blank = Texture::from(&image); blank = Texture::from(&image);
@ -25,7 +22,7 @@ MainBatch::MainBatch(size_t capacity)
MainBatch::~MainBatch() = default; MainBatch::~MainBatch() = default;
void MainBatch::setTexture(const Texture* texture) { void MainBatch::setTexture(const Texture *texture) {
if (texture == nullptr) { if (texture == nullptr) {
texture = blank.get(); texture = blank.get();
} }
@ -33,10 +30,10 @@ void MainBatch::setTexture(const Texture* texture) {
flush(); flush();
} }
this->texture = texture; this->texture = texture;
region = UVRegion {0.0f, 0.0f, 1.0f, 1.0f}; region = UVRegion{0.0f, 0.0f, 1.0f, 1.0f};
} }
void MainBatch::setTexture(const Texture* texture, const UVRegion& region) { void MainBatch::setTexture(const Texture *texture, const UVRegion &region) {
setTexture(texture); setTexture(texture);
this->region = region; this->region = region;
} }
@ -49,7 +46,7 @@ void MainBatch::flush() {
texture = blank.get(); texture = blank.get();
} }
texture->bind(); texture->bind();
mesh->reload(buffer.get(), index / VERTEX_SIZE); mesh->reload(buffer.get(), index);
mesh->draw(); mesh->draw();
index = 0; index = 0;
} }
@ -60,76 +57,76 @@ void MainBatch::begin() {
} }
void MainBatch::prepare(int vertices) { void MainBatch::prepare(int vertices) {
if (index + VERTEX_SIZE * vertices > capacity * VERTEX_SIZE) { if (index * vertices > capacity) {
flush(); flush();
} }
} }
glm::vec4 MainBatch::sampleLight( glm::vec4 MainBatch::sampleLight(
const glm::vec3& pos, const Chunks& chunks, bool backlight const glm::vec3 &pos, const Chunks &chunks, bool backlight
) { ) {
light_t light = chunks.getLight( light_t light = chunks.getLight(
std::floor(pos.x), std::floor(pos.x),
std::floor(std::min(CHUNK_H-1.0f, pos.y)), std::floor(std::min(CHUNK_H - 1.0f, pos.y)),
std::floor(pos.z)); std::floor(pos.z));
light_t minIntensity = backlight ? 1 : 0; light_t minIntensity = backlight ? 1 : 0;
return glm::vec4( return {
glm::max(Lightmap::extract(light, 0), minIntensity) / 15.0f, (float) glm::max(Lightmap::extract(light, 0), minIntensity) / 15.0f,
glm::max(Lightmap::extract(light, 1), minIntensity) / 15.0f, (float) glm::max(Lightmap::extract(light, 1), minIntensity) / 15.0f,
glm::max(Lightmap::extract(light, 2), minIntensity) / 15.0f, (float) glm::max(Lightmap::extract(light, 2), minIntensity) / 15.0f,
glm::max(Lightmap::extract(light, 3), minIntensity) / 15.0f (float) glm::max(Lightmap::extract(light, 3), minIntensity) / 15.0f
); };
} }
inline glm::vec4 do_tint(float value) { inline glm::vec4 do_tint(float value) {
return glm::vec4(value, value, value, 1.0f); return {value, value, value, 1.0f};
} }
void MainBatch::cube( void MainBatch::cube(
const glm::vec3& coord, const glm::vec3 &coord,
const glm::vec3& size, const glm::vec3 &size,
const UVRegion(&texfaces)[6], const UVRegion(&texfaces)[6],
const glm::vec4& tint, const glm::vec4 &tint,
bool shading bool shading
) { ) {
const glm::vec3 X(1.0f, 0.0f, 0.0f); const glm::vec3 X(1.0f, 0.0f, 0.0f);
const glm::vec3 Y(0.0f, 1.0f, 0.0f); const glm::vec3 Y(0.0f, 1.0f, 0.0f);
const glm::vec3 Z(0.0f, 0.0f, 1.0f); const glm::vec3 Z(0.0f, 0.0f, 1.0f);
quad( quad(
coord + Z * size.z * 0.5f, coord + Z * size.z * 0.5f,
X, Y, glm::vec2(size.x, size.y), X, Y, glm::vec2(size.x, size.y),
(shading ? do_tint(0.8) * tint : tint), (shading ? do_tint(0.8) * tint : tint),
glm::vec3(1.0f), texfaces[5] glm::vec3(1.0f), texfaces[5]
); );
quad( quad(
coord - Z * size.z * 0.5f, coord - Z * size.z * 0.5f,
-X, Y, glm::vec2(size.x, size.y), -X, Y, glm::vec2(size.x, size.y),
(shading ? do_tint(0.9f) * tint : tint), (shading ? do_tint(0.9f) * tint : tint),
glm::vec3(1.0f), texfaces[4] glm::vec3(1.0f), texfaces[4]
); );
quad( quad(
coord + Y * size.y * 0.5f, coord + Y * size.y * 0.5f,
-X, Z, glm::vec2(size.x, size.z), -X, Z, glm::vec2(size.x, size.z),
(shading ? do_tint(1.0f) * tint : tint), (shading ? do_tint(1.0f) * tint : tint),
glm::vec3(1.0f), texfaces[3] glm::vec3(1.0f), texfaces[3]
); );
quad( quad(
coord - Y * size.y * 0.5f, coord - Y * size.y * 0.5f,
X, Z, glm::vec2(size.x, size.z), X, Z, glm::vec2(size.x, size.z),
(shading ? do_tint(0.7f) * tint : tint), (shading ? do_tint(0.7f) * tint : tint),
glm::vec3(1.0f), texfaces[2] glm::vec3(1.0f), texfaces[2]
); );
quad( quad(
coord + X * size.x * 0.5f, coord + X * size.x * 0.5f,
-Z, Y, glm::vec2(size.z, size.y), -Z, Y, glm::vec2(size.z, size.y),
(shading ? do_tint(0.8f) * tint : tint), (shading ? do_tint(0.8f) * tint : tint),
glm::vec3(1.0f), texfaces[1] glm::vec3(1.0f), texfaces[1]
); );
quad( quad(
coord - X * size.x * 0.5f, coord - X * size.x * 0.5f,
Z, Y, glm::vec2(size.z, size.y), Z, Y, glm::vec2(size.z, size.y),
(shading ? do_tint(0.9f) * tint : tint), (shading ? do_tint(0.9f) * tint : tint),
glm::vec3(1.0f), texfaces[1] glm::vec3(1.0f), texfaces[1]
); );
} }

View File

@ -1,30 +1,46 @@
#pragma once #pragma once
#include <array>
#include <memory> #include <memory>
#include <stdint.h> #include <cstdint>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include "typedefs.hpp" #include "typedefs.hpp"
#include "maths/UVRegion.hpp" #include "maths/UVRegion.hpp"
#include "graphics/core/MeshData.hpp"
template<typename VertexStructure>
class Mesh; class Mesh;
class Texture; class Texture;
class Chunks; class Chunks;
struct MainBatchVertex {
glm::vec3 position;
glm::vec2 uv;
glm::vec3 tint;
std::array<uint8_t,4> color;
static constexpr VertexAttribute ATTRIBUTES[] = {
{VertexAttribute::Type::FLOAT, false, 3},
{VertexAttribute::Type::FLOAT, false, 2},
{VertexAttribute::Type::FLOAT, false, 3},
{VertexAttribute::Type::UNSIGNED_BYTE, true, 4},
{{}, 0}};
};
class MainBatch { class MainBatch {
std::unique_ptr<float[]> const buffer; std::unique_ptr<MainBatchVertex[]> const buffer;
size_t const capacity; size_t const capacity;
size_t index; size_t index;
UVRegion region {0.0f, 0.0f, 1.0f, 1.0f}; UVRegion region {0.0f, 0.0f, 1.0f, 1.0f};
std::unique_ptr<Mesh> mesh; std::unique_ptr<Mesh<MainBatchVertex>> mesh;
std::unique_ptr<Texture> blank; std::unique_ptr<Texture> blank;
const Texture* texture = nullptr; const Texture* texture = nullptr;
public: public:
/// xyz, uv, color, compressed lights /// xyz, uv, color, compressed lights
static inline constexpr uint VERTEX_SIZE = 9;
MainBatch(size_t capacity); MainBatch(size_t capacity);
@ -47,27 +63,16 @@ public:
const glm::vec4& light, const glm::vec4& light,
const glm::vec3& tint const glm::vec3& tint
) { ) {
float* buffer = this->buffer.get(); MainBatchVertex* buffer = this->buffer.get();
buffer[index++] = pos.x; buffer[index].position = pos;
buffer[index++] = pos.y; buffer[index].uv = {uv.x * region.getWidth() + region.u1,uv.y * region.getHeight() + region.v1};
buffer[index++] = pos.z; buffer[index].tint = tint;
buffer[index++] = uv.x * region.getWidth() + region.u1;
buffer[index++] = uv.y * region.getHeight() + region.v1;
buffer[index++] = tint.x;
buffer[index++] = tint.y;
buffer[index++] = tint.z;
union { buffer[index].color[0] = static_cast<uint8_t>(light.r * 255);
float floating; buffer[index].color[1] = static_cast<uint8_t>(light.g * 255);
uint32_t integer; buffer[index].color[2] = static_cast<uint8_t>(light.b * 255);
} compressed; buffer[index].color[3] = static_cast<uint8_t>(light.a * 255);
index++;
compressed.integer = (static_cast<uint32_t>(light.r * 255) & 0xff) << 24;
compressed.integer |= (static_cast<uint32_t>(light.g * 255) & 0xff) << 16;
compressed.integer |= (static_cast<uint32_t>(light.b * 255) & 0xff) << 8;
compressed.integer |= (static_cast<uint32_t>(light.a * 255) & 0xff);
buffer[index++] = compressed.floating;
} }
inline void quad( inline void quad(

View File

@ -1,14 +1,12 @@
#pragma once #pragma once
#include "maths/UVRegion.hpp"
#include <memory> #include <memory>
#include <vector> #include <vector>
#include <string> #include <string>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <unordered_map> #include <unordered_map>
class Mesh; template<typename VertexStructure> class Mesh;
class Texture; class Texture;
class Chunks; class Chunks;
class Assets; class Assets;

View File

@ -50,16 +50,16 @@ static inline UVRegion get_region_for(
void ModelsGenerator::prepare(Content& content, Assets& assets) { void ModelsGenerator::prepare(Content& content, Assets& assets) {
for (auto& [name, def] : content.blocks.getDefs()) { for (auto& [name, def] : content.blocks.getDefs()) {
if (def->model == BlockModel::custom && def->modelName.empty()) { if (def->model.type == BlockModelType::CUSTOM && def->model.name.empty()) {
assets.store( assets.store(
std::make_unique<model::Model>( std::make_unique<model::Model>(
loadCustomBlockModel( loadCustomBlockModel(
def->customModelRaw, assets, !def->shadeless def->model.customRaw, assets, !def->shadeless
) )
), ),
name + ".model" name + ".model"
); );
def->modelName = def->name + ".model"; def->model.name = def->name + ".model";
} }
} }
for (auto& [name, def] : content.items.getDefs()) { for (auto& [name, def] : content.items.getDefs()) {
@ -74,7 +74,7 @@ void ModelsGenerator::prepare(Content& content, Assets& assets) {
model::Model ModelsGenerator::fromCustom( model::Model ModelsGenerator::fromCustom(
const Assets& assets, const Assets& assets,
const std::vector<BoxModel>& modelBoxes, const std::vector<AABB>& modelBoxes,
const std::vector<std::string>& modelTextures, const std::vector<std::string>& modelTextures,
const std::vector<glm::vec3>& points, const std::vector<glm::vec3>& points,
bool lighting bool lighting
@ -95,32 +95,30 @@ model::Model ModelsGenerator::fromCustom(
modelBoxes[i].center(), modelBoxes[i].size() * 0.5f, boxtexfaces modelBoxes[i].center(), modelBoxes[i].size() * 0.5f, boxtexfaces
); );
} }
glm::vec3 norm {0, 1, 0};
for (size_t i = 0; i < points.size() / 4; i++) { for (size_t i = 0; i < points.size() / 4; i++) {
auto texture = modelTextures[modelBoxes.size() * 6 + i]; auto texture = modelTextures[modelBoxes.size() * 6 + i];
const glm::vec3& v0 = points[i * 4];
const glm::vec3& v1 = points[i * 4 + 1];
const glm::vec3& v2 = points[i * 4 + 2];
const glm::vec3& v3 = points[i * 4 + 3];
glm::vec3 edge1 = v1 - v0;
glm::vec3 edge2 = v2 - v0;
glm::vec3 norm = glm::cross(edge1, edge2);
norm = glm::normalize(norm);
auto& mesh = model.addMesh(texture); auto& mesh = model.addMesh(texture);
mesh.lighting = lighting; mesh.lighting = lighting;
auto reg = get_region_for(texture, assets); auto reg = get_region_for(texture, assets);
mesh.vertices.push_back( mesh.vertices.push_back({v0, glm::vec2(reg.u1, reg.v1), norm});
{points[i * 4 + 0], glm::vec2(reg.u1, reg.v1), norm} mesh.vertices.push_back({v1, glm::vec2(reg.u2, reg.v1), norm});
); mesh.vertices.push_back({v2, glm::vec2(reg.u2, reg.v2), norm});
mesh.vertices.push_back( mesh.vertices.push_back({v0, glm::vec2(reg.u1, reg.v1), norm});
{points[i * 4 + 1], glm::vec2(reg.u2, reg.v1), norm} mesh.vertices.push_back({v2, glm::vec2(reg.u2, reg.v2), norm});
); mesh.vertices.push_back({v3, glm::vec2(reg.u1, reg.v2), norm});
mesh.vertices.push_back(
{points[i * 4 + 2], glm::vec2(reg.u2, reg.v2), norm}
);
mesh.vertices.push_back(
{points[i * 4 + 0], glm::vec2(reg.u1, reg.v1), norm}
);
mesh.vertices.push_back(
{points[i * 4 + 2], glm::vec2(reg.u2, reg.v2), norm}
);
mesh.vertices.push_back(
{points[i * 4 + 3], glm::vec2(reg.u1, reg.v2), norm}
);
} }
return model; return model;
} }
@ -131,12 +129,12 @@ model::Model ModelsGenerator::generate(
if (def.iconType == ItemIconType::BLOCK) { if (def.iconType == ItemIconType::BLOCK) {
auto model = assets.require<model::Model>("block"); auto model = assets.require<model::Model>("block");
const auto& blockDef = content.blocks.require(def.icon); const auto& blockDef = content.blocks.require(def.icon);
if (blockDef.model == BlockModel::xsprite) { if (blockDef.model.type == BlockModelType::XSPRITE) {
return create_flat_model( return create_flat_model(
"blocks:" + blockDef.textureFaces.at(0), assets "blocks:" + blockDef.textureFaces.at(0), assets
); );
} else if (blockDef.model == BlockModel::custom) { } else if (blockDef.model.type == BlockModelType::CUSTOM) {
model = assets.require<model::Model>(blockDef.modelName); model = assets.require<model::Model>(blockDef.model.name);
for (auto& mesh : model.meshes) { for (auto& mesh : model.meshes) {
mesh.scale(glm::vec3(0.2f)); mesh.scale(glm::vec3(0.2f));
} }
@ -144,8 +142,8 @@ model::Model ModelsGenerator::generate(
} }
for (auto& mesh : model.meshes) { for (auto& mesh : model.meshes) {
mesh.lighting = !blockDef.shadeless; mesh.lighting = !blockDef.shadeless;
switch (blockDef.model) { switch (blockDef.model.type) {
case BlockModel::aabb: { case BlockModelType::AABB: {
glm::vec3 size = blockDef.hitboxes.at(0).size(); glm::vec3 size = blockDef.hitboxes.at(0).size();
float m = glm::max(size.x, glm::max(size.y, size.z)); float m = glm::max(size.x, glm::max(size.y, size.z));
m = glm::min(1.0f, m); m = glm::min(1.0f, m);

View File

@ -24,10 +24,10 @@
const int STARS_COUNT = 3000; const int STARS_COUNT = 3000;
const int STARS_SEED = 632; const int STARS_SEED = 632;
Skybox::Skybox(uint size, Shader& shader) Skybox::Skybox(uint size, Shader& shader)
: size(size), : size(size),
shader(shader), shader(shader),
batch3d(std::make_unique<Batch3D>(4096)) batch3d(std::make_unique<Batch3D>(4096))
{ {
auto cubemap = std::make_unique<Cubemap>(size, size, ImageFormat::rgb888); auto cubemap = std::make_unique<Cubemap>(size, size, ImageFormat::rgb888);
@ -35,12 +35,16 @@ Skybox::Skybox(uint size, Shader& shader)
glGenFramebuffers(1, &fboid); glGenFramebuffers(1, &fboid);
fbo = std::make_unique<Framebuffer>(fboid, 0, std::move(cubemap)); fbo = std::make_unique<Framebuffer>(fboid, 0, std::move(cubemap));
float vertices[] { SkyboxVertex vertices[]{
-1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, {{-1.0f, -1.0f}},
-1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f {{-1.0f, 1.0f}},
{{1.0f, 1.0f}},
{{-1.0f, -1.0f}},
{{1.0f, 1.0f}},
{{1.0f, -1.0f}}
}; };
VertexAttribute attrs[] {{2}, {0}};
mesh = std::make_unique<Mesh>(vertices, 6, attrs); mesh = std::make_unique<Mesh<SkyboxVertex>>(vertices, 6);
sprites.push_back(skysprite { sprites.push_back(skysprite {
"misc/moon", "misc/moon",
@ -95,11 +99,11 @@ void Skybox::drawStars(float angle, float opacity) {
} }
void Skybox::draw( void Skybox::draw(
const DrawContext& pctx, const DrawContext& pctx,
const Camera& camera, const Camera& camera,
const Assets& assets, const Assets& assets,
float daytime, float daytime,
float fog) float fog)
{ {
const glm::uvec2& viewport = pctx.getViewport(); const glm::uvec2& viewport = pctx.getViewport();
@ -116,7 +120,7 @@ void Skybox::draw(
float angle = daytime * glm::pi<float>() * 2.0f; float angle = daytime * glm::pi<float>() * 2.0f;
float opacity = glm::pow(1.0f-fog, 7.0f); float opacity = glm::pow(1.0f-fog, 7.0f);
for (auto& sprite : sprites) { for (auto& sprite : sprites) {
batch3d->texture(assets.get<Texture>(sprite.texture)); batch3d->texture(assets.get<Texture>(sprite.texture));
@ -129,7 +133,7 @@ void Skybox::draw(
if (!sprite.emissive) { if (!sprite.emissive) {
tint *= 0.6f+std::cos(angle)*0.4; tint *= 0.6f+std::cos(angle)*0.4;
} }
batch3d->sprite(pos, glm::vec3(0, 0, 1), batch3d->sprite(pos, glm::vec3(0, 0, 1),
up, 1, 1, UVRegion(), tint); up, 1, 1, UVRegion(), tint);
} }
@ -153,7 +157,7 @@ void Skybox::refresh(const DrawContext& pctx, float t, float mie, uint quality)
cubemap->bind(); cubemap->bind();
shader.use(); shader.use();
t *= glm::pi<float>()*2.0f; t *= glm::pi<float>()*2.0f;
lightDir = glm::normalize(glm::vec3(sin(t), -cos(t), 0.0f)); lightDir = glm::normalize(glm::vec3(sin(t), -cos(t), 0.0f));
shader.uniform1i("u_quality", quality); shader.uniform1i("u_quality", quality);
shader.uniform1f("u_mie", mie); shader.uniform1f("u_mie", mie);
@ -171,7 +175,7 @@ void Skybox::refresh(const DrawContext& pctx, float t, float mie, uint quality)
} }
prevMie = mie; prevMie = mie;
prevT = t; prevT = t;
cubemap->unbind(); cubemap->unbind();
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
} }
@ -190,7 +194,7 @@ void Skybox::refreshFace(uint face, Cubemap* cubemap) {
{0.0f, 1.0f, 0.0f}, {0.0f, 1.0f, 0.0f},
{0.0f, 1.0f, 0.0f}, {0.0f, 1.0f, 0.0f},
{0.0f, 0.0f, -1.0f}, {0.0f, 0.0f, -1.0f},
{0.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 1.0f},
{0.0f, 1.0f, 0.0f}, {0.0f, 1.0f, 0.0f},
{0.0f, 1.0f, 0.0f}, {0.0f, 1.0f, 0.0f},
@ -200,7 +204,7 @@ void Skybox::refreshFace(uint face, Cubemap* cubemap) {
{1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f},
{-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f},
{0.0f, -1.0f, 0.0f}, {0.0f, -1.0f, 0.0f},
{0.0f, 1.0f, 0.0f}, {0.0f, 1.0f, 0.0f},
{0.0f, 0.0f, -1.0f}, {0.0f, 0.0f, -1.0f},
{0.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 1.0f},

View File

@ -6,17 +6,25 @@
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include "typedefs.hpp" #include "typedefs.hpp"
#include "maths/fastmaths.hpp" #include "maths/fastmaths.hpp"
#include "graphics/core/MeshData.hpp"
class Mesh; template<typename VertexStructure> class Mesh;
class Shader; class Shader;
class Assets; class Assets;
class Camera; class Camera;
class Batch3D; class Batch3D;
class Shader;
class Cubemap; class Cubemap;
class Framebuffer; class Framebuffer;
class DrawContext; class DrawContext;
struct SkyboxVertex {
glm::vec2 position;
static constexpr VertexAttribute ATTRIBUTES[] {
{VertexAttribute::Type::FLOAT, false, 2},
{{}, 0}};
};
struct skysprite { struct skysprite {
std::string texture; std::string texture;
float phase; float phase;
@ -32,7 +40,7 @@ class Skybox {
FastRandom random; FastRandom random;
glm::vec3 lightDir; glm::vec3 lightDir;
std::unique_ptr<Mesh> mesh; std::unique_ptr<Mesh<SkyboxVertex>> mesh;
std::unique_ptr<Batch3D> batch3d; std::unique_ptr<Batch3D> batch3d;
std::vector<skysprite> sprites; std::vector<skysprite> sprites;
int frameid = 0; int frameid = 0;

View File

@ -1,6 +1,5 @@
#include "WorldRenderer.hpp" #include "WorldRenderer.hpp"
#include <GL/glew.h>
#include <assert.h> #include <assert.h>
#include <algorithm> #include <algorithm>
@ -119,6 +118,7 @@ void WorldRenderer::setupWorldShader(
shader.uniform1f("u_gamma", settings.graphics.gamma.get()); shader.uniform1f("u_gamma", settings.graphics.gamma.get());
shader.uniform1f("u_fogFactor", fogFactor); shader.uniform1f("u_fogFactor", fogFactor);
shader.uniform1f("u_fogCurve", settings.graphics.fogCurve.get()); shader.uniform1f("u_fogCurve", settings.graphics.fogCurve.get());
shader.uniform1i("u_debugLights", lightsDebug);
shader.uniform1f("u_weatherFogOpacity", weather.fogOpacity()); shader.uniform1f("u_weatherFogOpacity", weather.fogOpacity());
shader.uniform1f("u_weatherFogDencity", weather.fogDencity()); shader.uniform1f("u_weatherFogDencity", weather.fogDencity());
shader.uniform1f("u_weatherFogCurve", weather.fogCurve()); shader.uniform1f("u_weatherFogCurve", weather.fogCurve());
@ -443,6 +443,10 @@ void WorldRenderer::setDebug(bool flag) {
debug = flag; debug = flag;
} }
void WorldRenderer::toggleLightsDebug() {
lightsDebug = !lightsDebug;
}
Weather& WorldRenderer::getWeather() { Weather& WorldRenderer::getWeather() {
return weather; return weather;
} }

View File

@ -48,6 +48,7 @@ class WorldRenderer {
float timer = 0.0f; float timer = 0.0f;
bool debug = false; bool debug = false;
bool lightsDebug = false;
/// @brief Render block selection lines /// @brief Render block selection lines
void renderBlockSelection(); void renderBlockSelection();
@ -107,5 +108,7 @@ public:
void setDebug(bool flag); void setDebug(bool flag);
void toggleLightsDebug();
Weather& getWeather(); Weather& getWeather();
}; };

View File

@ -1,25 +1,36 @@
#pragma once #pragma once
#include <vector> #include <vector>
#include <array>
#include <memory> #include <memory>
#include <glm/vec2.hpp>
#include <glm/vec3.hpp> #include <glm/vec3.hpp>
#include "graphics/core/MeshData.hpp" #include "graphics/core/MeshData.hpp"
#include "util/Buffer.hpp" #include "util/Buffer.hpp"
/// @brief Chunk mesh vertex attributes /// @brief Chunk mesh vertex format
inline const VertexAttribute CHUNK_VATTRS[]{ {3}, {2}, {1}, {0} }; struct ChunkVertex {
/// @brief Chunk mesh vertex size divided by sizeof(float) glm::vec3 position;
inline constexpr int CHUNK_VERTEX_SIZE = 6; glm::vec2 uv;
std::array<uint8_t, 4> color;
static constexpr VertexAttribute ATTRIBUTES[] = {
{VertexAttribute::Type::FLOAT, false, 3},
{VertexAttribute::Type::FLOAT, false, 2},
{VertexAttribute::Type::UNSIGNED_BYTE, true, 4},
{{}, 0}};
};
template<typename VertexStructure>
class Mesh; class Mesh;
struct SortingMeshEntry { struct SortingMeshEntry {
glm::vec3 position; glm::vec3 position;
util::Buffer<float> vertexData; util::Buffer<ChunkVertex> vertexData;
long long distance; long long distance;
inline bool operator<(const SortingMeshEntry& o) const noexcept { inline bool operator<(const SortingMeshEntry &o) const noexcept {
return distance > o.distance; return distance > o.distance;
} }
}; };
@ -29,12 +40,12 @@ struct SortingMeshData {
}; };
struct ChunkMeshData { struct ChunkMeshData {
MeshData mesh; MeshData<ChunkVertex> mesh;
SortingMeshData sortingMesh; SortingMeshData sortingMesh;
}; };
struct ChunkMesh { struct ChunkMesh {
std::unique_ptr<Mesh> mesh; std::unique_ptr<Mesh<ChunkVertex> > mesh;
SortingMeshData sortingMeshData; SortingMeshData sortingMeshData;
std::unique_ptr<Mesh> sortedMesh = nullptr; std::unique_ptr<Mesh<ChunkVertex> > sortedMesh = nullptr;
}; };

View File

@ -312,7 +312,7 @@ static int l_get_textures(lua::State* L) {
static int l_get_model(lua::State* L) { static int l_get_model(lua::State* L) {
if (auto def = require_block(L)) { if (auto def = require_block(L)) {
return lua::pushlstring(L, BlockModelMeta.getName(def->model)); return lua::pushlstring(L, BlockModelTypeMeta.getName(def->model.type));
} }
return 0; return 0;
} }

View File

@ -143,7 +143,6 @@ void Block::cloneTo(Block& dst) {
if (particles) { if (particles) {
dst.particles = std::make_unique<ParticlesPreset>(*particles); dst.particles = std::make_unique<ParticlesPreset>(*particles);
} }
dst.customModelRaw = customModelRaw;
} }
static std::set<std::string, std::less<>> RESERVED_BLOCK_FIELDS { static std::set<std::string, std::less<>> RESERVED_BLOCK_FIELDS {

View File

@ -81,25 +81,35 @@ struct BlockRotProfile {
static inline std::string PANE_NAME = "pane"; static inline std::string PANE_NAME = "pane";
}; };
enum class BlockModel { enum class BlockModelType {
/// @brief invisible /// @brief invisible
none, NONE,
/// @brief default cube shape /// @brief default cube shape
block, BLOCK,
/// @brief X-shape (grass) /// @brief X-shape (grass)
xsprite, XSPRITE,
/// @brief box shape sized as block hitbox /// @brief box shape sized as block hitbox
aabb, AABB,
/// @brief custom model defined in json /// @brief custom model defined in json
custom CUSTOM
}; };
VC_ENUM_METADATA(BlockModel) struct BlockModel {
{"none", BlockModel::none}, BlockModelType type = BlockModelType::BLOCK;
{"block", BlockModel::block},
{"X", BlockModel::xsprite}, /// @brief Custom model raw data
{"aabb", BlockModel::aabb}, dv::value customRaw = nullptr;
{"custom", BlockModel::custom},
/// @brief Custom model name (generated or an asset)
std::string name = "";
};
VC_ENUM_METADATA(BlockModelType)
{"none", BlockModelType::NONE},
{"block", BlockModelType::BLOCK},
{"X", BlockModelType::XSPRITE},
{"aabb", BlockModelType::AABB},
{"custom", BlockModelType::CUSTOM},
VC_ENUM_END VC_ENUM_END
enum class CullingMode { enum class CullingMode {
@ -114,8 +124,6 @@ VC_ENUM_METADATA(CullingMode)
{"disabled", CullingMode::DISABLED}, {"disabled", CullingMode::DISABLED},
VC_ENUM_END VC_ENUM_END
using BoxModel = AABB;
/// @brief Common kit of block properties applied to groups of blocks /// @brief Common kit of block properties applied to groups of blocks
struct BlockMaterial : Serializable { struct BlockMaterial : Serializable {
std::string name; std::string name;
@ -154,13 +162,8 @@ public:
/// @brief Influences visible block sides for transparent blocks /// @brief Influences visible block sides for transparent blocks
uint8_t drawGroup = 0; uint8_t drawGroup = 0;
/// @brief Block model type /// @brief Block model
BlockModel model = BlockModel::block; BlockModel model {};
/// @brief Custom model raw data
dv::value customModelRaw = nullptr;
std::string modelName = "";
/// @brief Culling mode /// @brief Culling mode
CullingMode culling = CullingMode::DEFAULT; CullingMode culling = CullingMode::DEFAULT;

View File

@ -10,7 +10,6 @@
#include "coders/byte_utils.hpp" #include "coders/byte_utils.hpp"
#include "content/Content.hpp" #include "content/Content.hpp"
#include "world/files/WorldFiles.hpp" #include "world/files/WorldFiles.hpp"
#include "graphics/core/Mesh.hpp"
#include "lighting/Lightmap.hpp" #include "lighting/Lightmap.hpp"
#include "maths/aabb.hpp" #include "maths/aabb.hpp"
#include "maths/rays.hpp" #include "maths/rays.hpp"