assets-related refactor

This commit is contained in:
MihailRis 2024-04-10 17:44:17 +03:00
parent 216e38e411
commit befc9cf09c
14 changed files with 242 additions and 202 deletions

View File

@ -5,6 +5,7 @@
#include <string>
#include <memory>
#include <functional>
#include <unordered_map>
#include <vector>
@ -12,12 +13,18 @@ class Texture;
class Shader;
class Font;
class Atlas;
class Assets;
class UiDocument;
namespace audio {
class Sound;
}
namespace assetload {
/// @brief final work to do in the main thread
using postfunc = std::function<void(Assets*)>;
}
class Assets {
std::unordered_map<std::string, std::shared_ptr<Texture>> textures;
std::unordered_map<std::string, std::shared_ptr<Shader>> shaders;

View File

@ -49,9 +49,16 @@ bool AssetsLoader::loadNext() {
return false;
}
aloader_func loader = found->second;
bool status = loader(*this, assets, paths, entry.filename, entry.alias, entry.config);
entries.pop();
return status;
try {
auto postfunc = loader(*this, assets, paths, entry.filename, entry.alias, entry.config);
postfunc(assets);
entries.pop();
return true;
} catch (std::runtime_error& err) {
logger.error() << err.what();
entries.pop();
return false;
}
}
void addLayouts(int env, const std::string& prefix, const fs::path& folder, AssetsLoader& loader) {

View File

@ -1,6 +1,8 @@
#ifndef ASSETS_ASSETS_LOADER_H
#define ASSETS_ASSETS_LOADER_H
#include "Assets.h"
#include <string>
#include <memory>
#include <filesystem>
@ -23,7 +25,6 @@ enum class AssetType {
};
class ResPaths;
class Assets;
class AssetsLoader;
class Content;
@ -43,7 +44,14 @@ struct SoundCfg : AssetCfg {
SoundCfg(bool keepPCM) : keepPCM(keepPCM) {}
};
using aloader_func = std::function<bool(AssetsLoader&, Assets*, const ResPaths*, const std::string&, const std::string&, std::shared_ptr<AssetCfg>)>;
using aloader_func = std::function<assetload::postfunc(
AssetsLoader&,
Assets*,
const ResPaths*,
const std::string&,
const std::string&,
std::shared_ptr<AssetCfg>)
>;
struct aloader_entry {
AssetType tag;

View File

@ -1,6 +1,7 @@
#include "assetload_funcs.h"
#include <iostream>
#include <stdexcept>
#include <filesystem>
#include "Assets.h"
#include "AssetsLoader.h"
@ -9,6 +10,7 @@
#include "../files/engine_paths.h"
#include "../coders/png.h"
#include "../coders/json.h"
#include "../coders/GLSLExtension.h"
#include "../graphics/core/Shader.h"
#include "../graphics/core/Texture.h"
#include "../graphics/core/ImageData.h"
@ -28,7 +30,7 @@ static bool animation(
Atlas* dstAtlas
);
bool assetload::texture(
assetload::postfunc assetload::texture(
AssetsLoader&,
Assets* assets,
const ResPaths* paths,
@ -36,18 +38,15 @@ bool assetload::texture(
const std::string name,
std::shared_ptr<AssetCfg>
) {
std::unique_ptr<Texture> texture(
png::load_texture(paths->find(filename+".png").u8string())
std::shared_ptr<ImageData> image (
png::load_image(paths->find(filename+".png").u8string())
);
if (texture == nullptr) {
std::cerr << "failed to load texture '" << name << "'" << std::endl;
return false;
}
assets->store(texture.release(), name);
return true;
return [name, image](auto assets) {
assets->store(Texture::from(image.get()), name);
};
}
bool assetload::shader(
assetload::postfunc assetload::shader(
AssetsLoader&,
Assets* assets,
const ResPaths* paths,
@ -61,18 +60,16 @@ bool assetload::shader(
std::string vertexSource = files::read_string(vertexFile);
std::string fragmentSource = files::read_string(fragmentFile);
Shader* shader = Shader::create(
vertexFile.string(),
fragmentFile.string(),
vertexSource, fragmentSource
);
vertexSource = Shader::preprocessor->process(vertexFile, vertexSource);
fragmentSource = Shader::preprocessor->process(fragmentFile, fragmentSource);
if (shader == nullptr) {
std::cerr << "failed to load shader '" << name << "'" << std::endl;
return false;
}
assets->store(shader, name);
return true;
return [=](auto assets) {
assets->store(Shader::create(
vertexFile.u8string(),
fragmentFile.u8string(),
vertexSource, fragmentSource
), name);
};
}
static bool appendAtlas(AtlasBuilder& atlas, const fs::path& file) {
@ -85,17 +82,13 @@ static bool appendAtlas(AtlasBuilder& atlas, const fs::path& file) {
return false;
}
std::unique_ptr<ImageData> image(png::load_image(file.string()));
if (image == nullptr) {
std::cerr << "could not to load " << file.string() << std::endl;
return false;
}
image->fixAlphaColor();
atlas.add(name, image.release());
return true;
}
bool assetload::atlas(
assetload::postfunc assetload::atlas(
AssetsLoader&,
Assets* assets,
const ResPaths* paths,
@ -105,17 +98,23 @@ bool assetload::atlas(
) {
AtlasBuilder builder;
for (const auto& file : paths->listdir(directory)) {
if (!appendAtlas(builder, file)) continue;
if (!appendAtlas(builder, file))
continue;
}
std::set<std::string> names = builder.getNames();
Atlas* atlas = builder.build(2);
assets->store(atlas, name);
for (const auto& file : builder.getNames()) {
animation(assets, paths, "textures", file, atlas);
}
return true;
return [=](auto assets) {
atlas->prepare();
assets->store(atlas, name);
// FIXME
for (const auto& file : names) {
animation(assets, paths, "textures", file, atlas);
}
};
}
bool assetload::font(
assetload::postfunc assetload::font(
AssetsLoader&,
Assets* assets,
const ResPaths* paths,
@ -123,25 +122,24 @@ bool assetload::font(
const std::string name,
std::shared_ptr<AssetCfg>
) {
std::vector<std::unique_ptr<Texture>> pages;
auto pages = std::make_shared<std::vector<std::unique_ptr<ImageData>>>();
for (size_t i = 0; i <= 4; i++) {
std::string name = filename + "_" + std::to_string(i) + ".png";
name = paths->find(name).string();
std::unique_ptr<Texture> texture (png::load_texture(name));
if (texture == nullptr) {
std::cerr << "failed to load bitmap font '" << name;
std::cerr << "' (missing page " << std::to_string(i) << ")";
std::cerr << std::endl;
return false;
}
pages.push_back(std::move(texture));
std::unique_ptr<ImageData> image (png::load_image(name));
pages->push_back(std::move(image));
}
int res = pages[0]->getHeight() / 16;
assets->store(new Font(std::move(pages), res, 4), name);
return true;
return [=](auto assets) {
int res = pages->at(0)->getHeight() / 16;
std::vector<std::unique_ptr<Texture>> textures;
for (auto& page : *pages) {
textures.emplace_back(Texture::from(page.get()));
}
assets->store(new Font(std::move(textures), res, 4), name);
};
}
bool assetload::layout(
assetload::postfunc assetload::layout(
AssetsLoader& loader,
Assets* assets,
const ResPaths* paths,
@ -149,18 +147,19 @@ bool assetload::layout(
const std::string name,
std::shared_ptr<AssetCfg> config
) {
try {
auto cfg = dynamic_cast<LayoutCfg*>(config.get());
auto document = UiDocument::read(cfg->env, name, file);
assets->store(document.release(), name);
return true;
} catch (const parsing_error& err) {
std::cerr << "failed to parse layout XML '" << file << "'" << std::endl;
std::cerr << err.errorLog() << std::endl;
return false;
}
return [=](auto assets) {
try {
auto cfg = dynamic_cast<LayoutCfg*>(config.get());
auto document = UiDocument::read(cfg->env, name, file);
assets->store(document.release(), name);
} catch (const parsing_error& err) {
throw std::runtime_error(
"failed to parse layout XML '"+file+"':\n"+err.errorLog()
);
}
};
}
bool assetload::sound(
assetload::postfunc assetload::sound(
AssetsLoader& loader,
Assets* assets,
const ResPaths* paths,
@ -172,37 +171,35 @@ bool assetload::sound(
bool keepPCM = cfg ? cfg->keepPCM : false;
std::string extension = ".ogg";
try {
std::unique_ptr<audio::Sound> baseSound = nullptr;
std::unique_ptr<audio::Sound> baseSound = nullptr;
// looking for 'sound_name' as base sound
auto soundFile = paths->find(file+extension);
if (fs::exists(soundFile)) {
baseSound.reset(audio::load_sound(soundFile, keepPCM));
}
// looking for 'sound_name_0' as base sound
auto variantFile = paths->find(file+"_0"+extension);
if (fs::exists(variantFile)) {
baseSound.reset(audio::load_sound(variantFile, keepPCM));
}
// loading sound variants
for (uint i = 1; ; i++) {
auto variantFile = paths->find(file+"_"+std::to_string(i)+extension);
if (!fs::exists(variantFile)) {
break;
}
baseSound->variants.emplace_back(audio::load_sound(variantFile, keepPCM));
}
assets->store(baseSound.release(), name);
}
catch (std::runtime_error& err) {
std::cerr << err.what() << std::endl;
return false;
// looking for 'sound_name' as base sound
auto soundFile = paths->find(file+extension);
if (fs::exists(soundFile)) {
baseSound.reset(audio::load_sound(soundFile, keepPCM));
}
return true;
// looking for 'sound_name_0' as base sound
auto variantFile = paths->find(file+"_0"+extension);
if (fs::exists(variantFile)) {
baseSound.reset(audio::load_sound(variantFile, keepPCM));
}
// loading sound variants
for (uint i = 1; ; i++) {
auto variantFile = paths->find(file+"_"+std::to_string(i)+extension);
if (!fs::exists(variantFile)) {
break;
}
baseSound->variants.emplace_back(audio::load_sound(variantFile, keepPCM));
}
auto sound = baseSound.release();
return [=](auto assets) {
assets->store(sound, name);
};
}
// TODO: integrate
static bool animation(
Assets* assets,
const ResPaths* paths,
@ -256,10 +253,12 @@ static bool animation(
}
if (!contains) continue;
}
if (!appendAtlas(builder, file)) continue;
if (!appendAtlas(builder, file))
continue;
}
std::unique_ptr<Atlas> srcAtlas (builder.build(2));
srcAtlas->prepare();
Texture* srcTex = srcAtlas->getTexture();
Texture* dstTex = dstAtlas->getTexture();

View File

@ -1,6 +1,8 @@
#ifndef ASSETS_ASSET_LOADERS_H_
#define ASSETS_ASSET_LOADERS_H_
#include "Assets.h"
#include <string>
#include <memory>
@ -12,7 +14,7 @@ struct AssetCfg;
/// @brief see AssetsLoader.h: aloader_func
namespace assetload {
bool texture(
postfunc texture(
AssetsLoader&,
Assets*,
const ResPaths* paths,
@ -20,7 +22,7 @@ namespace assetload {
const std::string name,
std::shared_ptr<AssetCfg> settings
);
bool shader(
postfunc shader(
AssetsLoader&,
Assets*,
const ResPaths* paths,
@ -28,7 +30,7 @@ namespace assetload {
const std::string name,
std::shared_ptr<AssetCfg> settings
);
bool atlas(
postfunc atlas(
AssetsLoader&,
Assets*,
const ResPaths* paths,
@ -36,7 +38,7 @@ namespace assetload {
const std::string name,
std::shared_ptr<AssetCfg> settings
);
bool font(
postfunc font(
AssetsLoader&,
Assets*,
const ResPaths* paths,
@ -44,7 +46,7 @@ namespace assetload {
const std::string name,
std::shared_ptr<AssetCfg> settings
);
bool layout(
postfunc layout(
AssetsLoader&,
Assets*,
const ResPaths* paths,
@ -53,7 +55,7 @@ namespace assetload {
std::shared_ptr<AssetCfg> settings
);
bool sound(
postfunc sound(
AssetsLoader&,
Assets*,
const ResPaths* paths,

View File

@ -81,7 +81,7 @@ inline void source_line(std::stringstream& ss, uint linenum) {
ss << "#line " << linenum << "\n";
}
const std::string GLSLExtension::process(const fs::path file, const std::string& source) {
const std::string GLSLExtension::process(const fs::path& file, const std::string& source) {
std::stringstream ss;
size_t pos = 0;
uint linenum = 1;

View File

@ -29,7 +29,10 @@ public:
bool hasHeader(const std::string& name) const;
bool hasDefine(const std::string& name) const;
const std::string process(const std::filesystem::path file, const std::string& source);
const std::string process(
const std::filesystem::path& file,
const std::string& source
);
};
#endif // CODERS_GLSL_EXTESION_H_

View File

@ -343,18 +343,13 @@ ImageData* _png_load(const char* file){
ImageData* png::load_image(std::string filename) {
ImageData* image (_png_load(filename.c_str()));
if (image == nullptr) {
std::cerr << "Could not load image " << filename << std::endl;
return nullptr;
throw std::runtime_error("could not load image "+filename);
}
return image;
}
Texture* png::load_texture(std::string filename) {
std::unique_ptr<ImageData> image (_png_load(filename.c_str()));
if (image == nullptr){
std::cerr << "Could not load texture " << filename << std::endl;
return nullptr;
}
std::unique_ptr<ImageData> image (load_image(filename));
auto texture = Texture::from(image.get());
texture->setNearestFilter();
return texture;
@ -362,4 +357,4 @@ Texture* png::load_texture(std::string filename) {
void png::write_image(std::string filename, const ImageData* image) {
_png_write(filename.c_str(), image->getWidth(), image->getHeight(), (const ubyte*)image->getData(), image->getFormat() == ImageFormat::rgba8888);
}
}

View File

@ -109,7 +109,12 @@ void menus::create_new_world_panel(Engine* engine) {
auto seedInput = std::make_shared<TextBox>(seedstr, glm::vec4(6.0f));
panel->add(seedInput);
generatorTypeButton = guiutil::gotoButton(langs::get(L"World generator", L"world") + (L": ") + util::str2wstr_utf8(translate_generator_id(menus::generatorID)), "world_generators", engine->getGUI()->getMenu());
generatorTypeButton = guiutil::gotoButton(
langs::get(L"World generator", L"world") + L": " +
util::str2wstr_utf8(translate_generator_id(menus::generatorID)),
"world_generators",
engine->getGUI()->getMenu()
);
panel->add(generatorTypeButton);
panel->add(menus::create_button(L"Create World", glm::vec4(10), glm::vec4(1, 20, 1, 1),
@ -153,7 +158,7 @@ void menus::create_new_world_panel(Engine* engine) {
engine->getContent(),
engine->getContentPacks()
);
level->world->wfile->createDirectories();
level->getWorld()->wfile->createDirectories();
menus::generatorID = WorldGenerators::getDefaultGeneratorID();
engine->setScreen(std::make_shared<LevelScreen>(engine, level));
}));

View File

@ -6,7 +6,7 @@
#include "ImageData.h"
Atlas::Atlas(ImageData* image, std::unordered_map<std::string, UVRegion> regions)
: texture(Texture::from(image)),
: texture(nullptr),
image(image),
regions(regions) {
}
@ -14,6 +14,10 @@ Atlas::Atlas(ImageData* image, std::unordered_map<std::string, UVRegion> regions
Atlas::~Atlas() {
}
void Atlas::prepare() {
texture.reset(Texture::from(image.get()));
}
bool Atlas::has(const std::string& name) const {
return regions.find(name) != regions.end();
}
@ -80,8 +84,9 @@ Atlas* AtlasBuilder::build(uint extrusion, uint maxResolution) {
}
float unitX = 1.0f / width;
float unitY = 1.0f / height;
regions[entry.name] = UVRegion(unitX * x, unitY * y,
unitX * (x + w), unitY * (y + h));
regions[entry.name] = UVRegion(
unitX * x, unitY * y, unitX * (x + w), unitY * (y + h)
);
}
return new Atlas(canvas.release(), regions);
}

View File

@ -20,6 +20,8 @@ public:
Atlas(ImageData* image, std::unordered_map<std::string, UVRegion> regions);
~Atlas();
void prepare();
bool has(const std::string& name) const;
const UVRegion& get(const std::string& name) const;
@ -27,7 +29,6 @@ public:
ImageData* getImage() const;
};
struct atlasentry {
std::string name;
std::shared_ptr<ImageData> image;

View File

@ -17,7 +17,7 @@ namespace fs = std::filesystem;
GLSLExtension* Shader::preprocessor = new GLSLExtension();
Shader::Shader(unsigned int id) : id(id){
Shader::Shader(uint id) : id(id){
}
Shader::~Shader(){
@ -28,106 +28,101 @@ void Shader::use(){
glUseProgram(id);
}
void Shader::uniformMatrix(std::string name, glm::mat4 matrix){
GLuint transformLoc = glGetUniformLocation(id, name.c_str());
glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(matrix));
uint Shader::getUniformLocation(const std::string& name) {
auto found = uniformLocations.find(name);
if (found == uniformLocations.end()) {
uint location = glGetUniformLocation(id, name.c_str());
uniformLocations.emplace(name, location);
return location;
}
return found->second;
}
void Shader::uniform1i(std::string name, int x){
GLuint transformLoc = glGetUniformLocation(id, name.c_str());
glUniform1i(transformLoc, x);
void Shader::uniformMatrix(const std::string& name, glm::mat4 matrix){
glUniformMatrix4fv(getUniformLocation(name), 1, GL_FALSE, glm::value_ptr(matrix));
}
void Shader::uniform1f(std::string name, float x){
GLuint transformLoc = glGetUniformLocation(id, name.c_str());
glUniform1f(transformLoc, x);
void Shader::uniform1i(const std::string& name, int x){
glUniform1i(getUniformLocation(name), x);
}
void Shader::uniform2f(std::string name, float x, float y){
GLuint transformLoc = glGetUniformLocation(id, name.c_str());
glUniform2f(transformLoc, x, y);
void Shader::uniform1f(const std::string& name, float x){
glUniform1f(getUniformLocation(name), x);
}
void Shader::uniform2f(std::string name, glm::vec2 xy){
GLuint transformLoc = glGetUniformLocation(id, name.c_str());
glUniform2f(transformLoc, xy.x, xy.y);
void Shader::uniform2f(const std::string& name, float x, float y){
glUniform2f(getUniformLocation(name), x, 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::uniform2f(const std::string& name, glm::vec2 xy){
glUniform2f(getUniformLocation(name), 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);
void Shader::uniform2i(const std::string& name, glm::ivec2 xy){
glUniform2i(getUniformLocation(name), xy.x, xy.y);
}
void Shader::uniform3f(std::string name, glm::vec3 xyz){
GLuint transformLoc = glGetUniformLocation(id, name.c_str());
glUniform3f(transformLoc, xyz.x, xyz.y, xyz.z);
void Shader::uniform3f(const std::string& name, float x, float y, float z){
glUniform3f(getUniformLocation(name), x,y,z);
}
void Shader::uniform3f(const std::string& name, glm::vec3 xyz){
glUniform3f(getUniformLocation(name), xyz.x, xyz.y, xyz.z);
}
inline auto shader_deleter = [](GLuint* shader) {
glDeleteShader(*shader);
};
inline const uint GL_LOG_LEN = 512;
// shader should be deleted after shader program linking
using glshader = std::unique_ptr<GLuint, decltype(shader_deleter)>;
glshader compile_shader(GLenum type, const GLchar* source, const std::string& file) {
GLint success;
GLuint shader = glCreateShader(type);
glShaderSource(shader, 1, &source, nullptr);
glCompileShader(shader);
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success){
GLchar infoLog[GL_LOG_LEN];
glGetShaderInfoLog(shader, GL_LOG_LEN, nullptr, infoLog);
glDeleteShader(shader);
throw std::runtime_error(
"vertex shader compilation failed ("+file+"):\n"+std::string(infoLog)
);
}
return glshader(new GLuint(shader), shader_deleter);
}
Shader* Shader::create(
std::string vertexFile,
std::string fragmentFile,
std::string vertexCode,
std::string fragmentCode
const std::string& vertexFile,
const std::string& fragmentFile,
const std::string& vertexCode,
const std::string& fragmentCode
) {
vertexCode = preprocessor->process(fs::path(vertexFile), vertexCode);
fragmentCode = preprocessor->process(fs::path(fragmentFile), fragmentCode);
const GLchar* vCode = vertexCode.c_str();
const GLchar* fCode = fragmentCode.c_str();
const GLchar* vShaderCode = vertexCode.c_str();
const GLchar* fShaderCode = fragmentCode.c_str();
GLuint vertex, fragment;
GLint success;
GLchar infoLog[512];
// Vertex Shader
vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, 1, &vShaderCode, nullptr);
glCompileShader(vertex);
glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
if (!success){
glGetShaderInfoLog(vertex, 512, nullptr, infoLog);
std::cerr << "SHADER::VERTEX: compilation failed: " << vertexFile << std::endl;
std::cerr << infoLog << std::endl;
return nullptr;
}
// Fragment Shader
fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment, 1, &fShaderCode, nullptr);
glCompileShader(fragment);
glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);
if (!success){
glGetShaderInfoLog(fragment, 512, nullptr, infoLog);
std::cerr << "SHADER::FRAGMENT: compilation failed: " << vertexFile << std::endl;
std::cerr << infoLog << std::endl;
return nullptr;
}
glshader vertex = compile_shader(GL_VERTEX_SHADER, vCode, vertexFile);
glshader fragment = compile_shader(GL_FRAGMENT_SHADER, fCode, fragmentFile);
// Shader Program
GLint success;
GLuint id = glCreateProgram();
glAttachShader(id, vertex);
glAttachShader(id, fragment);
glAttachShader(id, *vertex);
glAttachShader(id, *fragment);
glLinkProgram(id);
glGetProgramiv(id, GL_LINK_STATUS, &success);
if (!success){
glGetProgramInfoLog(id, 512, nullptr, infoLog);
std::cerr << "SHADER::PROGRAM: linking failed" << std::endl;
std::cerr << infoLog << std::endl;
glDeleteShader(vertex);
glDeleteShader(fragment);
return nullptr;
GLchar infoLog[GL_LOG_LEN];
glGetProgramInfoLog(id, GL_LOG_LEN, nullptr, infoLog);
throw std::runtime_error(
"shader program linking failed:\n"+std::string(infoLog)
);
}
glDeleteShader(vertex);
glDeleteShader(fragment);
return new Shader(id);
}

View File

@ -1,35 +1,46 @@
#ifndef GRAPHICS_CORE_SHADER_H_
#define GRAPHICS_CORE_SHADER_H_
#include <string>
#include <glm/glm.hpp>
#include "../../typedefs.h"
#include <string>
#include <unordered_map>
#include <glm/glm.hpp>
class GLSLExtension;
class Shader {
uint id;
std::unordered_map<std::string, uint> uniformLocations;
uint getUniformLocation(const std::string& name);
public:
static GLSLExtension* preprocessor;
Shader(unsigned int id);
Shader(uint id);
~Shader();
void use();
void uniformMatrix(std::string name, glm::mat4 matrix);
void uniform1i(std::string name, int x);
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);
void uniformMatrix(const std::string&, glm::mat4 matrix);
void uniform1i(const std::string& name, int x);
void uniform1f(const std::string& name, float x);
void uniform2f(const std::string& name, float x, float y);
void uniform2f(const std::string& name, glm::vec2 xy);
void uniform2i(const std::string& name, glm::ivec2 xy);
void uniform3f(const std::string& name, float x, float y, float z);
void uniform3f(const std::string& name, glm::vec3 xyz);
/// @brief Create shader program using vertex and fragment shaders source.
/// @param vertexFile vertex shader file name
/// @param fragmentFile fragment shader file name
/// @param vertexSource vertex shader source code
/// @param fragmentSource fragment shader source code
/// @return linked shader program containing vertex and fragment shaders
static Shader* create(
std::string vertexFile,
std::string fragmentFile,
std::string vertexSource,
std::string fragmentSource
const std::string& vertexFile,
const std::string& fragmentFile,
const std::string& vertexSource,
const std::string& fragmentSource
);
};

View File

@ -142,5 +142,7 @@ std::unique_ptr<Atlas> BlocksPreview::build(
fbo.unbind();
Window::viewport(0, 0, Window::width, Window::height);
return std::unique_ptr<Atlas>(builder.build(2));
auto newAtlas = std::unique_ptr<Atlas>(builder.build(2));
newAtlas->prepare();
return newAtlas;
}