Merge pull request #175 from MihailRis/minimal_postprocessing
Minimal postprocessing and GL-related refactor
This commit is contained in:
commit
ce6a25c4c1
9
res/shaders/screen.glslf
Normal file
9
res/shaders/screen.glslf
Normal 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
res/shaders/screen.glslv
Normal file
13
res/shaders/screen.glslv
Normal 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);
|
||||
}
|
||||
|
||||
@ -74,6 +74,7 @@ void AssetsLoader::addDefaults(AssetsLoader& loader, const Content* content) {
|
||||
loader.add(ASSET_TEXTURE, TEXTURES_FOLDER"/gui/cross.png", "gui/cross");
|
||||
if (content) {
|
||||
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"/skybox_gen", "skybox_gen");
|
||||
loader.add(ASSET_TEXTURE, TEXTURES_FOLDER"/misc/moon.png", "misc/moon");
|
||||
|
||||
@ -136,7 +136,7 @@ bool assetload::font(
|
||||
}
|
||||
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);
|
||||
return true;
|
||||
}
|
||||
@ -270,13 +270,19 @@ static bool animation(
|
||||
Frame frame;
|
||||
UVRegion region = dstAtlas->get(name);
|
||||
|
||||
frame.dstPos = glm::ivec2(region.u1 * dstTex->width, region.v1 * dstTex->height);
|
||||
frame.size = glm::ivec2(region.u2 * dstTex->width, region.v2 * dstTex->height) - frame.dstPos;
|
||||
uint dstWidth = dstTex->getWidth();
|
||||
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()) {
|
||||
for (const auto& elem : builder.getNames()) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -288,7 +294,7 @@ static bool animation(
|
||||
}
|
||||
region = srcAtlas->get(elem.first);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -95,7 +95,7 @@ ImageData* BlocksPreview::draw(
|
||||
break;
|
||||
}
|
||||
}
|
||||
return fbo->texture->readData();
|
||||
return fbo->getTexture()->readData();
|
||||
}
|
||||
|
||||
std::unique_ptr<Atlas> BlocksPreview::build(
|
||||
@ -113,8 +113,8 @@ std::unique_ptr<Atlas> BlocksPreview::build(
|
||||
Viewport viewport(iconSize, iconSize);
|
||||
GfxContext pctx(nullptr, viewport, nullptr);
|
||||
GfxContext ctx = pctx.sub();
|
||||
ctx.cullFace(true);
|
||||
ctx.depthTest(true);
|
||||
ctx.setCullFace(true);
|
||||
ctx.setDepthTest(true);
|
||||
|
||||
Framebuffer fbo(iconSize, iconSize, true);
|
||||
Batch3D batch(1024);
|
||||
|
||||
@ -14,6 +14,7 @@
|
||||
#include "../graphics/Batch3D.h"
|
||||
#include "../graphics/Texture.h"
|
||||
#include "../graphics/LineBatch.h"
|
||||
#include "../graphics/PostProcessing.h"
|
||||
#include "../voxels/Chunks.h"
|
||||
#include "../voxels/Chunk.h"
|
||||
#include "../voxels/Block.h"
|
||||
@ -39,6 +40,7 @@ WorldRenderer::WorldRenderer(Engine* engine, LevelFrontend* frontend, Player* pl
|
||||
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>(
|
||||
@ -136,132 +138,171 @@ void WorldRenderer::drawChunks(Chunks* chunks, Camera* camera, Shader* shader) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void WorldRenderer::draw(const GfxContext& pctx, Camera* camera, bool hudVisible){
|
||||
EngineSettings& settings = engine->getSettings();
|
||||
|
||||
Window::clearDepth();
|
||||
skybox->refresh(pctx, level->world->daytime, 1.0f+fog*2.0f, 4);
|
||||
|
||||
const Content* content = level->content;
|
||||
auto indices = content->getIndices();
|
||||
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();
|
||||
|
||||
const Viewport& viewport = pctx.getViewport();
|
||||
int displayWidth = viewport.getWidth();
|
||||
int displayHeight = viewport.getHeight();
|
||||
float fogFactor = 15.0f / ((float)settings.chunks.loadDistance-2);
|
||||
|
||||
// Drawing background sky plane
|
||||
skybox->draw(pctx, camera, assets, level->getWorld()->daytime, fog);
|
||||
// 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);
|
||||
|
||||
Shader* linesShader = assets->getShader("lines");
|
||||
// Light emission when an emissive item is chosen
|
||||
{
|
||||
GfxContext ctx = pctx.sub();
|
||||
ctx.depthTest(true);
|
||||
ctx.cullFace(true);
|
||||
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);
|
||||
}
|
||||
|
||||
float fogFactor = 15.0f / ((float)settings.chunks.loadDistance-2);
|
||||
// Binding main shader textures
|
||||
skybox->bind();
|
||||
atlas->getTexture()->bind();
|
||||
|
||||
// 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);
|
||||
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
|
||||
{
|
||||
auto inventory = player->getInventory();
|
||||
ItemStack& stack = inventory->getSlot(player->getChosenSlot());
|
||||
ItemDef* item = indices->getItemDef(stack.getItemId());
|
||||
assert(item != nullptr);
|
||||
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);
|
||||
|
||||
// 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));
|
||||
}
|
||||
GfxContext ctx = wctx.sub();
|
||||
ctx.setDepthTest(true);
|
||||
ctx.setCullFace(true);
|
||||
renderLevel(ctx, camera, settings);
|
||||
// Selected block
|
||||
if (PlayerController::selectedBlockId != -1 && hudVisible){
|
||||
renderBlockSelection(camera, linesShader);
|
||||
}
|
||||
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;
|
||||
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.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();
|
||||
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) {
|
||||
|
||||
@ -20,17 +20,18 @@ class Batch3D;
|
||||
class LineBatch;
|
||||
class ChunksRenderer;
|
||||
class Shader;
|
||||
class Texture;
|
||||
class Frustum;
|
||||
class Engine;
|
||||
class Chunks;
|
||||
class LevelFrontend;
|
||||
class Skybox;
|
||||
class PostProcessing;
|
||||
|
||||
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;
|
||||
@ -38,12 +39,38 @@ class WorldRenderer {
|
||||
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 drawDebug(const GfxContext& context, Camera* camera);
|
||||
void drawBorders(int sx, int sy, int sz, int ex, int ey, int ez);
|
||||
|
||||
static float fog;
|
||||
|
||||
@ -8,6 +8,9 @@
|
||||
#include "../../graphics/Shader.h"
|
||||
#include "../../graphics/Mesh.h"
|
||||
#include "../../graphics/Batch3D.h"
|
||||
#include "../../graphics/Texture.h"
|
||||
#include "../../graphics/Cubemap.h"
|
||||
#include "../../graphics/Framebuffer.h"
|
||||
#include "../../window/Window.h"
|
||||
#include "../../window/Camera.h"
|
||||
|
||||
@ -19,21 +22,15 @@ const int STARS_COUNT = 3000;
|
||||
const int STARS_SEED = 632;
|
||||
|
||||
Skybox::Skybox(uint size, Shader* shader)
|
||||
: size(size),
|
||||
shader(shader),
|
||||
batch3d(new Batch3D(4096))
|
||||
: size(size),
|
||||
shader(shader),
|
||||
batch3d(std::make_unique<Batch3D>(4096))
|
||||
{
|
||||
glGenTextures(1, &cubemap);
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap);
|
||||
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);
|
||||
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);
|
||||
auto cubemap = std::make_unique<Cubemap>(size, size, ImageFormat::rgb888);
|
||||
|
||||
uint fboid;
|
||||
glGenFramebuffers(1, &fboid);
|
||||
fbo = std::make_unique<Framebuffer>(fboid, 0, std::move(cubemap));
|
||||
|
||||
float vertices[] {
|
||||
-1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f,
|
||||
@ -58,8 +55,6 @@ Skybox::Skybox(uint size, Shader* shader)
|
||||
}
|
||||
|
||||
Skybox::~Skybox() {
|
||||
glDeleteTextures(1, &cubemap);
|
||||
glDeleteFramebuffers(1, &fbo);
|
||||
}
|
||||
|
||||
void Skybox::drawBackground(Camera* camera, Assets* assets, int width, int height) {
|
||||
@ -109,7 +104,7 @@ void Skybox::draw(
|
||||
drawBackground(camera, assets, width, height);
|
||||
|
||||
GfxContext ctx = pctx.sub();
|
||||
ctx.blendMode(blendmode::addition);
|
||||
ctx.setBlendMode(blendmode::addition);
|
||||
|
||||
Shader* shader = assets->getShader("ui3d");
|
||||
shader->use();
|
||||
@ -141,15 +136,17 @@ void Skybox::draw(
|
||||
|
||||
void Skybox::refresh(const GfxContext& pctx, float t, float mie, uint quality) {
|
||||
GfxContext ctx = pctx.sub();
|
||||
ctx.depthMask(false);
|
||||
ctx.depthTest(false);
|
||||
ctx.setDepthMask(false);
|
||||
ctx.setDepthTest(false);
|
||||
ctx.setFramebuffer(fbo.get());
|
||||
ctx.setViewport(Viewport(size, size));
|
||||
|
||||
auto cubemap = dynamic_cast<Cubemap*>(fbo->getTexture());
|
||||
|
||||
ready = true;
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap);
|
||||
cubemap->bind();
|
||||
shader->use();
|
||||
Window::viewport(0,0, size, size);
|
||||
|
||||
const glm::vec3 xaxs[] = {
|
||||
{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->uniform3f("u_lightDir", glm::normalize(glm::vec3(sin(t), -cos(t), 0.0f)));
|
||||
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_yaxis", yaxs[face]);
|
||||
shader->uniform3f("u_zaxis", zaxs[face]);
|
||||
mesh->draw(GL_TRIANGLES);
|
||||
mesh->draw();
|
||||
}
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
|
||||
cubemap->unbind();
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
Window::viewport(0, 0, Window::width, Window::height);
|
||||
}
|
||||
|
||||
void Skybox::bind() const {
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap);
|
||||
fbo->getTexture()->bind();
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
}
|
||||
|
||||
void Skybox::unbind() const {
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
|
||||
fbo->getTexture()->unbind();
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,6 +13,7 @@ class Shader;
|
||||
class Assets;
|
||||
class Camera;
|
||||
class Batch3D;
|
||||
class Framebuffer;
|
||||
|
||||
struct skysprite {
|
||||
std::string texture;
|
||||
@ -22,8 +23,7 @@ struct skysprite {
|
||||
};
|
||||
|
||||
class Skybox {
|
||||
uint fbo;
|
||||
uint cubemap;
|
||||
std::unique_ptr<Framebuffer> fbo;
|
||||
uint size;
|
||||
Shader* shader;
|
||||
bool ready = false;
|
||||
@ -44,7 +44,8 @@ public:
|
||||
Camera* camera,
|
||||
Assets* assets,
|
||||
float daytime,
|
||||
float fog);
|
||||
float fog
|
||||
);
|
||||
|
||||
void refresh(const GfxContext& pctx, float t, float mie, uint quality);
|
||||
void bind() const;
|
||||
@ -54,4 +55,4 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
#endif // FRONTEND_GRAPHICS_SKYBOX_H_
|
||||
#endif // FRONTEND_GRAPHICS_SKYBOX_H_
|
||||
|
||||
@ -88,12 +88,11 @@ void Container::draw(const GfxContext* pctx, Assets* assets) {
|
||||
batch->flush();
|
||||
{
|
||||
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) {
|
||||
if (node->isVisible())
|
||||
node->draw(pctx, assets);
|
||||
}
|
||||
batch->flush();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -204,7 +204,7 @@ void Image::draw(const GfxContext* pctx, Assets* assets) {
|
||||
|
||||
auto texture = assets->getTexture(this->texture);
|
||||
if (texture && autoresize) {
|
||||
setSize(glm::vec2(texture->width, texture->height));
|
||||
setSize(glm::vec2(texture->getWidth(), texture->getHeight()));
|
||||
}
|
||||
batch->texture(texture);
|
||||
batch->setColor(color);
|
||||
@ -383,7 +383,7 @@ void TextBox::draw(const GfxContext* pctx, Assets* assets) {
|
||||
glm::vec2 size = getSize();
|
||||
|
||||
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();
|
||||
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->flush();
|
||||
}
|
||||
|
||||
void TextBox::drawBackground(const GfxContext* pctx, Assets* assets) {
|
||||
|
||||
@ -481,18 +481,16 @@ void Hud::draw(const GfxContext& ctx){
|
||||
// Crosshair
|
||||
if (!pause && !inventoryOpen && !player->debug) {
|
||||
GfxContext chctx = ctx.sub();
|
||||
chctx.blendMode(blendmode::inversion);
|
||||
chctx.setBlendMode(blendmode::inversion);
|
||||
auto texture = assets->getTexture("gui/crosshair");
|
||||
batch->texture(texture);
|
||||
int chsizex = texture != nullptr ? texture->width : 16;
|
||||
int chsizey = texture != nullptr ? texture->height : 16;
|
||||
int chsizex = texture != nullptr ? texture->getWidth() : 16;
|
||||
int chsizey = texture != nullptr ? texture->getHeight() : 16;
|
||||
batch->rect(
|
||||
(width-chsizex)/2, (height-chsizey)/2,
|
||||
chsizex, chsizey, 0,0, 1,1, 1,1,1,1
|
||||
);
|
||||
batch->flush();
|
||||
}
|
||||
batch->flush();
|
||||
}
|
||||
|
||||
void Hud::updateElementsPosition(const Viewport& viewport) {
|
||||
|
||||
@ -19,7 +19,7 @@ Batch2D::Batch2D(size_t capacity) : capacity(capacity), color(1.0f){
|
||||
ubyte pixels[] = {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@ -19,20 +19,18 @@ Batch3D::Batch3D(size_t capacity)
|
||||
};
|
||||
|
||||
buffer = new float[capacity * B3D_VERTEX_SIZE];
|
||||
mesh = new Mesh(buffer, 0, attrs);
|
||||
mesh = std::make_unique<Mesh>(buffer, 0, attrs);
|
||||
index = 0;
|
||||
|
||||
ubyte pixels[] = {
|
||||
255, 255, 255, 255,
|
||||
};
|
||||
blank = new Texture(pixels, 1, 1, GL_RGBA);
|
||||
blank = std::make_unique<Texture>(pixels, 1, 1, ImageFormat::rgba8888);
|
||||
_texture = nullptr;
|
||||
}
|
||||
|
||||
Batch3D::~Batch3D(){
|
||||
delete blank;
|
||||
delete[] buffer;
|
||||
delete mesh;
|
||||
}
|
||||
|
||||
void Batch3D::begin(){
|
||||
|
||||
@ -1,21 +1,23 @@
|
||||
#ifndef GRAPHICS_BATCH3D_H_
|
||||
#define GRAPHICS_BATCH3D_H_
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <glm/glm.hpp>
|
||||
#include "UVRegion.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <memory>
|
||||
#include <stdlib.h>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
class Mesh;
|
||||
class Texture;
|
||||
|
||||
class Batch3D {
|
||||
float* buffer;
|
||||
size_t capacity;
|
||||
Mesh* mesh;
|
||||
std::unique_ptr<Mesh> mesh;
|
||||
std::unique_ptr<Texture> blank;
|
||||
size_t index;
|
||||
|
||||
Texture* blank;
|
||||
|
||||
Texture* _texture;
|
||||
|
||||
void vertex(float x, float y, float z,
|
||||
|
||||
39
src/graphics/Cubemap.cpp
Normal file
39
src/graphics/Cubemap.cpp
Normal 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
src/graphics/Cubemap.h
Normal file
15
src/graphics/Cubemap.h
Normal 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_
|
||||
@ -3,38 +3,75 @@
|
||||
#include <GL/glew.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)
|
||||
: width(width), height(height) {
|
||||
glGenFramebuffers(1, &fbo);
|
||||
bind();
|
||||
GLuint tex;
|
||||
glGenTextures(1, &tex);
|
||||
glBindTexture(GL_TEXTURE_2D, tex);
|
||||
GLuint format = alpha ? GL_RGBA : GL_RGB;
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, nullptr);
|
||||
: width(width), height(height)
|
||||
{
|
||||
glGenFramebuffers(1, &fbo);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
|
||||
// Setup color attachment (texture)
|
||||
GLuint tex;
|
||||
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_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, 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);
|
||||
texture = new Texture(tex, width, height);
|
||||
texture = std::make_unique<Texture>(tex, width, height);
|
||||
|
||||
// Setup depth attachment
|
||||
glGenRenderbuffers(1, &depth);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, depth);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth);
|
||||
unbind();
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
Framebuffer::~Framebuffer() {
|
||||
delete texture;
|
||||
glDeleteFramebuffers(1, &fbo);
|
||||
glDeleteFramebuffers(1, &fbo);
|
||||
glDeleteRenderbuffers(1, &depth);
|
||||
}
|
||||
|
||||
void Framebuffer::bind() {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -3,20 +3,40 @@
|
||||
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
class Texture;
|
||||
|
||||
class Framebuffer {
|
||||
uint fbo;
|
||||
uint depth;
|
||||
uint fbo;
|
||||
uint depth;
|
||||
uint width;
|
||||
uint height;
|
||||
uint format;
|
||||
std::unique_ptr<Texture> texture;
|
||||
public:
|
||||
uint width;
|
||||
uint height;
|
||||
Texture* texture;
|
||||
Framebuffer(uint width, uint height, bool alpha=false);
|
||||
~Framebuffer();
|
||||
Framebuffer(uint fbo, uint depth, std::unique_ptr<Texture> texture);
|
||||
Framebuffer(uint width, uint height, bool alpha=false);
|
||||
~Framebuffer();
|
||||
|
||||
void bind();
|
||||
void unbind();
|
||||
/// @brief Use framebuffer
|
||||
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_ */
|
||||
|
||||
@ -3,10 +3,16 @@
|
||||
#include <GL/glew.h>
|
||||
|
||||
#include "Batch2D.h"
|
||||
#include "Framebuffer.h"
|
||||
|
||||
GfxContext::GfxContext(const GfxContext* parent, Viewport& viewport, Batch2D* g2d)
|
||||
: parent(parent), viewport(viewport), g2d(g2d) {
|
||||
}
|
||||
GfxContext::GfxContext(
|
||||
const GfxContext* parent,
|
||||
const Viewport& viewport,
|
||||
Batch2D* g2d
|
||||
) : parent(parent),
|
||||
viewport(viewport),
|
||||
g2d(g2d)
|
||||
{}
|
||||
|
||||
GfxContext::~GfxContext() {
|
||||
while (scissorsCount--) {
|
||||
@ -15,20 +21,39 @@ GfxContext::~GfxContext() {
|
||||
|
||||
if (parent == nullptr)
|
||||
return;
|
||||
|
||||
if (depthMask_ != parent->depthMask_) {
|
||||
glDepthMask(parent->depthMask_);
|
||||
|
||||
if (g2d) {
|
||||
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);
|
||||
}
|
||||
if (cullFace_ != parent->cullFace_) {
|
||||
if (cullFace_) glDisable(GL_CULL_FACE);
|
||||
if (cullFace != parent->cullFace) {
|
||||
if (cullFace) glDisable(GL_CULL_FACE);
|
||||
else glEnable(GL_CULL_FACE);
|
||||
}
|
||||
if (blendMode_ != parent->blendMode_) {
|
||||
Window::setBlendMode(parent->blendMode_);
|
||||
if (blendMode != parent->blendMode) {
|
||||
Window::setBlendMode(parent->blendMode);
|
||||
}
|
||||
}
|
||||
|
||||
@ -42,22 +67,40 @@ Batch2D* GfxContext::getBatch2D() const {
|
||||
|
||||
GfxContext GfxContext::sub() const {
|
||||
auto ctx = GfxContext(this, viewport, g2d);
|
||||
ctx.depthTest_ = depthTest_;
|
||||
ctx.cullFace_ = cullFace_;
|
||||
ctx.depthTest = depthTest;
|
||||
ctx.cullFace = cullFace;
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void GfxContext::depthMask(bool flag) {
|
||||
if (depthMask_ == flag)
|
||||
void GfxContext::setViewport(const Viewport& viewport) {
|
||||
this->viewport = viewport;
|
||||
Window::viewport(
|
||||
0, 0,
|
||||
viewport.getWidth(),
|
||||
viewport.getHeight()
|
||||
);
|
||||
}
|
||||
|
||||
void GfxContext::setFramebuffer(Framebuffer* fbo) {
|
||||
if (this->fbo == fbo)
|
||||
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);
|
||||
}
|
||||
|
||||
void GfxContext::depthTest(bool flag) {
|
||||
if (depthTest_ == flag)
|
||||
void GfxContext::setDepthTest(bool flag) {
|
||||
if (depthTest == flag)
|
||||
return;
|
||||
depthTest_ = flag;
|
||||
depthTest = flag;
|
||||
if (flag) {
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
} else {
|
||||
@ -65,10 +108,10 @@ void GfxContext::depthTest(bool flag) {
|
||||
}
|
||||
}
|
||||
|
||||
void GfxContext::cullFace(bool flag) {
|
||||
if (cullFace_ == flag)
|
||||
void GfxContext::setCullFace(bool flag) {
|
||||
if (cullFace == flag)
|
||||
return;
|
||||
cullFace_ = flag;
|
||||
cullFace = flag;
|
||||
if (flag) {
|
||||
glEnable(GL_CULL_FACE);
|
||||
} else {
|
||||
@ -76,14 +119,14 @@ void GfxContext::cullFace(bool flag) {
|
||||
}
|
||||
}
|
||||
|
||||
void GfxContext::blendMode(blendmode mode) {
|
||||
if (blendMode_ == mode)
|
||||
void GfxContext::setBlendMode(blendmode mode) {
|
||||
if (blendMode == mode)
|
||||
return;
|
||||
blendMode_ = mode;
|
||||
blendMode = mode;
|
||||
Window::setBlendMode(mode);
|
||||
}
|
||||
|
||||
void GfxContext::scissors(glm::vec4 area) {
|
||||
void GfxContext::setScissors(glm::vec4 area) {
|
||||
Window::pushScissor(area);
|
||||
scissorsCount++;
|
||||
}
|
||||
|
||||
@ -6,29 +6,33 @@
|
||||
#include "../window/Window.h"
|
||||
|
||||
class Batch2D;
|
||||
class Framebuffer;
|
||||
|
||||
class GfxContext {
|
||||
const GfxContext* parent;
|
||||
Viewport& viewport;
|
||||
Viewport viewport;
|
||||
Batch2D* const g2d;
|
||||
bool depthMask_ = true;
|
||||
bool depthTest_ = false;
|
||||
bool cullFace_ = false;
|
||||
blendmode blendMode_ = blendmode::normal;
|
||||
Framebuffer* fbo = nullptr;
|
||||
bool depthMask = true;
|
||||
bool depthTest = false;
|
||||
bool cullFace = false;
|
||||
blendmode blendMode = blendmode::normal;
|
||||
int scissorsCount = 0;
|
||||
public:
|
||||
GfxContext(const GfxContext* parent, Viewport& viewport, Batch2D* g2d);
|
||||
GfxContext(const GfxContext* parent, const Viewport& viewport, Batch2D* g2d);
|
||||
~GfxContext();
|
||||
|
||||
Batch2D* getBatch2D() const;
|
||||
const Viewport& getViewport() const;
|
||||
GfxContext sub() const;
|
||||
|
||||
void depthMask(bool flag);
|
||||
void depthTest(bool flag);
|
||||
void cullFace(bool flag);
|
||||
void blendMode(blendmode mode);
|
||||
void scissors(glm::vec4 area);
|
||||
void setViewport(const Viewport& viewport);
|
||||
void setFramebuffer(Framebuffer* fbo);
|
||||
void setDepthMask(bool flag);
|
||||
void setDepthTest(bool flag);
|
||||
void setCullFace(bool flag);
|
||||
void setBlendMode(blendmode mode);
|
||||
void setScissors(glm::vec4 area);
|
||||
};
|
||||
|
||||
#endif // GRAPHICS_GFX_CONTEXT_H_
|
||||
@ -21,10 +21,21 @@ public:
|
||||
Mesh(vertexBuffer, vertices, nullptr, 0, attrs) {};
|
||||
~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);
|
||||
|
||||
/// @brief Draw mesh with specified primitives type
|
||||
/// @param primitive primitives type
|
||||
void draw(unsigned int primitive);
|
||||
|
||||
/// @brief Draw mesh as triangles
|
||||
void draw();
|
||||
|
||||
/// @brief Total numbers of alive mesh objects
|
||||
static int meshesCount;
|
||||
};
|
||||
|
||||
|
||||
42
src/graphics/PostProcessing.cpp
Normal file
42
src/graphics/PostProcessing.cpp
Normal 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
src/graphics/PostProcessing.h
Normal file
37
src/graphics/PostProcessing.h
Normal 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_
|
||||
@ -52,6 +52,11 @@ void Shader::uniform2f(std::string name, glm::vec2 xy){
|
||||
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){
|
||||
GLuint transformLoc = glGetUniformLocation(id, name.c_str());
|
||||
glUniform3f(transformLoc, x,y,z);
|
||||
|
||||
@ -3,13 +3,14 @@
|
||||
|
||||
#include <string>
|
||||
#include <glm/glm.hpp>
|
||||
#include "../typedefs.h"
|
||||
|
||||
class GLSLExtension;
|
||||
|
||||
class Shader {
|
||||
uint id;
|
||||
public:
|
||||
static GLSLExtension* preprocessor;
|
||||
unsigned int id;
|
||||
|
||||
Shader(unsigned int id);
|
||||
~Shader();
|
||||
@ -20,6 +21,7 @@ public:
|
||||
void uniform1f(std::string name, float x);
|
||||
void uniform2f(std::string name, float x, float y);
|
||||
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, glm::vec3 xyz);
|
||||
|
||||
|
||||
@ -4,18 +4,23 @@
|
||||
#include <memory>
|
||||
|
||||
#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) {
|
||||
}
|
||||
|
||||
Texture::Texture(ubyte* data, int width, int height, uint format)
|
||||
Texture::Texture(ubyte* data, uint width, uint height, ImageFormat imageFormat)
|
||||
: width(width), height(height) {
|
||||
glGenTextures(1, &id);
|
||||
glBindTexture(GL_TEXTURE_2D, id);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
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_MAG_FILTER, GL_NEAREST);
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
@ -31,6 +36,10 @@ void Texture::bind(){
|
||||
glBindTexture(GL_TEXTURE_2D, id);
|
||||
}
|
||||
|
||||
void Texture::unbind() {
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
void Texture::reload(ubyte* data){
|
||||
glBindTexture(GL_TEXTURE_2D, id);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
|
||||
@ -56,13 +65,18 @@ void Texture::setNearestFilter() {
|
||||
Texture* Texture::from(const ImageData* image) {
|
||||
uint width = image->getWidth();
|
||||
uint height = image->getHeight();
|
||||
uint format;
|
||||
const void* data = image->getData();
|
||||
switch (image->getFormat()) {
|
||||
case ImageFormat::rgb888: format = GL_RGB; break;
|
||||
case ImageFormat::rgba8888: format = GL_RGBA; break;
|
||||
default:
|
||||
throw std::runtime_error("unsupported image data format");
|
||||
}
|
||||
return new Texture((ubyte*)data, width, height, format);
|
||||
return new Texture((ubyte*)data, width, height, image->getFormat());
|
||||
}
|
||||
|
||||
uint Texture::getWidth() const {
|
||||
return width;
|
||||
}
|
||||
|
||||
uint Texture::getHeight() const {
|
||||
return height;
|
||||
}
|
||||
|
||||
uint Texture::getId() const {
|
||||
return id;
|
||||
}
|
||||
|
||||
@ -3,24 +3,30 @@
|
||||
|
||||
#include <string>
|
||||
#include "../typedefs.h"
|
||||
|
||||
class ImageData;
|
||||
#include "ImageData.h"
|
||||
|
||||
class Texture {
|
||||
public:
|
||||
protected:
|
||||
uint id;
|
||||
int width;
|
||||
int height;
|
||||
Texture(uint id, int width, int height);
|
||||
Texture(ubyte* data, int width, int height, uint format);
|
||||
~Texture();
|
||||
uint width;
|
||||
uint height;
|
||||
public:
|
||||
Texture(uint id, uint width, uint height);
|
||||
Texture(ubyte* data, uint width, uint height, ImageFormat format);
|
||||
virtual ~Texture();
|
||||
|
||||
void bind();
|
||||
void reload(ubyte* data);
|
||||
virtual void bind();
|
||||
virtual void unbind();
|
||||
virtual void reload(ubyte* data);
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
@ -35,19 +35,23 @@ void TextureAnimator::update(float delta) {
|
||||
frame = elem.frames[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);
|
||||
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);
|
||||
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_DRAW_FRAMEBUFFER, fboD);
|
||||
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
|
||||
const int ext = 2;
|
||||
|
||||
@ -14,8 +14,8 @@ public:
|
||||
virtual uint getWidth() const;
|
||||
virtual uint getHeight() const;
|
||||
|
||||
glm::vec2 size() const {
|
||||
return glm::vec2(width, height);
|
||||
glm::ivec2 size() const {
|
||||
return glm::ivec2(width, height);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
19
src/graphics/gl_util.h
Normal file
19
src/graphics/gl_util.h
Normal 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_
|
||||
@ -3,83 +3,86 @@
|
||||
#include <algorithm>
|
||||
|
||||
inline int getPackerScore(rectangle& rect) {
|
||||
if (rect.width * rect.height > 100)
|
||||
return rect.height * rect.height * 1000;
|
||||
return (rect.width * rect.height * rect.height);
|
||||
if (rect.width * rect.height > 100)
|
||||
return rect.height * rect.height * 1000;
|
||||
return (rect.width * rect.height * rect.height);
|
||||
}
|
||||
|
||||
LMPacker::LMPacker(const uint32_t sizes[], size_t length) {
|
||||
for (unsigned int i = 0; i < length/2; i++) {
|
||||
rectangle rect(i, 0, 0, (int)sizes[i * 2], (int)sizes[i * 2 + 1]);
|
||||
rects.push_back(rect);
|
||||
}
|
||||
sort(rects.begin(), rects.end(), [](rectangle a, rectangle b) {
|
||||
return -getPackerScore(a) < -getPackerScore(b);
|
||||
});
|
||||
for (unsigned int i = 0; i < length/2; i++) {
|
||||
rectangle rect(i, 0, 0, (int)sizes[i * 2], (int)sizes[i * 2 + 1]);
|
||||
rects.push_back(rect);
|
||||
}
|
||||
sort(rects.begin(), rects.end(), [](rectangle a, rectangle b) {
|
||||
return -getPackerScore(a) < -getPackerScore(b);
|
||||
});
|
||||
}
|
||||
|
||||
LMPacker::~LMPacker() {
|
||||
if (matrix) {
|
||||
for (unsigned int y = 0; y < (height >> mbit); y++) {
|
||||
delete[] matrix[y];
|
||||
}
|
||||
delete[] matrix;
|
||||
}
|
||||
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,
|
||||
uint16_t extension, uint32_t mbit, uint32_t vstep) {
|
||||
cleanup();
|
||||
this->mbit = mbit;
|
||||
this->width = width;
|
||||
this->height = height;
|
||||
int mpix = 1 << mbit;
|
||||
cleanup();
|
||||
this->mbit = mbit;
|
||||
this->width = width;
|
||||
this->height = height;
|
||||
int mpix = 1 << mbit;
|
||||
|
||||
const unsigned int mwidth = width >> mbit;
|
||||
const unsigned int mheight = height >> mbit;
|
||||
matrix = new rectangle**[mheight];
|
||||
for (unsigned int y = 0; y < mheight; y++) {
|
||||
matrix[y] = new rectangle*[mwidth];
|
||||
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);
|
||||
const unsigned int mwidth = width >> mbit;
|
||||
const unsigned int mheight = height >> mbit;
|
||||
|
||||
matrix = new rectangle**[mheight];
|
||||
for (unsigned int y = 0; y < mheight; y++) {
|
||||
matrix[y] = new rectangle*[mwidth];
|
||||
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);
|
||||
rect.width += extension * 2;
|
||||
rect.height += extension * 2;
|
||||
if (mpix > 1) {
|
||||
if (rect.width % mpix > 0) {
|
||||
rect.extX = mpix - (rect.width % mpix);
|
||||
}
|
||||
if (rect.height % mpix > 0) {
|
||||
rect.extY = mpix - (rect.height % mpix);
|
||||
}
|
||||
}
|
||||
rect.width += rect.extX;
|
||||
rect.height += rect.extY;
|
||||
}
|
||||
bool built = true;
|
||||
for (unsigned int i = 0; i < rects.size(); i++) {
|
||||
rectangle* rect = &rects[i];
|
||||
if (!place(rect, vstep)) {
|
||||
built = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (unsigned int i = 0; i < rects.size(); i++) {
|
||||
rectangle& rect = rects[i];
|
||||
if (rect.width % mpix > 0) {
|
||||
rect.extX = mpix - (rect.width % mpix);
|
||||
}
|
||||
if (rect.height % mpix > 0) {
|
||||
rect.extY = mpix - (rect.height % mpix);
|
||||
}
|
||||
}
|
||||
rect.width += rect.extX;
|
||||
rect.height += rect.extY;
|
||||
}
|
||||
bool built = true;
|
||||
for (unsigned int i = 0; i < rects.size(); i++) {
|
||||
rectangle* rect = &rects[i];
|
||||
if (!place(rect, vstep)) {
|
||||
built = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (unsigned int i = 0; i < rects.size(); i++) {
|
||||
rectangle& rect = rects[i];
|
||||
rect.x += extension;
|
||||
rect.y += extension;
|
||||
rect.width -= extension * 2 + rect.extX;
|
||||
rect.height -= extension * 2 + rect.extY;
|
||||
}
|
||||
return built;
|
||||
}
|
||||
return built;
|
||||
}
|
||||
|
||||
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) {
|
||||
rectangle& rect = *rectptr;
|
||||
const unsigned int rw = rect.width >> mbit;
|
||||
const unsigned int rh = rect.height >> mbit;
|
||||
if (vstep > 1) {
|
||||
vstep = (vstep > rh ? vstep : rh);
|
||||
}
|
||||
const unsigned int mwidth = width >> mbit;
|
||||
const unsigned int mheight = height >> mbit;
|
||||
for (unsigned int y = 0; y + rh < mheight; y += vstep) {
|
||||
rectangle** line = matrix[y];
|
||||
bool skiplines = true;
|
||||
rectangle** lower = matrix[y + rh - 1];
|
||||
for (unsigned int x = 0; x + rw < mwidth; x++) {
|
||||
rectangle* prect = line[x];
|
||||
if (prect) {
|
||||
x = (prect->x >> mbit) + (prect->width >> mbit) - 1;
|
||||
} else {
|
||||
if (skiplines) {
|
||||
unsigned int lfree = 0;
|
||||
while (lfree + x < mwidth && !lower[x + lfree] && lfree < rw) {
|
||||
lfree++;
|
||||
}
|
||||
if (lfree >= rw)
|
||||
skiplines = false;
|
||||
}
|
||||
prect = findCollision(matrix, x, y, rw, rh);
|
||||
if (prect) {
|
||||
x = (prect->x >> mbit) + (prect->width >> mbit) - 1;
|
||||
continue;
|
||||
}
|
||||
fill(matrix, rectptr, x, y, rw, rh);
|
||||
rectangle& rect = *rectptr;
|
||||
const unsigned int rw = rect.width >> mbit;
|
||||
const unsigned int rh = rect.height >> mbit;
|
||||
if (vstep > 1) {
|
||||
vstep = (vstep > rh ? vstep : rh);
|
||||
}
|
||||
const unsigned int mwidth = width >> mbit;
|
||||
const unsigned int mheight = height >> mbit;
|
||||
for (unsigned int y = 0; y + rh < mheight; y += vstep) {
|
||||
rectangle** line = matrix[y];
|
||||
bool skiplines = true;
|
||||
rectangle** lower = matrix[y + rh - 1];
|
||||
for (unsigned int x = 0; x + rw < mwidth; x++) {
|
||||
rectangle* prect = line[x];
|
||||
if (prect) {
|
||||
x = (prect->x >> mbit) + (prect->width >> mbit) - 1;
|
||||
} else {
|
||||
if (skiplines) {
|
||||
unsigned int lfree = 0;
|
||||
while (lfree + x < mwidth && !lower[x + lfree] && lfree < rw) {
|
||||
lfree++;
|
||||
}
|
||||
if (lfree >= rw)
|
||||
skiplines = false;
|
||||
}
|
||||
prect = findCollision(matrix, x, y, rw, rh);
|
||||
if (prect) {
|
||||
x = (prect->x >> mbit) + (prect->width >> mbit) - 1;
|
||||
continue;
|
||||
}
|
||||
fill(matrix, rectptr, x, y, rw, rh);
|
||||
rectptr->x = x << mbit;
|
||||
rectptr->y = y << mbit;
|
||||
placed.push_back(rectptr);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (skiplines) {
|
||||
y += rh - vstep;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (skiplines) {
|
||||
y += rh - vstep;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -10,44 +10,44 @@
|
||||
#include <vector>
|
||||
|
||||
struct rectangle {
|
||||
unsigned int idx;
|
||||
int x;
|
||||
int y;
|
||||
int width;
|
||||
int height;
|
||||
int extX = 0;
|
||||
int extY = 0;
|
||||
unsigned int idx;
|
||||
int x;
|
||||
int y;
|
||||
int width;
|
||||
int height;
|
||||
int extX = 0;
|
||||
int extY = 0;
|
||||
|
||||
rectangle(unsigned int idx, int x, int y, int width, int height)
|
||||
: idx(idx), x(x), y(y), width(width), height(height){
|
||||
}
|
||||
rectangle(unsigned int idx, int x, int y, int width, int height)
|
||||
: idx(idx), x(x), y(y), width(width), height(height){
|
||||
}
|
||||
};
|
||||
|
||||
class LMPacker {
|
||||
std::vector<rectangle> rects;
|
||||
std::vector<rectangle*> placed;
|
||||
uint32_t width = 0;
|
||||
uint32_t height = 0;
|
||||
rectangle*** matrix = nullptr;
|
||||
uint32_t mbit = 0;
|
||||
std::vector<rectangle> rects;
|
||||
std::vector<rectangle*> placed;
|
||||
uint32_t width = 0;
|
||||
uint32_t height = 0;
|
||||
rectangle*** matrix = nullptr;
|
||||
uint32_t mbit = 0;
|
||||
|
||||
void cleanup();
|
||||
bool place(rectangle* rect, uint32_t vstep);
|
||||
void cleanup();
|
||||
bool place(rectangle* rect, uint32_t vstep);
|
||||
public:
|
||||
LMPacker(const uint32_t sizes[], size_t length);
|
||||
virtual ~LMPacker();
|
||||
LMPacker(const uint32_t sizes[], size_t length);
|
||||
virtual ~LMPacker();
|
||||
|
||||
bool buildCompact(uint32_t width, uint32_t height, uint16_t extension) {
|
||||
return build(width, height, extension, 0, 1);
|
||||
}
|
||||
bool buildFast(uint32_t width, uint32_t height, uint16_t extension) {
|
||||
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 buildCompact(uint32_t width, uint32_t height, uint16_t extension) {
|
||||
return build(width, height, extension, 0, 1);
|
||||
}
|
||||
bool buildFast(uint32_t width, uint32_t height, uint16_t extension) {
|
||||
return build(width, height, extension, 1, 2);
|
||||
}
|
||||
bool build(uint32_t width, uint32_t height, uint16_t extension, uint32_t mbit, uint32_t vstep);
|
||||
|
||||
std::vector<rectangle> getResult() {
|
||||
return rects;
|
||||
}
|
||||
std::vector<rectangle> getResult() {
|
||||
return rects;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* LMPACKER_H_ */
|
||||
Loading…
x
Reference in New Issue
Block a user