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,12 +27,11 @@ 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;
@ -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,7 +215,7 @@ 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);
@ -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
inline constexpr uint B3D_VERTEX_SIZE = 9;
Batch3D::Batch3D(size_t capacity) 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,44 +34,29 @@ 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(
@ -88,7 +67,7 @@ void Batch3D::face(
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,
@ -145,7 +124,7 @@ void Batch3D::sprite(
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();
} }
@ -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;
} }
@ -21,26 +20,16 @@ void LineBatch::line(
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,30 +1,47 @@
#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
@ -32,8 +49,6 @@ public:
/// @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,11 +18,11 @@ 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)
@ -40,34 +41,26 @@ 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
@ -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;
} }
@ -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);
@ -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++;
} }
} }
} }
@ -460,22 +478,22 @@ 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,22 +541,22 @@ 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;
@ -546,7 +564,7 @@ SortingMeshData BlocksRenderer::renderTranslucent(
default: default:
break; break;
} }
if (vertexOffset == 0) { if (vertexCount == 0) {
continue; continue;
} }
SortingMeshEntry entry { SortingMeshEntry entry {
@ -555,33 +573,32 @@ 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;
} }
} }
@ -591,14 +608,15 @@ SortingMeshData BlocksRenderer::renderTranslucent(
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();
} }
@ -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

@ -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",

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"