Merge branch 'main' into block_materials

This commit is contained in:
MihailRis
2024-03-08 23:25:39 +03:00
42 changed files with 945 additions and 484 deletions
+20
View File
@@ -120,6 +120,26 @@ function color_mt.__tostring(self)
return "rgba("..self[1]..", "..self[2]..", "..self[3]..", "..self[4]..")" return "rgba("..self[1]..", "..self[2]..", "..self[3]..", "..self[4]..")"
end end
-- events
events = {
handlers = {}
}
function events.on(event, func)
events.handlers[event] = events.handlers[event] or {}
table.insert(events.handlers[event], func)
end
function events.emit(event, ...)
result = nil
if events.handlers[event] then
for _, func in ipairs(events.handlers[event]) do
result = result or func(...)
end
end
return result
end
-- class designed for simple UI-nodes access via properties syntax -- class designed for simple UI-nodes access via properties syntax
local Element = {} local Element = {}
function Element.new(docname, name) function Element.new(docname, name)
+9
View File
@@ -0,0 +1,9 @@
in vec2 v_coord;
out vec4 f_color;
uniform sampler2D u_texture0;
void main(){
f_color = texture(u_texture0, v_coord);
}
+13
View File
@@ -0,0 +1,13 @@
layout (location = 0) in vec2 v_position;
out vec2 v_coord;
uniform ivec2 u_screenSize;
uniform float u_timer;
uniform float u_dayTime;
void main(){
v_coord = v_position * 0.5 + 0.5;
gl_Position = vec4(v_position, 0.0, 1.0);
}
+1
View File
@@ -74,6 +74,7 @@ void AssetsLoader::addDefaults(AssetsLoader& loader, const Content* content) {
loader.add(ASSET_TEXTURE, TEXTURES_FOLDER"/gui/cross.png", "gui/cross"); loader.add(ASSET_TEXTURE, TEXTURES_FOLDER"/gui/cross.png", "gui/cross");
if (content) { if (content) {
loader.add(ASSET_SHADER, SHADERS_FOLDER"/ui3d", "ui3d"); loader.add(ASSET_SHADER, SHADERS_FOLDER"/ui3d", "ui3d");
loader.add(ASSET_SHADER, SHADERS_FOLDER"/screen", "screen");
loader.add(ASSET_SHADER, SHADERS_FOLDER"/background", "background"); loader.add(ASSET_SHADER, SHADERS_FOLDER"/background", "background");
loader.add(ASSET_SHADER, SHADERS_FOLDER"/skybox_gen", "skybox_gen"); loader.add(ASSET_SHADER, SHADERS_FOLDER"/skybox_gen", "skybox_gen");
loader.add(ASSET_TEXTURE, TEXTURES_FOLDER"/misc/moon.png", "misc/moon"); loader.add(ASSET_TEXTURE, TEXTURES_FOLDER"/misc/moon.png", "misc/moon");
+11 -5
View File
@@ -136,7 +136,7 @@ bool assetload::font(
} }
pages.push_back(std::move(texture)); pages.push_back(std::move(texture));
} }
int res = pages[0]->height / 16; int res = pages[0]->getHeight() / 16;
assets->store(new Font(std::move(pages), res, 4), name); assets->store(new Font(std::move(pages), res, 4), name);
return true; return true;
} }
@@ -270,13 +270,19 @@ static bool animation(
Frame frame; Frame frame;
UVRegion region = dstAtlas->get(name); UVRegion region = dstAtlas->get(name);
frame.dstPos = glm::ivec2(region.u1 * dstTex->width, region.v1 * dstTex->height); uint dstWidth = dstTex->getWidth();
frame.size = glm::ivec2(region.u2 * dstTex->width, region.v2 * dstTex->height) - frame.dstPos; uint dstHeight = dstTex->getHeight();
uint srcWidth = srcTex->getWidth();
uint srcHeight = srcTex->getHeight();
frame.dstPos = glm::ivec2(region.u1 * dstWidth, region.v1 * dstHeight);
frame.size = glm::ivec2(region.u2 * dstWidth, region.v2 * dstHeight) - frame.dstPos;
if (frameList.empty()) { if (frameList.empty()) {
for (const auto& elem : builder.getNames()) { for (const auto& elem : builder.getNames()) {
region = srcAtlas->get(elem); region = srcAtlas->get(elem);
frame.srcPos = glm::ivec2(region.u1 * srcTex->width, srcTex->height - region.v2 * srcTex->height); frame.srcPos = glm::ivec2(region.u1 * srcWidth, srcHeight - region.v2 * srcHeight);
animation.addFrame(frame); animation.addFrame(frame);
} }
} }
@@ -288,7 +294,7 @@ static bool animation(
} }
region = srcAtlas->get(elem.first); region = srcAtlas->get(elem.first);
frame.duration = elem.second; frame.duration = elem.second;
frame.srcPos = glm::ivec2(region.u1 * srcTex->width, srcTex->height - region.v2 * srcTex->height); frame.srcPos = glm::ivec2(region.u1 * srcWidth, srcHeight - region.v2 * srcHeight);
animation.addFrame(frame); animation.addFrame(frame);
} }
} }
+6 -6
View File
@@ -31,8 +31,8 @@ void ContentBuilder::add(ContentPackRuntime* pack) {
Block& ContentBuilder::createBlock(std::string id) { Block& ContentBuilder::createBlock(std::string id) {
auto found = blockDefs.find(id); auto found = blockDefs.find(id);
if (found != blockDefs.end()) { if (found != blockDefs.end()) {
//return found->second; return *found->second;
throw namereuse_error("name "+id+" is already used", contenttype::item); // throw namereuse_error("name "+id+" is already used", contenttype::item);
} }
Block* block = new Block(id); Block* block = new Block(id);
add(block); add(block);
@@ -42,10 +42,10 @@ Block& ContentBuilder::createBlock(std::string id) {
ItemDef& ContentBuilder::createItem(std::string id) { ItemDef& ContentBuilder::createItem(std::string id) {
auto found = itemDefs.find(id); auto found = itemDefs.find(id);
if (found != itemDefs.end()) { if (found != itemDefs.end()) {
if (found->second->generated) { // if (found->second->generated) {
return *found->second; return *found->second;
} // }
throw namereuse_error("name "+id+" is already used", contenttype::item); // throw namereuse_error("name "+id+" is already used", contenttype::item);
} }
ItemDef* item = new ItemDef(id); ItemDef* item = new ItemDef(id);
add(item); add(item);
+25 -5
View File
@@ -36,6 +36,19 @@ bool ContentLoader::fixPackIndices(fs::path folder,
if (name[0] == '_') if (name[0] == '_')
continue; continue;
detected.push_back(name); detected.push_back(name);
} else if (fs::is_directory(file)) {
std::string space = file.stem().string();
if (space[0] == '_')
continue;
for (auto entry : fs::directory_iterator(file)) {
fs::path file = entry.path();
if (fs::is_regular_file(file) && file.extension() == ".json") {
std::string name = file.stem().string();
if (name[0] == '_')
continue;
detected.push_back(space + ':' + name);
}
}
} }
} }
} }
@@ -268,7 +281,7 @@ void ContentLoader::loadBlock(Block& def, std::string full, std::string name) {
auto folder = pack->folder; auto folder = pack->folder;
fs::path configFile = folder/fs::path("blocks/"+name+".json"); fs::path configFile = folder/fs::path("blocks/"+name+".json");
loadBlock(def, full, configFile); if (fs::exists(configFile)) loadBlock(def, full, configFile);
fs::path scriptfile = folder/fs::path("scripts/"+def.scriptName+".lua"); fs::path scriptfile = folder/fs::path("scripts/"+def.scriptName+".lua");
if (fs::is_regular_file(scriptfile)) { if (fs::is_regular_file(scriptfile)) {
@@ -280,7 +293,7 @@ void ContentLoader::loadItem(ItemDef& def, std::string full, std::string name) {
auto folder = pack->folder; auto folder = pack->folder;
fs::path configFile = folder/fs::path("items/"+name+".json"); fs::path configFile = folder/fs::path("items/"+name+".json");
loadItem(def, full, configFile); if (fs::exists(configFile)) loadItem(def, full, configFile);
fs::path scriptfile = folder/fs::path("scripts/"+def.scriptName+".lua"); fs::path scriptfile = folder/fs::path("scripts/"+def.scriptName+".lua");
if (fs::is_regular_file(scriptfile)) { if (fs::is_regular_file(scriptfile)) {
@@ -313,8 +326,11 @@ void ContentLoader::load(ContentBuilder& builder) {
if (blocksarr) { if (blocksarr) {
for (uint i = 0; i < blocksarr->size(); i++) { for (uint i = 0; i < blocksarr->size(); i++) {
std::string name = blocksarr->str(i); std::string name = blocksarr->str(i);
std::string full = pack->id+":"+name; auto colon = name.find(':');
std::string full = colon == std::string::npos ? pack->id + ":" + name : name;
if (colon != std::string::npos) name[colon] = '/';
auto& def = builder.createBlock(full); auto& def = builder.createBlock(full);
if (colon != std::string::npos) def.scriptName = name.substr(0, colon) + '/' + def.scriptName;
loadBlock(def, full, name); loadBlock(def, full, name);
stats.totalBlocks++; stats.totalBlocks++;
if (!def.hidden) { if (!def.hidden) {
@@ -336,8 +352,12 @@ void ContentLoader::load(ContentBuilder& builder) {
if (itemsarr) { if (itemsarr) {
for (uint i = 0; i < itemsarr->size(); i++) { for (uint i = 0; i < itemsarr->size(); i++) {
std::string name = itemsarr->str(i); std::string name = itemsarr->str(i);
std::string full = pack->id+":"+name; auto colon = name.find(':');
loadItem(builder.createItem(full), full, name); std::string full = colon == std::string::npos ? pack->id + ":" + name : name;
if (colon != std::string::npos) name[colon] = '/';
auto& def = builder.createItem(full);
if (colon != std::string::npos) def.scriptName = name.substr(0, colon) + '/' + def.scriptName;
loadItem(def, full, name);
stats.totalItems++; stats.totalItems++;
} }
} }
+3 -3
View File
@@ -95,7 +95,7 @@ ImageData* BlocksPreview::draw(
break; break;
} }
} }
return fbo->texture->readData(); return fbo->getTexture()->readData();
} }
std::unique_ptr<Atlas> BlocksPreview::build( std::unique_ptr<Atlas> BlocksPreview::build(
@@ -113,8 +113,8 @@ std::unique_ptr<Atlas> BlocksPreview::build(
Viewport viewport(iconSize, iconSize); Viewport viewport(iconSize, iconSize);
GfxContext pctx(nullptr, viewport, nullptr); GfxContext pctx(nullptr, viewport, nullptr);
GfxContext ctx = pctx.sub(); GfxContext ctx = pctx.sub();
ctx.cullFace(true); ctx.setCullFace(true);
ctx.depthTest(true); ctx.setDepthTest(true);
Framebuffer fbo(iconSize, iconSize, true); Framebuffer fbo(iconSize, iconSize, true);
Batch3D batch(1024); Batch3D batch(1024);
+153 -112
View File
@@ -14,6 +14,7 @@
#include "../graphics/Batch3D.h" #include "../graphics/Batch3D.h"
#include "../graphics/Texture.h" #include "../graphics/Texture.h"
#include "../graphics/LineBatch.h" #include "../graphics/LineBatch.h"
#include "../graphics/PostProcessing.h"
#include "../voxels/Chunks.h" #include "../voxels/Chunks.h"
#include "../voxels/Chunk.h" #include "../voxels/Chunk.h"
#include "../voxels/Block.h" #include "../voxels/Block.h"
@@ -39,6 +40,7 @@ WorldRenderer::WorldRenderer(Engine* engine, LevelFrontend* frontend, Player* pl
level(frontend->getLevel()), level(frontend->getLevel()),
player(player) player(player)
{ {
postProcessing = std::make_unique<PostProcessing>();
frustumCulling = std::make_unique<Frustum>(); frustumCulling = std::make_unique<Frustum>();
lineBatch = std::make_unique<LineBatch>(); lineBatch = std::make_unique<LineBatch>();
renderer = std::make_unique<ChunksRenderer>( renderer = std::make_unique<ChunksRenderer>(
@@ -136,132 +138,171 @@ void WorldRenderer::drawChunks(Chunks* chunks, Camera* camera, Shader* shader) {
} }
} }
void WorldRenderer::renderLevel(
void WorldRenderer::draw(const GfxContext& pctx, Camera* camera, bool hudVisible){ const GfxContext& ctx,
EngineSettings& settings = engine->getSettings(); Camera* camera,
const EngineSettings& settings
Window::clearDepth(); ) {
skybox->refresh(pctx, level->world->daytime, 1.0f+fog*2.0f, 4);
const Content* content = level->content;
auto indices = content->getIndices();
Assets* assets = engine->getAssets(); Assets* assets = engine->getAssets();
Atlas* atlas = assets->getAtlas("blocks"); Atlas* atlas = assets->getAtlas("blocks");
Shader* shader = assets->getShader("main"); Shader* shader = assets->getShader("main");
auto indices = level->content->getIndices();
const Viewport& viewport = pctx.getViewport(); float fogFactor = 15.0f / ((float)settings.chunks.loadDistance-2);
int displayWidth = viewport.getWidth();
int displayHeight = viewport.getHeight();
// Drawing background sky plane // Setting up main shader
skybox->draw(pctx, camera, assets, level->getWorld()->daytime, fog); 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);
Shader* linesShader = assets->getShader("lines"); // Light emission when an emissive item is chosen
{ {
GfxContext ctx = pctx.sub(); auto inventory = player->getInventory();
ctx.depthTest(true); ItemStack& stack = inventory->getSlot(player->getChosenSlot());
ctx.cullFace(true); 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);
}
float fogFactor = 15.0f / ((float)settings.chunks.loadDistance-2); // Binding main shader textures
skybox->bind();
atlas->getTexture()->bind();
// Setting up main shader drawChunks(level->chunks.get(), camera, shader);
shader->use();
shader->uniformMatrix("u_proj", camera->getProjection()); skybox->unbind();
shader->uniformMatrix("u_view", camera->getView()); }
shader->uniform1f("u_gamma", settings.graphics.gamma);
shader->uniform1f("u_fogFactor", fogFactor); void WorldRenderer::renderBlockSelection(Camera* camera, Shader* linesShader) {
shader->uniform1f("u_fogCurve", settings.graphics.fogCurve); auto indices = level->content->getIndices();
shader->uniform1f("u_dayTime", level->world->daytime); blockid_t id = PlayerController::selectedBlockId;
shader->uniform3f("u_cameraPos", camera->position); auto block = indices->getBlockDef(id);
shader->uniform1i("u_cubemap", 1); 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
{ {
auto inventory = player->getInventory(); GfxContext ctx = wctx.sub();
ItemStack& stack = inventory->getSlot(player->getChosenSlot()); ctx.setDepthTest(true);
ItemDef* item = indices->getItemDef(stack.getItemId()); ctx.setCullFace(true);
assert(item != nullptr); renderLevel(ctx, camera, settings);
float multiplier = 0.5f; // Selected block
shader->uniform3f("u_torchlightColor", if (PlayerController::selectedBlockId != -1 && hudVisible){
item->emission[0] / 15.0f * multiplier, renderBlockSelection(camera, linesShader);
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);
// Selected block
if (PlayerController::selectedBlockId != -1 && hudVisible){
blockid_t id = PlayerController::selectedBlockId;
Block* block = indices->getBlockDef(id);
assert(block != nullptr);
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();
}
skybox->unbind();
}
if (hudVisible && player->debug) {
GfxContext ctx = pctx.sub();
ctx.depthTest(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; if (hudVisible && player->debug) {
glm::vec3 tsl(displayWidth/2, displayHeight/2, 0.f); renderDebugLines(wctx, camera, linesShader, settings);
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.depthTest(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.depthTest(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();
} }
// 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) { void WorldRenderer::drawBorders(int sx, int sy, int sz, int ex, int ey, int ez) {
+29 -2
View File
@@ -20,17 +20,18 @@ class Batch3D;
class LineBatch; class LineBatch;
class ChunksRenderer; class ChunksRenderer;
class Shader; class Shader;
class Texture;
class Frustum; class Frustum;
class Engine; class Engine;
class Chunks; class Chunks;
class LevelFrontend; class LevelFrontend;
class Skybox; class Skybox;
class PostProcessing;
class WorldRenderer { class WorldRenderer {
Engine* engine; Engine* engine;
Level* level; Level* level;
Player* player; Player* player;
std::unique_ptr<PostProcessing> postProcessing;
std::unique_ptr<Frustum> frustumCulling; std::unique_ptr<Frustum> frustumCulling;
std::unique_ptr<LineBatch> lineBatch; std::unique_ptr<LineBatch> lineBatch;
std::unique_ptr<ChunksRenderer> renderer; std::unique_ptr<ChunksRenderer> renderer;
@@ -38,12 +39,38 @@ class WorldRenderer {
std::unique_ptr<Batch3D> batch3d; std::unique_ptr<Batch3D> batch3d;
bool drawChunk(size_t index, Camera* camera, Shader* shader, bool culling); bool drawChunk(size_t index, Camera* camera, Shader* shader, bool culling);
void drawChunks(Chunks* chunks, Camera* camera, Shader* shader); 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: public:
WorldRenderer(Engine* engine, LevelFrontend* frontend, Player* player); WorldRenderer(Engine* engine, LevelFrontend* frontend, Player* player);
~WorldRenderer(); ~WorldRenderer();
void draw(const GfxContext& context, Camera* camera, bool hudVisible); void draw(const GfxContext& context, Camera* camera, bool hudVisible);
void drawDebug(const GfxContext& context, Camera* camera);
void drawBorders(int sx, int sy, int sz, int ex, int ey, int ez); void drawBorders(int sx, int sy, int sz, int ex, int ey, int ez);
static float fog; static float fog;
+24 -29
View File
@@ -8,6 +8,9 @@
#include "../../graphics/Shader.h" #include "../../graphics/Shader.h"
#include "../../graphics/Mesh.h" #include "../../graphics/Mesh.h"
#include "../../graphics/Batch3D.h" #include "../../graphics/Batch3D.h"
#include "../../graphics/Texture.h"
#include "../../graphics/Cubemap.h"
#include "../../graphics/Framebuffer.h"
#include "../../window/Window.h" #include "../../window/Window.h"
#include "../../window/Camera.h" #include "../../window/Camera.h"
@@ -19,21 +22,15 @@ 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(new Batch3D(4096)) batch3d(std::make_unique<Batch3D>(4096))
{ {
glGenTextures(1, &cubemap); auto cubemap = std::make_unique<Cubemap>(size, size, ImageFormat::rgb888);
glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); uint fboid;
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glGenFramebuffers(1, &fboid);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); fbo = std::make_unique<Framebuffer>(fboid, 0, std::move(cubemap));
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
for (uint face = 0; face < 6; face++) {
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, 0, GL_RGB, size, size, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
}
glGenFramebuffers(1, &fbo);
float vertices[] { float 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,
@@ -58,8 +55,6 @@ Skybox::Skybox(uint size, Shader* shader)
} }
Skybox::~Skybox() { Skybox::~Skybox() {
glDeleteTextures(1, &cubemap);
glDeleteFramebuffers(1, &fbo);
} }
void Skybox::drawBackground(Camera* camera, Assets* assets, int width, int height) { void Skybox::drawBackground(Camera* camera, Assets* assets, int width, int height) {
@@ -109,7 +104,7 @@ void Skybox::draw(
drawBackground(camera, assets, width, height); drawBackground(camera, assets, width, height);
GfxContext ctx = pctx.sub(); GfxContext ctx = pctx.sub();
ctx.blendMode(blendmode::addition); ctx.setBlendMode(blendmode::addition);
Shader* shader = assets->getShader("ui3d"); Shader* shader = assets->getShader("ui3d");
shader->use(); shader->use();
@@ -141,15 +136,17 @@ void Skybox::draw(
void Skybox::refresh(const GfxContext& pctx, float t, float mie, uint quality) { void Skybox::refresh(const GfxContext& pctx, float t, float mie, uint quality) {
GfxContext ctx = pctx.sub(); GfxContext ctx = pctx.sub();
ctx.depthMask(false); ctx.setDepthMask(false);
ctx.depthTest(false); ctx.setDepthTest(false);
ctx.setFramebuffer(fbo.get());
ctx.setViewport(Viewport(size, size));
auto cubemap = dynamic_cast<Cubemap*>(fbo->getTexture());
ready = true; ready = true;
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glActiveTexture(GL_TEXTURE1); glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap); cubemap->bind();
shader->use(); shader->use();
Window::viewport(0,0, size, size);
const glm::vec3 xaxs[] = { const glm::vec3 xaxs[] = {
{0.0f, 0.0f, -1.0f}, {0.0f, 0.0f, -1.0f},
@@ -186,26 +183,24 @@ void Skybox::refresh(const GfxContext& pctx, float t, float mie, uint quality) {
shader->uniform1f("u_fog", mie - 1.0f); shader->uniform1f("u_fog", mie - 1.0f);
shader->uniform3f("u_lightDir", glm::normalize(glm::vec3(sin(t), -cos(t), 0.0f))); shader->uniform3f("u_lightDir", glm::normalize(glm::vec3(sin(t), -cos(t), 0.0f)));
for (uint face = 0; face < 6; face++) { for (uint face = 0; face < 6; face++) {
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, cubemap, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, cubemap->getId(), 0);
shader->uniform3f("u_xaxis", xaxs[face]); shader->uniform3f("u_xaxis", xaxs[face]);
shader->uniform3f("u_yaxis", yaxs[face]); shader->uniform3f("u_yaxis", yaxs[face]);
shader->uniform3f("u_zaxis", zaxs[face]); shader->uniform3f("u_zaxis", zaxs[face]);
mesh->draw(GL_TRIANGLES); mesh->draw();
} }
glBindTexture(GL_TEXTURE_CUBE_MAP, 0); cubemap->unbind();
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
Window::viewport(0, 0, Window::width, Window::height);
} }
void Skybox::bind() const { void Skybox::bind() const {
glActiveTexture(GL_TEXTURE1); glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap); fbo->getTexture()->bind();
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
} }
void Skybox::unbind() const { void Skybox::unbind() const {
glActiveTexture(GL_TEXTURE1); glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_CUBE_MAP, 0); fbo->getTexture()->unbind();
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
} }
+4 -3
View File
@@ -13,6 +13,7 @@ class Shader;
class Assets; class Assets;
class Camera; class Camera;
class Batch3D; class Batch3D;
class Framebuffer;
struct skysprite { struct skysprite {
std::string texture; std::string texture;
@@ -22,8 +23,7 @@ struct skysprite {
}; };
class Skybox { class Skybox {
uint fbo; std::unique_ptr<Framebuffer> fbo;
uint cubemap;
uint size; uint size;
Shader* shader; Shader* shader;
bool ready = false; bool ready = false;
@@ -44,7 +44,8 @@ public:
Camera* camera, Camera* camera,
Assets* assets, Assets* assets,
float daytime, float daytime,
float fog); float fog
);
void refresh(const GfxContext& pctx, float t, float mie, uint quality); void refresh(const GfxContext& pctx, float t, float mie, uint quality);
void bind() const; void bind() const;
+1 -2
View File
@@ -88,12 +88,11 @@ void Container::draw(const GfxContext* pctx, Assets* assets) {
batch->flush(); batch->flush();
{ {
GfxContext ctx = pctx->sub(); GfxContext ctx = pctx->sub();
ctx.scissors(glm::vec4(pos.x, pos.y, size.x, size.y)); ctx.setScissors(glm::vec4(pos.x, pos.y, size.x, size.y));
for (auto node : nodes) { for (auto node : nodes) {
if (node->isVisible()) if (node->isVisible())
node->draw(pctx, assets); node->draw(pctx, assets);
} }
batch->flush();
} }
} }
+2 -3
View File
@@ -204,7 +204,7 @@ void Image::draw(const GfxContext* pctx, Assets* assets) {
auto texture = assets->getTexture(this->texture); auto texture = assets->getTexture(this->texture);
if (texture && autoresize) { if (texture && autoresize) {
setSize(glm::vec2(texture->width, texture->height)); setSize(glm::vec2(texture->getWidth(), texture->getHeight()));
} }
batch->texture(texture); batch->texture(texture);
batch->setColor(color); batch->setColor(color);
@@ -383,7 +383,7 @@ void TextBox::draw(const GfxContext* pctx, Assets* assets) {
glm::vec2 size = getSize(); glm::vec2 size = getSize();
auto subctx = pctx->sub(); auto subctx = pctx->sub();
subctx.scissors(glm::vec4(pos.x, pos.y, size.x, size.y)); subctx.setScissors(glm::vec4(pos.x, pos.y, size.x, size.y));
const int lineHeight = font->getLineHeight() * label->getLineInterval(); const int lineHeight = font->getLineHeight() * label->getLineInterval();
glm::vec2 lcoord = label->calcPos(); glm::vec2 lcoord = label->calcPos();
@@ -418,7 +418,6 @@ void TextBox::draw(const GfxContext* pctx, Assets* assets) {
batch->rect(lcoord.x, lcoord.y+label->getLineYOffset(endLine), end, lineHeight); batch->rect(lcoord.x, lcoord.y+label->getLineYOffset(endLine), end, lineHeight);
} }
} }
batch->flush();
} }
void TextBox::drawBackground(const GfxContext* pctx, Assets* assets) { void TextBox::drawBackground(const GfxContext* pctx, Assets* assets) {
+3 -5
View File
@@ -481,18 +481,16 @@ void Hud::draw(const GfxContext& ctx){
// Crosshair // Crosshair
if (!pause && !inventoryOpen && !player->debug) { if (!pause && !inventoryOpen && !player->debug) {
GfxContext chctx = ctx.sub(); GfxContext chctx = ctx.sub();
chctx.blendMode(blendmode::inversion); chctx.setBlendMode(blendmode::inversion);
auto texture = assets->getTexture("gui/crosshair"); auto texture = assets->getTexture("gui/crosshair");
batch->texture(texture); batch->texture(texture);
int chsizex = texture != nullptr ? texture->width : 16; int chsizex = texture != nullptr ? texture->getWidth() : 16;
int chsizey = texture != nullptr ? texture->height : 16; int chsizey = texture != nullptr ? texture->getHeight() : 16;
batch->rect( batch->rect(
(width-chsizex)/2, (height-chsizey)/2, (width-chsizex)/2, (height-chsizey)/2,
chsizex, chsizey, 0,0, 1,1, 1,1,1,1 chsizex, chsizey, 0,0, 1,1, 1,1,1,1
); );
batch->flush();
} }
batch->flush();
} }
void Hud::updateElementsPosition(const Viewport& viewport) { void Hud::updateElementsPosition(const Viewport& viewport) {
+1 -1
View File
@@ -19,7 +19,7 @@ Batch2D::Batch2D(size_t capacity) : capacity(capacity), color(1.0f){
ubyte pixels[] = { ubyte pixels[] = {
0xFF, 0xFF, 0xFF, 0xFF 0xFF, 0xFF, 0xFF, 0xFF
}; };
blank = std::make_unique<Texture>(pixels, 1, 1, GL_RGBA); blank = std::make_unique<Texture>(pixels, 1, 1, ImageFormat::rgba8888);
_texture = nullptr; _texture = nullptr;
} }
+2 -4
View File
@@ -19,20 +19,18 @@ Batch3D::Batch3D(size_t capacity)
}; };
buffer = new float[capacity * B3D_VERTEX_SIZE]; buffer = new float[capacity * B3D_VERTEX_SIZE];
mesh = new Mesh(buffer, 0, attrs); mesh = std::make_unique<Mesh>(buffer, 0, attrs);
index = 0; index = 0;
ubyte pixels[] = { ubyte pixels[] = {
255, 255, 255, 255, 255, 255, 255, 255,
}; };
blank = new Texture(pixels, 1, 1, GL_RGBA); blank = std::make_unique<Texture>(pixels, 1, 1, ImageFormat::rgba8888);
_texture = nullptr; _texture = nullptr;
} }
Batch3D::~Batch3D(){ Batch3D::~Batch3D(){
delete blank;
delete[] buffer; delete[] buffer;
delete mesh;
} }
void Batch3D::begin(){ void Batch3D::begin(){
+6 -4
View File
@@ -1,21 +1,23 @@
#ifndef GRAPHICS_BATCH3D_H_ #ifndef GRAPHICS_BATCH3D_H_
#define GRAPHICS_BATCH3D_H_ #define GRAPHICS_BATCH3D_H_
#include <stdlib.h>
#include <glm/glm.hpp>
#include "UVRegion.h" #include "UVRegion.h"
#include "../typedefs.h" #include "../typedefs.h"
#include <memory>
#include <stdlib.h>
#include <glm/glm.hpp>
class Mesh; class Mesh;
class Texture; class Texture;
class Batch3D { class Batch3D {
float* buffer; float* buffer;
size_t capacity; size_t capacity;
Mesh* mesh; std::unique_ptr<Mesh> mesh;
std::unique_ptr<Texture> blank;
size_t index; size_t index;
Texture* blank;
Texture* _texture; Texture* _texture;
void vertex(float x, float y, float z, void vertex(float x, float y, float z,
+39
View File
@@ -0,0 +1,39 @@
#include "Cubemap.h"
#include "gl_util.h"
#include <GL/glew.h>
Cubemap::Cubemap(uint width, uint height, ImageFormat imageFormat)
: Texture(0, width, height)
{
glGenTextures(1, &id);
glBindTexture(GL_TEXTURE_CUBE_MAP, id);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
uint format = gl::to_gl_format(imageFormat);
for (uint face = 0; face < 6; face++) {
glTexImage2D(
GL_TEXTURE_CUBE_MAP_POSITIVE_X + face,
0,
format,
width,
height,
0,
format,
GL_UNSIGNED_BYTE,
NULL
);
}
}
void Cubemap::bind(){
glBindTexture(GL_TEXTURE_CUBE_MAP, id);
}
void Cubemap::unbind() {
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
}
+15
View File
@@ -0,0 +1,15 @@
#ifndef GRAPHICS_CUBEMAP_H_
#define GRAPHICS_CUBEMAP_H_
#include "Texture.h"
/// @brief Cubemap texture
class Cubemap : public Texture {
public:
Cubemap(uint width, uint height, ImageFormat format);
virtual void bind() override;
virtual void unbind() override;
};
#endif // GRAPHICS_CUBEMAP_H_
+51 -14
View File
@@ -3,38 +3,75 @@
#include <GL/glew.h> #include <GL/glew.h>
#include "Texture.h" #include "Texture.h"
Framebuffer::Framebuffer(uint fbo, uint depth, std::unique_ptr<Texture> texture)
: fbo(fbo), depth(depth), texture(std::move(texture))
{
if (texture) {
width = texture->getWidth();
height = texture->getHeight();
} else {
width = 0;
height = 0;
}
}
Framebuffer::Framebuffer(uint width, uint height, bool alpha) Framebuffer::Framebuffer(uint width, uint height, bool alpha)
: width(width), height(height) { : width(width), height(height)
glGenFramebuffers(1, &fbo); {
bind(); glGenFramebuffers(1, &fbo);
GLuint tex; glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex); // Setup color attachment (texture)
GLuint format = alpha ? GL_RGBA : GL_RGB; GLuint tex;
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, nullptr); format = alpha ? GL_RGBA : GL_RGB;
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
texture = new Texture(tex, width, height); texture = std::make_unique<Texture>(tex, width, height);
// Setup depth attachment
glGenRenderbuffers(1, &depth); glGenRenderbuffers(1, &depth);
glBindRenderbuffer(GL_RENDERBUFFER, depth); glBindRenderbuffer(GL_RENDERBUFFER, depth);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth);
unbind(); glBindFramebuffer(GL_FRAMEBUFFER, 0);
} }
Framebuffer::~Framebuffer() { Framebuffer::~Framebuffer() {
delete texture; glDeleteFramebuffers(1, &fbo);
glDeleteFramebuffers(1, &fbo);
glDeleteRenderbuffers(1, &depth); glDeleteRenderbuffers(1, &depth);
} }
void Framebuffer::bind() { void Framebuffer::bind() {
glBindFramebuffer(GL_FRAMEBUFFER, fbo); glBindFramebuffer(GL_FRAMEBUFFER, fbo);
} }
void Framebuffer::unbind() { void Framebuffer::unbind() {
glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void Framebuffer::resize(uint width, uint height) {
if (this->width == width && this->height == height) {
return;
}
texture->bind();
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, nullptr);
texture->unbind();
}
Texture* Framebuffer::getTexture() const {
return texture.get();
}
uint Framebuffer::getWidth() const {
return width;
}
uint Framebuffer::getHeight() const {
return height;
} }
+29 -9
View File
@@ -3,20 +3,40 @@
#include "../typedefs.h" #include "../typedefs.h"
#include <memory>
class Texture; class Texture;
class Framebuffer { class Framebuffer {
uint fbo; uint fbo;
uint depth; uint depth;
uint width;
uint height;
uint format;
std::unique_ptr<Texture> texture;
public: public:
uint width; Framebuffer(uint fbo, uint depth, std::unique_ptr<Texture> texture);
uint height; Framebuffer(uint width, uint height, bool alpha=false);
Texture* texture; ~Framebuffer();
Framebuffer(uint width, uint height, bool alpha=false);
~Framebuffer();
void bind(); /// @brief Use framebuffer
void unbind(); void bind();
/// @brief Stop using framebuffer
void unbind();
/// @brief Update framebuffer texture size
/// @param width new width
/// @param height new height
void resize(uint width, uint height);
/// @brief Get framebuffer color attachment
Texture* getTexture() const;
/// @brief Get framebuffer width
uint getWidth() const;
/// @brief Get framebuffer height
uint getHeight() const;
}; };
#endif /* SRC_GRAPHICS_FRAMEBUFFER_H_ */ #endif /* SRC_GRAPHICS_FRAMEBUFFER_H_ */
+69 -26
View File
@@ -3,10 +3,16 @@
#include <GL/glew.h> #include <GL/glew.h>
#include "Batch2D.h" #include "Batch2D.h"
#include "Framebuffer.h"
GfxContext::GfxContext(const GfxContext* parent, Viewport& viewport, Batch2D* g2d) GfxContext::GfxContext(
: parent(parent), viewport(viewport), g2d(g2d) { const GfxContext* parent,
} const Viewport& viewport,
Batch2D* g2d
) : parent(parent),
viewport(viewport),
g2d(g2d)
{}
GfxContext::~GfxContext() { GfxContext::~GfxContext() {
while (scissorsCount--) { while (scissorsCount--) {
@@ -16,19 +22,38 @@ GfxContext::~GfxContext() {
if (parent == nullptr) if (parent == nullptr)
return; return;
if (depthMask_ != parent->depthMask_) { if (g2d) {
glDepthMask(parent->depthMask_); g2d->flush();
} }
if (depthTest_ != parent->depthTest_) {
if (depthTest_) glDisable(GL_DEPTH_TEST); if (fbo != parent->fbo) {
if (fbo) {
fbo->unbind();
}
if (parent->fbo) {
parent->fbo->bind();
}
}
Window::viewport(
0, 0,
parent->viewport.getWidth(),
parent->viewport.getHeight()
);
if (depthMask != parent->depthMask) {
glDepthMask(parent->depthMask);
}
if (depthTest != parent->depthTest) {
if (depthTest) glDisable(GL_DEPTH_TEST);
else glEnable(GL_DEPTH_TEST); else glEnable(GL_DEPTH_TEST);
} }
if (cullFace_ != parent->cullFace_) { if (cullFace != parent->cullFace) {
if (cullFace_) glDisable(GL_CULL_FACE); if (cullFace) glDisable(GL_CULL_FACE);
else glEnable(GL_CULL_FACE); else glEnable(GL_CULL_FACE);
} }
if (blendMode_ != parent->blendMode_) { if (blendMode != parent->blendMode) {
Window::setBlendMode(parent->blendMode_); Window::setBlendMode(parent->blendMode);
} }
} }
@@ -42,22 +67,40 @@ Batch2D* GfxContext::getBatch2D() const {
GfxContext GfxContext::sub() const { GfxContext GfxContext::sub() const {
auto ctx = GfxContext(this, viewport, g2d); auto ctx = GfxContext(this, viewport, g2d);
ctx.depthTest_ = depthTest_; ctx.depthTest = depthTest;
ctx.cullFace_ = cullFace_; ctx.cullFace = cullFace;
return ctx; return ctx;
} }
void GfxContext::depthMask(bool flag) { void GfxContext::setViewport(const Viewport& viewport) {
if (depthMask_ == flag) this->viewport = viewport;
Window::viewport(
0, 0,
viewport.getWidth(),
viewport.getHeight()
);
}
void GfxContext::setFramebuffer(Framebuffer* fbo) {
if (this->fbo == fbo)
return; return;
depthMask_ = flag; this->fbo = fbo;
if (fbo) {
fbo->bind();
}
}
void GfxContext::setDepthMask(bool flag) {
if (depthMask == flag)
return;
depthMask = flag;
glDepthMask(GL_FALSE + flag); glDepthMask(GL_FALSE + flag);
} }
void GfxContext::depthTest(bool flag) { void GfxContext::setDepthTest(bool flag) {
if (depthTest_ == flag) if (depthTest == flag)
return; return;
depthTest_ = flag; depthTest = flag;
if (flag) { if (flag) {
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
} else { } else {
@@ -65,10 +108,10 @@ void GfxContext::depthTest(bool flag) {
} }
} }
void GfxContext::cullFace(bool flag) { void GfxContext::setCullFace(bool flag) {
if (cullFace_ == flag) if (cullFace == flag)
return; return;
cullFace_ = flag; cullFace = flag;
if (flag) { if (flag) {
glEnable(GL_CULL_FACE); glEnable(GL_CULL_FACE);
} else { } else {
@@ -76,14 +119,14 @@ void GfxContext::cullFace(bool flag) {
} }
} }
void GfxContext::blendMode(blendmode mode) { void GfxContext::setBlendMode(blendmode mode) {
if (blendMode_ == mode) if (blendMode == mode)
return; return;
blendMode_ = mode; blendMode = mode;
Window::setBlendMode(mode); Window::setBlendMode(mode);
} }
void GfxContext::scissors(glm::vec4 area) { void GfxContext::setScissors(glm::vec4 area) {
Window::pushScissor(area); Window::pushScissor(area);
scissorsCount++; scissorsCount++;
} }
+15 -11
View File
@@ -6,29 +6,33 @@
#include "../window/Window.h" #include "../window/Window.h"
class Batch2D; class Batch2D;
class Framebuffer;
class GfxContext { class GfxContext {
const GfxContext* parent; const GfxContext* parent;
Viewport& viewport; Viewport viewport;
Batch2D* const g2d; Batch2D* const g2d;
bool depthMask_ = true; Framebuffer* fbo = nullptr;
bool depthTest_ = false; bool depthMask = true;
bool cullFace_ = false; bool depthTest = false;
blendmode blendMode_ = blendmode::normal; bool cullFace = false;
blendmode blendMode = blendmode::normal;
int scissorsCount = 0; int scissorsCount = 0;
public: public:
GfxContext(const GfxContext* parent, Viewport& viewport, Batch2D* g2d); GfxContext(const GfxContext* parent, const Viewport& viewport, Batch2D* g2d);
~GfxContext(); ~GfxContext();
Batch2D* getBatch2D() const; Batch2D* getBatch2D() const;
const Viewport& getViewport() const; const Viewport& getViewport() const;
GfxContext sub() const; GfxContext sub() const;
void depthMask(bool flag); void setViewport(const Viewport& viewport);
void depthTest(bool flag); void setFramebuffer(Framebuffer* fbo);
void cullFace(bool flag); void setDepthMask(bool flag);
void blendMode(blendmode mode); void setDepthTest(bool flag);
void scissors(glm::vec4 area); void setCullFace(bool flag);
void setBlendMode(blendmode mode);
void setScissors(glm::vec4 area);
}; };
#endif // GRAPHICS_GFX_CONTEXT_H_ #endif // GRAPHICS_GFX_CONTEXT_H_
+11
View File
@@ -21,10 +21,21 @@ public:
Mesh(vertexBuffer, vertices, nullptr, 0, attrs) {}; Mesh(vertexBuffer, vertices, nullptr, 0, attrs) {};
~Mesh(); ~Mesh();
/// @brief Update GL vertex and index buffers data without changing VAO attributes
/// @param vertexBuffer vertex data buffer
/// @param vertices number of vertices in new buffer
/// @param indexBuffer indices buffer
/// @param indices 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 float* vertexBuffer, size_t vertices, const int* indexBuffer = nullptr, size_t indices = 0);
/// @brief Draw mesh with specified primitives type
/// @param primitive primitives type
void draw(unsigned int primitive); void draw(unsigned int primitive);
/// @brief Draw mesh as triangles
void draw(); void draw();
/// @brief Total numbers of alive mesh objects
static int meshesCount; static int meshesCount;
}; };
+42
View File
@@ -0,0 +1,42 @@
#include "PostProcessing.h"
#include "Mesh.h"
#include "Shader.h"
#include "Texture.h"
#include "Framebuffer.h"
#include <stdexcept>
PostProcessing::PostProcessing() {
// Fullscreen quad mesh bulding
float 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
};
vattr attrs[] {{2}, {0}};
quadMesh = std::make_unique<Mesh>(vertices, 6, attrs);
}
PostProcessing::~PostProcessing() {
}
void PostProcessing::use(GfxContext& context) {
const auto& vp = context.getViewport();
if (fbo) {
fbo->resize(vp.getWidth(), vp.getHeight());
} else {
fbo = std::make_unique<Framebuffer>(vp.getWidth(), vp.getHeight());
}
context.setFramebuffer(fbo.get());
}
void PostProcessing::render(const GfxContext& context, Shader* screenShader) {
if (fbo == nullptr) {
throw std::runtime_error("'use(...)' was never called");
}
const auto& viewport = context.getViewport();
screenShader->use();
screenShader->uniform2i("u_screenSize", viewport.size());
fbo->getTexture()->bind();
quadMesh->draw();
}
+37
View File
@@ -0,0 +1,37 @@
#ifndef GRAPHICS_POST_PROCESSING_H_
#define GRAPHICS_POST_PROCESSING_H_
#include "Viewport.h"
#include "GfxContext.h"
#include <memory>
class Mesh;
class Shader;
class Framebuffer;
/// @brief Framebuffer with blitting with shaders.
/// @attention Current implementation does not support multiple render passes
/// for multiple effects. Will be implemented in v0.21
class PostProcessing {
/// @brief Main framebuffer (lasy field)
std::unique_ptr<Framebuffer> fbo;
/// @brief Fullscreen quad mesh as the post-processing canvas
std::unique_ptr<Mesh> quadMesh;
public:
PostProcessing();
~PostProcessing();
/// @brief Prepare and bind framebuffer
/// @param context graphics context will be modified
void use(GfxContext& context);
/// @brief Render fullscreen quad using the passed shader
/// with framebuffer texture bound
/// @param context graphics context
/// @param screenShader shader used for fullscreen quad
/// @throws std::runtime_error if use(...) wasn't called before
void render(const GfxContext& context, Shader* screenShader);
};
#endif // GRAPHICS_POST_PROCESSING_H_
+5
View File
@@ -52,6 +52,11 @@ void Shader::uniform2f(std::string name, glm::vec2 xy){
glUniform2f(transformLoc, xy.x, xy.y); glUniform2f(transformLoc, xy.x, xy.y);
} }
void Shader::uniform2i(std::string name, glm::ivec2 xy){
GLuint transformLoc = glGetUniformLocation(id, name.c_str());
glUniform2i(transformLoc, xy.x, xy.y);
}
void Shader::uniform3f(std::string name, float x, float y, float z){ void Shader::uniform3f(std::string name, float x, float y, float z){
GLuint transformLoc = glGetUniformLocation(id, name.c_str()); GLuint transformLoc = glGetUniformLocation(id, name.c_str());
glUniform3f(transformLoc, x,y,z); glUniform3f(transformLoc, x,y,z);
+3 -1
View File
@@ -3,13 +3,14 @@
#include <string> #include <string>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include "../typedefs.h"
class GLSLExtension; class GLSLExtension;
class Shader { class Shader {
uint id;
public: public:
static GLSLExtension* preprocessor; static GLSLExtension* preprocessor;
unsigned int id;
Shader(unsigned int id); Shader(unsigned int id);
~Shader(); ~Shader();
@@ -20,6 +21,7 @@ public:
void uniform1f(std::string name, float x); void uniform1f(std::string name, float x);
void uniform2f(std::string name, float x, float y); void uniform2f(std::string name, float x, float y);
void uniform2f(std::string name, glm::vec2 xy); void uniform2f(std::string name, glm::vec2 xy);
void uniform2i(std::string name, glm::ivec2 xy);
void uniform3f(std::string name, float x, float y, float z); void uniform3f(std::string name, float x, float y, float z);
void uniform3f(std::string name, glm::vec3 xyz); void uniform3f(std::string name, glm::vec3 xyz);
+26 -12
View File
@@ -4,18 +4,23 @@
#include <memory> #include <memory>
#include "ImageData.h" #include "ImageData.h"
#include "gl_util.h"
Texture::Texture(uint id, int width, int height) Texture::Texture(uint id, uint width, uint height)
: id(id), width(width), height(height) { : id(id), width(width), height(height) {
} }
Texture::Texture(ubyte* data, int width, int height, uint format) Texture::Texture(ubyte* data, uint width, uint height, ImageFormat imageFormat)
: width(width), height(height) { : width(width), height(height) {
glGenTextures(1, &id); glGenTextures(1, &id);
glBindTexture(GL_TEXTURE_2D, id); glBindTexture(GL_TEXTURE_2D, id);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0,
format, GL_UNSIGNED_BYTE, (GLvoid *) data); GLenum format = gl::to_gl_format(imageFormat);
glTexImage2D(
GL_TEXTURE_2D, 0, format, width, height, 0,
format, GL_UNSIGNED_BYTE, (GLvoid *) data
);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glGenerateMipmap(GL_TEXTURE_2D); glGenerateMipmap(GL_TEXTURE_2D);
@@ -31,6 +36,10 @@ void Texture::bind(){
glBindTexture(GL_TEXTURE_2D, id); glBindTexture(GL_TEXTURE_2D, id);
} }
void Texture::unbind() {
glBindTexture(GL_TEXTURE_2D, 0);
}
void Texture::reload(ubyte* data){ void Texture::reload(ubyte* data){
glBindTexture(GL_TEXTURE_2D, id); glBindTexture(GL_TEXTURE_2D, id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
@@ -56,13 +65,18 @@ void Texture::setNearestFilter() {
Texture* Texture::from(const ImageData* image) { Texture* Texture::from(const ImageData* image) {
uint width = image->getWidth(); uint width = image->getWidth();
uint height = image->getHeight(); uint height = image->getHeight();
uint format;
const void* data = image->getData(); const void* data = image->getData();
switch (image->getFormat()) { return new Texture((ubyte*)data, width, height, image->getFormat());
case ImageFormat::rgb888: format = GL_RGB; break; }
case ImageFormat::rgba8888: format = GL_RGBA; break;
default: uint Texture::getWidth() const {
throw std::runtime_error("unsupported image data format"); return width;
} }
return new Texture((ubyte*)data, width, height, format);
uint Texture::getHeight() const {
return height;
}
uint Texture::getId() const {
return id;
} }
+17 -11
View File
@@ -3,24 +3,30 @@
#include <string> #include <string>
#include "../typedefs.h" #include "../typedefs.h"
#include "ImageData.h"
class ImageData;
class Texture { class Texture {
public: protected:
uint id; uint id;
int width; uint width;
int height; uint height;
Texture(uint id, int width, int height); public:
Texture(ubyte* data, int width, int height, uint format); Texture(uint id, uint width, uint height);
~Texture(); Texture(ubyte* data, uint width, uint height, ImageFormat format);
virtual ~Texture();
void bind(); virtual void bind();
void reload(ubyte* data); virtual void unbind();
virtual void reload(ubyte* data);
void setNearestFilter(); void setNearestFilter();
ImageData* readData(); virtual ImageData* readData();
virtual uint getWidth() const;
virtual uint getHeight() const;
virtual uint getId() const;
static Texture* from(const ImageData* image); static Texture* from(const ImageData* image);
}; };
+8 -4
View File
@@ -35,19 +35,23 @@ void TextureAnimator::update(float delta) {
frame = elem.frames[elem.currentFrame]; frame = elem.frames[elem.currentFrame];
} }
if (frameNum != elem.currentFrame){ if (frameNum != elem.currentFrame){
if (changedTextures.find(elem.dstTexture->id) == changedTextures.end()) changedTextures.insert(elem.dstTexture->id); uint elemDstId = elem.dstTexture->getId();
uint elemSrcId = elem.srcTexture->getId();
if (changedTextures.find(elemDstId) == changedTextures.end())
changedTextures.insert(elemDstId);
glBindFramebuffer(GL_FRAMEBUFFER, fboD); glBindFramebuffer(GL_FRAMEBUFFER, fboD);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, elem.dstTexture->id, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, elemDstId, 0);
glBindFramebuffer(GL_FRAMEBUFFER, fboR); glBindFramebuffer(GL_FRAMEBUFFER, fboR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, elem.srcTexture->id, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, elemSrcId, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboD); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboD);
glBindFramebuffer(GL_READ_FRAMEBUFFER, fboR); glBindFramebuffer(GL_READ_FRAMEBUFFER, fboR);
float srcPosY = elem.srcTexture->height - frame.size.y - frame.srcPos.y; // vertical flip float srcPosY = elem.srcTexture->getHeight() - frame.size.y - frame.srcPos.y; // vertical flip
// Extensions // Extensions
const int ext = 2; const int ext = 2;
+2 -2
View File
@@ -14,8 +14,8 @@ public:
virtual uint getWidth() const; virtual uint getWidth() const;
virtual uint getHeight() const; virtual uint getHeight() const;
glm::vec2 size() const { glm::ivec2 size() const {
return glm::vec2(width, height); return glm::ivec2(width, height);
} }
}; };
+19
View File
@@ -0,0 +1,19 @@
#ifndef GRAPHICS_GL_UTIL_H_
#define GRAPHICS_GL_UTIL_H_
#include <GL/glew.h>
#include "ImageData.h"
namespace gl {
inline GLenum to_gl_format(ImageFormat imageFormat) {
switch (imageFormat) {
case ImageFormat::rgb888: return GL_RGB;
case ImageFormat::rgba8888: return GL_RGBA;
default:
return 0;
}
}
}
#endif // GRAPHICS_GL_UTIL_H_
+28 -2
View File
@@ -1,5 +1,6 @@
#include "LuaState.h" #include "LuaState.h"
#include <iomanip>
#include <iostream> #include <iostream>
#include "lua_util.h" #include "lua_util.h"
#include "api_lua.h" #include "api_lua.h"
@@ -217,8 +218,8 @@ int lua::LuaState::pushnil() {
return 1; return 1;
} }
bool lua::LuaState::getfield(const std::string& name) { bool lua::LuaState::getfield(const std::string& name, int idx) {
lua_getfield(L, -1, name.c_str()); lua_getfield(L, idx, name.c_str());
if (lua_isnil(L, -1)) { if (lua_isnil(L, -1)) {
lua_pop(L, -1); lua_pop(L, -1);
return false; return false;
@@ -287,3 +288,28 @@ void lua::LuaState::removeEnvironment(int id) {
lua_pushnil(L); lua_pushnil(L);
setglobal(envName(id)); setglobal(envName(id));
} }
void lua::LuaState::dumpStack() {
int top = gettop();
for (int i = 1; i <= top; i++) {
std::cout << std::setw(3) << i << std::setw(20) << luaL_typename(L, i) << std::setw(30);
switch (lua_type(L, i)) {
case LUA_TNUMBER:
std::cout << tonumber(i);
break;
case LUA_TSTRING:
std::cout << tostring(i);
break;
case LUA_TBOOLEAN:
std::cout << (toboolean(i) ? "true" : "false");
break;
case LUA_TNIL:
std::cout << "nil";
break;
default:
std::cout << lua_topointer(L, i);
break;
}
std::cout << std::endl;
}
}
+4 -2
View File
@@ -41,8 +41,8 @@ namespace lua {
int pushnil(); int pushnil();
int pushglobals(); int pushglobals();
void pop(int n=1); void pop(int n=1);
bool getfield(const std::string& name); bool getfield(const std::string& name, int idx = -1);
void setfield(const std::string& name, int idx=-2); void setfield(const std::string& name, int idx = -2);
bool toboolean(int idx); bool toboolean(int idx);
luaint tointeger(int idx); luaint tointeger(int idx);
luanumber tonumber(int idx); luanumber tonumber(int idx);
@@ -61,6 +61,8 @@ namespace lua {
int createEnvironment(int parent); int createEnvironment(int parent);
void removeEnvironment(int id); void removeEnvironment(int id);
const std::string storeAnonymous(); const std::string storeAnonymous();
void dumpStack();
}; };
} }
+2
View File
@@ -228,6 +228,8 @@ const luaL_Reg blocklib [] = {
{"get_Z", lua_wrap_errors<l_get_block_z>}, {"get_Z", lua_wrap_errors<l_get_block_z>},
{"get_states", lua_wrap_errors<l_get_block_states>}, {"get_states", lua_wrap_errors<l_get_block_states>},
{"set_states", lua_wrap_errors<l_set_block_states>}, {"set_states", lua_wrap_errors<l_set_block_states>},
{"get_rotation", lua_wrap_errors<l_get_block_rotation>},
{"set_rotation", lua_wrap_errors<l_set_block_rotation>},
{"get_user_bits", lua_wrap_errors<l_get_block_user_bits>}, {"get_user_bits", lua_wrap_errors<l_get_block_user_bits>},
{"set_user_bits", lua_wrap_errors<l_set_block_user_bits>}, {"set_user_bits", lua_wrap_errors<l_set_block_user_bits>},
{NULL, NULL} {NULL, NULL}
+67 -70
View File
@@ -105,25 +105,19 @@ void scripting::on_world_load(Level* level, BlocksController* blocks) {
load_script("world.lua"); load_script("world.lua");
for (auto& pack : scripting::engine->getContentPacks()) { for (auto& pack : scripting::engine->getContentPacks()) {
if (state->getglobal(pack.id+".worldopen")) { emit_event(pack.id + ".worldopen");
state->callNoThrow(0);
}
} }
} }
void scripting::on_world_save() { void scripting::on_world_save() {
for (auto& pack : scripting::engine->getContentPacks()) { for (auto& pack : scripting::engine->getContentPacks()) {
if (state->getglobal(pack.id+".worldsave")) { emit_event(pack.id + ".worldsave");
state->callNoThrow(0);
}
} }
} }
void scripting::on_world_quit() { void scripting::on_world_quit() {
for (auto& pack : scripting::engine->getContentPacks()) { for (auto& pack : scripting::engine->getContentPacks()) {
if (state->getglobal(pack.id+".worldquit")) { emit_event(pack.id + ".worldquit");
state->callNoThrow(0);
}
} }
if (state->getglobal("__scripts_cleanup")) { if (state->getglobal("__scripts_cleanup")) {
state->callNoThrow(0); state->callNoThrow(0);
@@ -134,109 +128,97 @@ void scripting::on_world_quit() {
} }
void scripting::on_blocks_tick(const Block* block, int tps) { void scripting::on_blocks_tick(const Block* block, int tps) {
std::string name = block->name+".blockstick"; std::string name = block->name + ".blockstick";
if (state->getglobal(name)) { emit_event(name, [tps] (lua::LuaState* state) {
state->pushinteger(tps); state->pushinteger(tps);
state->callNoThrow(1); return 1;
} });
} }
void scripting::update_block(const Block* block, int x, int y, int z) { void scripting::update_block(const Block* block, int x, int y, int z) {
std::string name = block->name+".update"; std::string name = block->name + ".update";
if (state->getglobal(name)) { emit_event(name, [x, y, z] (lua::LuaState* state) {
state->pushivec3(x, y, z); state->pushivec3(x, y, z);
state->callNoThrow(3); return 3;
} });
} }
void scripting::random_update_block(const Block* block, int x, int y, int z) { void scripting::random_update_block(const Block* block, int x, int y, int z) {
std::string name = block->name+".randupdate"; std::string name = block->name + ".randupdate";
if (state->getglobal(name)) { emit_event(name, [x, y, z] (lua::LuaState* state) {
state->pushivec3(x, y, z); state->pushivec3(x, y, z);
state->callNoThrow(3); return 3;
} });
} }
void scripting::on_block_placed(Player* player, const Block* block, int x, int y, int z) { void scripting::on_block_placed(Player* player, const Block* block, int x, int y, int z) {
std::string name = block->name+".placed"; std::string name = block->name + ".placed";
if (state->getglobal(name)) { emit_event(name, [x, y, z, player] (lua::LuaState* state) {
state->pushivec3(x, y, z); state->pushivec3(x, y, z);
state->pushinteger(player->getId()); state->pushinteger(player->getId());
state->callNoThrow(4); return 4;
} });
} }
void scripting::on_block_broken(Player* player, const Block* block, int x, int y, int z) { void scripting::on_block_broken(Player* player, const Block* block, int x, int y, int z) {
std::string name = block->name+".broken"; std::string name = block->name + ".broken";
if (state->getglobal(name)) { emit_event(name, [x, y, z, player] (lua::LuaState* state) {
state->pushivec3(x, y, z); state->pushivec3(x, y, z);
state->pushinteger(player->getId()); state->pushinteger(player->getId());
state->callNoThrow(4); return 4;
} });
} }
bool scripting::on_block_interact(Player* player, const Block* block, int x, int y, int z) { bool scripting::on_block_interact(Player* player, const Block* block, int x, int y, int z) {
std::string name = block->name+".interact"; std::string name = block->name + ".interact";
if (state->getglobal(name)) { return emit_event(name, [x, y, z, player] (lua::LuaState* state) {
state->pushivec3(x, y, z); state->pushivec3(x, y, z);
state->pushinteger(player->getId()); state->pushinteger(player->getId());
if (state->callNoThrow(4)) { return 4;
return state->toboolean(-1); });
}
}
return false;
} }
bool scripting::on_item_use(Player* player, const ItemDef* item) { bool scripting::on_item_use(Player* player, const ItemDef* item) {
std::string name = item->name+".use"; std::string name = item->name + ".use";
if (state->getglobal(name)) { return emit_event(name, [player] (lua::LuaState* state) {
state->pushinteger(player->getId()); state->pushinteger(player->getId());
if (state->callNoThrow(1)) { return 1;
return state->toboolean(-1); });
}
}
return false;
} }
bool scripting::on_item_use_on_block(Player* player, const ItemDef* item, int x, int y, int z) { bool scripting::on_item_use_on_block(Player* player, const ItemDef* item, int x, int y, int z) {
std::string name = item->name+".useon"; std::string name = item->name + ".useon";
if (state->getglobal(name)) { return emit_event(name, [x, y, z, player] (lua::LuaState* state) {
state->pushivec3(x, y, z); state->pushivec3(x, y, z);
state->pushinteger(player->getId()); state->pushinteger(player->getId());
if (state->callNoThrow(4)) { return 4;
return state->toboolean(-1); });
}
}
return false;
} }
bool scripting::on_item_break_block(Player* player, const ItemDef* item, int x, int y, int z) { bool scripting::on_item_break_block(Player* player, const ItemDef* item, int x, int y, int z) {
std::string name = item->name+".blockbreakby"; std::string name = item->name + ".blockbreakby";
if (state->getglobal(name)) { return emit_event(name, [x, y, z, player] (lua::LuaState* state) {
state->pushivec3(x, y, z); state->pushivec3(x, y, z);
state->pushinteger(player->getId()); state->pushinteger(player->getId());
if (state->callNoThrow(4)) { return 4;
return state->toboolean(-1); });
}
}
return false;
} }
void scripting::on_ui_open(UiDocument* layout, Inventory* inventory, glm::ivec3 blockcoord) { void scripting::on_ui_open(UiDocument* layout, Inventory* inventory, glm::ivec3 blockcoord) {
std::string name = layout->getId()+".open"; std::string name = layout->getId() + ".open";
if (state->getglobal(name)) { emit_event(name, [inventory, blockcoord] (lua::LuaState* state) {
state->pushinteger(inventory == nullptr ? 0 : inventory->getId()); state->pushinteger(inventory == nullptr ? 0 : inventory->getId());
state->pushivec3(blockcoord.x, blockcoord.y, blockcoord.z); state->pushivec3(blockcoord.x, blockcoord.y, blockcoord.z);
state->callNoThrow(4); return 4;
} });
} }
void scripting::on_ui_close(UiDocument* layout, Inventory* inventory) { void scripting::on_ui_close(UiDocument* layout, Inventory* inventory) {
std::string name = layout->getId()+".close"; std::string name = layout->getId() + ".close";
if (state->getglobal(name)) { emit_event(name, [inventory] (lua::LuaState* state) {
state->pushinteger(inventory->getId()); state->pushinteger(inventory == nullptr ? 0 : inventory->getId());
state->callNoThrow(1); return 1;
} });
} }
bool scripting::register_event(int env, const std::string& name, const std::string& id) { bool scripting::register_event(int env, const std::string& name, const std::string& id) {
@@ -244,17 +226,32 @@ bool scripting::register_event(int env, const std::string& name, const std::stri
state->pushglobals(); state->pushglobals();
} }
if (state->getfield(name)) { if (state->getfield(name)) {
state->pop();
state->getglobal("events");
state->getfield("on");
state->pushstring(id);
state->getfield(name, -4);
state->callNoThrow(2);
state->pop();
// remove previous name // remove previous name
state->pushnil(); state->pushnil();
state->setfield(name, -3); state->setfield(name);
// add new global name
state->setglobal(id);
state->pop();
return true; return true;
} }
return false; return false;
} }
bool scripting::emit_event(const std::string &name, std::function<int(lua::LuaState *)> args) {
state->getglobal("events");
state->getfield("emit");
state->pushstring(name);
state->callNoThrow(args(state) + 1);
bool result = state->toboolean(-1);
state->pop(2);
return result;
}
void scripting::load_block_script(int env, std::string prefix, fs::path file, block_funcs_set& funcsset) { void scripting::load_block_script(int env, std::string prefix, fs::path file, block_funcs_set& funcsset) {
std::string src = files::read_string(file); std::string src = files::read_string(file);
std::cout << "loading script " << file.u8string() << std::endl; std::cout << "loading script " << file.u8string() << std::endl;
+4
View File
@@ -4,6 +4,7 @@
#include "../../delegates.h" #include "../../delegates.h"
#include "lua/LuaState.h"
#include "scripting_functional.h" #include "scripting_functional.h"
namespace fs = std::filesystem; namespace fs = std::filesystem;
@@ -44,6 +45,9 @@ namespace scripting {
extern bool register_event(int env, const std::string& name, const std::string& id); extern bool register_event(int env, const std::string& name, const std::string& id);
static inline int noargs(lua::LuaState *) { return 0; }
extern bool emit_event(const std::string& name, std::function<int(lua::LuaState* state)> args = noargs);
std::unique_ptr<Environment> create_environment(int parent=0); std::unique_ptr<Environment> create_environment(int parent=0);
std::unique_ptr<Environment> create_pack_environment(const ContentPack& pack); std::unique_ptr<Environment> create_pack_environment(const ContentPack& pack);
std::unique_ptr<Environment> create_doc_environment(int parent, const std::string& name); std::unique_ptr<Environment> create_doc_environment(int parent, const std::string& name);
+7 -7
View File
@@ -22,21 +22,21 @@ void scripting::on_frontend_init(Hud* hud) {
scripting::state->openlib("hud", hudlib, 0); scripting::state->openlib("hud", hudlib, 0);
for (auto& pack : scripting::engine->getContentPacks()) { for (auto& pack : scripting::engine->getContentPacks()) {
if (state->getglobal(pack.id+".hudopen")) { emit_event(pack.id + ".hudopen", [&] (lua::LuaState* state) {
state->pushinteger(hud->getPlayer()->getId()); state->pushinteger(hud->getPlayer()->getId());
state->callNoThrow(1); return 1;
} });
} }
} }
void scripting::on_frontend_close() { void scripting::on_frontend_close() {
scripting::hud = nullptr;
for (auto& pack : scripting::engine->getContentPacks()) { for (auto& pack : scripting::engine->getContentPacks()) {
if (state->getglobal(pack.id+".hudclose")) { emit_event(pack.id + ".hudclose", [&] (lua::LuaState* state) {
state->pushinteger(hud->getPlayer()->getId()); state->pushinteger(hud->getPlayer()->getId());
state->callNoThrow(1); return 1;
} });
} }
scripting::hud = nullptr;
} }
void scripting::load_hud_script(int env, std::string packid, fs::path file) { void scripting::load_hud_script(int env, std::string packid, fs::path file) {
+97 -94
View File
@@ -3,83 +3,86 @@
#include <algorithm> #include <algorithm>
inline int getPackerScore(rectangle& rect) { inline int getPackerScore(rectangle& rect) {
if (rect.width * rect.height > 100) if (rect.width * rect.height > 100)
return rect.height * rect.height * 1000; return rect.height * rect.height * 1000;
return (rect.width * rect.height * rect.height); return (rect.width * rect.height * rect.height);
} }
LMPacker::LMPacker(const uint32_t sizes[], size_t length) { LMPacker::LMPacker(const uint32_t sizes[], size_t length) {
for (unsigned int i = 0; i < length/2; i++) { for (unsigned int i = 0; i < length/2; i++) {
rectangle rect(i, 0, 0, (int)sizes[i * 2], (int)sizes[i * 2 + 1]); rectangle rect(i, 0, 0, (int)sizes[i * 2], (int)sizes[i * 2 + 1]);
rects.push_back(rect); rects.push_back(rect);
} }
sort(rects.begin(), rects.end(), [](rectangle a, rectangle b) { sort(rects.begin(), rects.end(), [](rectangle a, rectangle b) {
return -getPackerScore(a) < -getPackerScore(b); return -getPackerScore(a) < -getPackerScore(b);
}); });
} }
LMPacker::~LMPacker() { LMPacker::~LMPacker() {
if (matrix) { cleanup();
for (unsigned int y = 0; y < (height >> mbit); y++) {
delete[] matrix[y];
}
delete[] matrix;
}
} }
void LMPacker::cleanup() { void LMPacker::cleanup() {
placed.clear(); if (matrix) {
for (unsigned int y = 0; y < (height >> mbit); y++) {
delete[] matrix[y];
}
delete[] matrix;
}
placed.clear();
} }
bool LMPacker::build(uint32_t width, uint32_t height, bool LMPacker::build(uint32_t width, uint32_t height,
uint16_t extension, uint32_t mbit, uint32_t vstep) { uint16_t extension, uint32_t mbit, uint32_t vstep) {
cleanup(); cleanup();
this->mbit = mbit; this->mbit = mbit;
this->width = width; this->width = width;
this->height = height; this->height = height;
int mpix = 1 << mbit; int mpix = 1 << mbit;
const unsigned int mwidth = width >> mbit; const unsigned int mwidth = width >> mbit;
const unsigned int mheight = height >> mbit; const unsigned int mheight = height >> mbit;
matrix = new rectangle**[mheight];
for (unsigned int y = 0; y < mheight; y++) { matrix = new rectangle**[mheight];
matrix[y] = new rectangle*[mwidth]; for (unsigned int y = 0; y < mheight; y++) {
for (unsigned int x = 0; x < mwidth; x++) { matrix[y] = new rectangle*[mwidth];
matrix[y][x] = nullptr; for (unsigned int x = 0; x < mwidth; x++) {
} matrix[y][x] = nullptr;
} }
for (unsigned int i = 0; i < rects.size(); i++) { }
rectangle& rect = rects[i];
rect = rectangle(rect.idx, 0, 0, rect.width, rect.height); for (unsigned int i = 0; i < rects.size(); i++) {
rectangle& rect = rects[i];
rect = rectangle(rect.idx, 0, 0, rect.width, rect.height);
rect.width += extension * 2; rect.width += extension * 2;
rect.height += extension * 2; rect.height += extension * 2;
if (mpix > 1) { if (mpix > 1) {
if (rect.width % mpix > 0) { if (rect.width % mpix > 0) {
rect.extX = mpix - (rect.width % mpix); rect.extX = mpix - (rect.width % mpix);
} }
if (rect.height % mpix > 0) { if (rect.height % mpix > 0) {
rect.extY = mpix - (rect.height % mpix); rect.extY = mpix - (rect.height % mpix);
} }
} }
rect.width += rect.extX; rect.width += rect.extX;
rect.height += rect.extY; rect.height += rect.extY;
} }
bool built = true; bool built = true;
for (unsigned int i = 0; i < rects.size(); i++) { for (unsigned int i = 0; i < rects.size(); i++) {
rectangle* rect = &rects[i]; rectangle* rect = &rects[i];
if (!place(rect, vstep)) { if (!place(rect, vstep)) {
built = false; built = false;
break; break;
} }
} }
for (unsigned int i = 0; i < rects.size(); i++) { for (unsigned int i = 0; i < rects.size(); i++) {
rectangle& rect = rects[i]; rectangle& rect = rects[i];
rect.x += extension; rect.x += extension;
rect.y += extension; rect.y += extension;
rect.width -= extension * 2 + rect.extX; rect.width -= extension * 2 + rect.extX;
rect.height -= extension * 2 + rect.extY; rect.height -= extension * 2 + rect.extY;
} }
return built; return built;
} }
inline rectangle* findCollision(rectangle*** matrix, int x, int y, int w, int h) { inline rectangle* findCollision(rectangle*** matrix, int x, int y, int w, int h) {
@@ -103,47 +106,47 @@ inline void fill(rectangle*** matrix, rectangle* rect, int x, int y, int w, int
} }
bool LMPacker::place(rectangle* rectptr, uint32_t vstep) { bool LMPacker::place(rectangle* rectptr, uint32_t vstep) {
rectangle& rect = *rectptr; rectangle& rect = *rectptr;
const unsigned int rw = rect.width >> mbit; const unsigned int rw = rect.width >> mbit;
const unsigned int rh = rect.height >> mbit; const unsigned int rh = rect.height >> mbit;
if (vstep > 1) { if (vstep > 1) {
vstep = (vstep > rh ? vstep : rh); vstep = (vstep > rh ? vstep : rh);
} }
const unsigned int mwidth = width >> mbit; const unsigned int mwidth = width >> mbit;
const unsigned int mheight = height >> mbit; const unsigned int mheight = height >> mbit;
for (unsigned int y = 0; y + rh < mheight; y += vstep) { for (unsigned int y = 0; y + rh < mheight; y += vstep) {
rectangle** line = matrix[y]; rectangle** line = matrix[y];
bool skiplines = true; bool skiplines = true;
rectangle** lower = matrix[y + rh - 1]; rectangle** lower = matrix[y + rh - 1];
for (unsigned int x = 0; x + rw < mwidth; x++) { for (unsigned int x = 0; x + rw < mwidth; x++) {
rectangle* prect = line[x]; rectangle* prect = line[x];
if (prect) { if (prect) {
x = (prect->x >> mbit) + (prect->width >> mbit) - 1; x = (prect->x >> mbit) + (prect->width >> mbit) - 1;
} else { } else {
if (skiplines) { if (skiplines) {
unsigned int lfree = 0; unsigned int lfree = 0;
while (lfree + x < mwidth && !lower[x + lfree] && lfree < rw) { while (lfree + x < mwidth && !lower[x + lfree] && lfree < rw) {
lfree++; lfree++;
} }
if (lfree >= rw) if (lfree >= rw)
skiplines = false; skiplines = false;
} }
prect = findCollision(matrix, x, y, rw, rh); prect = findCollision(matrix, x, y, rw, rh);
if (prect) { if (prect) {
x = (prect->x >> mbit) + (prect->width >> mbit) - 1; x = (prect->x >> mbit) + (prect->width >> mbit) - 1;
continue; continue;
} }
fill(matrix, rectptr, x, y, rw, rh); fill(matrix, rectptr, x, y, rw, rh);
rectptr->x = x << mbit; rectptr->x = x << mbit;
rectptr->y = y << mbit; rectptr->y = y << mbit;
placed.push_back(rectptr); placed.push_back(rectptr);
return true; return true;
} }
} }
if (skiplines) { if (skiplines) {
y += rh - vstep; y += rh - vstep;
} }
} }
return false; return false;
} }
+30 -30
View File
@@ -10,44 +10,44 @@
#include <vector> #include <vector>
struct rectangle { struct rectangle {
unsigned int idx; unsigned int idx;
int x; int x;
int y; int y;
int width; int width;
int height; int height;
int extX = 0; int extX = 0;
int extY = 0; int extY = 0;
rectangle(unsigned int idx, int x, int y, int width, int height) rectangle(unsigned int idx, int x, int y, int width, int height)
: idx(idx), x(x), y(y), width(width), height(height){ : idx(idx), x(x), y(y), width(width), height(height){
} }
}; };
class LMPacker { class LMPacker {
std::vector<rectangle> rects; std::vector<rectangle> rects;
std::vector<rectangle*> placed; std::vector<rectangle*> placed;
uint32_t width = 0; uint32_t width = 0;
uint32_t height = 0; uint32_t height = 0;
rectangle*** matrix = nullptr; rectangle*** matrix = nullptr;
uint32_t mbit = 0; uint32_t mbit = 0;
void cleanup(); void cleanup();
bool place(rectangle* rect, uint32_t vstep); bool place(rectangle* rect, uint32_t vstep);
public: public:
LMPacker(const uint32_t sizes[], size_t length); LMPacker(const uint32_t sizes[], size_t length);
virtual ~LMPacker(); virtual ~LMPacker();
bool buildCompact(uint32_t width, uint32_t height, uint16_t extension) { bool buildCompact(uint32_t width, uint32_t height, uint16_t extension) {
return build(width, height, extension, 0, 1); return build(width, height, extension, 0, 1);
} }
bool buildFast(uint32_t width, uint32_t height, uint16_t extension) { bool buildFast(uint32_t width, uint32_t height, uint16_t extension) {
return build(width, height, extension, 1, 2); return build(width, height, extension, 1, 2);
} }
bool build(uint32_t width, uint32_t height, uint16_t extension, uint32_t mbit, uint32_t vstep); bool build(uint32_t width, uint32_t height, uint16_t extension, uint32_t mbit, uint32_t vstep);
std::vector<rectangle> getResult() { std::vector<rectangle> getResult() {
return rects; return rects;
} }
}; };
#endif /* LMPACKER_H_ */ #endif /* LMPACKER_H_ */