Refactor mesh handling to use templated vertex structures for improved type safety and flexibility

This commit is contained in:
REDxEYE 2025-03-29 22:20:54 +03:00
parent bba647db5c
commit 1ffbeb8148
28 changed files with 591 additions and 521 deletions

View File

@ -49,3 +49,11 @@ if(VOXELENGINE_BUILD_TESTS)
endif() endif()
add_subdirectory(vctest) add_subdirectory(vctest)
add_custom_target(copy_resources ALL
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_CURRENT_SOURCE_DIR}/res
${CMAKE_CURRENT_BINARY_DIR}/res
COMMENT "Copying resource directory to the build directory"
)
add_dependencies(${PROJECT_NAME} copy_resources)

View File

@ -46,10 +46,15 @@
], ],
"buildPresets": [ "buildPresets": [
{ {
"name": "default-vs-msvc-windows", "name": "Debug build",
"configurePreset": "default-vs-msvc-windows", "configurePreset": "default-vs-msvc-windows",
"configuration": "Debug" "configuration": "Debug"
}, },
{
"name": "Release build",
"configurePreset": "default-vs-msvc-windows",
"configuration": "Release"
},
{ {
"name": "default-ninja-gnu-linux", "name": "default-ninja-gnu-linux",
"configurePreset": "default-ninja-gnu-linux", "configurePreset": "default-ninja-gnu-linux",

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,7 +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); vec4 decomp_light = v_light;
vec3 light = decomp_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);

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

@ -2,7 +2,7 @@
layout (location = 0) in vec3 v_position; layout (location = 0) in vec3 v_position;
layout (location = 1) in vec2 v_texCoord; layout (location = 1) in vec2 v_texCoord;
layout (location = 2) in float v_light; layout (location = 2) in vec4 v_light;
out vec4 a_color; out vec4 a_color;
out vec2 a_texCoord; out vec2 a_texCoord;
@ -27,13 +27,13 @@ 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); vec4 decomp_light = v_light;
vec3 light = decomp_light.rgb; vec3 light = decomp_light.rgb;
float torchlight = max(0.0, 1.0-distance(u_cameraPos, modelpos.xyz) / float torchlight = max(0.0, 1.0-distance(u_cameraPos, modelpos.xyz) /
u_torchlightDistance); u_torchlightDistance);
light += torchlight * u_torchlightColor; light += torchlight * u_torchlightColor;
a_color = vec4(pow(light, vec3(u_gamma)),1.0f); a_color = vec4(pow(light, vec3(u_gamma)),1.0f);

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

@ -8,15 +8,10 @@
#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, Batch2DVertex::ATTRIBUTES);
};
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 +46,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 +86,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 +106,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 +129,7 @@ void Batch2D::rect(
bool flippedY, bool flippedY,
glm::vec4 tint glm::vec4 tint
) { ) {
if (index + 6 * B2D_VERTEX_SIZE >= capacity) { if (index + 6 >= capacity) {
flush(); flush();
} }
setPrimitive(DrawPrimitive::triangle); setPrimitive(DrawPrimitive::triangle);
@ -230,14 +217,14 @@ void Batch2D::rect(
} }
void Batch2D::lineRect(float x, float y, float w, float h) { void Batch2D::lineRect(float x, float y, float w, float h) {
if (index + 8 * B2D_VERTEX_SIZE >= capacity) { if (index + 8 >= capacity) {
flush(); flush();
} }
setPrimitive(DrawPrimitive::line); setPrimitive(DrawPrimitive::line);
vertex(x, y, 0.0f, 0.0f, color.r, color.g, color.b, color.a); vertex(x, y, 0.0f, 0.0f, color.r, color.g, color.b, color.a);
vertex(x, y+h, 0.0f, 1.0f, color.r, color.g, color.b, color.a); vertex(x, y+h, 0.0f, 1.0f, color.r, color.g, color.b, color.a);
vertex(x, y+h, 0.0f, 1.0f, color.r, color.g, color.b, color.a); vertex(x, y+h, 0.0f, 1.0f, color.r, color.g, color.b, color.a);
vertex(x+w, y+h, 1.0f, 1.0f, color.r, color.g, color.b, color.a); vertex(x+w, y+h, 1.0f, 1.0f, color.r, color.g, color.b, color.a);
@ -253,7 +240,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 +258,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 +279,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 +365,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,33 @@
#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[] {
{GL_FLOAT, false, 2},
{GL_FLOAT, false,2},
{GL_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

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

@ -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, LineVertex::ATTRIBUTES);
index = 0; index = 0;
} }
@ -16,31 +15,21 @@ LineBatch::~LineBatch(){
} }
void LineBatch::line( void LineBatch::line(
float x1, float y1, float x1, float y1,
float z1, float x2, float z1, float x2,
float y2, float z2, float y2, float z2,
float r, float g, float b, float a float r, float g, float b, float a
) { ) {
if (index + LB_VERTEX_SIZE * 2 >= capacity) { if (index + 2 >= capacity) {
flush(); flush();
} }
buffer[index] = x1; buffer[index].position = {x1,y1,z1};
buffer[index+1] = y1; buffer[index].color = {r,g,b,a};
buffer[index+2] = z1; index++;
buffer[index+3] = r;
buffer[index+4] = g;
buffer[index+5] = b;
buffer[index+6] = a;
index += LB_VERTEX_SIZE;
buffer[index] = x2; buffer[index].position = {x2,y2,z2};
buffer[index+1] = y2; buffer[index].color = {r,g,b,a};
buffer[index+2] = z2; index++;
buffer[index+3] = r;
buffer[index+4] = g;
buffer[index+5] = b;
buffer[index+6] = a;
index += LB_VERTEX_SIZE;
} }
void LineBatch::box(float x, float y, float z, float w, float h, float d, void LineBatch::box(float x, float y, float z, float w, float h, float d,
@ -68,7 +57,7 @@ void LineBatch::box(float x, float y, float z, float w, float h, float d,
void LineBatch::flush(){ void LineBatch::flush(){
if (index == 0) if (index == 0)
return; return;
mesh->reload(buffer.get(), index / LB_VERTEX_SIZE); mesh->reload(buffer.get(), index);
mesh->draw(GL_LINES); mesh->draw(GL_LINES);
index = 0; index = 0;
} }

View File

@ -5,12 +5,21 @@
#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[] { {GL_FLOAT,false,3},{GL_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,8 @@
#include "Mesh.hpp" //
#include <assert.h> // Created by RED on 24.03.2025.
#include <GL/glew.h> //
int Mesh::meshesCount = 0; #include "graphics/core/Mesh.hpp"
int Mesh::drawCalls = 0;
inline size_t calc_vertex_size(const VertexAttribute* attrs) { int MeshStats::meshesCount = 0;
size_t vertexSize = 0; int MeshStats::drawCalls = 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,31 +1,43 @@
#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; 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(const VertexStructure *vertexBuffer, size_t vertices, const uint32_t *indexBuffer, size_t indices,
Mesh(vertexBuffer, vertices, nullptr, 0, attrs) {}; const VertexAttribute *attrs);
Mesh(const VertexStructure *vertexBuffer, size_t vertices, const VertexAttribute *attrs) : Mesh<VertexStructure>(
vertexBuffer, vertices, nullptr, 0, attrs) {
};
~Mesh(); ~Mesh();
/// @brief Update GL vertex and index buffers data without changing VAO attributes /// @brief Update GL vertex and index buffers data without changing VAO attributes
/// @param vertexBuffer vertex data buffer /// @param vertexBuffer vertex data buffer
/// @param vertices number of vertices in new buffer /// @param vertexCount number of vertices in new buffer
/// @param indexBuffer indices buffer /// @param indexBuffer indices buffer
/// @param indices number of values in indices buffer /// @param indexCount number of values in indices buffer
void reload(const float* vertexBuffer, size_t vertices, const int* indexBuffer = nullptr, size_t indices = 0); void reload(const VertexStructure *vertexBuffer, size_t vertexCount, const uint32_t *indexBuffer = nullptr,
size_t indexCount = 0);
/// @brief Draw mesh with specified primitives type /// @brief Draw mesh with specified primitives type
/// @param primitive primitives type /// @param primitive primitives type
void draw(unsigned int primitive) const; void draw(unsigned int primitive) const;
@ -34,6 +46,6 @@ public:
void draw() const; void draw() const;
/// @brief Total numbers of alive mesh objects /// @brief Total numbers of alive mesh objects
static int meshesCount;
static int drawCalls;
}; };
#include "graphics/core/Mesh.inl"

View File

@ -0,0 +1,92 @@
#pragma once
#include <GL/glew.h>
#include "MeshData.hpp"
template<typename VertexStructure>
Mesh<VertexStructure>::Mesh(const MeshData<VertexStructure>& data)
: Mesh(data.vertices.data(),
data.vertices.size(),
data.indices.data(),
data.indices.size(),
data.attrs.data()) {}
template<typename VertexStructure>
Mesh<VertexStructure>::Mesh(const VertexStructure* vertexBuffer, size_t vertices, const uint32_t* indexBuffer, size_t indices, const VertexAttribute* attrs) :
ibo(0),
vao(0),
vbo(0),
vertexCount(0),
indexCount(0)
{
MeshStats::meshesCount++;
vertexSize = 0;
for (int i = 0; attrs[i].count; i++) {
vertexSize += attrs[i].size();
}
size_t tmp = sizeof(VertexStructure);
assert(vertexSize==tmp);
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, 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 * vertexSize, 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,42 @@
#pragma once #pragma once
#include <vector> #include <stdexcept>
#include <GL/glew.h>
#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; uint32_t type;
bool normalized;
ubyte count;
[[nodiscard]] uint32_t size() const {
switch (type) {
case GL_FLOAT:
return count * sizeof(float);
case GL_UNSIGNED_INT:
case GL_INT:
return count * sizeof(uint32_t);
case GL_UNSIGNED_SHORT:
case GL_SHORT:
return count * sizeof(uint16_t);
case GL_UNSIGNED_BYTE:
case GL_BYTE:
return count * sizeof(uint8_t);
default:
throw std::runtime_error("VertexAttribute type is not supported");
}
}
}; };
/// @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 +45,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, PostProcessingVertex::ATTRIBUTES);
} }
PostProcessing::~PostProcessing() = default; PostProcessing::~PostProcessing() = default;

View File

@ -2,14 +2,25 @@
#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[] {
{GL_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 +29,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

@ -11,24 +11,25 @@
const glm::vec3 BlocksRenderer::SUN_VECTOR (0.2275f,0.9388f,-0.1005f); const glm::vec3 BlocksRenderer::SUN_VECTOR (0.2275f,0.9388f,-0.1005f);
BlocksRenderer::BlocksRenderer( BlocksRenderer::BlocksRenderer(
size_t capacity, size_t capacity,
const Content& content, const Content& content,
const ContentGfxCache& cache, const ContentGfxCache& cache,
const EngineSettings& settings const EngineSettings& settings
) : content(content), ) : content(content),
vertexBuffer(std::make_unique<float[]>(capacity * CHUNK_VERTEX_SIZE)), vertexBuffer(std::make_unique<ChunkVertex[]>(capacity)),
indexBuffer(std::make_unique<int[]>(capacity)), indexBuffer(std::make_unique<uint32_t[]>(capacity)),
vertexCount(0),
vertexOffset(0), vertexOffset(0),
indexOffset(0), indexCount(0),
indexSize(0),
capacity(capacity), capacity(capacity),
cache(cache), cache(cache),
settings(settings) settings(settings)
{ {
voxelsBuffer = std::make_unique<VoxelsVolume>( voxelsBuffer = std::make_unique<VoxelsVolume>(
CHUNK_W + voxelBufferPadding*2, CHUNK_W + voxelBufferPadding*2,
CHUNK_H, CHUNK_H,
CHUNK_D + voxelBufferPadding*2); CHUNK_D + voxelBufferPadding*2);
blockDefsCache = content.getIndices()->blocks.getDefs(); blockDefsCache = content.getIndices()->blocks.getDefs();
} }
@ -40,39 +41,31 @@ BlocksRenderer::~BlocksRenderer() {
void BlocksRenderer::vertex( void BlocksRenderer::vertex(
const glm::vec3& coord, float u, float v, const glm::vec4& light const glm::vec3& coord, float u, float v, const glm::vec4& light
) { ) {
vertexBuffer[vertexOffset++] = coord.x;
vertexBuffer[vertexOffset++] = coord.y;
vertexBuffer[vertexOffset++] = coord.z;
vertexBuffer[vertexOffset++] = u; vertexBuffer[vertexCount].position = coord;
vertexBuffer[vertexOffset++] = v;
union { vertexBuffer[vertexCount].uv = {u,v};
float floating;
uint32_t integer;
} compressed;
compressed.integer = (static_cast<uint32_t>(light.r * 255) & 0xff) << 24; vertexBuffer[vertexCount].color[0] = static_cast<uint8_t>(light.r * 255);
compressed.integer |= (static_cast<uint32_t>(light.g * 255) & 0xff) << 16; vertexBuffer[vertexCount].color[1] = static_cast<uint8_t>(light.g * 255);
compressed.integer |= (static_cast<uint32_t>(light.b * 255) & 0xff) << 8; vertexBuffer[vertexCount].color[2] = static_cast<uint8_t>(light.b * 255);
compressed.integer |= (static_cast<uint32_t>(light.a * 255) & 0xff); vertexBuffer[vertexCount].color[3] = static_cast<uint8_t>(light.a * 255);
vertexCount++;
vertexBuffer[vertexOffset++] = compressed.floating;
} }
void BlocksRenderer::index(int a, int b, int c, int d, int e, int f) { void BlocksRenderer::index(uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_t e, uint32_t f) {
indexBuffer[indexSize++] = indexOffset + a; indexBuffer[indexCount++] = static_cast<uint32_t>(vertexOffset + a);
indexBuffer[indexSize++] = indexOffset + b; indexBuffer[indexCount++] = static_cast<uint32_t>(vertexOffset + b);
indexBuffer[indexSize++] = indexOffset + c; indexBuffer[indexCount++] = static_cast<uint32_t>(vertexOffset + c);
indexBuffer[indexSize++] = indexOffset + d; indexBuffer[indexCount++] = static_cast<uint32_t>(vertexOffset + d);
indexBuffer[indexSize++] = indexOffset + e; indexBuffer[indexCount++] = static_cast<uint32_t>(vertexOffset + e);
indexBuffer[indexSize++] = indexOffset + f; indexBuffer[indexCount++] = static_cast<uint32_t>(vertexOffset + f);
indexOffset += 4; vertexOffset += 4;
} }
/// @brief Add face with precalculated lights /// @brief Add face with precalculated lights
void BlocksRenderer::face( void BlocksRenderer::face(
const glm::vec3& coord, const glm::vec3& coord,
float w, float h, float d, float w, float h, float d,
const glm::vec3& axisX, const glm::vec3& axisX,
const glm::vec3& axisY, const glm::vec3& axisY,
@ -81,7 +74,7 @@ void BlocksRenderer::face(
const glm::vec4(&lights)[4], const glm::vec4(&lights)[4],
const glm::vec4& tint const glm::vec4& tint
) { ) {
if (vertexOffset + CHUNK_VERTEX_SIZE * 4 > capacity) { if (vertexCount + 4 >= capacity) {
overflow = true; overflow = true;
return; return;
} }
@ -97,7 +90,7 @@ void BlocksRenderer::face(
} }
void BlocksRenderer::vertexAO( void BlocksRenderer::vertexAO(
const glm::vec3& coord, const glm::vec3& coord,
float u, float v, float u, float v,
const glm::vec4& tint, const glm::vec4& tint,
const glm::vec3& axisX, const glm::vec3& axisX,
@ -121,7 +114,7 @@ void BlocksRenderer::faceAO(
const UVRegion& region, const UVRegion& region,
bool lights bool lights
) { ) {
if (vertexOffset + CHUNK_VERTEX_SIZE * 4 > capacity) { if (vertexCount + 4 >= capacity) {
overflow = true; overflow = true;
return; return;
} }
@ -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;
} }
@ -178,10 +171,10 @@ void BlocksRenderer::face(
} }
void BlocksRenderer::blockXSprite( void BlocksRenderer::blockXSprite(
int x, int y, int z, int x, int y, int z,
const glm::vec3& size, const glm::vec3& size,
const UVRegion& texface1, const UVRegion& texface1,
const UVRegion& texface2, const UVRegion& texface2,
float spread float spread
) { ) {
glm::vec4 lights1[] { glm::vec4 lights1[] {
@ -207,12 +200,12 @@ void BlocksRenderer::blockXSprite(
face({x + xs, y, z + zs}, w, size.y, 0, {-1, 0, 1}, {0, 1, 0}, glm::vec3(), face({x + xs, y, z + zs}, w, size.y, 0, {-1, 0, 1}, {0, 1, 0}, glm::vec3(),
texface1, lights2, tint); texface1, lights2, tint);
face({x + xs, y, z + zs}, w, size.y, 0, {1, 0, 1}, {0, 1, 0}, glm::vec3(), face({x + xs, y, z + zs}, w, size.y, 0, {1, 0, 1}, {0, 1, 0}, glm::vec3(),
texface1, lights1, tint); texface1, lights1, tint);
face({x + xs, y, z + zs}, w, size.y, 0, {-1, 0, -1}, {0, 1, 0}, glm::vec3(), face({x + xs, y, z + zs}, w, size.y, 0, {-1, 0, -1}, {0, 1, 0}, glm::vec3(),
texface2, lights2, tint); texface2, lights2, tint);
face({x + xs, y, z + zs}, w, size.y, 0, {1, 0, -1}, {0, 1, 0}, glm::vec3(), face({x + xs, y, z + zs}, w, size.y, 0, {1, 0, -1}, {0, 1, 0}, glm::vec3(),
texface2, lights1, tint); texface2, lights1, tint);
} }
@ -221,8 +214,8 @@ void BlocksRenderer::blockXSprite(
/// @brief AABB blocks render method /// @brief AABB blocks render method
void BlocksRenderer::blockAABB( void BlocksRenderer::blockAABB(
const glm::ivec3& icoord, const glm::ivec3& icoord,
const UVRegion(&texfaces)[6], const UVRegion(&texfaces)[6],
const Block* block, const Block* block,
ubyte rotation, ubyte rotation,
bool lights, bool lights,
bool ao bool ao
@ -249,7 +242,7 @@ void BlocksRenderer::blockAABB(
orient.transform(hitbox); orient.transform(hitbox);
} }
coord -= glm::vec3(0.5f) - hitbox.center(); coord -= glm::vec3(0.5f) - hitbox.center();
if (ao) { if (ao) {
faceAO(coord, X*size.x, Y*size.y, Z*size.z, texfaces[5], lights); // north faceAO(coord, X*size.x, Y*size.y, Z*size.z, texfaces[5], lights); // north
faceAO(coord, -X*size.x, Y*size.y, -Z*size.z, texfaces[4], lights); // south faceAO(coord, -X*size.x, Y*size.y, -Z*size.z, texfaces[4], lights); // south
@ -289,7 +282,7 @@ 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;
} }
@ -314,7 +307,7 @@ void BlocksRenderer::blockCustomModel(
r, r,
n n
); );
indexBuffer[indexSize++] = indexOffset++; indexBuffer[indexCount++] = vertexOffset++;
} }
} }
} }
@ -322,9 +315,9 @@ void BlocksRenderer::blockCustomModel(
/* Fastest solid shaded blocks render method */ /* Fastest solid shaded blocks render method */
void BlocksRenderer::blockCube( void BlocksRenderer::blockCube(
const glm::ivec3& coord, const glm::ivec3& coord,
const UVRegion(&texfaces)[6], const UVRegion(&texfaces)[6],
const Block& block, const Block& block,
blockstate states, blockstate states,
bool lights, bool lights,
bool ao bool ao
@ -340,7 +333,7 @@ void BlocksRenderer::blockCube(
Y = orient.axes[1]; Y = orient.axes[1];
Z = orient.axes[2]; Z = orient.axes[2];
} }
if (ao) { if (ao) {
if (isOpen(coord + Z, block)) { if (isOpen(coord + Z, block)) {
faceAO(coord, X, Y, Z, texfaces[5], lights); faceAO(coord, X, Y, Z, texfaces[5], lights);
@ -383,8 +376,8 @@ void BlocksRenderer::blockCube(
} }
bool BlocksRenderer::isOpenForLight(int x, int y, int z) const { bool BlocksRenderer::isOpenForLight(int x, int y, int z) const {
blockid_t id = voxelsBuffer->pickBlockId(chunk->x * CHUNK_W + x, blockid_t id = voxelsBuffer->pickBlockId(chunk->x * CHUNK_W + x,
y, y,
chunk->z * CHUNK_D + z); chunk->z * CHUNK_D + z);
if (id == BLOCK_VOID) { if (id == BLOCK_VOID) {
return false; return false;
@ -398,7 +391,7 @@ bool BlocksRenderer::isOpenForLight(int x, int y, int z) const {
glm::vec4 BlocksRenderer::pickLight(int x, int y, int z) const { glm::vec4 BlocksRenderer::pickLight(int x, int y, int z) const {
if (isOpenForLight(x, y, z)) { if (isOpenForLight(x, y, z)) {
light_t light = voxelsBuffer->pickLight(chunk->x * CHUNK_W + x, y, light_t light = voxelsBuffer->pickLight(chunk->x * CHUNK_W + x, y,
chunk->z * CHUNK_D + z); chunk->z * CHUNK_D + z);
return glm::vec4(Lightmap::extract(light, 0), return glm::vec4(Lightmap::extract(light, 0),
Lightmap::extract(light, 1), Lightmap::extract(light, 1),
@ -426,8 +419,8 @@ glm::vec4 BlocksRenderer::pickSoftLight(
float x, float y, float z, const glm::ivec3& right, const glm::ivec3& up float x, float y, float z, const glm::ivec3& right, const glm::ivec3& up
) const { ) const {
return pickSoftLight({ return pickSoftLight({
static_cast<int>(std::round(x)), static_cast<int>(std::round(x)),
static_cast<int>(std::round(y)), static_cast<int>(std::round(y)),
static_cast<int>(std::round(z))}, static_cast<int>(std::round(z))},
right, up); right, up);
} }
@ -466,17 +459,17 @@ void BlocksRenderer::render(
def.ambientOcclusion); def.ambientOcclusion);
break; break;
case BlockModel::xsprite: { case BlockModel::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 BlockModel::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 BlockModel::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;
} }
@ -529,24 +522,24 @@ SortingMeshData BlocksRenderer::renderTranslucent(
def.ambientOcclusion); def.ambientOcclusion);
break; break;
case BlockModel::xsprite: { case BlockModel::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 BlockModel::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 BlockModel::custom: {
blockCustomModel({x, y, z}, &def, vox.state.rotation, blockCustomModel({x, y, z}, &def, vox.state.rotation,
!def.shadeless, def.ambientOcclusion); !def.shadeless, def.ambientOcclusion);
break; break;
} }
default: default:
break; break;
} }
if (vertexOffset == 0) { if (vertexCount == 0) {
continue; continue;
} }
SortingMeshEntry entry { SortingMeshEntry entry {
@ -555,50 +548,50 @@ SortingMeshData BlocksRenderer::renderTranslucent(
y + 0.5f, y + 0.5f,
z + chunk->z * CHUNK_D + 0.5f z + chunk->z * CHUNK_D + 0.5f
), ),
util::Buffer<float>(indexSize * CHUNK_VERTEX_SIZE), 0}; util::Buffer<ChunkVertex>(indexCount), 0};
totalSize += entry.vertexData.size(); totalSize += entry.vertexData.size();
for (int j = 0; j < indexSize; j++) { for (int j = 0; j < indexCount; j++) {
std::memcpy( std::memcpy(
entry.vertexData.data() + j * CHUNK_VERTEX_SIZE, entry.vertexData.data() + j,
vertexBuffer.get() + indexBuffer[j] * CHUNK_VERTEX_SIZE, vertexBuffer.get() + indexBuffer[j],
sizeof(float) * CHUNK_VERTEX_SIZE sizeof(ChunkVertex)
); );
float& vx = entry.vertexData[j * CHUNK_VERTEX_SIZE + 0]; ChunkVertex& vertex = entry.vertexData[j];
float& vy = entry.vertexData[j * CHUNK_VERTEX_SIZE + 1];
float& vz = entry.vertexData[j * CHUNK_VERTEX_SIZE + 2];
if (!aabbInit) { if (!aabbInit) {
aabbInit = true; aabbInit = true;
aabb.a = aabb.b = {vx, vy, vz}; aabb.a = aabb.b = vertex.position;
} else { } else {
aabb.addPoint(glm::vec3(vx, vy, vz)); aabb.addPoint(vertex.position);
} }
vx += chunk->x * CHUNK_W + 0.5f;
vy += 0.5f; vertex.position.x += chunk->x * CHUNK_W + 0.5f;
vz += chunk->z * CHUNK_D + 0.5f; vertex.position.y += 0.5f;
vertex.position.z += chunk->z * CHUNK_D + 0.5f;
} }
sortingMesh.entries.push_back(std::move(entry)); sortingMesh.entries.push_back(std::move(entry));
vertexOffset = 0; vertexCount = 0;
indexOffset = indexSize = 0; vertexOffset = indexCount = 0;
} }
} }
// additional powerful optimization // additional powerful optimization
auto size = aabb.size(); auto size = aabb.size();
if ((size.y < 0.01f || size.x < 0.01f || size.z < 0.01f) && if ((size.y < 0.01f || size.x < 0.01f || size.z < 0.01f) &&
sortingMesh.entries.size() > 1) { sortingMesh.entries.size() > 1) {
SortingMeshEntry newEntry { SortingMeshEntry newEntry {
sortingMesh.entries[0].position, sortingMesh.entries[0].position,
util::Buffer<float>(totalSize), util::Buffer<ChunkVertex>(totalSize),
0 0
}; };
size_t offset = 0; size_t offset = 0;
for (const auto& entry : sortingMesh.entries) { for (const auto& entry : sortingMesh.entries) {
std::memcpy( std::memcpy(
newEntry.vertexData.data() + offset, newEntry.vertexData.data() + offset,
entry.vertexData.data(), entry.vertexData.size() * sizeof(float) entry.vertexData.data(),
entry.vertexData.size() * sizeof(ChunkVertex)
); );
offset += entry.vertexData.size(); offset += entry.vertexData.size();
} }
@ -630,7 +623,7 @@ void BlocksRenderer::build(const Chunk* chunk, const Chunks* chunks) {
const voxel& vox = voxels[i]; const voxel& vox = voxels[i];
blockid_t id = vox.id; blockid_t id = vox.id;
const auto& def = *blockDefsCache[id]; const auto& def = *blockDefsCache[id];
if (beginEnds[def.drawGroup][0] == 0) { if (beginEnds[def.drawGroup][0] == 0) {
beginEnds[def.drawGroup][0] = i+1; beginEnds[def.drawGroup][0] = i+1;
} }
@ -639,36 +632,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, ChunkVertex::ATTRIBUTES
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,10 @@ 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() / CHUNK_VERTEX_SIZE, entry.vertexData.size(),
CHUNK_VATTRS ChunkVertex::ATTRIBUTES
); );
} }
found->second.sortedMesh->draw(); found->second.sortedMesh->draw();
@ -310,13 +310,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, ChunkVertex::ATTRIBUTES
); );
} }
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, MainBatchVertex::ATTRIBUTES)) {
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,47 @@
#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[] = {
{GL_FLOAT, false, 3},
{GL_FLOAT, false, 2},
{GL_FLOAT, false, 3},
{GL_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 +64,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

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

View File

@ -6,17 +6,23 @@
#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[] {{GL_FLOAT,false,2}, {0}};
};
struct skysprite { struct skysprite {
std::string texture; std::string texture;
float phase; float phase;
@ -32,7 +38,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,25 +1,43 @@
#pragma once #pragma once
#include <vector> #include <vector>
#include <array>
#include <memory> #include <memory>
#include <GL/glew.h>
#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
inline const VertexAttribute CHUNK_VATTRS[]{ {3}, {2}, {1}, {0} };
/// @brief Chunk mesh vertex size divided by sizeof(float)
inline constexpr int CHUNK_VERTEX_SIZE = 6;
/// @brief Chunk mesh vertex format
#pragma pack(push, 2)
struct ChunkVertex {
glm::vec3 position;
glm::vec2 uv;
std::array<uint8_t, 4> color;
static constexpr VertexAttribute ATTRIBUTES[] = {
{GL_FLOAT, false, 3},
{GL_FLOAT, false, 2},
{GL_UNSIGNED_BYTE, true, 4},
{0}
};
};
#pragma pack(pop)
/// @brief Chunk mesh vertex attributes
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 +47,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;
}; };