This commit is contained in:
MihailRis
2024-03-19 00:49:45 +03:00
parent 258666c377
commit 48bedc5d8e
9 changed files with 105 additions and 106 deletions
+146
View File
@@ -0,0 +1,146 @@
#include "BlocksPreview.h"
#include <glm/ext.hpp>
#include "../../assets/Assets.h"
#include "../../constants.h"
#include "../../content/Content.h"
#include "../../frontend/ContentGfxCache.h"
#include "../../voxels/Block.h"
#include "../../window/Camera.h"
#include "../../window/Window.h"
#include "../core/Atlas.h"
#include "../core/Batch3D.h"
#include "../core/Framebuffer.h"
#include "../core/GfxContext.h"
#include "../core/Shader.h"
#include "../core/Texture.h"
#include "../core/Viewport.h"
ImageData* BlocksPreview::draw(
const ContentGfxCache* cache,
Shader* shader,
Framebuffer* fbo,
Batch3D* batch,
const Block* def,
int size
){
Window::clear();
blockid_t id = def->rt.id;
const UVRegion texfaces[6]{cache->getRegion(id, 0), cache->getRegion(id, 1),
cache->getRegion(id, 2), cache->getRegion(id, 3),
cache->getRegion(id, 4), cache->getRegion(id, 5)};
glm::vec3 offset(0.1f, 0.5f, 0.1f);
switch (def->model) {
case BlockModel::none:
// something went wrong...
break;
case BlockModel::block:
shader->uniformMatrix("u_apply", glm::translate(glm::mat4(1.0f), offset));
batch->blockCube(glm::vec3(size * 0.63f), texfaces,
glm::vec4(1.0f), !def->rt.emissive);
batch->flush();
break;
case BlockModel::aabb:
{
glm::vec3 hitbox = glm::vec3();
for (const auto& box : def->hitboxes)
hitbox = glm::max(hitbox, box.size());
offset.y += (1.0f - hitbox).y * 0.5f;
shader->uniformMatrix("u_apply", glm::translate(glm::mat4(1.0f), offset));
batch->blockCube(hitbox * glm::vec3(size * 0.63f),
texfaces, glm::vec4(1.0f), !def->rt.emissive);
}
batch->flush();
break;
case BlockModel::custom:
{
glm::vec3 hitbox = glm::vec3();
for (const auto& box : def->modelBoxes)
hitbox = glm::max(hitbox, box.size());
offset.y += (1.0f - hitbox).y * 0.5f;
shader->uniformMatrix("u_apply", glm::translate(glm::mat4(1.0f), offset));
for (size_t i = 0; i < def->modelBoxes.size(); i++) {
const UVRegion (&texfaces)[6] = {
def->modelUVs[i * 6],
def->modelUVs[i * 6 + 1],
def->modelUVs[i * 6 + 2],
def->modelUVs[i * 6 + 3],
def->modelUVs[i * 6 + 4],
def->modelUVs[i * 6 + 5]
};
batch->cube(def->modelBoxes[i].a * glm::vec3(1.0f, 1.0f, -1.0f) * glm::vec3(size * 0.63f), def->modelBoxes[i].size() * glm::vec3(size * 0.63f), texfaces, glm::vec4(1.0f), !def->rt.emissive);
}
for (size_t i = 0; i < def->modelExtraPoints.size() / 4; i++) {
const UVRegion& reg = def->modelUVs[def->modelBoxes.size() * 6 + i];
batch->point((def->modelExtraPoints[i * 4 + 0] - glm::vec3(0.0f, 0.0f, 1.0f)) * glm::vec3(size * 0.63f), glm::vec2(reg.u1, reg.v1), glm::vec4(1.0));
batch->point((def->modelExtraPoints[i * 4 + 1] - glm::vec3(0.0f, 0.0f, 1.0f)) * glm::vec3(size * 0.63f), glm::vec2(reg.u2, reg.v1), glm::vec4(1.0));
batch->point((def->modelExtraPoints[i * 4 + 2] - glm::vec3(0.0f, 0.0f, 1.0f)) * glm::vec3(size * 0.63f), glm::vec2(reg.u2, reg.v2), glm::vec4(1.0));
batch->point((def->modelExtraPoints[i * 4 + 0] - glm::vec3(0.0f, 0.0f, 1.0f)) * glm::vec3(size * 0.63f), glm::vec2(reg.u1, reg.v1), glm::vec4(1.0));
batch->point((def->modelExtraPoints[i * 4 + 2] - glm::vec3(0.0f, 0.0f, 1.0f)) * glm::vec3(size * 0.63f), glm::vec2(reg.u2, reg.v2), glm::vec4(1.0));
batch->point((def->modelExtraPoints[i * 4 + 3] - glm::vec3(0.0f, 0.0f, 1.0f)) * glm::vec3(size * 0.63f), glm::vec2(reg.u1, reg.v2), glm::vec4(1.0));
}
batch->flush();
}
break;
case BlockModel::xsprite: {
glm::vec3 right = glm::normalize(glm::vec3(1.f, 0.f, -1.f));
batch->sprite(right*float(size)*0.43f+glm::vec3(0, size*0.4f, 0),
glm::vec3(0.f, 1.f, 0.f),
right,
size*0.5f, size*0.6f,
texfaces[0],
glm::vec4(1.0f));
batch->flush();
break;
}
}
return fbo->getTexture()->readData();
}
std::unique_ptr<Atlas> BlocksPreview::build(
const ContentGfxCache* cache,
Assets* assets,
const Content* content
) {
auto indices = content->getIndices();
size_t count = indices->countBlockDefs();
size_t iconSize = ITEM_ICON_SIZE;
Shader* shader = assets->getShader("ui3d");
Atlas* atlas = assets->getAtlas("blocks");
Viewport viewport(iconSize, iconSize);
GfxContext pctx(nullptr, viewport, nullptr);
GfxContext ctx = pctx.sub();
ctx.setCullFace(true);
ctx.setDepthTest(true);
Framebuffer fbo(iconSize, iconSize, true);
Batch3D batch(1024);
batch.begin();
shader->use();
shader->uniformMatrix("u_projview",
glm::ortho(0.0f, float(iconSize), 0.0f, float(iconSize),
-100.0f, 100.0f) *
glm::lookAt(glm::vec3(2, 2, 2),
glm::vec3(0.0f),
glm::vec3(0, 1, 0)));
AtlasBuilder builder;
Window::viewport(0, 0, iconSize, iconSize);
Window::setBgColor(glm::vec4(0.0f));
fbo.bind();
for (size_t i = 0; i < count; i++) {
auto def = indices->getBlockDef(i);
atlas->getTexture()->bind();
builder.add(def->name, draw(cache, shader, &fbo, &batch, def, iconSize));
}
fbo.unbind();
Window::viewport(0, 0, Window::width, Window::height);
return std::unique_ptr<Atlas>(builder.build(2));
}
+36
View File
@@ -0,0 +1,36 @@
#ifndef GRAPHICS_RENDER_BLOCKS_PREVIEW_H_
#define GRAPHICS_RENDER_BLOCKS_PREVIEW_H_
#include "../../typedefs.h"
#include <glm/glm.hpp>
#include <memory>
class Assets;
class ImageData;
class Atlas;
class Framebuffer;
class Batch3D;
class Block;
class Content;
class Shader;
class ContentGfxCache;
class BlocksPreview {
static ImageData* draw(
const ContentGfxCache* cache,
Shader* shader,
Framebuffer* framebuffer,
Batch3D* batch,
const Block* block,
int size
);
public:
static std::unique_ptr<Atlas> build(
const ContentGfxCache* cache,
Assets* assets,
const Content* content
);
};
#endif // GRAPHICS_RENDER_BLOCKS_PREVIEW_H_
+348
View File
@@ -0,0 +1,348 @@
#include "WorldRenderer.h"
#include "../../assets/Assets.h"
#include "../../content/Content.h"
#include "../../engine.h"
#include "../../frontend/LevelFrontend.h"
#include "../../items/Inventory.h"
#include "../../items/ItemDef.h"
#include "../../items/ItemStack.h"
#include "../../logic/PlayerController.h"
#include "../../maths/FrustumCulling.h"
#include "../../maths/voxmaths.h"
#include "../../objects/Player.h"
#include "../../settings.h"
#include "../../voxels/Block.h"
#include "../../voxels/Chunk.h"
#include "../../voxels/Chunks.h"
#include "../../window/Camera.h"
#include "../../window/Window.h"
#include "../../world/Level.h"
#include "../../world/LevelEvents.h"
#include "../../world/World.h"
#include "../core/Atlas.h"
#include "../core/Batch3D.h"
#include "../core/GfxContext.h"
#include "../core/LineBatch.h"
#include "../core/Mesh.h"
#include "../core/PostProcessing.h"
#include "../core/Shader.h"
#include "../core/Texture.h"
#include "ChunksRenderer.h"
#include "Skybox.h"
#include <assert.h>
#include <GL/glew.h>
#include <iostream>
#include <memory>
WorldRenderer::WorldRenderer(Engine* engine, LevelFrontend* frontend, Player* player)
: engine(engine),
level(frontend->getLevel()),
player(player)
{
postProcessing = std::make_unique<PostProcessing>();
frustumCulling = std::make_unique<Frustum>();
lineBatch = std::make_unique<LineBatch>();
renderer = std::make_unique<ChunksRenderer>(
level,
frontend->getContentGfxCache(),
engine->getSettings()
);
batch3d = std::make_unique<Batch3D>(4096);
auto& settings = engine->getSettings();
level->events->listen(EVT_CHUNK_HIDDEN,
[this](lvl_event_type type, Chunk* chunk) {
renderer->unload(chunk);
}
);
auto assets = engine->getAssets();
skybox = std::make_unique<Skybox>(
settings.graphics.skyboxResolution,
assets->getShader("skybox_gen")
);
}
WorldRenderer::~WorldRenderer() {
}
bool WorldRenderer::drawChunk(
size_t index,
Camera* camera,
Shader* shader,
bool culling
){
auto chunk = level->chunks->chunks[index];
if (!chunk->isLighted()) {
return false;
}
float distance = glm::distance(
camera->position,
glm::vec3((chunk->x + 0.5f) * CHUNK_W,
camera->position.y,
(chunk->z + 0.5f) * CHUNK_D)
);
auto mesh = renderer->getOrRender(chunk, distance < CHUNK_W*1.5f);
if (mesh == nullptr) {
return false;
}
if (culling){
glm::vec3 min(
chunk->x * CHUNK_W,
chunk->bottom,
chunk->z * CHUNK_D
);
glm::vec3 max(
chunk->x * CHUNK_W + CHUNK_W,
chunk->top,
chunk->z * CHUNK_D + CHUNK_D
);
if (!frustumCulling->IsBoxVisible(min, max))
return false;
}
glm::vec3 coord(chunk->x*CHUNK_W+0.5f, 0.5f, chunk->z*CHUNK_D+0.5f);
glm::mat4 model = glm::translate(glm::mat4(1.0f), coord);
shader->uniformMatrix("u_model", model);
mesh->draw();
return true;
}
void WorldRenderer::drawChunks(Chunks* chunks, Camera* camera, Shader* shader) {
renderer->update();
std::vector<size_t> indices;
for (size_t i = 0; i < chunks->volume; i++){
if (chunks->chunks[i] == nullptr)
continue;
indices.push_back(i);
}
float px = camera->position.x / (float)CHUNK_W;
float pz = camera->position.z / (float)CHUNK_D;
std::sort(indices.begin(), indices.end(), [chunks, px, pz](size_t i, size_t j) {
auto a = chunks->chunks[i];
auto b = chunks->chunks[j];
return ((a->x + 0.5f - px)*(a->x + 0.5f - px) +
(a->z + 0.5f - pz)*(a->z + 0.5f - pz)
>
(b->x + 0.5f - px)*(b->x + 0.5f - px) +
(b->z + 0.5f - pz)*(b->z + 0.5f - pz));
});
bool culling = engine->getSettings().graphics.frustumCulling;
if (culling) {
frustumCulling->update(camera->getProjView());
}
chunks->visible = 0;
for (size_t i = 0; i < indices.size(); i++){
chunks->visible += drawChunk(indices[i], camera, shader, culling);
}
}
void WorldRenderer::renderLevel(
const GfxContext& ctx,
Camera* camera,
const EngineSettings& settings
) {
Assets* assets = engine->getAssets();
Atlas* atlas = assets->getAtlas("blocks");
Shader* shader = assets->getShader("main");
auto indices = level->content->getIndices();
float fogFactor = 15.0f / ((float)settings.chunks.loadDistance-2);
// Setting up main shader
shader->use();
shader->uniformMatrix("u_proj", camera->getProjection());
shader->uniformMatrix("u_view", camera->getView());
shader->uniform1f("u_gamma", settings.graphics.gamma);
shader->uniform1f("u_fogFactor", fogFactor);
shader->uniform1f("u_fogCurve", settings.graphics.fogCurve);
shader->uniform1f("u_dayTime", level->world->daytime);
shader->uniform3f("u_cameraPos", camera->position);
shader->uniform1i("u_cubemap", 1);
// Light emission when an emissive item is chosen
{
auto inventory = player->getInventory();
ItemStack& stack = inventory->getSlot(player->getChosenSlot());
auto item = indices->getItemDef(stack.getItemId());
float multiplier = 0.5f;
shader->uniform3f("u_torchlightColor",
item->emission[0] / 15.0f * multiplier,
item->emission[1] / 15.0f * multiplier,
item->emission[2] / 15.0f * multiplier
);
shader->uniform1f("u_torchlightDistance", 6.0f);
}
// Binding main shader textures
skybox->bind();
atlas->getTexture()->bind();
drawChunks(level->chunks.get(), camera, shader);
skybox->unbind();
}
void WorldRenderer::renderBlockSelection(Camera* camera, Shader* linesShader) {
auto indices = level->content->getIndices();
blockid_t id = PlayerController::selectedBlockId;
auto block = indices->getBlockDef(id);
const glm::vec3 pos = PlayerController::selectedBlockPosition;
const glm::vec3 point = PlayerController::selectedPointPosition;
const glm::vec3 norm = PlayerController::selectedBlockNormal;
std::vector<AABB>& hitboxes = block->rotatable
? block->rt.hitboxes[PlayerController::selectedBlockStates]
: block->hitboxes;
linesShader->use();
linesShader->uniformMatrix("u_projview", camera->getProjView());
lineBatch->lineWidth(2.0f);
for (auto& hitbox: hitboxes) {
const glm::vec3 center = pos + hitbox.center();
const glm::vec3 size = hitbox.size();
lineBatch->box(center, size + glm::vec3(0.02), glm::vec4(0.f, 0.f, 0.f, 0.5f));
if (player->debug) {
lineBatch->line(point, point+norm*0.5f, glm::vec4(1.0f, 0.0f, 1.0f, 1.0f));
}
}
lineBatch->render();
}
void WorldRenderer::renderDebugLines(
const GfxContext& pctx,
Camera* camera,
Shader* linesShader,
const EngineSettings& settings
) {
GfxContext ctx = pctx.sub();
const auto& viewport = ctx.getViewport();
uint displayWidth = viewport.getWidth();
uint displayHeight = viewport.getHeight();
ctx.setDepthTest(true);
linesShader->use();
if (settings.debug.showChunkBorders){
linesShader->uniformMatrix("u_projview", camera->getProjView());
glm::vec3 coord = player->camera->position;
if (coord.x < 0) coord.x--;
if (coord.z < 0) coord.z--;
int cx = floordiv((int)coord.x, CHUNK_W);
int cz = floordiv((int)coord.z, CHUNK_D);
drawBorders(
cx * CHUNK_W, 0, cz * CHUNK_D,
(cx + 1) * CHUNK_W, CHUNK_H, (cz + 1) * CHUNK_D
);
}
float length = 40.f;
glm::vec3 tsl(displayWidth/2, displayHeight/2, 0.f);
glm::mat4 model(glm::translate(glm::mat4(1.f), tsl));
linesShader->uniformMatrix("u_projview", glm::ortho(
0.f, (float)displayWidth,
0.f, (float)displayHeight,
-length, length) * model * glm::inverse(camera->rotation)
);
ctx.setDepthTest(false);
lineBatch->lineWidth(4.0f);
lineBatch->line(0.f, 0.f, 0.f, length, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f);
lineBatch->line(0.f, 0.f, 0.f, 0.f, length, 0.f, 0.f, 0.f, 0.f, 1.f);
lineBatch->line(0.f, 0.f, 0.f, 0.f, 0.f, length, 0.f, 0.f, 0.f, 1.f);
lineBatch->render();
ctx.setDepthTest(true);
lineBatch->lineWidth(2.0f);
lineBatch->line(0.f, 0.f, 0.f, length, 0.f, 0.f, 1.f, 0.f, 0.f, 1.f);
lineBatch->line(0.f, 0.f, 0.f, 0.f, length, 0.f, 0.f, 1.f, 0.f, 1.f);
lineBatch->line(0.f, 0.f, 0.f, 0.f, 0.f, length, 0.f, 0.f, 1.f, 1.f);
lineBatch->render();
}
void WorldRenderer::draw(const GfxContext& pctx, Camera* camera, bool hudVisible){
EngineSettings& settings = engine->getSettings();
skybox->refresh(pctx, level->world->daytime, 1.0f+fog*2.0f, 4);
Assets* assets = engine->getAssets();
Shader* linesShader = assets->getShader("lines");
// World render scope with diegetic HUD included
{
GfxContext wctx = pctx.sub();
postProcessing->use(wctx);
Window::clearDepth();
// Drawing background sky plane
skybox->draw(pctx, camera, assets, level->getWorld()->daytime, fog);
// Actually world render with depth buffer on
{
GfxContext ctx = wctx.sub();
ctx.setDepthTest(true);
ctx.setCullFace(true);
renderLevel(ctx, camera, settings);
// Selected block
if (PlayerController::selectedBlockId != -1 && hudVisible){
renderBlockSelection(camera, linesShader);
}
}
if (hudVisible && player->debug) {
renderDebugLines(wctx, camera, linesShader, settings);
}
}
// Rendering fullscreen quad with
auto screenShader = assets->getShader("screen");
screenShader->use();
screenShader->uniform1f("u_timer", Window::time());
screenShader->uniform1f("u_dayTime", level->world->daytime);
postProcessing->render(pctx, screenShader);
}
void WorldRenderer::drawBorders(int sx, int sy, int sz, int ex, int ey, int ez) {
int ww = ex-sx;
int dd = ez-sz;
/*corner*/ {
lineBatch->line(sx, sy, sz,
sx, ey, sz, 0.8f, 0, 0.8f, 1);
lineBatch->line(sx, sy, ez,
sx, ey, ez, 0.8f, 0, 0.8f, 1);
lineBatch->line(ex, sy, sz,
ex, ey, sz, 0.8f, 0, 0.8f, 1);
lineBatch->line(ex, sy, ez,
ex, ey, ez, 0.8f, 0, 0.8f, 1);
}
for (int i = 2; i < ww; i+=2) {
lineBatch->line(sx + i, sy, sz,
sx + i, ey, sz, 0, 0, 0.8f, 1);
lineBatch->line(sx + i, sy, ez,
sx + i, ey, ez, 0, 0, 0.8f, 1);
}
for (int i = 2; i < dd; i+=2) {
lineBatch->line(sx, sy, sz + i,
sx, ey, sz + i, 0.8f, 0, 0, 1);
lineBatch->line(ex, sy, sz + i,
ex, ey, sz + i, 0.8f, 0, 0, 1);
}
for (int i = sy; i < ey; i+=2){
lineBatch->line(sx, i, sz,
sx, i, ez, 0, 0.8f, 0, 1);
lineBatch->line(sx, i, ez,
ex, i, ez, 0, 0.8f, 0, 1);
lineBatch->line(ex, i, ez,
ex, i, sz, 0, 0.8f, 0, 1);
lineBatch->line(ex, i, sz,
sx, i, sz, 0, 0.8f, 0, 1);
}
lineBatch->render();
}
float WorldRenderer::fog = 0.0f;
+80
View File
@@ -0,0 +1,80 @@
#ifndef GRAPHICS_RENDER_WORLD_RENDERER_H_
#define GRAPHICS_RENDER_WORLD_RENDERER_H_
#include <vector>
#include <memory>
#include <algorithm>
#include <GL/glew.h>
#include <string>
#include <glm/glm.hpp>
#include <glm/ext.hpp>
#include <glm/gtc/matrix_transform.hpp>
class Level;
class Player;
class Camera;
class Batch3D;
class LineBatch;
class ChunksRenderer;
class Shader;
class Frustum;
class Engine;
class Chunks;
class LevelFrontend;
class Skybox;
class PostProcessing;
class GfxContext;
struct EngineSettings;
class WorldRenderer {
Engine* engine;
Level* level;
Player* player;
std::unique_ptr<PostProcessing> postProcessing;
std::unique_ptr<Frustum> frustumCulling;
std::unique_ptr<LineBatch> lineBatch;
std::unique_ptr<ChunksRenderer> renderer;
std::unique_ptr<Skybox> skybox;
std::unique_ptr<Batch3D> batch3d;
bool drawChunk(size_t index, Camera* camera, Shader* shader, bool culling);
void drawChunks(Chunks* chunks, Camera* camera, Shader* shader);
/// @brief Render level without diegetic interface
/// @param context graphics context
/// @param camera active camera
/// @param settings engine settings
void renderLevel(
const GfxContext& context,
Camera* camera,
const EngineSettings& settings
);
/// @brief Render block selection lines
/// @param camera active camera
/// @param linesShader shader used
void renderBlockSelection(Camera* camera, Shader* linesShader);
/// @brief Render all debug lines (chunks borders, coord system guides)
/// @param context graphics context
/// @param camera active camera
/// @param linesShader shader used
/// @param settings engine settings
void renderDebugLines(
const GfxContext& context,
Camera* camera,
Shader* linesShader,
const EngineSettings& settings
);
public:
WorldRenderer(Engine* engine, LevelFrontend* frontend, Player* player);
~WorldRenderer();
void draw(const GfxContext& context, Camera* camera, bool hudVisible);
void drawBorders(int sx, int sy, int sz, int ex, int ey, int ez);
static float fog;
};
#endif // GRAPHICS_RENDER_WORLD_RENDERER_H_