commit
531334f059
@ -1,6 +1,6 @@
|
||||
# Documentation
|
||||
|
||||
Documentation for release 0.27.
|
||||
Documentation for release 0.28.
|
||||
|
||||
## Sections
|
||||
|
||||
|
||||
@ -11,7 +11,7 @@ Subsections:
|
||||
- [Libraries](#)
|
||||
- [app](scripting/builtins/libapp.md)
|
||||
- [base64](scripting/builtins/libbase64.md)
|
||||
- [bjson, json, toml](scripting/filesystem.md)
|
||||
- [bjson, json, toml, yaml](scripting/filesystem.md)
|
||||
- [block](scripting/builtins/libblock.md)
|
||||
- [byteutil](scripting/builtins/libbyteutil.md)
|
||||
- [cameras](scripting/builtins/libcameras.md)
|
||||
|
||||
@ -36,6 +36,22 @@ toml.parse(code: str) -> table
|
||||
|
||||
Parses a TOML string into a table.
|
||||
|
||||
## *yaml* library
|
||||
|
||||
The library contains functions for serializing and deserializing tables:
|
||||
|
||||
```python
|
||||
yaml.tostring(object: table) -> str
|
||||
```
|
||||
|
||||
Serializes an object into a YAML string.
|
||||
|
||||
```python
|
||||
yaml.parse(code: str) -> table
|
||||
```
|
||||
|
||||
Parses a YAML string into a table.
|
||||
|
||||
## *bjson* library
|
||||
|
||||
The library contains functions for working with the binary data exchange format [vcbjson](../../specs/binary_json_spec.md).
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
# Документация
|
||||
|
||||
Документация версии 0.27.
|
||||
Документация версии 0.28.
|
||||
|
||||
## Разделы
|
||||
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
- [Библиотеки](#)
|
||||
- [app](scripting/builtins/libapp.md)
|
||||
- [base64](scripting/builtins/libbase64.md)
|
||||
- [bjson, json, toml](scripting/filesystem.md)
|
||||
- [bjson, json, toml, yaml](scripting/filesystem.md)
|
||||
- [block](scripting/builtins/libblock.md)
|
||||
- [byteutil](scripting/builtins/libbyteutil.md)
|
||||
- [cameras](scripting/builtins/libcameras.md)
|
||||
|
||||
@ -36,6 +36,22 @@ toml.parse(code: str) -> table
|
||||
|
||||
Парсит TOML строку в таблицу.
|
||||
|
||||
## Библиотека yaml
|
||||
|
||||
Библиотека содержит функции для сериализации и десериализации таблиц:
|
||||
|
||||
```python
|
||||
yaml.tostring(object: table) -> str
|
||||
```
|
||||
|
||||
Сериализует объект в YAML строку.
|
||||
|
||||
```python
|
||||
yaml.parse(code: str) -> table
|
||||
```
|
||||
|
||||
Парсит YAML строку в таблицу.
|
||||
|
||||
## Библиотека bjson
|
||||
|
||||
Библиотека содержит функции для работы с двоичным форматом обмена данными [vcbjson](../../specs/binary_json_spec.md).
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"id": "base",
|
||||
"title": "Base",
|
||||
"version": "0.27",
|
||||
"version": "0.28",
|
||||
"description": "basic content package"
|
||||
}
|
||||
|
||||
@ -19,13 +19,14 @@
|
||||
#include "items/ItemDef.hpp"
|
||||
#include "Assets.hpp"
|
||||
#include "assetload_funcs.hpp"
|
||||
#include "engine/Engine.hpp"
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
static debug::Logger logger("assets-loader");
|
||||
|
||||
AssetsLoader::AssetsLoader(Assets* assets, const ResPaths* paths)
|
||||
: assets(assets), paths(paths) {
|
||||
AssetsLoader::AssetsLoader(Engine& engine, Assets& assets, const ResPaths& paths)
|
||||
: engine(engine), assets(assets), paths(paths) {
|
||||
addLoader(AssetType::SHADER, assetload::shader);
|
||||
addLoader(AssetType::TEXTURE, assetload::texture);
|
||||
addLoader(AssetType::FONT, assetload::font);
|
||||
@ -73,7 +74,7 @@ void AssetsLoader::loadNext() {
|
||||
aloader_func loader = getLoader(entry.tag);
|
||||
auto postfunc =
|
||||
loader(this, paths, entry.filename, entry.alias, entry.config);
|
||||
postfunc(assets);
|
||||
postfunc(&assets);
|
||||
entries.pop();
|
||||
} catch (std::runtime_error& err) {
|
||||
logger.error() << err.what();
|
||||
@ -101,7 +102,7 @@ static void add_layouts(
|
||||
AssetType::LAYOUT,
|
||||
file.string(),
|
||||
name,
|
||||
std::make_shared<LayoutCfg>(env)
|
||||
std::make_shared<LayoutCfg>(&loader.getEngine().getGUI(), env)
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -199,7 +200,7 @@ void AssetsLoader::processPreloadConfig(const io::path& file) {
|
||||
}
|
||||
|
||||
void AssetsLoader::processPreloadConfigs(const Content* content) {
|
||||
auto preloadFile = paths->getMainRoot() / "preload.json";
|
||||
io::path preloadFile = "res:preload.json";
|
||||
if (io::exists(preloadFile)) {
|
||||
processPreloadConfig(preloadFile);
|
||||
}
|
||||
@ -211,7 +212,7 @@ void AssetsLoader::processPreloadConfigs(const Content* content) {
|
||||
continue;
|
||||
}
|
||||
const auto& pack = entry.second;
|
||||
auto preloadFile = pack->getInfo().folder / "preload.json";
|
||||
preloadFile = pack->getInfo().folder / "preload.json";
|
||||
if (io::exists(preloadFile)) {
|
||||
processPreloadConfig(preloadFile);
|
||||
}
|
||||
@ -296,7 +297,11 @@ bool AssetsLoader::loadExternalTexture(
|
||||
return false;
|
||||
}
|
||||
|
||||
const ResPaths* AssetsLoader::getPaths() const {
|
||||
Engine& AssetsLoader::getEngine() {
|
||||
return engine;
|
||||
}
|
||||
|
||||
const ResPaths& AssetsLoader::getPaths() const {
|
||||
return paths;
|
||||
}
|
||||
|
||||
@ -324,7 +329,7 @@ std::shared_ptr<Task> AssetsLoader::startTask(runnable onDone) {
|
||||
std::make_shared<util::ThreadPool<aloader_entry, assetload::postfunc>>(
|
||||
"assets-loader-pool",
|
||||
[=]() { return std::make_shared<LoaderWorker>(this); },
|
||||
[=](const assetload::postfunc& func) { func(assets); }
|
||||
[this](const assetload::postfunc& func) { func(&assets); }
|
||||
);
|
||||
pool->setOnComplete(std::move(onDone));
|
||||
while (!entries.empty()) {
|
||||
|
||||
@ -18,6 +18,11 @@
|
||||
class ResPaths;
|
||||
class AssetsLoader;
|
||||
class Content;
|
||||
class Engine;
|
||||
|
||||
namespace gui {
|
||||
class GUI;
|
||||
}
|
||||
|
||||
struct AssetCfg {
|
||||
virtual ~AssetCfg() {
|
||||
@ -25,9 +30,10 @@ struct AssetCfg {
|
||||
};
|
||||
|
||||
struct LayoutCfg : AssetCfg {
|
||||
gui::GUI* gui;
|
||||
scriptenv env;
|
||||
|
||||
LayoutCfg(scriptenv env) : env(std::move(env)) {
|
||||
LayoutCfg(gui::GUI* gui, scriptenv env) : gui(gui), env(std::move(env)) {
|
||||
}
|
||||
};
|
||||
|
||||
@ -51,7 +57,7 @@ struct AtlasCfg : AssetCfg {
|
||||
|
||||
using aloader_func = std::function<
|
||||
assetload::
|
||||
postfunc(AssetsLoader*, const ResPaths*, const std::string&, const std::string&, std::shared_ptr<AssetCfg>)>;
|
||||
postfunc(AssetsLoader*, const ResPaths&, const std::string&, const std::string&, std::shared_ptr<AssetCfg>)>;
|
||||
|
||||
struct aloader_entry {
|
||||
AssetType tag;
|
||||
@ -61,11 +67,12 @@ struct aloader_entry {
|
||||
};
|
||||
|
||||
class AssetsLoader {
|
||||
Assets* assets;
|
||||
Engine& engine;
|
||||
Assets& assets;
|
||||
std::map<AssetType, aloader_func> loaders;
|
||||
std::queue<aloader_entry> entries;
|
||||
std::set<std::pair<AssetType, std::string>> enqueued;
|
||||
const ResPaths* paths;
|
||||
const ResPaths& paths;
|
||||
|
||||
void tryAddSound(const std::string& name);
|
||||
|
||||
@ -76,7 +83,7 @@ class AssetsLoader {
|
||||
void processPreloadConfig(const io::path& file);
|
||||
void processPreloadConfigs(const Content* content);
|
||||
public:
|
||||
AssetsLoader(Assets* assets, const ResPaths* paths);
|
||||
AssetsLoader(Engine& engine, Assets& assets, const ResPaths& paths);
|
||||
void addLoader(AssetType tag, aloader_func func);
|
||||
|
||||
/// @brief Enqueue asset load
|
||||
@ -98,7 +105,7 @@ public:
|
||||
|
||||
std::shared_ptr<Task> startTask(runnable onDone);
|
||||
|
||||
const ResPaths* getPaths() const;
|
||||
const ResPaths& getPaths() const;
|
||||
aloader_func getLoader(AssetType tag);
|
||||
|
||||
/// @brief Enqueue core and content assets
|
||||
@ -111,4 +118,6 @@ public:
|
||||
const std::string& name,
|
||||
const std::vector<io::path>& alternatives
|
||||
);
|
||||
|
||||
Engine& getEngine();
|
||||
};
|
||||
|
||||
@ -34,7 +34,7 @@ namespace fs = std::filesystem;
|
||||
|
||||
static bool load_animation(
|
||||
Assets* assets,
|
||||
const ResPaths* paths,
|
||||
const ResPaths& paths,
|
||||
const std::string& atlasName,
|
||||
const std::string& directory,
|
||||
const std::string& name,
|
||||
@ -43,14 +43,14 @@ static bool load_animation(
|
||||
|
||||
assetload::postfunc assetload::texture(
|
||||
AssetsLoader*,
|
||||
const ResPaths* paths,
|
||||
const ResPaths& paths,
|
||||
const std::string& filename,
|
||||
const std::string& name,
|
||||
const std::shared_ptr<AssetCfg>&
|
||||
) {
|
||||
auto actualFile = paths->find(filename + ".png");
|
||||
auto actualFile = paths.find(filename + ".png");
|
||||
try {
|
||||
std::shared_ptr<ImageData> image(imageio::read(actualFile).release());
|
||||
std::shared_ptr<ImageData> image(imageio::read(actualFile));
|
||||
return [name, image, actualFile](auto assets) {
|
||||
assets->store(Texture::from(image.get()), name);
|
||||
};
|
||||
@ -62,13 +62,13 @@ assetload::postfunc assetload::texture(
|
||||
|
||||
assetload::postfunc assetload::shader(
|
||||
AssetsLoader*,
|
||||
const ResPaths* paths,
|
||||
const ResPaths& paths,
|
||||
const std::string& filename,
|
||||
const std::string& name,
|
||||
const std::shared_ptr<AssetCfg>&
|
||||
) {
|
||||
io::path vertexFile = paths->find(filename + ".glslv");
|
||||
io::path fragmentFile = paths->find(filename + ".glslf");
|
||||
io::path vertexFile = paths.find(filename + ".glslv");
|
||||
io::path fragmentFile = paths.find(filename + ".glslf");
|
||||
|
||||
std::string vertexSource = io::read_string(vertexFile);
|
||||
std::string fragmentSource = io::read_string(fragmentFile);
|
||||
@ -104,14 +104,14 @@ static bool append_atlas(AtlasBuilder& atlas, const io::path& file) {
|
||||
|
||||
assetload::postfunc assetload::atlas(
|
||||
AssetsLoader* loader,
|
||||
const ResPaths* paths,
|
||||
const ResPaths& paths,
|
||||
const std::string& directory,
|
||||
const std::string& name,
|
||||
const std::shared_ptr<AssetCfg>& config
|
||||
) {
|
||||
auto atlasConfig = std::dynamic_pointer_cast<AtlasCfg>(config);
|
||||
if (atlasConfig && atlasConfig->type == AtlasType::SEPARATE) {
|
||||
for (const auto& file : paths->listdir(directory)) {
|
||||
for (const auto& file : paths.listdir(directory)) {
|
||||
if (!imageio::is_read_supported(file.extension()))
|
||||
continue;
|
||||
loader->add(
|
||||
@ -123,7 +123,7 @@ assetload::postfunc assetload::atlas(
|
||||
return [](auto){};
|
||||
}
|
||||
AtlasBuilder builder;
|
||||
for (const auto& file : paths->listdir(directory)) {
|
||||
for (const auto& file : paths.listdir(directory)) {
|
||||
if (!imageio::is_read_supported(file.extension())) continue;
|
||||
if (!append_atlas(builder, file)) continue;
|
||||
}
|
||||
@ -140,7 +140,7 @@ assetload::postfunc assetload::atlas(
|
||||
|
||||
assetload::postfunc assetload::font(
|
||||
AssetsLoader*,
|
||||
const ResPaths* paths,
|
||||
const ResPaths& paths,
|
||||
const std::string& filename,
|
||||
const std::string& name,
|
||||
const std::shared_ptr<AssetCfg>&
|
||||
@ -148,7 +148,7 @@ assetload::postfunc assetload::font(
|
||||
auto pages = std::make_shared<std::vector<std::unique_ptr<ImageData>>>();
|
||||
for (size_t i = 0; i <= 1024; i++) {
|
||||
std::string pagefile = filename + "_" + std::to_string(i) + ".png";
|
||||
auto file = paths->find(pagefile);
|
||||
auto file = paths.find(pagefile);
|
||||
if (io::exists(file)) {
|
||||
pages->push_back(imageio::read(file));
|
||||
} else if (i == 0) {
|
||||
@ -177,7 +177,7 @@ assetload::postfunc assetload::font(
|
||||
|
||||
assetload::postfunc assetload::layout(
|
||||
AssetsLoader*,
|
||||
const ResPaths* paths,
|
||||
const ResPaths&,
|
||||
const std::string& file,
|
||||
const std::string& name,
|
||||
const std::shared_ptr<AssetCfg>& config
|
||||
@ -189,6 +189,7 @@ assetload::postfunc assetload::layout(
|
||||
auto prefix = name.substr(0, pos);
|
||||
assets->store(
|
||||
UiDocument::read(
|
||||
*cfg->gui,
|
||||
cfg->env,
|
||||
name,
|
||||
file,
|
||||
@ -205,7 +206,7 @@ assetload::postfunc assetload::layout(
|
||||
}
|
||||
assetload::postfunc assetload::sound(
|
||||
AssetsLoader*,
|
||||
const ResPaths* paths,
|
||||
const ResPaths& paths,
|
||||
const std::string& file,
|
||||
const std::string& name,
|
||||
const std::shared_ptr<AssetCfg>& config
|
||||
@ -219,13 +220,13 @@ assetload::postfunc assetload::sound(
|
||||
for (size_t i = 0; i < extensions.size(); i++) {
|
||||
extension = extensions[i];
|
||||
// looking for 'sound_name' as base sound
|
||||
auto soundFile = paths->find(file + extension);
|
||||
auto soundFile = paths.find(file + extension);
|
||||
if (io::exists(soundFile)) {
|
||||
baseSound = audio::load_sound(soundFile, keepPCM);
|
||||
break;
|
||||
}
|
||||
// looking for 'sound_name_0' as base sound
|
||||
auto variantFile = paths->find(file + "_0" + extension);
|
||||
auto variantFile = paths.find(file + "_0" + extension);
|
||||
if (io::exists(variantFile)) {
|
||||
baseSound = audio::load_sound(variantFile, keepPCM);
|
||||
break;
|
||||
@ -238,7 +239,7 @@ assetload::postfunc assetload::sound(
|
||||
// loading sound variants
|
||||
for (uint i = 1;; i++) {
|
||||
auto variantFile =
|
||||
paths->find(file + "_" + std::to_string(i) + extension);
|
||||
paths.find(file + "_" + std::to_string(i) + extension);
|
||||
if (!io::exists(variantFile)) {
|
||||
break;
|
||||
}
|
||||
@ -264,12 +265,12 @@ static void request_textures(AssetsLoader* loader, const model::Model& model) {
|
||||
|
||||
assetload::postfunc assetload::model(
|
||||
AssetsLoader* loader,
|
||||
const ResPaths* paths,
|
||||
const ResPaths& paths,
|
||||
const std::string& file,
|
||||
const std::string& name,
|
||||
const std::shared_ptr<AssetCfg>&
|
||||
) {
|
||||
auto path = paths->find(file + ".vec3");
|
||||
auto path = paths.find(file + ".vec3");
|
||||
if (io::exists(path)) {
|
||||
auto bytes = io::read_bytes_buffer(path);
|
||||
auto modelVEC3 = std::make_shared<vec3::File>(vec3::load(path.string(), bytes));
|
||||
@ -289,7 +290,7 @@ assetload::postfunc assetload::model(
|
||||
}
|
||||
};
|
||||
}
|
||||
path = paths->find(file + ".obj");
|
||||
path = paths.find(file + ".obj");
|
||||
auto text = io::read_string(path);
|
||||
try {
|
||||
auto model = obj::parse(path.string(), text).release();
|
||||
@ -383,7 +384,7 @@ inline bool contains(
|
||||
|
||||
static bool load_animation(
|
||||
Assets* assets,
|
||||
const ResPaths* paths,
|
||||
const ResPaths& paths,
|
||||
const std::string& atlasName,
|
||||
const std::string& directory,
|
||||
const std::string& name,
|
||||
@ -391,20 +392,20 @@ static bool load_animation(
|
||||
) {
|
||||
std::string animsDir = directory + "/animation";
|
||||
|
||||
for (const auto& folder : paths->listdir(animsDir)) {
|
||||
for (const auto& folder : paths.listdir(animsDir)) {
|
||||
if (!io::is_directory(folder)) continue;
|
||||
if (folder.name() != name) continue;
|
||||
//FIXME: if (fs::is_empty(folder)) continue;
|
||||
|
||||
AtlasBuilder builder;
|
||||
append_atlas(builder, paths->find(directory + "/" + name + ".png"));
|
||||
append_atlas(builder, paths.find(directory + "/" + name + ".png"));
|
||||
|
||||
std::vector<std::pair<std::string, int>> frameList;
|
||||
std::string animFile = folder.string() + "/animation.json";
|
||||
if (io::exists(animFile)) {
|
||||
read_anim_file(animFile, frameList);
|
||||
}
|
||||
for (const auto& file : paths->listdir(animsDir + "/" + name)) {
|
||||
for (const auto& file : paths.listdir(animsDir + "/" + name)) {
|
||||
if (!frameList.empty() &&
|
||||
!contains(frameList, file.stem())) {
|
||||
continue;
|
||||
|
||||
@ -15,49 +15,49 @@ struct AssetCfg;
|
||||
namespace assetload {
|
||||
postfunc texture(
|
||||
AssetsLoader*,
|
||||
const ResPaths* paths,
|
||||
const ResPaths& paths,
|
||||
const std::string& filename,
|
||||
const std::string& name,
|
||||
const std::shared_ptr<AssetCfg>& settings
|
||||
);
|
||||
postfunc shader(
|
||||
AssetsLoader*,
|
||||
const ResPaths* paths,
|
||||
const ResPaths& paths,
|
||||
const std::string& filename,
|
||||
const std::string& name,
|
||||
const std::shared_ptr<AssetCfg>& settings
|
||||
);
|
||||
postfunc atlas(
|
||||
AssetsLoader*,
|
||||
const ResPaths* paths,
|
||||
const ResPaths& paths,
|
||||
const std::string& directory,
|
||||
const std::string& name,
|
||||
const std::shared_ptr<AssetCfg>& settings
|
||||
);
|
||||
postfunc font(
|
||||
AssetsLoader*,
|
||||
const ResPaths* paths,
|
||||
const ResPaths& paths,
|
||||
const std::string& filename,
|
||||
const std::string& name,
|
||||
const std::shared_ptr<AssetCfg>& settings
|
||||
);
|
||||
postfunc layout(
|
||||
AssetsLoader*,
|
||||
const ResPaths* paths,
|
||||
const ResPaths& paths,
|
||||
const std::string& file,
|
||||
const std::string& name,
|
||||
const std::shared_ptr<AssetCfg>& settings
|
||||
);
|
||||
postfunc sound(
|
||||
AssetsLoader*,
|
||||
const ResPaths* paths,
|
||||
const ResPaths& paths,
|
||||
const std::string& file,
|
||||
const std::string& name,
|
||||
const std::shared_ptr<AssetCfg>& settings
|
||||
);
|
||||
postfunc model(
|
||||
AssetsLoader*,
|
||||
const ResPaths* paths,
|
||||
const ResPaths& paths,
|
||||
const std::string& file,
|
||||
const std::string& name,
|
||||
const std::shared_ptr<AssetCfg>& settings
|
||||
|
||||
@ -17,12 +17,12 @@ static debug::Logger logger("audio");
|
||||
using namespace audio;
|
||||
|
||||
namespace {
|
||||
static speakerid_t nextId = 1;
|
||||
static Backend* backend;
|
||||
static std::unordered_map<speakerid_t, std::unique_ptr<Speaker>> speakers;
|
||||
static std::unordered_map<speakerid_t, std::shared_ptr<Stream>> streams;
|
||||
static std::vector<std::unique_ptr<Channel>> channels;
|
||||
static util::ObjectsKeeper objects_keeper {};
|
||||
speakerid_t nextId = 1;
|
||||
Backend* backend;
|
||||
std::unordered_map<speakerid_t, std::unique_ptr<Speaker>> speakers;
|
||||
std::unordered_map<speakerid_t, std::shared_ptr<Stream>> streams;
|
||||
std::vector<std::unique_ptr<Channel>> channels;
|
||||
util::ObjectsKeeper objects_keeper {};
|
||||
}
|
||||
|
||||
Channel::Channel(std::string name) : name(std::move(name)) {
|
||||
|
||||
@ -7,16 +7,20 @@ template <typename CharT>
|
||||
class BasicParser {
|
||||
using StringT = std::basic_string<CharT>;
|
||||
using StringViewT = std::basic_string_view<CharT>;
|
||||
|
||||
void skipWhitespaceHashComment(bool newline = true);
|
||||
protected:
|
||||
std::string_view filename;
|
||||
StringViewT source;
|
||||
uint pos = 0;
|
||||
uint line = 1;
|
||||
uint linestart = 0;
|
||||
bool hashComment = false;
|
||||
|
||||
virtual void skipWhitespace();
|
||||
void skipWhitespace(bool newline = true);
|
||||
void skip(size_t n);
|
||||
void skipLine();
|
||||
void skipEmptyLines();
|
||||
bool skipTo(const StringT& substring);
|
||||
void expect(CharT expected);
|
||||
void expect(const StringT& substring);
|
||||
|
||||
@ -31,10 +31,17 @@ namespace {
|
||||
}
|
||||
|
||||
template<typename CharT>
|
||||
void BasicParser<CharT>::skipWhitespace() {
|
||||
void BasicParser<CharT>::skipWhitespace(bool newline) {
|
||||
if (hashComment) {
|
||||
skipWhitespaceHashComment(newline);
|
||||
return;
|
||||
}
|
||||
while (hasNext()) {
|
||||
char next = source[pos];
|
||||
if (next == '\n') {
|
||||
if (!newline) {
|
||||
break;
|
||||
}
|
||||
line++;
|
||||
linestart = ++pos;
|
||||
continue;
|
||||
@ -47,6 +54,36 @@ void BasicParser<CharT>::skipWhitespace() {
|
||||
}
|
||||
}
|
||||
|
||||
template<typename CharT>
|
||||
void BasicParser<CharT>::skipWhitespaceHashComment(bool newline) {
|
||||
while (hasNext()) {
|
||||
char next = source[pos];
|
||||
if (next == '\n') {
|
||||
if (!newline) {
|
||||
break;
|
||||
}
|
||||
line++;
|
||||
linestart = ++pos;
|
||||
continue;
|
||||
}
|
||||
if (is_whitespace(next)) {
|
||||
pos++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hasNext() && source[pos] == '#') {
|
||||
if (!newline) {
|
||||
readUntilEOL();
|
||||
return;
|
||||
}
|
||||
skipLine();
|
||||
if (hasNext() && (is_whitespace(source[pos]) || source[pos] == '#')) {
|
||||
skipWhitespaceHashComment(newline);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename CharT>
|
||||
void BasicParser<CharT>::skip(size_t n) {
|
||||
n = std::min(n, source.length() - pos);
|
||||
@ -73,6 +110,12 @@ void BasicParser<CharT>::skipLine() {
|
||||
}
|
||||
}
|
||||
|
||||
template<typename CharT>
|
||||
void BasicParser<CharT>::skipEmptyLines() {
|
||||
skipWhitespace();
|
||||
pos = linestart;
|
||||
}
|
||||
|
||||
template<typename CharT>
|
||||
bool BasicParser<CharT>::skipTo(const std::basic_string<CharT>& substring) {
|
||||
size_t idx = source.find(substring, pos);
|
||||
@ -240,9 +283,12 @@ std::basic_string_view<CharT> BasicParser<CharT>::readUntilWhitespace() {
|
||||
template <typename CharT>
|
||||
std::basic_string_view<CharT> BasicParser<CharT>::readUntilEOL() {
|
||||
int start = pos;
|
||||
while (hasNext() && source[pos] != '\r' && source[pos] != '\n') {
|
||||
while (hasNext() && source[pos] != '\n') {
|
||||
pos++;
|
||||
}
|
||||
if (pos > start && source[pos - 1] == '\r') {
|
||||
return source.substr(start, pos - start - 1);
|
||||
}
|
||||
return source.substr(start, pos - start);
|
||||
}
|
||||
|
||||
|
||||
@ -13,13 +13,14 @@ using namespace json;
|
||||
|
||||
namespace {
|
||||
class Parser : BasicParser<char> {
|
||||
dv::value parseList();
|
||||
dv::value parseObject();
|
||||
dv::value parseValue();
|
||||
public:
|
||||
public:
|
||||
Parser(std::string_view filename, std::string_view source);
|
||||
|
||||
dv::value parse();
|
||||
private:
|
||||
dv::value parseList();
|
||||
dv::value parseObject();
|
||||
dv::value parseValue();
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -16,16 +16,6 @@ using namespace toml;
|
||||
class TomlReader : BasicParser<char> {
|
||||
dv::value root;
|
||||
|
||||
void skipWhitespace() override {
|
||||
BasicParser::skipWhitespace();
|
||||
if (hasNext() && source[pos] == '#') {
|
||||
skipLine();
|
||||
if (hasNext() && is_whitespace(peek())) {
|
||||
skipWhitespace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// modified version of BaseParser.parseString
|
||||
// todo: extract common part
|
||||
std::string parseMultilineString() {
|
||||
@ -214,6 +204,7 @@ class TomlReader : BasicParser<char> {
|
||||
public:
|
||||
TomlReader(std::string_view file, std::string_view source)
|
||||
: BasicParser(file, source), root(dv::object()) {
|
||||
hashComment = true;
|
||||
}
|
||||
|
||||
dv::value read() {
|
||||
|
||||
459
src/coders/yaml.cpp
Normal file
459
src/coders/yaml.cpp
Normal file
@ -0,0 +1,459 @@
|
||||
#include "yaml.hpp"
|
||||
#include "BasicParser.hpp"
|
||||
|
||||
#include <iomanip>
|
||||
|
||||
using namespace yaml;
|
||||
|
||||
namespace {
|
||||
enum Chomping {
|
||||
CLIP, STRIP, KEEP
|
||||
};
|
||||
|
||||
class Parser : BasicParser<char> {
|
||||
public:
|
||||
Parser(std::string_view filename, std::string_view source);
|
||||
|
||||
dv::value parseValue();
|
||||
dv::value parseFullValue(int indent);
|
||||
dv::value parseArray(int indent = 0);
|
||||
dv::value parseObject(dv::value&& object, int indent = 0);
|
||||
dv::value parseInlineArray();
|
||||
dv::value parseInlineObject();
|
||||
private:
|
||||
int countIndent();
|
||||
bool expectIndent(int indent);
|
||||
std::string_view readYamlIdentifier();
|
||||
std::string readMultilineString(int indent, bool eols, Chomping chomp);
|
||||
};
|
||||
}
|
||||
|
||||
inline bool is_yaml_identifier_char(int c) {
|
||||
return c > 20 && c != ':' && c != ' ' && c != '\n' && c != '\r' &&
|
||||
c != '\t' && c != '\f' && c != '\v';
|
||||
}
|
||||
|
||||
static dv::value perform_literal(std::string_view literal) {
|
||||
if (literal == "true" || literal == "True" ||
|
||||
literal == "false" || literal == "False") {
|
||||
return literal[0] == 't';
|
||||
}
|
||||
if (literal == "null" || literal == "Null") {
|
||||
return nullptr;
|
||||
}
|
||||
return std::string(literal);
|
||||
}
|
||||
|
||||
Parser::Parser(std::string_view filename, std::string_view source)
|
||||
: BasicParser(filename, source) {
|
||||
hashComment = true;
|
||||
}
|
||||
|
||||
bool Parser::expectIndent(int required) {
|
||||
int indent = 0;
|
||||
while (hasNext() && source[pos] == ' ' && indent < required) {
|
||||
indent++;
|
||||
pos++;
|
||||
}
|
||||
return indent >= required;
|
||||
}
|
||||
|
||||
std::string Parser::readMultilineString(int indent, bool eols, Chomping chomp) {
|
||||
int next_indent = countIndent();
|
||||
if (next_indent <= indent) {
|
||||
throw error("indentation error");
|
||||
}
|
||||
std::stringstream ss;
|
||||
ss << readUntilEOL();
|
||||
if (hasNext()) {
|
||||
skip(1);
|
||||
}
|
||||
int trailingEmpties = 0;
|
||||
while (true) {
|
||||
while (expectIndent(next_indent)) {
|
||||
trailingEmpties = 0;
|
||||
ss << (eols ? '\n' : ' ');
|
||||
ss << readUntilEOL();
|
||||
if (hasNext()) {
|
||||
skip(1);
|
||||
}
|
||||
}
|
||||
while (true) {
|
||||
skipWhitespace(false);
|
||||
if (!hasNext() || source[pos] != '\n') {
|
||||
break;
|
||||
}
|
||||
skip(1);
|
||||
trailingEmpties++;
|
||||
}
|
||||
if (!expectIndent(next_indent)) {
|
||||
break;
|
||||
}
|
||||
pos = linestart;
|
||||
}
|
||||
if (chomp == KEEP) {
|
||||
for (int i = 0; i < trailingEmpties - 1; i++) {
|
||||
ss << (eols ? '\n' : ' ');
|
||||
}
|
||||
}
|
||||
ss << '\n';
|
||||
|
||||
pos = linestart;
|
||||
|
||||
auto string = ss.str();
|
||||
if (chomp == STRIP) {
|
||||
util::trim(string);
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
std::string_view Parser::readYamlIdentifier() {
|
||||
char c = peek();
|
||||
if (!is_yaml_identifier_char(c)) {
|
||||
throw error("identifier expected");
|
||||
}
|
||||
int start = pos;
|
||||
while (hasNext() && is_yaml_identifier_char(source[pos])) {
|
||||
pos++;
|
||||
}
|
||||
return source.substr(start, pos - start);
|
||||
}
|
||||
|
||||
int Parser::countIndent() {
|
||||
int indent = 0;
|
||||
while (hasNext() && source[pos] == ' ') {
|
||||
indent++;
|
||||
pos++;
|
||||
}
|
||||
return indent;
|
||||
}
|
||||
|
||||
dv::value Parser::parseValue() {
|
||||
char c = peek();
|
||||
if (is_digit(c)) {
|
||||
return parseNumber(1);
|
||||
} else if (c == '-' || c == '+') {
|
||||
skip(1);
|
||||
return parseNumber(c == '-' ? -1 : 1);
|
||||
} else if (c == '"' || c == '\'') {
|
||||
skip(1);
|
||||
return parseString(c, true);
|
||||
} else if (c == '[') {
|
||||
return parseInlineArray();
|
||||
} else if (c == '{') {
|
||||
return parseInlineObject();
|
||||
} else {
|
||||
return perform_literal(readUntilEOL());
|
||||
}
|
||||
throw error("unexpected character");
|
||||
}
|
||||
|
||||
dv::value Parser::parseInlineArray() {
|
||||
expect('[');
|
||||
auto list = dv::list();
|
||||
while (peek() != ']') {
|
||||
if (peek() == '#') {
|
||||
skipLine();
|
||||
continue;
|
||||
}
|
||||
list.add(parseValue());
|
||||
|
||||
char next = peek();
|
||||
if (next == ',') {
|
||||
pos++;
|
||||
} else if (next == ']') {
|
||||
break;
|
||||
} else {
|
||||
throw error("',' expected");
|
||||
}
|
||||
}
|
||||
pos++;
|
||||
return list;
|
||||
}
|
||||
|
||||
dv::value Parser::parseInlineObject() {
|
||||
expect('{');
|
||||
dv::value object = dv::object();
|
||||
while (peek() != '}') {
|
||||
if (peek() == '#') {
|
||||
skipLine();
|
||||
continue;
|
||||
}
|
||||
auto name = readYamlIdentifier();
|
||||
expect(':');
|
||||
object[std::string(name)] = parseValue();
|
||||
|
||||
char next = peek();
|
||||
if (next == ',') {
|
||||
pos++;
|
||||
} else if (next == '}') {
|
||||
break;
|
||||
} else {
|
||||
throw error("',' expected");
|
||||
}
|
||||
}
|
||||
pos++;
|
||||
return object;
|
||||
}
|
||||
|
||||
dv::value Parser::parseFullValue(int indent) {
|
||||
dv::value value;
|
||||
char c = source[pos];
|
||||
if (c == '\n') {
|
||||
skip(1);
|
||||
skipEmptyLines();
|
||||
int init_pos = pos;
|
||||
int next_indent = countIndent();
|
||||
if (next_indent < indent) {
|
||||
throw error("indentation error");
|
||||
}
|
||||
if (source[pos] == '-') {
|
||||
pos = init_pos;
|
||||
return parseArray(next_indent);
|
||||
} else {
|
||||
pos = init_pos;
|
||||
return parseObject(dv::object(), next_indent);
|
||||
}
|
||||
} else if (is_digit(c)) {
|
||||
return parseNumber(1);
|
||||
} else if (c == '-' || c == '+') {
|
||||
skip(1);
|
||||
return parseNumber(c == '-' ? -1 : 1);
|
||||
} else if (c == '"' || c == '\'') {
|
||||
skip(1);
|
||||
return parseString(c, true);
|
||||
} else if (c == '[') {
|
||||
return parseInlineArray();
|
||||
} else if (c == '{') {
|
||||
return parseInlineObject();
|
||||
} else if (c == '|' || c == '>') {
|
||||
skip(1);
|
||||
Chomping chomp = CLIP;
|
||||
if (source[pos] == '-' || source[pos] == '+') {
|
||||
chomp = source[pos] == '-' ? STRIP : KEEP;
|
||||
skip(1);
|
||||
}
|
||||
skipWhitespace(false);
|
||||
expectNewLine();
|
||||
return readMultilineString(indent, c == '|', chomp);
|
||||
} else {
|
||||
return perform_literal(readUntilEOL());
|
||||
}
|
||||
}
|
||||
|
||||
dv::value Parser::parseArray(int indent) {
|
||||
dv::value list = dv::list();
|
||||
|
||||
while (hasNext()) {
|
||||
skipEmptyLines();
|
||||
int next_indent = countIndent();
|
||||
if (next_indent < indent) {
|
||||
pos = linestart;
|
||||
break;
|
||||
}
|
||||
expect('-');
|
||||
skipWhitespace();
|
||||
size_t nlpos = source.find('\n', pos);
|
||||
size_t colonpos = source.find(':', pos);
|
||||
if (nlpos == std::string::npos && colonpos == std::string::npos) {
|
||||
list.add(perform_literal(readUntilEOL()));
|
||||
break;
|
||||
}
|
||||
if (nlpos < colonpos) {
|
||||
list.add(parseFullValue(next_indent));
|
||||
skipLine();
|
||||
} else {
|
||||
auto name = readYamlIdentifier();
|
||||
expect(':');
|
||||
skipWhitespace(false);
|
||||
dv::value object = dv::object();
|
||||
object[std::string(name)] = parseFullValue(next_indent);
|
||||
skipEmptyLines();
|
||||
next_indent = countIndent();
|
||||
if (next_indent > indent) {
|
||||
pos = linestart;
|
||||
object = parseObject(std::move(object), next_indent);
|
||||
} else {
|
||||
pos = linestart;
|
||||
}
|
||||
list.add(std::move(object));
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
dv::value Parser::parseObject(dv::value&& object, int indent) {
|
||||
skipEmptyLines();
|
||||
while (hasNext()) {
|
||||
size_t prev_pos = pos;
|
||||
int next_indent = countIndent();
|
||||
if (source[pos] == '\n') {
|
||||
skip(1);
|
||||
continue;
|
||||
}
|
||||
if (next_indent < indent) {
|
||||
pos = prev_pos;
|
||||
break;
|
||||
}
|
||||
char c = peek();
|
||||
if (!is_yaml_identifier_char(c)) {
|
||||
if (!is_whitespace(c)) {
|
||||
throw error("invalid character");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
auto name = readYamlIdentifier();
|
||||
expect(':');
|
||||
skipWhitespace(false);
|
||||
object[std::string(name)] = parseFullValue(indent);
|
||||
skipEmptyLines();
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
dv::value yaml::parse(std::string_view filename, std::string_view source) {
|
||||
return Parser(filename, source).parseObject(dv::object());
|
||||
}
|
||||
|
||||
dv::value yaml::parse(std::string_view source) {
|
||||
return parse("[string]", source);
|
||||
}
|
||||
|
||||
static void add_indent(std::stringstream& ss, int indent) {
|
||||
for (int i = 0; i < indent; i++) {
|
||||
ss << " ";
|
||||
}
|
||||
}
|
||||
|
||||
static void insert_string(
|
||||
std::stringstream& ss, const std::string& string, int indent
|
||||
) {
|
||||
bool has_spec_chars = false;
|
||||
bool multiline = false;
|
||||
for (char c : string) {
|
||||
if (c < ' ' || c == '"' || c == '\'') {
|
||||
has_spec_chars = true;
|
||||
if (multiline) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (c == '\n') {
|
||||
multiline = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (multiline) {
|
||||
ss << "|-\n";
|
||||
size_t offset = 0;
|
||||
size_t newoffset = 0;
|
||||
|
||||
do {
|
||||
offset = newoffset;
|
||||
if (offset == string.length() - 1 && string[offset] == '\n') {
|
||||
break;
|
||||
}
|
||||
add_indent(ss, indent);
|
||||
newoffset = string.find('\n', offset + 1);
|
||||
if (newoffset == std::string::npos) {
|
||||
ss << string.substr(offset);
|
||||
break;
|
||||
} else {
|
||||
ss << string.substr(offset + 1, newoffset - offset - 1);
|
||||
}
|
||||
ss << '\n';
|
||||
} while (true);
|
||||
} else {
|
||||
if (has_spec_chars || string.empty()) {
|
||||
ss << util::escape(string, false);
|
||||
} else {
|
||||
ss << string;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void to_string(
|
||||
std::stringstream& ss,
|
||||
const dv::value& value,
|
||||
int indent,
|
||||
bool eliminateIndent = false
|
||||
) {
|
||||
using dv::value_type;
|
||||
|
||||
switch (value.getType()) {
|
||||
case value_type::string:
|
||||
insert_string(ss, value.asString(), indent);
|
||||
break;
|
||||
case value_type::number:
|
||||
ss << std::setprecision(15) << value.asNumber();
|
||||
break;
|
||||
case value_type::integer:
|
||||
ss << value.asInteger();
|
||||
break;
|
||||
case value_type::boolean:
|
||||
ss << (value.asBoolean() ? "true" : "false");
|
||||
break;
|
||||
case value_type::none:
|
||||
ss << "null";
|
||||
break;
|
||||
case value_type::object: {
|
||||
if (value.empty()) {
|
||||
ss << "{}";
|
||||
break;
|
||||
}
|
||||
bool first = true;
|
||||
for (const auto& [key, elem] : value.asObject()) {
|
||||
if (!first) {
|
||||
ss << '\n';
|
||||
}
|
||||
if (!eliminateIndent) {
|
||||
add_indent(ss, indent);
|
||||
} else {
|
||||
eliminateIndent = false;
|
||||
}
|
||||
ss << key << ": ";
|
||||
if ((elem.isObject() || elem.isList()) && !elem.empty()) {
|
||||
ss << "\n";
|
||||
to_string(ss, elem, indent + 1);
|
||||
} else {
|
||||
to_string(ss, elem, indent + 1);
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case value_type::list: {
|
||||
if (value.empty()) {
|
||||
ss << "[]";
|
||||
break;
|
||||
}
|
||||
bool first = true;
|
||||
for (const auto& elem : value) {
|
||||
if (!first) {
|
||||
ss << '\n';
|
||||
}
|
||||
if (!eliminateIndent) {
|
||||
add_indent(ss, indent);
|
||||
} else {
|
||||
eliminateIndent = false;
|
||||
}
|
||||
ss << "- ";
|
||||
to_string(ss, elem, indent + 1, true);
|
||||
first = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case value_type::bytes: {
|
||||
const auto& bytes = value.asBytes();
|
||||
auto b64 = util::base64_encode(bytes.data(), bytes.size());
|
||||
b64 = util::join(util::split_by_n(b64, 64), '\n');
|
||||
insert_string(ss, b64, indent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string yaml::stringify(const dv::value& value) {
|
||||
std::stringstream ss;
|
||||
to_string(ss, value, 0);
|
||||
return ss.str();
|
||||
}
|
||||
12
src/coders/yaml.hpp
Normal file
12
src/coders/yaml.hpp
Normal file
@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "data/dv.hpp"
|
||||
|
||||
namespace yaml {
|
||||
dv::value parse(std::string_view filename, std::string_view source);
|
||||
dv::value parse(std::string_view source);
|
||||
|
||||
std::string stringify(const dv::value& value);
|
||||
}
|
||||
@ -6,7 +6,7 @@
|
||||
#include <string>
|
||||
|
||||
inline constexpr int ENGINE_VERSION_MAJOR = 0;
|
||||
inline constexpr int ENGINE_VERSION_MINOR = 27;
|
||||
inline constexpr int ENGINE_VERSION_MINOR = 28;
|
||||
|
||||
#ifdef NDEBUG
|
||||
inline constexpr bool ENGINE_DEBUG_BUILD = false;
|
||||
@ -14,7 +14,7 @@ inline constexpr bool ENGINE_DEBUG_BUILD = false;
|
||||
inline constexpr bool ENGINE_DEBUG_BUILD = true;
|
||||
#endif // NDEBUG
|
||||
|
||||
inline const std::string ENGINE_VERSION_STRING = "0.27";
|
||||
inline const std::string ENGINE_VERSION_STRING = "0.28";
|
||||
|
||||
/// @brief world regions format version
|
||||
inline constexpr uint REGION_FORMAT_VERSION = 3;
|
||||
|
||||
133
src/content/ContentControl.cpp
Normal file
133
src/content/ContentControl.cpp
Normal file
@ -0,0 +1,133 @@
|
||||
#include "ContentControl.hpp"
|
||||
|
||||
#include "io/io.hpp"
|
||||
#include "io/engine_paths.hpp"
|
||||
#include "Content.hpp"
|
||||
#include "ContentPack.hpp"
|
||||
#include "ContentBuilder.hpp"
|
||||
#include "ContentLoader.hpp"
|
||||
#include "PacksManager.hpp"
|
||||
#include "objects/rigging.hpp"
|
||||
#include "logic/scripting/scripting.hpp"
|
||||
#include "core_defs.hpp"
|
||||
|
||||
static void load_configs(Input& input, const io::path& root) {
|
||||
auto configFolder = root / "config";
|
||||
}
|
||||
|
||||
ContentControl::ContentControl(
|
||||
EnginePaths& paths, Input& input, std::function<void()> postContent
|
||||
)
|
||||
: paths(paths),
|
||||
input(input),
|
||||
postContent(std::move(postContent)),
|
||||
basePacks(io::read_list("res:config/builtins.list")),
|
||||
manager(std::make_unique<PacksManager>()) {
|
||||
manager->setSources({
|
||||
"world:content",
|
||||
"user:content",
|
||||
"res:content",
|
||||
});
|
||||
}
|
||||
|
||||
ContentControl::~ContentControl() = default;
|
||||
|
||||
Content* ContentControl::get() {
|
||||
return content.get();
|
||||
}
|
||||
|
||||
const Content* ContentControl::get() const {
|
||||
return content.get();
|
||||
}
|
||||
|
||||
std::vector<std::string>& ContentControl::getBasePacks() {
|
||||
return basePacks;
|
||||
}
|
||||
|
||||
void ContentControl::resetContent() {
|
||||
paths.setCurrentWorldFolder("");
|
||||
|
||||
scripting::cleanup();
|
||||
std::vector<PathsRoot> resRoots;
|
||||
{
|
||||
auto pack = ContentPack::createCore(paths);
|
||||
resRoots.push_back({"core", pack.folder});
|
||||
load_configs(input, pack.folder);
|
||||
}
|
||||
manager->scan();
|
||||
for (const auto& pack : manager->getAll(basePacks)) {
|
||||
resRoots.push_back({pack.id, pack.folder});
|
||||
}
|
||||
paths.resPaths = ResPaths(resRoots);
|
||||
content.reset();
|
||||
|
||||
contentPacks.clear();
|
||||
contentPacks = manager->getAll(basePacks);
|
||||
|
||||
postContent();
|
||||
}
|
||||
|
||||
void ContentControl::loadContent(const std::vector<std::string>& names) {
|
||||
manager->scan();
|
||||
contentPacks = manager->getAll(manager->assemble(names));
|
||||
loadContent();
|
||||
}
|
||||
|
||||
void ContentControl::loadContent() {
|
||||
scripting::cleanup();
|
||||
|
||||
std::vector<std::string> names;
|
||||
for (auto& pack : contentPacks) {
|
||||
names.push_back(pack.id);
|
||||
}
|
||||
manager->scan();
|
||||
names = manager->assemble(names);
|
||||
contentPacks = manager->getAll(names);
|
||||
|
||||
std::vector<PathsRoot> entryPoints;
|
||||
for (auto& pack : contentPacks) {
|
||||
entryPoints.emplace_back(pack.id, pack.folder);
|
||||
}
|
||||
paths.setEntryPoints(std::move(entryPoints));
|
||||
|
||||
ContentBuilder contentBuilder;
|
||||
corecontent::setup(input, contentBuilder);
|
||||
|
||||
auto corePack = ContentPack::createCore(paths);
|
||||
|
||||
auto allPacks = contentPacks;
|
||||
allPacks.insert(allPacks.begin(), corePack);
|
||||
|
||||
// Setup filesystem entry points
|
||||
std::vector<PathsRoot> resRoots;
|
||||
for (auto& pack : allPacks) {
|
||||
resRoots.push_back({pack.id, pack.folder});
|
||||
}
|
||||
paths.resPaths = ResPaths(resRoots);
|
||||
// Load content
|
||||
for (auto& pack : allPacks) {
|
||||
ContentLoader(&pack, contentBuilder, paths.resPaths).load();
|
||||
load_configs(input, pack.folder);
|
||||
}
|
||||
content = contentBuilder.build();
|
||||
scripting::on_content_load(content.get());
|
||||
|
||||
ContentLoader::loadScripts(*content);
|
||||
|
||||
postContent();
|
||||
}
|
||||
|
||||
std::vector<ContentPack>& ContentControl::getContentPacks() {
|
||||
return contentPacks;
|
||||
}
|
||||
|
||||
std::vector<ContentPack> ContentControl::getAllContentPacks() {
|
||||
auto packs = contentPacks;
|
||||
packs.insert(packs.begin(), ContentPack::createCore(paths));
|
||||
return packs;
|
||||
}
|
||||
|
||||
PacksManager& ContentControl::scan() {
|
||||
manager->scan();
|
||||
return *manager;
|
||||
}
|
||||
51
src/content/ContentControl.hpp
Normal file
51
src/content/ContentControl.hpp
Normal file
@ -0,0 +1,51 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
|
||||
#include "ContentPack.hpp"
|
||||
|
||||
class Content;
|
||||
class PacksManager;
|
||||
class EnginePaths;
|
||||
class Input;
|
||||
|
||||
namespace io {
|
||||
class path;
|
||||
}
|
||||
|
||||
class ContentControl {
|
||||
public:
|
||||
ContentControl(
|
||||
EnginePaths& paths, Input& input, std::function<void()> postContent
|
||||
);
|
||||
~ContentControl();
|
||||
|
||||
Content* get();
|
||||
|
||||
const Content* get() const;
|
||||
|
||||
std::vector<std::string>& getBasePacks();
|
||||
|
||||
/// @brief Reset content to base packs list
|
||||
void resetContent();
|
||||
|
||||
void loadContent(const std::vector<std::string>& names);
|
||||
|
||||
void loadContent();
|
||||
|
||||
std::vector<ContentPack>& getContentPacks();
|
||||
std::vector<ContentPack> getAllContentPacks();
|
||||
|
||||
PacksManager& scan();
|
||||
private:
|
||||
EnginePaths& paths;
|
||||
Input& input;
|
||||
std::unique_ptr<Content> content;
|
||||
std::function<void()> postContent;
|
||||
std::vector<std::string> basePacks;
|
||||
std::unique_ptr<PacksManager> manager;
|
||||
std::vector<ContentPack> contentPacks;
|
||||
};
|
||||
@ -15,12 +15,13 @@ namespace fs = std::filesystem;
|
||||
|
||||
ContentPack ContentPack::createCore(const EnginePaths& paths) {
|
||||
return ContentPack {
|
||||
"core", "Core", ENGINE_VERSION_STRING, "", "", "res:", "res:", {}
|
||||
"core", "Core", ENGINE_VERSION_STRING, "", "", "res:", {}
|
||||
};
|
||||
}
|
||||
|
||||
const std::vector<std::string> ContentPack::RESERVED_NAMES = {
|
||||
"res", "abs", "local", "core", "user", "world", "none", "null"};
|
||||
"res", "abs", "local", "core", "user", "world", "none", "null"
|
||||
};
|
||||
|
||||
contentpack_error::contentpack_error(
|
||||
std::string packId, io::path folder, const std::string& message
|
||||
@ -70,7 +71,7 @@ static void checkContentPackId(const std::string& id, const io::path& folder) {
|
||||
}
|
||||
}
|
||||
|
||||
ContentPack ContentPack::read(const std::string& path, const io::path& folder) {
|
||||
ContentPack ContentPack::read(const io::path& folder) {
|
||||
auto root = io::read_json(folder / PACKAGE_FILENAME);
|
||||
ContentPack pack;
|
||||
root.at("id").get(pack.id);
|
||||
@ -90,7 +91,6 @@ ContentPack ContentPack::read(const std::string& path, const io::path& folder) {
|
||||
root.at("description").get(pack.description);
|
||||
root.at("source").get(pack.source);
|
||||
pack.folder = folder;
|
||||
pack.path = path;
|
||||
|
||||
if (auto found = root.at("dependencies")) {
|
||||
const auto& dependencies = *found;
|
||||
@ -124,7 +124,7 @@ ContentPack ContentPack::read(const std::string& path, const io::path& folder) {
|
||||
}
|
||||
|
||||
void ContentPack::scanFolder(
|
||||
const std::string& path, const io::path& folder, std::vector<ContentPack>& packs
|
||||
const io::path& folder, std::vector<ContentPack>& packs
|
||||
) {
|
||||
if (!io::is_directory(folder)) {
|
||||
return;
|
||||
@ -133,9 +133,7 @@ void ContentPack::scanFolder(
|
||||
if (!io::is_directory(packFolder)) continue;
|
||||
if (!is_pack(packFolder)) continue;
|
||||
try {
|
||||
packs.push_back(
|
||||
read(path + "/" + packFolder.name(), packFolder)
|
||||
);
|
||||
packs.push_back(read(packFolder));
|
||||
} catch (const contentpack_error& err) {
|
||||
std::cerr << "package.json error at " << err.getFolder().string();
|
||||
std::cerr << ": " << err.what() << std::endl;
|
||||
|
||||
@ -43,7 +43,6 @@ struct ContentPack {
|
||||
std::string creator = "";
|
||||
std::string description = "no description";
|
||||
io::path folder;
|
||||
std::string path;
|
||||
std::vector<DependencyPack> dependencies;
|
||||
std::string source = "";
|
||||
|
||||
@ -58,14 +57,10 @@ struct ContentPack {
|
||||
static const std::vector<std::string> RESERVED_NAMES;
|
||||
|
||||
static bool is_pack(const io::path& folder);
|
||||
static ContentPack read(
|
||||
const std::string& path, const io::path& folder
|
||||
);
|
||||
static ContentPack read(const io::path& folder);
|
||||
|
||||
static void scanFolder(
|
||||
const std::string& path,
|
||||
const io::path& folder,
|
||||
std::vector<ContentPack>& packs
|
||||
const io::path& folder, std::vector<ContentPack>& packs
|
||||
);
|
||||
|
||||
static std::vector<std::string> worldPacksList(
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
|
||||
PacksManager::PacksManager() = default;
|
||||
|
||||
void PacksManager::setSources(std::vector<std::pair<std::string, io::path>> sources) {
|
||||
void PacksManager::setSources(std::vector<io::path> sources) {
|
||||
this->sources = std::move(sources);
|
||||
}
|
||||
|
||||
@ -15,8 +15,8 @@ void PacksManager::scan() {
|
||||
packs.clear();
|
||||
|
||||
std::vector<ContentPack> packsList;
|
||||
for (auto& [path, folder] : sources) {
|
||||
ContentPack::scanFolder(path, folder, packsList);
|
||||
for (auto& folder : sources) {
|
||||
ContentPack::scanFolder(folder, packsList);
|
||||
for (auto& pack : packsList) {
|
||||
packs.try_emplace(pack.id, pack);
|
||||
}
|
||||
|
||||
@ -8,12 +8,12 @@
|
||||
|
||||
class PacksManager {
|
||||
std::unordered_map<std::string, ContentPack> packs;
|
||||
std::vector<std::pair<std::string, io::path>> sources;
|
||||
std::vector<io::path> sources;
|
||||
public:
|
||||
PacksManager();
|
||||
|
||||
/// @brief Set content packs sources (search folders)
|
||||
void setSources(std::vector<std::pair<std::string, io::path>> sources);
|
||||
void setSources(std::vector<io::path> sources);
|
||||
|
||||
/// @brief Scan sources and collect all found packs excluding duplication.
|
||||
/// Scanning order depends on sources order
|
||||
|
||||
@ -5,13 +5,12 @@
|
||||
#include "content/ContentBuilder.hpp"
|
||||
#include "io/io.hpp"
|
||||
#include "io/engine_paths.hpp"
|
||||
#include "window/Window.hpp"
|
||||
#include "window/Events.hpp"
|
||||
#include "window/input.hpp"
|
||||
#include "voxels/Block.hpp"
|
||||
#include "coders/toml.hpp"
|
||||
|
||||
// All in-game definitions (blocks, items, etc..)
|
||||
void corecontent::setup(ContentBuilder& builder) {
|
||||
void corecontent::setup(Input& input, ContentBuilder& builder) {
|
||||
{
|
||||
Block& block = builder.blocks.create(CORE_AIR);
|
||||
block.replaceable = true;
|
||||
@ -30,8 +29,8 @@ void corecontent::setup(ContentBuilder& builder) {
|
||||
|
||||
auto bindsFile = "res:bindings.toml";
|
||||
if (io::is_regular_file(bindsFile)) {
|
||||
Events::loadBindings(
|
||||
bindsFile, io::read_string(bindsFile), BindType::BIND
|
||||
input.getBindings().read(
|
||||
toml::parse(bindsFile, io::read_string(bindsFile)), BindType::BIND
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -28,8 +28,9 @@ inline const std::string BIND_PLAYER_FAST_INTERACTOIN =
|
||||
"player.fast_interaction";
|
||||
inline const std::string BIND_HUD_INVENTORY = "hud.inventory";
|
||||
|
||||
class Input;
|
||||
class ContentBuilder;
|
||||
|
||||
namespace corecontent {
|
||||
void setup(ContentBuilder& builder);
|
||||
void setup(Input& input, ContentBuilder& builder);
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
#include <string.h>
|
||||
#include <algorithm>
|
||||
|
||||
#include "data/dv.hpp"
|
||||
#include "util/data_io.hpp"
|
||||
#include "util/stringutil.hpp"
|
||||
|
||||
|
||||
6
src/data/dv_fwd.hpp
Normal file
6
src/data/dv_fwd.hpp
Normal file
@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
namespace dv {
|
||||
class value;
|
||||
struct optionalvalue;
|
||||
}
|
||||
@ -7,6 +7,7 @@
|
||||
|
||||
#include "delegates.hpp"
|
||||
#include "typedefs.hpp"
|
||||
#include "util/observer_handler.hpp"
|
||||
|
||||
enum class setting_format { simple, percent };
|
||||
|
||||
@ -41,15 +42,14 @@ public:
|
||||
: Setting(format), initial(value), value(value) {
|
||||
}
|
||||
|
||||
observer_handler observe(consumer<T> callback, bool callOnStart = false) {
|
||||
ObserverHandler observe(consumer<T> callback, bool callOnStart = false) {
|
||||
const int id = nextid++;
|
||||
observers.emplace(id, callback);
|
||||
if (callOnStart) {
|
||||
callback(value);
|
||||
}
|
||||
return std::shared_ptr<int>(new int(id), [this](int* id) { //-V508
|
||||
observers.erase(*id);
|
||||
delete id;
|
||||
return ObserverHandler([this, id]() {
|
||||
observers.erase(id);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -12,9 +12,7 @@
|
||||
#include "coders/json.hpp"
|
||||
#include "coders/toml.hpp"
|
||||
#include "coders/commons.hpp"
|
||||
#include "content/Content.hpp"
|
||||
#include "content/ContentBuilder.hpp"
|
||||
#include "content/ContentLoader.hpp"
|
||||
#include "content/ContentControl.hpp"
|
||||
#include "core_defs.hpp"
|
||||
#include "io/io.hpp"
|
||||
#include "frontend/locale.hpp"
|
||||
@ -31,10 +29,8 @@
|
||||
#include "logic/scripting/scripting.hpp"
|
||||
#include "logic/scripting/scripting_hud.hpp"
|
||||
#include "network/Network.hpp"
|
||||
#include "util/listutil.hpp"
|
||||
#include "util/platform.hpp"
|
||||
#include "window/Camera.hpp"
|
||||
#include "window/Events.hpp"
|
||||
#include "window/input.hpp"
|
||||
#include "window/Window.hpp"
|
||||
#include "world/Level.hpp"
|
||||
@ -50,8 +46,6 @@
|
||||
|
||||
static debug::Logger logger("engine");
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
static std::unique_ptr<ImageData> load_icon() {
|
||||
try {
|
||||
auto file = "res:textures/misc/icon.png";
|
||||
@ -65,20 +59,21 @@ static std::unique_ptr<ImageData> load_icon() {
|
||||
}
|
||||
|
||||
Engine::Engine() = default;
|
||||
Engine::~Engine() = default;
|
||||
|
||||
static std::unique_ptr<Engine> engine;
|
||||
static std::unique_ptr<Engine> instance = nullptr;
|
||||
|
||||
Engine& Engine::getInstance() {
|
||||
if (!engine) {
|
||||
engine = std::make_unique<Engine>();
|
||||
if (!instance) {
|
||||
instance = std::make_unique<Engine>();
|
||||
}
|
||||
return *engine;
|
||||
return *instance;
|
||||
}
|
||||
|
||||
void Engine::initialize(CoreParameters coreParameters) {
|
||||
params = std::move(coreParameters);
|
||||
settingsHandler = std::make_unique<SettingsHandler>(settings);
|
||||
interpreter = std::make_unique<cmd::CommandsInterpreter>();
|
||||
cmd = std::make_unique<cmd::CommandsInterpreter>();
|
||||
network = network::Network::create(settings.network);
|
||||
|
||||
logger.info() << "engine version: " << ENGINE_VERSION_STRING;
|
||||
@ -93,46 +88,80 @@ void Engine::initialize(CoreParameters coreParameters) {
|
||||
}
|
||||
loadSettings();
|
||||
|
||||
auto resdir = paths.getResourcesFolder();
|
||||
|
||||
controller = std::make_unique<EngineController>(*this);
|
||||
if (!params.headless) {
|
||||
if (Window::initialize(&settings.display)){
|
||||
std::string title = "VoxelCore v" +
|
||||
std::to_string(ENGINE_VERSION_MAJOR) + "." +
|
||||
std::to_string(ENGINE_VERSION_MINOR);
|
||||
if (ENGINE_DEBUG_BUILD) {
|
||||
title += " [debug]";
|
||||
}
|
||||
auto [window, input] = Window::initialize(&settings.display, title);
|
||||
if (!window || !input){
|
||||
throw initialize_error("could not initialize window");
|
||||
}
|
||||
time.set(Window::time());
|
||||
window->setFramerate(settings.display.framerate.get());
|
||||
|
||||
time.set(window->time());
|
||||
if (auto icon = load_icon()) {
|
||||
icon->flipY();
|
||||
Window::setIcon(icon.get());
|
||||
window->setIcon(icon.get());
|
||||
}
|
||||
this->window = std::move(window);
|
||||
this->input = std::move(input);
|
||||
|
||||
loadControls();
|
||||
|
||||
gui = std::make_unique<gui::GUI>();
|
||||
gui = std::make_unique<gui::GUI>(*this);
|
||||
if (ENGINE_DEBUG_BUILD) {
|
||||
menus::create_version_label(*this);
|
||||
menus::create_version_label(*gui);
|
||||
}
|
||||
keepAlive(settings.display.fullscreen.observe(
|
||||
[this](bool value) {
|
||||
if (value != this->window->isFullscreen()) {
|
||||
this->window->toggleFullscreen();
|
||||
}
|
||||
},
|
||||
true
|
||||
));
|
||||
}
|
||||
audio::initialize(!params.headless, settings.audio);
|
||||
|
||||
bool langNotSet = settings.ui.language.get() == "auto";
|
||||
if (langNotSet) {
|
||||
settings.ui.language.set(langs::locale_by_envlocale(
|
||||
platform::detect_locale(),
|
||||
"res:"
|
||||
));
|
||||
settings.ui.language.set(
|
||||
langs::locale_by_envlocale(platform::detect_locale())
|
||||
);
|
||||
}
|
||||
content = std::make_unique<ContentControl>(paths, *input, [this]() {
|
||||
langs::setup(langs::get_current(), paths.resPaths.collectRoots());
|
||||
if (!isHeadless()) {
|
||||
for (auto& pack : content->getAllContentPacks()) {
|
||||
auto configFolder = pack.folder / "config";
|
||||
auto bindsFile = configFolder / "bindings.toml";
|
||||
if (io::is_regular_file(bindsFile)) {
|
||||
input->getBindings().read(
|
||||
toml::parse(
|
||||
bindsFile.string(), io::read_string(bindsFile)
|
||||
),
|
||||
BindType::BIND
|
||||
);
|
||||
}
|
||||
}
|
||||
loadAssets();
|
||||
}
|
||||
});
|
||||
scripting::initialize(this);
|
||||
if (!isHeadless()) {
|
||||
gui->setPageLoader(scripting::create_page_loader());
|
||||
}
|
||||
keepAlive(settings.ui.language.observe([this](auto lang) {
|
||||
setLanguage(lang);
|
||||
langs::setup(lang, paths.resPaths.collectRoots());
|
||||
}, true));
|
||||
basePacks = io::read_list("res:config/builtins.list");
|
||||
}
|
||||
|
||||
void Engine::loadSettings() {
|
||||
io::path settings_file = paths.getSettingsFile();
|
||||
io::path settings_file = EnginePaths::SETTINGS_FILE;
|
||||
if (io::is_regular_file(settings_file)) {
|
||||
logger.info() << "loading settings";
|
||||
std::string text = io::read_string(settings_file);
|
||||
@ -146,33 +175,30 @@ void Engine::loadSettings() {
|
||||
}
|
||||
|
||||
void Engine::loadControls() {
|
||||
io::path controls_file = paths.getControlsFile();
|
||||
io::path controls_file = EnginePaths::CONTROLS_FILE;
|
||||
if (io::is_regular_file(controls_file)) {
|
||||
logger.info() << "loading controls";
|
||||
std::string text = io::read_string(controls_file);
|
||||
Events::loadBindings(controls_file.string(), text, BindType::BIND);
|
||||
input->getBindings().read(
|
||||
toml::parse(controls_file.string(), text), BindType::BIND
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void Engine::onAssetsLoaded() {
|
||||
assets->setup();
|
||||
gui->onAssetsLoad(assets.get());
|
||||
}
|
||||
|
||||
void Engine::updateHotkeys() {
|
||||
if (Events::jpressed(keycode::F2)) {
|
||||
if (input->jpressed(Keycode::F2)) {
|
||||
saveScreenshot();
|
||||
}
|
||||
if (Events::jpressed(keycode::F8)) {
|
||||
if (input->jpressed(Keycode::F8)) {
|
||||
gui->toggleDebug();
|
||||
}
|
||||
if (Events::jpressed(keycode::F11)) {
|
||||
if (input->jpressed(Keycode::F11)) {
|
||||
settings.display.fullscreen.toggle();
|
||||
}
|
||||
}
|
||||
|
||||
void Engine::saveScreenshot() {
|
||||
auto image = Window::takeScreenshot();
|
||||
auto image = window->takeScreenshot();
|
||||
image->flipY();
|
||||
io::path filename = paths.getNewScreenshotFile("png");
|
||||
imageio::write(filename.string(), image.get());
|
||||
@ -197,39 +223,38 @@ void Engine::updateFrontend() {
|
||||
double delta = time.getDelta();
|
||||
updateHotkeys();
|
||||
audio::update(delta);
|
||||
gui->act(delta, Viewport(Window::width, Window::height));
|
||||
gui->act(delta, window->getSize());
|
||||
screen->update(delta);
|
||||
gui->postAct();
|
||||
}
|
||||
|
||||
void Engine::nextFrame() {
|
||||
Window::setFramerate(
|
||||
Window::isIconified() && settings.display.limitFpsIconified.get()
|
||||
window->setFramerate(
|
||||
window->isIconified() && settings.display.limitFpsIconified.get()
|
||||
? 20
|
||||
: settings.display.framerate.get()
|
||||
);
|
||||
Window::swapBuffers();
|
||||
Events::pollEvents();
|
||||
window->swapBuffers();
|
||||
input->pollEvents();
|
||||
}
|
||||
|
||||
void Engine::renderFrame() {
|
||||
screen->draw(time.getDelta());
|
||||
|
||||
Viewport viewport(Window::width, Window::height);
|
||||
DrawContext ctx(nullptr, viewport, nullptr);
|
||||
DrawContext ctx(nullptr, *window, nullptr);
|
||||
gui->draw(ctx, *assets);
|
||||
}
|
||||
|
||||
void Engine::saveSettings() {
|
||||
logger.info() << "saving settings";
|
||||
io::write_string(paths.getSettingsFile(), toml::stringify(*settingsHandler));
|
||||
io::write_string(EnginePaths::SETTINGS_FILE, toml::stringify(*settingsHandler));
|
||||
if (!params.headless) {
|
||||
logger.info() << "saving bindings";
|
||||
io::write_string(paths.getControlsFile(), Events::writeBindings());
|
||||
io::write_string(EnginePaths::CONTROLS_FILE, input->getBindings().write());
|
||||
}
|
||||
}
|
||||
|
||||
Engine::~Engine() {
|
||||
void Engine::close() {
|
||||
saveSettings();
|
||||
logger.info() << "shutting down";
|
||||
if (screen) {
|
||||
@ -238,7 +263,7 @@ Engine::~Engine() {
|
||||
}
|
||||
content.reset();
|
||||
assets.reset();
|
||||
interpreter.reset();
|
||||
cmd.reset();
|
||||
if (gui) {
|
||||
gui.reset();
|
||||
logger.info() << "gui finished";
|
||||
@ -249,45 +274,34 @@ Engine::~Engine() {
|
||||
scripting::close();
|
||||
logger.info() << "scripting finished";
|
||||
if (!params.headless) {
|
||||
Window::terminate();
|
||||
window.reset();
|
||||
logger.info() << "window closed";
|
||||
}
|
||||
logger.info() << "engine finished";
|
||||
}
|
||||
|
||||
void Engine::terminate() {
|
||||
engine.reset();
|
||||
instance->close();
|
||||
instance.reset();
|
||||
}
|
||||
|
||||
EngineController* Engine::getController() {
|
||||
return controller.get();
|
||||
}
|
||||
|
||||
cmd::CommandsInterpreter* Engine::getCommandsInterpreter() {
|
||||
return interpreter.get();
|
||||
}
|
||||
|
||||
PacksManager Engine::createPacksManager(const io::path& worldFolder) {
|
||||
PacksManager manager;
|
||||
manager.setSources({
|
||||
{"world:content", worldFolder.empty() ? worldFolder : worldFolder / "content"},
|
||||
{"user:content", "user:content"},
|
||||
{"res:content", "res:content"}
|
||||
});
|
||||
return manager;
|
||||
}
|
||||
|
||||
void Engine::setLevelConsumer(OnWorldOpen levelConsumer) {
|
||||
this->levelConsumer = std::move(levelConsumer);
|
||||
}
|
||||
|
||||
void Engine::loadAssets() {
|
||||
logger.info() << "loading assets";
|
||||
Shader::preprocessor->setPaths(resPaths.get());
|
||||
Shader::preprocessor->setPaths(&paths.resPaths);
|
||||
|
||||
auto content = this->content->get();
|
||||
|
||||
auto new_assets = std::make_unique<Assets>();
|
||||
AssetsLoader loader(new_assets.get(), resPaths.get());
|
||||
AssetsLoader::addDefaults(loader, content.get());
|
||||
AssetsLoader loader(*this, *new_assets, paths.resPaths);
|
||||
AssetsLoader::addDefaults(loader, content);
|
||||
|
||||
// no need
|
||||
// correct log messages order is more useful
|
||||
@ -301,139 +315,11 @@ void Engine::loadAssets() {
|
||||
}
|
||||
}
|
||||
assets = std::move(new_assets);
|
||||
|
||||
if (content == nullptr) {
|
||||
return;
|
||||
if (content) {
|
||||
ModelsGenerator::prepare(*content, *assets);
|
||||
}
|
||||
for (auto& [name, def] : content->blocks.getDefs()) {
|
||||
if (def->model == BlockModel::custom && def->modelName.empty()) {
|
||||
assets->store(
|
||||
std::make_unique<model::Model>(
|
||||
ModelsGenerator::loadCustomBlockModel(
|
||||
def->customModelRaw, *assets, !def->shadeless
|
||||
)
|
||||
),
|
||||
name + ".model"
|
||||
);
|
||||
def->modelName = def->name + ".model";
|
||||
}
|
||||
}
|
||||
for (auto& [name, def] : content->items.getDefs()) {
|
||||
assets->store(
|
||||
std::make_unique<model::Model>(
|
||||
ModelsGenerator::generate(*def, *content, *assets)
|
||||
),
|
||||
name + ".model"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static void load_configs(const io::path& root) {
|
||||
auto configFolder = root / "config";
|
||||
auto bindsFile = configFolder / "bindings.toml";
|
||||
if (io::is_regular_file(bindsFile)) {
|
||||
Events::loadBindings(
|
||||
bindsFile.string(), io::read_string(bindsFile), BindType::BIND
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void Engine::loadContent() {
|
||||
scripting::cleanup();
|
||||
|
||||
std::vector<std::string> names;
|
||||
for (auto& pack : contentPacks) {
|
||||
names.push_back(pack.id);
|
||||
}
|
||||
|
||||
ContentBuilder contentBuilder;
|
||||
corecontent::setup(contentBuilder);
|
||||
|
||||
paths.setContentPacks(&contentPacks);
|
||||
PacksManager manager = createPacksManager(paths.getCurrentWorldFolder());
|
||||
manager.scan();
|
||||
names = manager.assemble(names);
|
||||
contentPacks = manager.getAll(names);
|
||||
|
||||
auto corePack = ContentPack::createCore(paths);
|
||||
|
||||
// Setup filesystem entry points
|
||||
std::vector<PathsRoot> resRoots {
|
||||
{"core", corePack.folder}
|
||||
};
|
||||
for (auto& pack : contentPacks) {
|
||||
resRoots.push_back({pack.id, pack.folder});
|
||||
}
|
||||
resPaths = std::make_unique<ResPaths>("res:", resRoots);
|
||||
|
||||
// Load content
|
||||
{
|
||||
ContentLoader(&corePack, contentBuilder, *resPaths).load();
|
||||
load_configs(corePack.folder);
|
||||
}
|
||||
for (auto& pack : contentPacks) {
|
||||
ContentLoader(&pack, contentBuilder, *resPaths).load();
|
||||
load_configs(pack.folder);
|
||||
}
|
||||
content = contentBuilder.build();
|
||||
interpreter->reset();
|
||||
scripting::on_content_load(content.get());
|
||||
|
||||
ContentLoader::loadScripts(*content);
|
||||
|
||||
langs::setup("res:", langs::current->getId(), contentPacks);
|
||||
if (!isHeadless()) {
|
||||
loadAssets();
|
||||
onAssetsLoaded();
|
||||
}
|
||||
}
|
||||
|
||||
void Engine::resetContent() {
|
||||
scripting::cleanup();
|
||||
std::vector<PathsRoot> resRoots;
|
||||
{
|
||||
auto pack = ContentPack::createCore(paths);
|
||||
resRoots.push_back({"core", pack.folder});
|
||||
load_configs(pack.folder);
|
||||
}
|
||||
auto manager = createPacksManager(io::path());
|
||||
manager.scan();
|
||||
for (const auto& pack : manager.getAll(basePacks)) {
|
||||
resRoots.push_back({pack.id, pack.folder});
|
||||
}
|
||||
resPaths = std::make_unique<ResPaths>("res:", resRoots);
|
||||
contentPacks.clear();
|
||||
content.reset();
|
||||
|
||||
langs::setup("res:", langs::current->getId(), contentPacks);
|
||||
if (!isHeadless()) {
|
||||
loadAssets();
|
||||
onAssetsLoaded();
|
||||
}
|
||||
|
||||
contentPacks = manager.getAll(basePacks);
|
||||
}
|
||||
|
||||
void Engine::loadWorldContent(const io::path& folder) {
|
||||
contentPacks.clear();
|
||||
auto packNames = ContentPack::worldPacksList(folder);
|
||||
PacksManager manager;
|
||||
manager.setSources(
|
||||
{{"world:content", folder.empty() ? folder : folder / "content"},
|
||||
{"user:content", "user:content"},
|
||||
{"res:content", "res:content"}}
|
||||
);
|
||||
manager.scan();
|
||||
contentPacks = manager.getAll(manager.assemble(packNames));
|
||||
paths.setCurrentWorldFolder(folder);
|
||||
loadContent();
|
||||
}
|
||||
|
||||
void Engine::loadAllPacks() {
|
||||
PacksManager manager = createPacksManager(paths.getCurrentWorldFolder());
|
||||
manager.scan();
|
||||
auto allnames = manager.getAllNames();
|
||||
contentPacks = manager.getAll(manager.assemble(allnames));
|
||||
assets->setup();
|
||||
gui->onAssetsLoad(assets.get());
|
||||
}
|
||||
|
||||
void Engine::setScreen(std::shared_ptr<Screen> screen) {
|
||||
@ -443,10 +329,6 @@ void Engine::setScreen(std::shared_ptr<Screen> screen) {
|
||||
this->screen = std::move(screen);
|
||||
}
|
||||
|
||||
void Engine::setLanguage(std::string locale) {
|
||||
langs::setup("res:", std::move(locale), contentPacks);
|
||||
}
|
||||
|
||||
void Engine::onWorldOpen(std::unique_ptr<Level> level, int64_t localPlayer) {
|
||||
logger.info() << "world open";
|
||||
levelConsumer(std::move(level), localPlayer);
|
||||
@ -460,7 +342,7 @@ void Engine::onWorldClosed() {
|
||||
void Engine::quit() {
|
||||
quitSignal = true;
|
||||
if (!isHeadless()) {
|
||||
Window::setShouldClose(true);
|
||||
window->setShouldClose(true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -468,10 +350,6 @@ bool Engine::isQuitSignal() const {
|
||||
return quitSignal;
|
||||
}
|
||||
|
||||
gui::GUI* Engine::getGUI() {
|
||||
return gui.get();
|
||||
}
|
||||
|
||||
EngineSettings& Engine::getSettings() {
|
||||
return settings;
|
||||
}
|
||||
@ -480,34 +358,12 @@ Assets* Engine::getAssets() {
|
||||
return assets.get();
|
||||
}
|
||||
|
||||
const Content* Engine::getContent() const {
|
||||
return content.get();
|
||||
}
|
||||
|
||||
Content* Engine::getWriteableContent() {
|
||||
return content.get();
|
||||
}
|
||||
|
||||
std::vector<ContentPack> Engine::getAllContentPacks() {
|
||||
auto packs = getContentPacks();
|
||||
packs.insert(packs.begin(), ContentPack::createCore(paths));
|
||||
return packs;
|
||||
}
|
||||
|
||||
std::vector<ContentPack>& Engine::getContentPacks() {
|
||||
return contentPacks;
|
||||
}
|
||||
|
||||
std::vector<std::string>& Engine::getBasePacks() {
|
||||
return basePacks;
|
||||
}
|
||||
|
||||
EnginePaths& Engine::getPaths() {
|
||||
return paths;
|
||||
}
|
||||
|
||||
ResPaths* Engine::getResPaths() {
|
||||
return resPaths.get();
|
||||
ResPaths& Engine::getResPaths() {
|
||||
return paths.resPaths;
|
||||
}
|
||||
|
||||
std::shared_ptr<Screen> Engine::getScreen() {
|
||||
@ -518,10 +374,6 @@ SettingsHandler& Engine::getSettingsHandler() {
|
||||
return *settingsHandler;
|
||||
}
|
||||
|
||||
network::Network& Engine::getNetwork() {
|
||||
return *network;
|
||||
}
|
||||
|
||||
Time& Engine::getTime() {
|
||||
return time;
|
||||
}
|
||||
@ -533,3 +385,7 @@ const CoreParameters& Engine::getCoreParameters() const {
|
||||
bool Engine::isHeadless() const {
|
||||
return params.headless;
|
||||
}
|
||||
|
||||
ContentControl& Engine::getContentControl() {
|
||||
return *content;
|
||||
}
|
||||
|
||||
@ -4,10 +4,6 @@
|
||||
#include "typedefs.hpp"
|
||||
#include "settings.hpp"
|
||||
|
||||
#include "assets/Assets.hpp"
|
||||
#include "content/content_fwd.hpp"
|
||||
#include "content/ContentPack.hpp"
|
||||
#include "content/PacksManager.hpp"
|
||||
#include "io/engine_paths.hpp"
|
||||
#include "io/settings_io.hpp"
|
||||
#include "util/ObjectsKeeper.hpp"
|
||||
@ -15,17 +11,15 @@
|
||||
#include "Time.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class Window;
|
||||
class Assets;
|
||||
class Level;
|
||||
class Screen;
|
||||
class EnginePaths;
|
||||
class ResPaths;
|
||||
class ContentControl;
|
||||
class EngineController;
|
||||
class SettingsHandler;
|
||||
struct EngineSettings;
|
||||
class Input;
|
||||
|
||||
namespace gui {
|
||||
class GUI;
|
||||
@ -62,13 +56,12 @@ class Engine : public util::ObjectsKeeper {
|
||||
std::unique_ptr<SettingsHandler> settingsHandler;
|
||||
std::unique_ptr<Assets> assets;
|
||||
std::shared_ptr<Screen> screen;
|
||||
std::vector<ContentPack> contentPacks;
|
||||
std::unique_ptr<Content> content;
|
||||
std::unique_ptr<ResPaths> resPaths;
|
||||
std::unique_ptr<ContentControl> content;
|
||||
std::unique_ptr<EngineController> controller;
|
||||
std::unique_ptr<cmd::CommandsInterpreter> interpreter;
|
||||
std::unique_ptr<cmd::CommandsInterpreter> cmd;
|
||||
std::unique_ptr<network::Network> network;
|
||||
std::vector<std::string> basePacks;
|
||||
std::unique_ptr<Window> window;
|
||||
std::unique_ptr<Input> input;
|
||||
std::unique_ptr<gui::GUI> gui;
|
||||
PostRunnables postRunnables;
|
||||
Time time;
|
||||
@ -87,6 +80,7 @@ public:
|
||||
static Engine& getInstance();
|
||||
|
||||
void initialize(CoreParameters coreParameters);
|
||||
void close();
|
||||
|
||||
static void terminate();
|
||||
|
||||
@ -99,39 +93,15 @@ public:
|
||||
void renderFrame();
|
||||
void nextFrame();
|
||||
|
||||
/// @brief Called after assets loading when all engine systems are initialized
|
||||
void onAssetsLoaded();
|
||||
|
||||
/// @brief Set screen (scene).
|
||||
/// nullptr may be used to delete previous screen before creating new one,
|
||||
/// not-null value must be set before next frame
|
||||
/// @param screen nullable screen
|
||||
void setScreen(std::shared_ptr<Screen> screen);
|
||||
|
||||
/// @brief Change locale to specified
|
||||
/// @param locale isolanguage_ISOCOUNTRY (example: en_US)
|
||||
void setLanguage(std::string locale);
|
||||
|
||||
/// @brief Load all selected content-packs and reload assets
|
||||
void loadContent();
|
||||
|
||||
/// @brief Reset content to base packs list
|
||||
void resetContent();
|
||||
|
||||
/// @brief Collect world content-packs and load content
|
||||
/// @see loadContent
|
||||
/// @param folder world folder
|
||||
void loadWorldContent(const io::path& folder);
|
||||
|
||||
/// @brief Collect all available content-packs from res/content
|
||||
void loadAllPacks();
|
||||
|
||||
/// @brief Get active assets storage instance
|
||||
Assets* getAssets();
|
||||
|
||||
/// @brief Get main UI controller
|
||||
gui::GUI* getGUI();
|
||||
|
||||
/// @brief Get writeable engine settings structure instance
|
||||
EngineSettings& getSettings();
|
||||
|
||||
@ -139,7 +109,7 @@ public:
|
||||
EnginePaths& getPaths();
|
||||
|
||||
/// @brief Get engine resource paths controller
|
||||
ResPaths* getResPaths();
|
||||
ResPaths& getResPaths();
|
||||
|
||||
void onWorldOpen(std::unique_ptr<Level> level, int64_t localPlayer);
|
||||
void onWorldClosed();
|
||||
@ -148,18 +118,6 @@ public:
|
||||
|
||||
bool isQuitSignal() const;
|
||||
|
||||
/// @brief Get current Content instance
|
||||
const Content* getContent() const;
|
||||
|
||||
Content* getWriteableContent();
|
||||
|
||||
/// @brief Get selected content packs
|
||||
std::vector<ContentPack>& getContentPacks();
|
||||
|
||||
std::vector<ContentPack> getAllContentPacks();
|
||||
|
||||
std::vector<std::string>& getBasePacks();
|
||||
|
||||
/// @brief Get current screen
|
||||
std::shared_ptr<Screen> getScreen();
|
||||
|
||||
@ -171,19 +129,36 @@ public:
|
||||
void saveScreenshot();
|
||||
|
||||
EngineController* getController();
|
||||
cmd::CommandsInterpreter* getCommandsInterpreter();
|
||||
|
||||
PacksManager createPacksManager(const io::path& worldFolder);
|
||||
|
||||
void setLevelConsumer(OnWorldOpen levelConsumer);
|
||||
|
||||
SettingsHandler& getSettingsHandler();
|
||||
|
||||
network::Network& getNetwork();
|
||||
|
||||
Time& getTime();
|
||||
|
||||
const CoreParameters& getCoreParameters() const;
|
||||
|
||||
bool isHeadless() const;
|
||||
|
||||
ContentControl& getContentControl();
|
||||
|
||||
gui::GUI& getGUI() {
|
||||
return *gui;
|
||||
}
|
||||
|
||||
Input& getInput() {
|
||||
return *input;
|
||||
}
|
||||
|
||||
Window& getWindow() {
|
||||
return *window;
|
||||
}
|
||||
|
||||
network::Network& getNetwork() {
|
||||
return *network;
|
||||
}
|
||||
|
||||
cmd::CommandsInterpreter& getCmd() {
|
||||
return *cmd;
|
||||
}
|
||||
};
|
||||
|
||||
@ -14,6 +14,7 @@ Mainloop::Mainloop(Engine& engine) : engine(engine) {
|
||||
|
||||
void Mainloop::run() {
|
||||
auto& time = engine.getTime();
|
||||
auto& window = engine.getWindow();
|
||||
|
||||
engine.setLevelConsumer([this](auto level, int64_t localPlayer) {
|
||||
if (level == nullptr) {
|
||||
@ -32,10 +33,10 @@ void Mainloop::run() {
|
||||
engine.setScreen(std::make_shared<MenuScreen>(engine));
|
||||
|
||||
logger.info() << "main loop started";
|
||||
while (!Window::isShouldClose()){
|
||||
time.update(Window::time());
|
||||
while (!window.isShouldClose()){
|
||||
time.update(window.time());
|
||||
engine.updateFrontend();
|
||||
if (!Window::isIconified()) {
|
||||
if (!window.isIconified()) {
|
||||
engine.renderFrame();
|
||||
}
|
||||
engine.postUpdate();
|
||||
|
||||
@ -69,10 +69,6 @@ void ContentGfxCache::refresh() {
|
||||
|
||||
ContentGfxCache::~ContentGfxCache() = default;
|
||||
|
||||
const Content* ContentGfxCache::getContent() const {
|
||||
return &content;
|
||||
}
|
||||
|
||||
const model::Model& ContentGfxCache::getModel(blockid_t id) const {
|
||||
const auto& found = models.find(id);
|
||||
if (found == models.end()) {
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
#include <stdexcept>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "maths/UVRegion.hpp"
|
||||
#include "graphics/commons/Model.hpp"
|
||||
|
||||
class Content;
|
||||
@ -15,10 +16,6 @@ class Block;
|
||||
struct UVRegion;
|
||||
struct GraphicsSettings;
|
||||
|
||||
namespace model {
|
||||
struct Model;
|
||||
}
|
||||
|
||||
class ContentGfxCache {
|
||||
const Content& content;
|
||||
const Assets& assets;
|
||||
@ -41,8 +38,6 @@ public:
|
||||
|
||||
const model::Model& getModel(blockid_t id) const;
|
||||
|
||||
const Content* getContent() const;
|
||||
|
||||
void refresh(const Block& block, const Atlas& atlas);
|
||||
|
||||
void refresh();
|
||||
|
||||
@ -12,27 +12,33 @@
|
||||
#include "objects/Player.hpp"
|
||||
#include "voxels/Block.hpp"
|
||||
#include "world/Level.hpp"
|
||||
#include "engine/Engine.hpp"
|
||||
|
||||
LevelFrontend::LevelFrontend(
|
||||
Engine& engine,
|
||||
Player* currentPlayer,
|
||||
LevelController* controller,
|
||||
Assets& assets,
|
||||
const EngineSettings& settings
|
||||
)
|
||||
: level(*controller->getLevel()),
|
||||
controller(controller),
|
||||
assets(assets),
|
||||
assets(*engine.getAssets()),
|
||||
contentCache(std::make_unique<ContentGfxCache>(
|
||||
level.content, assets, settings.graphics
|
||||
)) {
|
||||
assets.store(
|
||||
BlocksPreview::build(
|
||||
*contentCache, assets, *level.content.getIndices()
|
||||
engine.getWindow(),
|
||||
*contentCache,
|
||||
*engine.getAssets(),
|
||||
*level.content.getIndices()
|
||||
),
|
||||
"block-previews"
|
||||
);
|
||||
|
||||
auto& rassets = assets;
|
||||
controller->getBlocksController()->listenBlockInteraction(
|
||||
[currentPlayer, controller, &assets](auto player, const auto& pos, const auto& def, BlockInteraction type) {
|
||||
[currentPlayer, controller, &rassets](auto player, const auto& pos, const auto& def, BlockInteraction type) {
|
||||
const auto& level = *controller->getLevel();
|
||||
auto material = level.content.findBlockMaterial(def.material);
|
||||
if (material == nullptr) {
|
||||
@ -40,7 +46,7 @@ LevelFrontend::LevelFrontend(
|
||||
}
|
||||
|
||||
if (type == BlockInteraction::step) {
|
||||
auto sound = assets.get<audio::Sound>(material->stepsSound);
|
||||
auto sound = rassets.get<audio::Sound>(material->stepsSound);
|
||||
glm::vec3 pos {};
|
||||
auto soundsCamera = currentPlayer->currentCamera.get();
|
||||
if (soundsCamera == currentPlayer->spCamera.get() ||
|
||||
@ -66,10 +72,10 @@ LevelFrontend::LevelFrontend(
|
||||
audio::Sound* sound = nullptr;
|
||||
switch (type) {
|
||||
case BlockInteraction::placing:
|
||||
sound = assets.get<audio::Sound>(material->placeSound);
|
||||
sound = rassets.get<audio::Sound>(material->placeSound);
|
||||
break;
|
||||
case BlockInteraction::destruction:
|
||||
sound = assets.get<audio::Sound>(material->breakSound);
|
||||
sound = rassets.get<audio::Sound>(material->breakSound);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -95,14 +101,6 @@ Level& LevelFrontend::getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
const Level& LevelFrontend::getLevel() const {
|
||||
return level;
|
||||
}
|
||||
|
||||
const Assets& LevelFrontend::getAssets() const {
|
||||
return assets;
|
||||
}
|
||||
|
||||
ContentGfxCache& LevelFrontend::getContentGfxCache() {
|
||||
return *contentCache;
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
class Level;
|
||||
class Assets;
|
||||
class Player;
|
||||
class Engine;
|
||||
class ContentGfxCache;
|
||||
class LevelController;
|
||||
struct EngineSettings;
|
||||
@ -12,20 +13,18 @@ struct EngineSettings;
|
||||
class LevelFrontend {
|
||||
Level& level;
|
||||
LevelController* controller;
|
||||
const Assets& assets;
|
||||
Assets& assets;
|
||||
std::unique_ptr<ContentGfxCache> contentCache;
|
||||
public:
|
||||
LevelFrontend(
|
||||
Engine& engine,
|
||||
Player* currentPlayer,
|
||||
LevelController* controller,
|
||||
Assets& assets,
|
||||
const EngineSettings& settings
|
||||
);
|
||||
~LevelFrontend();
|
||||
|
||||
Level& getLevel();
|
||||
const Level& getLevel() const;
|
||||
const Assets& getAssets() const;
|
||||
const ContentGfxCache& getContentGfxCache() const;
|
||||
ContentGfxCache& getContentGfxCache();
|
||||
LevelController* getController() const;
|
||||
|
||||
@ -21,11 +21,11 @@ void UiDocument::rebuildIndices() {
|
||||
gui::UINode::getIndices(root, map);
|
||||
}
|
||||
|
||||
const uinodes_map& UiDocument::getMap() const {
|
||||
const UINodesMap& UiDocument::getMap() const {
|
||||
return map;
|
||||
}
|
||||
|
||||
uinodes_map& UiDocument::getMapWriteable() {
|
||||
UINodesMap& UiDocument::getMapWriteable() {
|
||||
return map;
|
||||
}
|
||||
|
||||
@ -54,6 +54,7 @@ scriptenv UiDocument::getEnvironment() const {
|
||||
}
|
||||
|
||||
std::unique_ptr<UiDocument> UiDocument::read(
|
||||
gui::GUI& gui,
|
||||
const scriptenv& penv,
|
||||
const std::string& name,
|
||||
const io::path& file,
|
||||
@ -66,7 +67,7 @@ std::unique_ptr<UiDocument> UiDocument::read(
|
||||
? scripting::create_doc_environment(scripting::get_root_environment(), name)
|
||||
: scripting::create_doc_environment(penv, name);
|
||||
|
||||
gui::UiXmlReader reader(env);
|
||||
gui::UiXmlReader reader(gui, env);
|
||||
auto view = reader.readXML(file.string(), *xmldoc->getRoot());
|
||||
view->setId("root");
|
||||
uidocscript script {};
|
||||
@ -80,8 +81,7 @@ std::unique_ptr<UiDocument> UiDocument::read(
|
||||
}
|
||||
|
||||
std::shared_ptr<gui::UINode> UiDocument::readElement(
|
||||
const io::path& file, const std::string& fileName
|
||||
gui::GUI& gui, const io::path& file, const std::string& fileName
|
||||
) {
|
||||
auto document = read(nullptr, file.name(), file, fileName);
|
||||
return document->getRoot();
|
||||
return read(gui, nullptr, file.name(), file, fileName)->getRoot();
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
#include "io/fwd.hpp"
|
||||
|
||||
namespace gui {
|
||||
class GUI;
|
||||
class UINode;
|
||||
}
|
||||
|
||||
@ -18,12 +19,12 @@ struct uidocscript {
|
||||
bool onclose : 1;
|
||||
};
|
||||
|
||||
using uinodes_map = std::unordered_map<std::string, std::shared_ptr<gui::UINode>>;
|
||||
using UINodesMap = std::unordered_map<std::string, std::shared_ptr<gui::UINode>>;
|
||||
|
||||
class UiDocument {
|
||||
std::string id;
|
||||
uidocscript script;
|
||||
uinodes_map map;
|
||||
UINodesMap map;
|
||||
std::shared_ptr<gui::UINode> root;
|
||||
scriptenv env;
|
||||
public:
|
||||
@ -37,20 +38,21 @@ public:
|
||||
void rebuildIndices();
|
||||
|
||||
const std::string& getId() const;
|
||||
const uinodes_map& getMap() const;
|
||||
uinodes_map& getMapWriteable();
|
||||
const UINodesMap& getMap() const;
|
||||
UINodesMap& getMapWriteable();
|
||||
std::shared_ptr<gui::UINode> getRoot() const;
|
||||
std::shared_ptr<gui::UINode> get(const std::string& id) const;
|
||||
const uidocscript& getScript() const;
|
||||
scriptenv getEnvironment() const;
|
||||
|
||||
static std::unique_ptr<UiDocument> read(
|
||||
gui::GUI&,
|
||||
const scriptenv& parent_env,
|
||||
const std::string& name,
|
||||
const io::path& file,
|
||||
const std::string& fileName
|
||||
);
|
||||
static std::shared_ptr<gui::UINode> readElement(
|
||||
const io::path& file, const std::string& fileName
|
||||
gui::GUI&, const io::path& file, const std::string& fileName
|
||||
);
|
||||
};
|
||||
|
||||
@ -35,8 +35,8 @@
|
||||
|
||||
using namespace gui;
|
||||
|
||||
static std::shared_ptr<Label> create_label(wstringsupplier supplier) {
|
||||
auto label = std::make_shared<Label>(L"-");
|
||||
static std::shared_ptr<Label> create_label(GUI& gui, wstringsupplier supplier) {
|
||||
auto label = std::make_shared<Label>(gui, L"-");
|
||||
label->textSupplier(std::move(supplier));
|
||||
return label;
|
||||
}
|
||||
@ -50,7 +50,10 @@ std::shared_ptr<UINode> create_debug_panel(
|
||||
Player& player,
|
||||
bool allowDebugCheats
|
||||
) {
|
||||
auto panel = std::make_shared<Panel>(glm::vec2(300, 200), glm::vec4(5.0f), 2.0f);
|
||||
auto& gui = engine.getGUI();
|
||||
auto panel = std::make_shared<Panel>(
|
||||
gui, glm::vec2(300, 200), glm::vec4(5.0f), 2.0f
|
||||
);
|
||||
panel->setId("hud.debug-panel");
|
||||
panel->setPos(glm::vec2(10, 10));
|
||||
|
||||
@ -87,48 +90,48 @@ std::shared_ptr<UINode> create_debug_panel(
|
||||
lastTotalUpload = totalUpload;
|
||||
});
|
||||
|
||||
panel->add(create_label([]() { return L"fps: "+fpsString;}));
|
||||
panel->add(create_label(gui, []() { return L"fps: "+fpsString;}));
|
||||
|
||||
panel->add(create_label([]() {
|
||||
panel->add(create_label(gui, []() {
|
||||
return L"meshes: " + std::to_wstring(Mesh::meshesCount);
|
||||
}));
|
||||
panel->add(create_label([]() {
|
||||
panel->add(create_label(gui, []() {
|
||||
int drawCalls = Mesh::drawCalls;
|
||||
Mesh::drawCalls = 0;
|
||||
return L"draw-calls: " + std::to_wstring(drawCalls);
|
||||
}));
|
||||
panel->add(create_label([]() {
|
||||
panel->add(create_label(gui, []() {
|
||||
return L"speakers: " + std::to_wstring(audio::count_speakers())+
|
||||
L" streams: " + std::to_wstring(audio::count_streams());
|
||||
}));
|
||||
panel->add(create_label([]() {
|
||||
panel->add(create_label(gui, []() {
|
||||
return L"lua-stack: " + std::to_wstring(scripting::get_values_on_stack());
|
||||
}));
|
||||
panel->add(create_label([]() { return netSpeedString; }));
|
||||
panel->add(create_label([&engine]() {
|
||||
panel->add(create_label(gui, []() { return netSpeedString; }));
|
||||
panel->add(create_label(gui, [&engine]() {
|
||||
auto& settings = engine.getSettings();
|
||||
bool culling = settings.graphics.frustumCulling.get();
|
||||
return L"frustum-culling: "+std::wstring(culling ? L"on" : L"off");
|
||||
}));
|
||||
panel->add(create_label([=]() {
|
||||
panel->add(create_label(gui, [=]() {
|
||||
return L"particles: " +
|
||||
std::to_wstring(ParticlesRenderer::visibleParticles) +
|
||||
L" emitters: " +
|
||||
std::to_wstring(ParticlesRenderer::aliveEmitters);
|
||||
}));
|
||||
panel->add(create_label([&]() {
|
||||
panel->add(create_label(gui, [&]() {
|
||||
return L"chunks: "+std::to_wstring(level.chunks->size())+
|
||||
L" visible: "+std::to_wstring(ChunksRenderer::visibleChunks);
|
||||
}));
|
||||
panel->add(create_label([&]() {
|
||||
panel->add(create_label(gui, [&]() {
|
||||
return L"entities: "+std::to_wstring(level.entities->size())+L" next: "+
|
||||
std::to_wstring(level.entities->peekNextID());
|
||||
}));
|
||||
panel->add(create_label([&]() {
|
||||
panel->add(create_label(gui, [&]() {
|
||||
return L"players: "+std::to_wstring(level.players->size())+L" local: "+
|
||||
std::to_wstring(player.getId());
|
||||
}));
|
||||
panel->add(create_label([&]() -> std::wstring {
|
||||
panel->add(create_label(gui, [&]() -> std::wstring {
|
||||
const auto& vox = player.selection.vox;
|
||||
std::wstringstream stream;
|
||||
stream << "r:" << vox.state.rotation << " s:"
|
||||
@ -141,7 +144,7 @@ std::shared_ptr<UINode> create_debug_panel(
|
||||
L" "+stream.str();
|
||||
}
|
||||
}));
|
||||
panel->add(create_label([&]() -> std::wstring {
|
||||
panel->add(create_label(gui, [&]() -> std::wstring {
|
||||
const auto& selection = player.selection;
|
||||
const auto& vox = selection.vox;
|
||||
if (vox.id == BLOCK_VOID) {
|
||||
@ -151,7 +154,7 @@ std::shared_ptr<UINode> create_debug_panel(
|
||||
L" y: " + std::to_wstring(selection.actualPosition.y) +
|
||||
L" z: " + std::to_wstring(selection.actualPosition.z);
|
||||
}));
|
||||
panel->add(create_label([&]() {
|
||||
panel->add(create_label(gui, [&]() {
|
||||
auto eid = player.getSelectedEntity();
|
||||
if (eid == ENTITY_NONE) {
|
||||
return std::wstring {L"entity: -"};
|
||||
@ -162,7 +165,7 @@ std::shared_ptr<UINode> create_debug_panel(
|
||||
return std::wstring {L"entity: error (invalid UID)"};
|
||||
}
|
||||
}));
|
||||
panel->add(create_label([&](){
|
||||
panel->add(create_label(gui, [&](){
|
||||
auto indices = level.content.getIndices();
|
||||
if (auto def = indices->blocks.get(player.selection.vox.id)) {
|
||||
return L"name: " + util::str2wstr_utf8(def->name);
|
||||
@ -170,23 +173,23 @@ std::shared_ptr<UINode> create_debug_panel(
|
||||
return std::wstring {L"name: void"};
|
||||
}
|
||||
}));
|
||||
panel->add(create_label([&](){
|
||||
panel->add(create_label(gui, [&](){
|
||||
return L"seed: "+std::to_wstring(level.getWorld()->getSeed());
|
||||
}));
|
||||
|
||||
for (int ax = 0; ax < 3; ax++) {
|
||||
auto sub = std::make_shared<Container>(glm::vec2(250, 27));
|
||||
auto sub = std::make_shared<Container>(gui, glm::vec2(250, 27));
|
||||
|
||||
std::wstring str = L"x: ";
|
||||
str[0] += ax;
|
||||
auto label = std::make_shared<Label>(str);
|
||||
auto label = std::make_shared<Label>(gui, str);
|
||||
label->setMargin(glm::vec4(2, 3, 2, 3));
|
||||
label->setSize(glm::vec2(20, 27));
|
||||
sub->add(label);
|
||||
sub->setColor(glm::vec4(0.0f));
|
||||
|
||||
// Coord input
|
||||
auto box = std::make_shared<TextBox>(L"");
|
||||
auto box = std::make_shared<TextBox>(gui, L"");
|
||||
auto boxRef = box.get();
|
||||
box->setTextSupplier([&player, ax]() {
|
||||
return util::to_wstring(player.getPosition()[ax], 2);
|
||||
@ -212,7 +215,7 @@ std::shared_ptr<UINode> create_debug_panel(
|
||||
panel->add(sub);
|
||||
}
|
||||
auto& worldInfo = level.getWorld()->getInfo();
|
||||
panel->add(create_label([&](){
|
||||
panel->add(create_label(gui, [&](){
|
||||
int hour, minute, second;
|
||||
timeutil::from_value(worldInfo.daytime, hour, minute, second);
|
||||
|
||||
@ -222,20 +225,20 @@ std::shared_ptr<UINode> create_debug_panel(
|
||||
return L"time: "+timeString;
|
||||
}));
|
||||
if (allowDebugCheats) {
|
||||
auto bar = std::make_shared<TrackBar>(0.0f, 1.0f, 1.0f, 0.005f, 8);
|
||||
auto bar = std::make_shared<TrackBar>(gui, 0.0f, 1.0f, 1.0f, 0.005f, 8);
|
||||
bar->setSupplier([&]() {return worldInfo.daytime;});
|
||||
bar->setConsumer([&](double val) {worldInfo.daytime = val;});
|
||||
panel->add(bar);
|
||||
}
|
||||
if (allowDebugCheats) {
|
||||
auto bar = std::make_shared<TrackBar>(0.0f, 1.0f, 0.0f, 0.005f, 8);
|
||||
auto bar = std::make_shared<TrackBar>(gui, 0.0f, 1.0f, 0.0f, 0.005f, 8);
|
||||
bar->setSupplier([&]() {return worldInfo.fog;});
|
||||
bar->setConsumer([&](double val) {worldInfo.fog = val;});
|
||||
panel->add(bar);
|
||||
}
|
||||
{
|
||||
auto checkbox = std::make_shared<FullCheckBox>(
|
||||
L"Show Chunk Borders", glm::vec2(400, 24)
|
||||
gui, L"Show Chunk Borders", glm::vec2(400, 24)
|
||||
);
|
||||
checkbox->setSupplier([=]() {
|
||||
return WorldRenderer::showChunkBorders;
|
||||
@ -247,7 +250,7 @@ std::shared_ptr<UINode> create_debug_panel(
|
||||
}
|
||||
{
|
||||
auto checkbox = std::make_shared<FullCheckBox>(
|
||||
L"Show Hitboxes", glm::vec2(400, 24)
|
||||
gui, L"Show Hitboxes", glm::vec2(400, 24)
|
||||
);
|
||||
checkbox->setSupplier([=]() {
|
||||
return WorldRenderer::showEntitiesDebug;
|
||||
@ -259,7 +262,7 @@ std::shared_ptr<UINode> create_debug_panel(
|
||||
}
|
||||
{
|
||||
auto checkbox = std::make_shared<FullCheckBox>(
|
||||
L"Show Generator Minimap", glm::vec2(400, 24)
|
||||
gui, L"Show Generator Minimap", glm::vec2(400, 24)
|
||||
);
|
||||
checkbox->setSupplier([=]() {
|
||||
return Hud::showGeneratorMinimap;
|
||||
|
||||
@ -13,8 +13,6 @@
|
||||
#include "graphics/core/Batch2D.hpp"
|
||||
#include "graphics/core/Batch3D.hpp"
|
||||
#include "graphics/core/DrawContext.hpp"
|
||||
#include "graphics/core/Font.hpp"
|
||||
#include "graphics/core/Mesh.hpp"
|
||||
#include "graphics/core/Shader.hpp"
|
||||
#include "graphics/core/Texture.hpp"
|
||||
#include "graphics/core/ImageData.hpp"
|
||||
@ -42,7 +40,6 @@
|
||||
#include "voxels/Chunks.hpp"
|
||||
#include "voxels/GlobalChunks.hpp"
|
||||
#include "window/Camera.hpp"
|
||||
#include "window/Events.hpp"
|
||||
#include "window/input.hpp"
|
||||
#include "window/Window.hpp"
|
||||
#include "world/Level.hpp"
|
||||
@ -126,7 +123,7 @@ std::shared_ptr<InventoryView> Hud::createContentAccess() {
|
||||
inventory->getSlot(player.getChosenSlot()).set(item);
|
||||
});
|
||||
|
||||
InventoryBuilder builder;
|
||||
InventoryBuilder builder(gui);
|
||||
builder.addGrid(8, itemsCount-1, glm::vec2(), glm::vec4(8, 8, 12, 8), true, slotLayout);
|
||||
auto view = builder.build();
|
||||
view->bind(accessInventory, &content);
|
||||
@ -139,7 +136,7 @@ std::shared_ptr<InventoryView> Hud::createHotbar() {
|
||||
auto& content = frontend.getLevel().content;
|
||||
|
||||
SlotLayout slotLayout(-1, glm::vec2(), false, false, nullptr, nullptr, nullptr);
|
||||
InventoryBuilder builder;
|
||||
InventoryBuilder builder(gui);
|
||||
builder.addGrid(10, 10, glm::vec2(), glm::vec4(4), true, slotLayout);
|
||||
auto view = builder.build();
|
||||
view->setId("hud.hotbar");
|
||||
@ -153,8 +150,10 @@ static constexpr uint WORLDGEN_IMG_SIZE = 128U;
|
||||
|
||||
Hud::Hud(Engine& engine, LevelFrontend& frontend, Player& player)
|
||||
: engine(engine),
|
||||
input(engine.getInput()),
|
||||
assets(*engine.getAssets()),
|
||||
gui(*engine.getGUI()),
|
||||
gui(engine.getGUI()),
|
||||
menu(*engine.getGUI().getMenu()),
|
||||
frontend(frontend),
|
||||
player(player),
|
||||
debugImgWorldGen(std::make_unique<ImageData>(
|
||||
@ -163,7 +162,7 @@ Hud::Hud(Engine& engine, LevelFrontend& frontend, Player& player)
|
||||
contentAccess = createContentAccess();
|
||||
contentAccess->setId("hud.content-access");
|
||||
contentAccessPanel = std::make_shared<Panel>(
|
||||
contentAccess->getSize(), glm::vec4(0.0f), 0.0f
|
||||
gui, contentAccess->getSize(), glm::vec4(0.0f), 0.0f
|
||||
);
|
||||
contentAccessPanel->setColor(glm::vec4());
|
||||
contentAccessPanel->add(contentAccess);
|
||||
@ -172,6 +171,7 @@ Hud::Hud(Engine& engine, LevelFrontend& frontend, Player& player)
|
||||
|
||||
hotbarView = createHotbar();
|
||||
darkOverlay = guiutil::create(
|
||||
gui,
|
||||
"<container size='4000' color='#00000080' z-index='-1' visible='false'/>"
|
||||
);
|
||||
|
||||
@ -183,13 +183,13 @@ Hud::Hud(Engine& engine, LevelFrontend& frontend, Player& player)
|
||||
engine, frontend.getLevel(), player, allowDebugCheats
|
||||
);
|
||||
debugPanel->setZIndex(2);
|
||||
gui.add(debugPanel);
|
||||
|
||||
gui.add(debugPanel);
|
||||
gui.add(darkOverlay);
|
||||
gui.add(hotbarView);
|
||||
gui.add(contentAccessPanel);
|
||||
|
||||
auto dplotter = std::make_shared<Plotter>(350, 250, 2000, 16);
|
||||
auto dplotter = std::make_shared<Plotter>(gui, 350, 250, 2000, 16);
|
||||
dplotter->setGravity(Gravity::bottom_right);
|
||||
dplotter->setInteractive(false);
|
||||
add(HudElement(HudElementMode::PERMANENT, nullptr, dplotter, true));
|
||||
@ -197,9 +197,10 @@ Hud::Hud(Engine& engine, LevelFrontend& frontend, Player& player)
|
||||
assets.store(Texture::from(debugImgWorldGen.get()), DEBUG_WORLDGEN_IMAGE);
|
||||
|
||||
debugMinimap = guiutil::create(
|
||||
"<image src='"+DEBUG_WORLDGEN_IMAGE+
|
||||
gui,
|
||||
"<image src='" + DEBUG_WORLDGEN_IMAGE +
|
||||
"' pos='0' size='256' gravity='top-right' margin='0,20,0,0'/>"
|
||||
);
|
||||
);
|
||||
add(HudElement(HudElementMode::PERMANENT, nullptr, debugMinimap, true));
|
||||
}
|
||||
|
||||
@ -223,11 +224,12 @@ void Hud::cleanup() {
|
||||
}
|
||||
|
||||
void Hud::processInput(bool visible) {
|
||||
auto menu = gui.getMenu();
|
||||
if (!Window::isFocused() && !menu->hasOpenPage() && !isInventoryOpen()) {
|
||||
const auto& window = engine.getWindow();
|
||||
if (!window.isFocused() && !menu.hasOpenPage() && !isInventoryOpen()) {
|
||||
setPause(true);
|
||||
}
|
||||
if (!pause && visible && Events::jactive(BIND_HUD_INVENTORY)) {
|
||||
const auto& bindings = input.getBindings();
|
||||
if (!pause && visible && bindings.jactive(BIND_HUD_INVENTORY)) {
|
||||
if (inventoryOpen) {
|
||||
closeInventory();
|
||||
} else {
|
||||
@ -240,24 +242,25 @@ void Hud::processInput(bool visible) {
|
||||
}
|
||||
|
||||
void Hud::updateHotbarControl() {
|
||||
if (!inventoryOpen && Events::scroll) {
|
||||
int scroll = input.getScroll();
|
||||
if (!inventoryOpen && scroll) {
|
||||
int slot = player.getChosenSlot();
|
||||
slot = (slot - Events::scroll) % 10;
|
||||
slot = (slot - scroll) % 10;
|
||||
if (slot < 0) {
|
||||
slot += 10;
|
||||
}
|
||||
player.setChosenSlot(slot);
|
||||
}
|
||||
for (
|
||||
int i = static_cast<int>(keycode::NUM_1);
|
||||
i <= static_cast<int>(keycode::NUM_9);
|
||||
int i = static_cast<int>(Keycode::NUM_1);
|
||||
i <= static_cast<int>(Keycode::NUM_9);
|
||||
i++
|
||||
) {
|
||||
if (Events::jpressed(i)) {
|
||||
player.setChosenSlot(i - static_cast<int>(keycode::NUM_1));
|
||||
if (input.jpressed(static_cast<Keycode>(i))) {
|
||||
player.setChosenSlot(i - static_cast<int>(Keycode::NUM_1));
|
||||
}
|
||||
}
|
||||
if (Events::jpressed(keycode::NUM_0)) {
|
||||
if (input.jpressed(Keycode::NUM_0)) {
|
||||
player.setChosenSlot(9);
|
||||
}
|
||||
}
|
||||
@ -311,7 +314,6 @@ void Hud::updateWorldGenDebug() {
|
||||
|
||||
void Hud::update(bool visible) {
|
||||
const auto& chunks = *player.chunks;
|
||||
const auto& menu = gui.getMenu();
|
||||
|
||||
debugPanel->setVisible(
|
||||
debug && visible && !(inventoryOpen && inventoryView == nullptr)
|
||||
@ -320,14 +322,14 @@ void Hud::update(bool visible) {
|
||||
if (!visible && inventoryOpen) {
|
||||
closeInventory();
|
||||
}
|
||||
if (pause && !menu->hasOpenPage()) {
|
||||
if (pause && !menu.hasOpenPage()) {
|
||||
setPause(false);
|
||||
}
|
||||
if (!gui.isFocusCaught()) {
|
||||
processInput(visible);
|
||||
}
|
||||
if ((menu->hasOpenPage() || inventoryOpen) == Events::isCursorLocked()) {
|
||||
Events::toggleCursor();
|
||||
if ((menu.hasOpenPage() || inventoryOpen) == input.getCursor().locked) {
|
||||
input.toggleCursor();
|
||||
}
|
||||
|
||||
if (blockUI) {
|
||||
@ -341,10 +343,11 @@ void Hud::update(bool visible) {
|
||||
element.getNode()->setVisible(visible);
|
||||
}
|
||||
|
||||
const auto& windowSize = engine.getWindow().getSize();
|
||||
glm::vec2 caSize = contentAccessPanel->getSize();
|
||||
contentAccessPanel->setVisible(inventoryView != nullptr && showContentPanel);
|
||||
contentAccessPanel->setSize(glm::vec2(caSize.x, Window::height));
|
||||
contentAccess->setMinSize(glm::vec2(1, Window::height));
|
||||
contentAccessPanel->setSize(glm::vec2(caSize.x, windowSize.y));
|
||||
contentAccess->setMinSize(glm::vec2(1, windowSize.y));
|
||||
hotbarView->setVisible(visible && !(secondUI && !inventoryView));
|
||||
|
||||
if (visible) {
|
||||
@ -447,6 +450,7 @@ void Hud::showExchangeSlot() {
|
||||
auto& content = level.content;
|
||||
exchangeSlotInv = level.inventories->createVirtual(1);
|
||||
exchangeSlot = std::make_shared<SlotView>(
|
||||
gui,
|
||||
SlotLayout(-1, glm::vec2(), false, false, nullptr, nullptr, nullptr)
|
||||
);
|
||||
exchangeSlot->bind(exchangeSlotInv->getId(), exchangeSlotInv->getSlot(0), &content);
|
||||
@ -587,18 +591,16 @@ void Hud::setDebug(bool flag) {
|
||||
}
|
||||
|
||||
void Hud::draw(const DrawContext& ctx){
|
||||
const Viewport& viewport = ctx.getViewport();
|
||||
const uint width = viewport.getWidth();
|
||||
const uint height = viewport.getHeight();
|
||||
auto menu = gui.getMenu();
|
||||
const auto& viewport = ctx.getViewport();
|
||||
|
||||
bool is_menu_open = menu->hasOpenPage();
|
||||
bool is_menu_open = menu.hasOpenPage();
|
||||
darkOverlay->setVisible(is_menu_open);
|
||||
menu->setVisible(is_menu_open);
|
||||
menu.setVisible(is_menu_open);
|
||||
|
||||
updateElementsPosition(viewport);
|
||||
|
||||
uicamera->setFov(height);
|
||||
uicamera->setFov(viewport.y);
|
||||
uicamera->setAspectRatio(viewport.x / static_cast<float>(viewport.y));
|
||||
|
||||
auto batch = ctx.getBatch2D();
|
||||
batch->begin();
|
||||
@ -616,28 +618,28 @@ void Hud::draw(const DrawContext& ctx){
|
||||
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
|
||||
(viewport.x - chsizex) / 2, (viewport.y - chsizey) / 2,
|
||||
chsizex, chsizey, 0, 0, 1, 1, 1, 1, 1, 1
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void Hud::updateElementsPosition(const Viewport& viewport) {
|
||||
const uint width = viewport.getWidth();
|
||||
const uint height = viewport.getHeight();
|
||||
|
||||
void Hud::updateElementsPosition(const glm::uvec2& viewport) {
|
||||
if (inventoryOpen) {
|
||||
float caWidth = inventoryView && showContentPanel
|
||||
? contentAccess->getSize().x
|
||||
: 0.0f;
|
||||
contentAccessPanel->setPos(glm::vec2(width-caWidth, 0));
|
||||
contentAccessPanel->setPos(glm::vec2(viewport.x - caWidth, 0));
|
||||
|
||||
glm::vec2 invSize = inventoryView ? inventoryView->getSize() : glm::vec2();
|
||||
if (secondUI == nullptr) {
|
||||
if (inventoryView) {
|
||||
inventoryView->setPos(glm::vec2(
|
||||
glm::min(width/2-invSize.x/2, width-caWidth-10-invSize.x),
|
||||
height/2-invSize.y/2
|
||||
glm::min(
|
||||
viewport.x / 2 - invSize.x / 2,
|
||||
viewport.x - caWidth - 10 - invSize.x
|
||||
),
|
||||
viewport.y / 2 - invSize.y / 2
|
||||
));
|
||||
}
|
||||
} else {
|
||||
@ -647,25 +649,29 @@ void Hud::updateElementsPosition(const Viewport& viewport) {
|
||||
float totalHeight = invSize.y + secondUISize.y + interval;
|
||||
if (inventoryView) {
|
||||
inventoryView->setPos(glm::vec2(
|
||||
glm::min(width/2-invwidth/2, width-caWidth-10-invwidth),
|
||||
height/2+totalHeight/2-invSize.y
|
||||
glm::min(
|
||||
viewport.x / 2 - invwidth / 2,
|
||||
viewport.x - caWidth - 10 - invwidth
|
||||
),
|
||||
viewport.y / 2 + totalHeight / 2 - invSize.y
|
||||
));
|
||||
}
|
||||
if (secondUI->getPositionFunc() == nullptr) {
|
||||
secondUI->setPos(glm::vec2(
|
||||
glm::min(
|
||||
width / 2.f - invwidth / 2.f,
|
||||
width - caWidth - (inventoryView ? 10 : 0) - invwidth
|
||||
viewport.x / 2.f - invwidth / 2.f,
|
||||
viewport.x - caWidth - (inventoryView ? 10 : 0) -
|
||||
invwidth
|
||||
),
|
||||
height / 2.f - totalHeight / 2.f
|
||||
viewport.y / 2.f - totalHeight / 2.f
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (exchangeSlot != nullptr) {
|
||||
exchangeSlot->setPos(glm::vec2(Events::cursor));
|
||||
exchangeSlot->setPos(input.getCursor().pos);
|
||||
}
|
||||
hotbarView->setPos(glm::vec2(width/2, height-65));
|
||||
hotbarView->setPos(glm::vec2(viewport.x / 2, viewport.y - 65));
|
||||
hotbarView->setSelected(player.getChosenSlot());
|
||||
}
|
||||
|
||||
@ -689,12 +695,11 @@ void Hud::setPause(bool pause) {
|
||||
closeInventory();
|
||||
}
|
||||
|
||||
const auto& menu = gui.getMenu();
|
||||
if (!pause && menu->hasOpenPage()) {
|
||||
menu->reset();
|
||||
if (!pause && menu.hasOpenPage()) {
|
||||
menu.reset();
|
||||
}
|
||||
if (pause && !menu->hasOpenPage()) {
|
||||
menu->setPage("pause");
|
||||
if (pause && !menu.hasOpenPage()) {
|
||||
menu.setPage("pause");
|
||||
}
|
||||
}
|
||||
|
||||
@ -730,9 +735,8 @@ void Hud::setDebugCheats(bool flag) {
|
||||
|
||||
void Hud::setAllowPause(bool flag) {
|
||||
if (pause) {
|
||||
auto menu = gui.getMenu();
|
||||
setPause(false);
|
||||
menu->setPage("pause", true);
|
||||
menu.setPage("pause", true);
|
||||
}
|
||||
allowPause = flag;
|
||||
}
|
||||
|
||||
@ -18,11 +18,12 @@ class Inventory;
|
||||
class LevelFrontend;
|
||||
class UiDocument;
|
||||
class DrawContext;
|
||||
class Viewport;
|
||||
class ImageData;
|
||||
class Input;
|
||||
|
||||
namespace gui {
|
||||
class GUI;
|
||||
class Menu;
|
||||
class UINode;
|
||||
class Panel;
|
||||
class Container;
|
||||
@ -71,9 +72,11 @@ public:
|
||||
|
||||
class Hud : public util::ObjectsKeeper {
|
||||
Engine& engine;
|
||||
Input& input;
|
||||
Assets& assets;
|
||||
std::unique_ptr<Camera> uicamera;
|
||||
gui::GUI& gui;
|
||||
gui::Menu& menu;
|
||||
std::unique_ptr<Camera> uicamera;
|
||||
LevelFrontend& frontend;
|
||||
Player& player;
|
||||
|
||||
@ -127,7 +130,7 @@ class Hud : public util::ObjectsKeeper {
|
||||
std::shared_ptr<gui::InventoryView> createHotbar();
|
||||
|
||||
void processInput(bool visible);
|
||||
void updateElementsPosition(const Viewport& viewport);
|
||||
void updateElementsPosition(const glm::uvec2& viewport);
|
||||
void updateHotbarControl();
|
||||
void cleanup();
|
||||
|
||||
|
||||
@ -4,7 +4,6 @@
|
||||
|
||||
#include "coders/json.hpp"
|
||||
#include "coders/BasicParser.hpp"
|
||||
#include "content/ContentPack.hpp"
|
||||
#include "io/io.hpp"
|
||||
#include "util/stringutil.hpp"
|
||||
#include "data/dv.hpp"
|
||||
@ -14,9 +13,12 @@ static debug::Logger logger("locale");
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
using namespace std::literals;
|
||||
using namespace langs;
|
||||
|
||||
std::unique_ptr<langs::Lang> langs::current;
|
||||
std::unordered_map<std::string, langs::LocaleInfo> langs::locales_info;
|
||||
namespace {
|
||||
std::unique_ptr<langs::Lang> current;
|
||||
std::unordered_map<std::string, LocaleInfo> locales_info;
|
||||
}
|
||||
|
||||
langs::Lang::Lang(std::string locale) : locale(std::move(locale)) {
|
||||
}
|
||||
@ -40,18 +42,10 @@ const std::string& langs::Lang::getId() const {
|
||||
/// @brief Language key-value txt files parser
|
||||
namespace {
|
||||
class Reader : BasicParser<char> {
|
||||
void skipWhitespace() override {
|
||||
BasicParser::skipWhitespace();
|
||||
if (hasNext() && source[pos] == '#') {
|
||||
skipLine();
|
||||
if (hasNext() && is_whitespace(peek())) {
|
||||
skipWhitespace();
|
||||
}
|
||||
}
|
||||
}
|
||||
public:
|
||||
Reader(std::string_view file, std::string_view source)
|
||||
: BasicParser(file, source) {
|
||||
hashComment = true;
|
||||
}
|
||||
|
||||
void read(langs::Lang& lang, const std::string &prefix) {
|
||||
@ -69,11 +63,11 @@ namespace {
|
||||
};
|
||||
}
|
||||
|
||||
void langs::loadLocalesInfo(const io::path& resdir, std::string& fallback) {
|
||||
auto file = resdir / langs::TEXTS_FOLDER / "langs.json";
|
||||
static void load_locales_info(std::string& fallback) {
|
||||
auto file = io::path("res:") / langs::TEXTS_FOLDER / "langs.json";
|
||||
auto root = io::read_json(file);
|
||||
|
||||
langs::locales_info.clear();
|
||||
::locales_info.clear();
|
||||
root.at("fallback").get(fallback);
|
||||
|
||||
if (auto found = root.at("langs")) {
|
||||
@ -88,16 +82,62 @@ void langs::loadLocalesInfo(const io::path& resdir, std::string& fallback) {
|
||||
continue;
|
||||
}
|
||||
logline << key << " ";
|
||||
langs::locales_info[key] = LocaleInfo {key, name};
|
||||
::locales_info[key] = LocaleInfo {key, name};
|
||||
}
|
||||
logline << "added";
|
||||
}
|
||||
}
|
||||
|
||||
std::string langs::locale_by_envlocale(const std::string& envlocale, const io::path& resdir){
|
||||
static void load(
|
||||
const std::string& locale,
|
||||
const std::vector<io::path>& roots,
|
||||
Lang& lang
|
||||
) {
|
||||
io::path filename = io::path(TEXTS_FOLDER) / (locale + LANG_FILE_EXT);
|
||||
io::path core_file = io::path("res:") / filename;
|
||||
|
||||
if (io::is_regular_file(core_file)) {
|
||||
std::string text = io::read_string(core_file);
|
||||
Reader reader(core_file.string(), text);
|
||||
reader.read(lang, "");
|
||||
}
|
||||
for (auto root : roots) {
|
||||
io::path file = root / filename;
|
||||
if (io::is_regular_file(file)) {
|
||||
std::string text = io::read_string(file);
|
||||
Reader reader(file.string(), text);
|
||||
reader.read(lang, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
static void load(
|
||||
const std::string& locale,
|
||||
const std::string& fallback,
|
||||
const std::vector<io::path>& roots
|
||||
) {
|
||||
auto lang = std::make_unique<Lang>(locale);
|
||||
load(fallback, roots, *lang.get());
|
||||
if (locale != fallback) {
|
||||
load(locale, roots, *lang.get());
|
||||
}
|
||||
current = std::move(lang);
|
||||
}
|
||||
|
||||
const std::string& langs::get_current() {
|
||||
if (current == nullptr) {
|
||||
throw std::runtime_error("localization is not initialized");
|
||||
}
|
||||
return current->getId();
|
||||
}
|
||||
|
||||
const std::unordered_map<std::string, LocaleInfo>& langs::get_locales_info() {
|
||||
return ::locales_info;
|
||||
}
|
||||
|
||||
std::string langs::locale_by_envlocale(const std::string& envlocale){
|
||||
std::string fallback = FALLBACK_DEFAULT;
|
||||
if (locales_info.size() == 0) {
|
||||
loadLocalesInfo(resdir, fallback);
|
||||
load_locales_info(fallback);
|
||||
}
|
||||
if (locales_info.find(envlocale) != locales_info.end()) {
|
||||
logger.info() << "locale " << envlocale << " is automatically selected";
|
||||
@ -115,49 +155,16 @@ std::string langs::locale_by_envlocale(const std::string& envlocale, const io::p
|
||||
}
|
||||
}
|
||||
|
||||
void langs::load(const io::path& resdir,
|
||||
const std::string& locale,
|
||||
const std::vector<ContentPack>& packs,
|
||||
Lang& lang) {
|
||||
io::path filename = io::path(TEXTS_FOLDER) / (locale + LANG_FILE_EXT);
|
||||
io::path core_file = resdir / filename;
|
||||
|
||||
if (io::is_regular_file(core_file)) {
|
||||
std::string text = io::read_string(core_file);
|
||||
Reader reader(core_file.string(), text);
|
||||
reader.read(lang, "");
|
||||
}
|
||||
for (auto pack : packs) {
|
||||
io::path file = pack.folder / filename;
|
||||
if (io::is_regular_file(file)) {
|
||||
std::string text = io::read_string(file);
|
||||
Reader reader(file.string(), text);
|
||||
reader.read(lang, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void langs::load(const io::path& resdir,
|
||||
const std::string& locale,
|
||||
const std::string& fallback,
|
||||
const std::vector<ContentPack>& packs) {
|
||||
auto lang = std::make_unique<Lang>(locale);
|
||||
load(resdir, fallback, packs, *lang.get());
|
||||
if (locale != fallback) {
|
||||
load(resdir, locale, packs, *lang.get());
|
||||
}
|
||||
current = std::move(lang);
|
||||
}
|
||||
|
||||
void langs::setup(const io::path& resdir,
|
||||
std::string locale,
|
||||
const std::vector<ContentPack>& packs) {
|
||||
void langs::setup(
|
||||
std::string locale,
|
||||
const std::vector<io::path>& roots
|
||||
) {
|
||||
std::string fallback = langs::FALLBACK_DEFAULT;
|
||||
langs::loadLocalesInfo(resdir, fallback);
|
||||
if (langs::locales_info.find(locale) == langs::locales_info.end()) {
|
||||
load_locales_info(fallback);
|
||||
if (locales_info.find(locale) == locales_info.end()) {
|
||||
locale = fallback;
|
||||
}
|
||||
langs::load(resdir, locale, fallback, packs);
|
||||
load(locale, fallback, roots);
|
||||
}
|
||||
|
||||
const std::wstring& langs::get(const std::wstring& key) {
|
||||
|
||||
@ -7,8 +7,6 @@
|
||||
|
||||
#include "io/fwd.hpp"
|
||||
|
||||
struct ContentPack;
|
||||
|
||||
namespace langs {
|
||||
const char LANG_FILE_EXT[] = ".txt";
|
||||
const char TEXTS_FOLDER[] = "texts";
|
||||
@ -41,30 +39,17 @@ namespace langs {
|
||||
std::string name;
|
||||
};
|
||||
|
||||
extern std::unique_ptr<Lang> current;
|
||||
extern std::unordered_map<std::string, LocaleInfo> locales_info;
|
||||
std::string locale_by_envlocale(const std::string& envlocale);
|
||||
|
||||
extern void loadLocalesInfo(
|
||||
const io::path& resdir,
|
||||
std::string& fallback);
|
||||
const std::string& get_current();
|
||||
const std::unordered_map<std::string, LocaleInfo>& get_locales_info();
|
||||
|
||||
extern std::string locale_by_envlocale(const std::string& envlocale,
|
||||
const io::path& resdir);
|
||||
const std::wstring& get(const std::wstring& key);
|
||||
const std::wstring& get(
|
||||
const std::wstring& key, const std::wstring& context
|
||||
);
|
||||
|
||||
extern void load(const io::path& resdir,
|
||||
const std::string& locale,
|
||||
const std::vector<ContentPack>& packs,
|
||||
Lang& lang);
|
||||
extern void load(const io::path& resdir,
|
||||
const std::string& locale,
|
||||
const std::string& fallback,
|
||||
const std::vector<ContentPack>& packs);
|
||||
|
||||
extern const std::wstring& get(const std::wstring& key);
|
||||
extern const std::wstring& get(const std::wstring& key,
|
||||
const std::wstring& context);
|
||||
|
||||
extern void setup(const io::path& resdir,
|
||||
std::string locale,
|
||||
const std::vector<ContentPack>& packs);
|
||||
/// @brief Change locale to specified
|
||||
/// @param locale isolanguage_ISOCOUNTRY (example: en_US)
|
||||
void setup(std::string locale, const std::vector<io::path>& roots);
|
||||
}
|
||||
|
||||
@ -1,82 +1,88 @@
|
||||
#include "menu.hpp"
|
||||
|
||||
#include "locale.hpp"
|
||||
#include "UiDocument.hpp"
|
||||
#include "screens/MenuScreen.hpp"
|
||||
|
||||
#include "delegates.hpp"
|
||||
#include "engine/Engine.hpp"
|
||||
#include "data/dv.hpp"
|
||||
#include "interfaces/Task.hpp"
|
||||
#include "io/engine_paths.hpp"
|
||||
#include "graphics/ui/elements/Menu.hpp"
|
||||
#include "graphics/ui/gui_util.hpp"
|
||||
#include "graphics/ui/GUI.hpp"
|
||||
#include "logic/scripting/scripting.hpp"
|
||||
#include "settings.hpp"
|
||||
#include "coders/commons.hpp"
|
||||
#include "util/stringutil.hpp"
|
||||
#include "window/Window.hpp"
|
||||
|
||||
#include <filesystem>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
#include "UiDocument.hpp"
|
||||
#include "coders/commons.hpp"
|
||||
#include "data/dv.hpp"
|
||||
#include "delegates.hpp"
|
||||
#include "engine/Engine.hpp"
|
||||
#include "graphics/ui/GUI.hpp"
|
||||
#include "graphics/ui/elements/Menu.hpp"
|
||||
#include "graphics/ui/gui_util.hpp"
|
||||
#include "interfaces/Task.hpp"
|
||||
#include "io/engine_paths.hpp"
|
||||
#include "locale.hpp"
|
||||
#include "logic/scripting/scripting.hpp"
|
||||
#include "screens/MenuScreen.hpp"
|
||||
#include "settings.hpp"
|
||||
#include "util/stringutil.hpp"
|
||||
#include "assets/assetload_funcs.hpp"
|
||||
#include "content/ContentPack.hpp"
|
||||
|
||||
using namespace gui;
|
||||
|
||||
void menus::create_version_label(Engine& engine) {
|
||||
auto gui = engine.getGUI();
|
||||
auto text = ENGINE_VERSION_STRING+" debug build";
|
||||
gui->add(guiutil::create(
|
||||
"<label z-index='1000' color='#FFFFFF80' gravity='top-right' margin='4'>"
|
||||
+text+
|
||||
"</label>"
|
||||
void menus::create_version_label(gui::GUI& gui) {
|
||||
auto text = ENGINE_VERSION_STRING + " debug build";
|
||||
gui.add(guiutil::create(
|
||||
gui,
|
||||
"<label z-index='1000' color='#FFFFFF80' gravity='top-right' "
|
||||
"margin='4'>" +
|
||||
text + "</label>"
|
||||
));
|
||||
}
|
||||
|
||||
bool menus::call(Engine& engine, runnable func) {
|
||||
void menus::call(Engine& engine, runnable func) {
|
||||
if (engine.isHeadless()) {
|
||||
throw std::runtime_error("menus::call(...) in headless mode");
|
||||
}
|
||||
try {
|
||||
func();
|
||||
return true;
|
||||
} catch (const contentpack_error& error) {
|
||||
engine.setScreen(std::make_shared<MenuScreen>(engine));
|
||||
// could not to find or read pack
|
||||
guiutil::alert(
|
||||
engine, langs::get(L"error.pack-not-found")+L": "+
|
||||
util::str2wstr_utf8(error.getPackId())
|
||||
engine,
|
||||
langs::get(L"error.pack-not-found") + L": " +
|
||||
util::str2wstr_utf8(error.getPackId())
|
||||
);
|
||||
return false;
|
||||
throw std::runtime_error(error);
|
||||
} catch (const assetload::error& error) {
|
||||
engine.setScreen(std::make_shared<MenuScreen>(engine));
|
||||
guiutil::alert(
|
||||
engine, langs::get(L"Assets Load Error", L"menu")+L":\n"+
|
||||
engine,
|
||||
langs::get(L"Assets Load Error", L"menu") + L":\n" +
|
||||
util::str2wstr_utf8(error.what())
|
||||
);
|
||||
return false;
|
||||
throw std::runtime_error(error);
|
||||
} catch (const parsing_error& error) {
|
||||
engine.setScreen(std::make_shared<MenuScreen>(engine));
|
||||
guiutil::alert(engine, util::str2wstr_utf8(error.errorLog()));
|
||||
return false;
|
||||
throw std::runtime_error(error);
|
||||
} catch (const std::runtime_error& error) {
|
||||
engine.setScreen(std::make_shared<MenuScreen>(engine));
|
||||
guiutil::alert(
|
||||
engine, langs::get(L"Content Error", L"menu")+L":\n"+
|
||||
engine,
|
||||
langs::get(L"Content Error", L"menu") + L":\n" +
|
||||
util::str2wstr_utf8(error.what())
|
||||
);
|
||||
return false;
|
||||
throw std::runtime_error(error);
|
||||
}
|
||||
}
|
||||
|
||||
UiDocument* menus::show(Engine& engine, const std::string& name, std::vector<dv::value> args) {
|
||||
auto menu = engine.getGUI()->getMenu();
|
||||
auto file = engine.getResPaths()->find("layouts/"+name+".xml");
|
||||
auto fullname = "core:layouts/"+name;
|
||||
UiDocument* menus::show(
|
||||
Engine& engine, const std::string& name, std::vector<dv::value> args
|
||||
) {
|
||||
auto menu = engine.getGUI().getMenu();
|
||||
auto file = engine.getResPaths().find("layouts/" + name + ".xml");
|
||||
auto fullname = "core:layouts/" + name;
|
||||
|
||||
auto documentPtr = UiDocument::read(
|
||||
scripting::get_root_environment(), fullname, file, "core:layouts/"+name
|
||||
engine.getGUI(),
|
||||
scripting::get_root_environment(),
|
||||
fullname,
|
||||
file,
|
||||
"core:layouts/" + name
|
||||
);
|
||||
auto document = documentPtr.get();
|
||||
engine.getAssets()->store(std::move(documentPtr), fullname);
|
||||
@ -86,18 +92,20 @@ UiDocument* menus::show(Engine& engine, const std::string& name, std::vector<dv:
|
||||
return document;
|
||||
}
|
||||
|
||||
void menus::show_process_panel(Engine& engine, const std::shared_ptr<Task>& task, const std::wstring& text) {
|
||||
void menus::show_process_panel(
|
||||
Engine& engine, const std::shared_ptr<Task>& task, const std::wstring& text
|
||||
) {
|
||||
uint initialWork = task->getWorkTotal();
|
||||
|
||||
auto menu = engine.getGUI()->getMenu();
|
||||
auto menu = engine.getGUI().getMenu();
|
||||
menu->reset();
|
||||
auto doc = menus::show(engine, "process", {
|
||||
util::wstr2str_utf8(langs::get(text))
|
||||
});
|
||||
std::dynamic_pointer_cast<Container>(doc->getRoot())->listenInterval(0.01f, [=]() {
|
||||
task->update();
|
||||
auto doc =
|
||||
menus::show(engine, "process", {util::wstr2str_utf8(langs::get(text))});
|
||||
std::dynamic_pointer_cast<Container>(doc->getRoot())
|
||||
->listenInterval(0.01f, [=]() {
|
||||
task->update();
|
||||
|
||||
uint tasksDone = task->getWorkDone();
|
||||
scripting::on_ui_progress(doc, tasksDone, initialWork);
|
||||
});
|
||||
uint tasksDone = task->getWorkDone();
|
||||
scripting::on_ui_progress(doc, tasksDone, initialWork);
|
||||
});
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "data/dv.hpp"
|
||||
#include "graphics/ui/elements/Menu.hpp"
|
||||
#include "delegates.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@ -12,9 +12,13 @@ class Engine;
|
||||
|
||||
class UiDocument;
|
||||
|
||||
namespace gui {
|
||||
class GUI;
|
||||
}
|
||||
|
||||
namespace menus {
|
||||
/// @brief Create development version label at the top-right screen corner
|
||||
void create_version_label(Engine& engine);
|
||||
void create_version_label(gui::GUI& gui);
|
||||
|
||||
UiDocument* show(
|
||||
Engine& engine,
|
||||
@ -22,7 +26,11 @@ namespace menus {
|
||||
std::vector<dv::value> args
|
||||
);
|
||||
|
||||
void show_process_panel(Engine& engine, const std::shared_ptr<Task>& task, const std::wstring& text=L"");
|
||||
void show_process_panel(
|
||||
Engine& engine,
|
||||
const std::shared_ptr<Task>& task,
|
||||
const std::wstring& text = L""
|
||||
);
|
||||
|
||||
bool call(Engine& engine, runnable func);
|
||||
void call(Engine& engine, runnable func);
|
||||
}
|
||||
|
||||
@ -6,19 +6,19 @@
|
||||
#include "core_defs.hpp"
|
||||
#include "debug/Logger.hpp"
|
||||
#include "engine/Engine.hpp"
|
||||
#include "io/io.hpp"
|
||||
#include "assets/Assets.hpp"
|
||||
#include "frontend/ContentGfxCache.hpp"
|
||||
#include "frontend/LevelFrontend.hpp"
|
||||
#include "frontend/hud.hpp"
|
||||
#include "graphics/core/DrawContext.hpp"
|
||||
#include "graphics/core/ImageData.hpp"
|
||||
#include "graphics/core/PostProcessing.hpp"
|
||||
#include "graphics/core/Viewport.hpp"
|
||||
#include "graphics/render/Decorator.hpp"
|
||||
#include "graphics/render/WorldRenderer.hpp"
|
||||
#include "graphics/ui/GUI.hpp"
|
||||
#include "graphics/ui/elements/Menu.hpp"
|
||||
#include "graphics/ui/GUI.hpp"
|
||||
#include "frontend/ContentGfxCache.hpp"
|
||||
#include "graphics/core/TextureAnimation.hpp"
|
||||
#include "io/io.hpp"
|
||||
#include "logic/LevelController.hpp"
|
||||
#include "logic/PlayerController.hpp"
|
||||
#include "logic/scripting/scripting.hpp"
|
||||
@ -29,7 +29,6 @@
|
||||
#include "util/stringutil.hpp"
|
||||
#include "voxels/Chunks.hpp"
|
||||
#include "window/Camera.hpp"
|
||||
#include "window/Events.hpp"
|
||||
#include "window/Window.hpp"
|
||||
#include "world/Level.hpp"
|
||||
#include "world/World.hpp"
|
||||
@ -43,12 +42,14 @@ LevelScreen::LevelScreen(
|
||||
)
|
||||
: Screen(engine),
|
||||
world(*levelPtr->getWorld()),
|
||||
postProcessing(std::make_unique<PostProcessing>()) {
|
||||
postProcessing(std::make_unique<PostProcessing>()),
|
||||
gui(engine.getGUI()),
|
||||
input(engine.getInput()) {
|
||||
Level* level = levelPtr.get();
|
||||
|
||||
auto& settings = engine.getSettings();
|
||||
auto& assets = *engine.getAssets();
|
||||
auto menu = engine.getGUI()->getMenu();
|
||||
auto menu = engine.getGUI().getMenu();
|
||||
menu->reset();
|
||||
|
||||
auto player = level->players->get(localPlayer);
|
||||
@ -57,14 +58,11 @@ LevelScreen::LevelScreen(
|
||||
controller =
|
||||
std::make_unique<LevelController>(&engine, std::move(levelPtr), player);
|
||||
playerController = std::make_unique<PlayerController>(
|
||||
settings,
|
||||
*level,
|
||||
*player,
|
||||
*controller->getBlocksController()
|
||||
settings, *level, *player, *controller->getBlocksController()
|
||||
);
|
||||
|
||||
frontend = std::make_unique<LevelFrontend>(
|
||||
player, controller.get(), assets, settings
|
||||
engine, player, controller.get(), settings
|
||||
);
|
||||
renderer = std::make_unique<WorldRenderer>(
|
||||
engine, *frontend, *player
|
||||
@ -87,7 +85,7 @@ LevelScreen::LevelScreen(
|
||||
keepAlive(settings.camera.fov.observe([=](double value) {
|
||||
player->fpCamera->setFov(glm::radians(value));
|
||||
}));
|
||||
keepAlive(Events::getBinding(BIND_CHUNKS_RELOAD).onactived.add([=](){
|
||||
keepAlive(input.addCallback(BIND_CHUNKS_RELOAD, [=]() {
|
||||
player->chunks->saveAndClear();
|
||||
renderer->clear();
|
||||
return false;
|
||||
@ -107,7 +105,7 @@ LevelScreen::~LevelScreen() {
|
||||
}
|
||||
scripting::on_frontend_close();
|
||||
// unblock all bindings
|
||||
Events::enableBindings();
|
||||
input.getBindings().enableAll();
|
||||
controller->onWorldQuit();
|
||||
engine.getPaths().setCurrentWorldFolder("");
|
||||
}
|
||||
@ -162,10 +160,13 @@ void LevelScreen::saveWorldPreview() {
|
||||
Camera camera = *player->fpCamera;
|
||||
camera.setFov(glm::radians(70.0f));
|
||||
|
||||
DrawContext pctx(nullptr, {Window::width, Window::height}, batch.get());
|
||||
DrawContext pctx(nullptr, engine.getWindow(), batch.get());
|
||||
|
||||
Viewport viewport(previewSize * 1.5, previewSize);
|
||||
DrawContext ctx(&pctx, viewport, batch.get());
|
||||
DrawContext ctx(&pctx, engine.getWindow(), batch.get());
|
||||
ctx.setViewport(
|
||||
{static_cast<uint>(previewSize * 1.5),
|
||||
static_cast<uint>(previewSize)}
|
||||
);
|
||||
|
||||
renderer->draw(ctx, camera, false, true, 0.0f, *postProcessing);
|
||||
auto image = postProcessing->toImage();
|
||||
@ -178,13 +179,14 @@ void LevelScreen::saveWorldPreview() {
|
||||
|
||||
void LevelScreen::updateHotkeys() {
|
||||
auto& settings = engine.getSettings();
|
||||
if (Events::jpressed(keycode::O)) {
|
||||
|
||||
if (input.jpressed(Keycode::O)) {
|
||||
settings.graphics.frustumCulling.toggle();
|
||||
}
|
||||
if (Events::jpressed(keycode::F1)) {
|
||||
if (input.jpressed(Keycode::F1)) {
|
||||
hudVisible = !hudVisible;
|
||||
}
|
||||
if (Events::jpressed(keycode::F3)) {
|
||||
if (input.jpressed(Keycode::F3)) {
|
||||
debug = !debug;
|
||||
hud->setDebug(debug);
|
||||
renderer->setDebug(debug);
|
||||
@ -199,19 +201,16 @@ void LevelScreen::updateAudio() {
|
||||
audio::get_channel("regular")->setPaused(paused);
|
||||
audio::get_channel("ambient")->setPaused(paused);
|
||||
glm::vec3 velocity {};
|
||||
if (auto hitbox = player->getHitbox()) {
|
||||
if (auto hitbox = player->getHitbox()) {
|
||||
velocity = hitbox->velocity;
|
||||
}
|
||||
audio::set_listener(
|
||||
camera->position,
|
||||
velocity,
|
||||
camera->dir,
|
||||
glm::vec3(0, 1, 0)
|
||||
camera->position, velocity, camera->dir, glm::vec3(0, 1, 0)
|
||||
);
|
||||
}
|
||||
|
||||
void LevelScreen::update(float delta) {
|
||||
auto& gui = *engine.getGUI();
|
||||
auto& gui = engine.getGUI();
|
||||
|
||||
if (!gui.isFocusCaught()) {
|
||||
updateHotkeys();
|
||||
@ -225,10 +224,15 @@ void LevelScreen::update(float delta) {
|
||||
if (!paused) {
|
||||
world.updateTimers(delta);
|
||||
animator->update(delta);
|
||||
playerController->update(delta, !inputLocked);
|
||||
playerController->update(delta, inputLocked ? nullptr : &engine.getInput());
|
||||
}
|
||||
controller->update(glm::min(delta, 0.2f), paused);
|
||||
playerController->postUpdate(delta, !inputLocked, paused);
|
||||
playerController->postUpdate(
|
||||
delta,
|
||||
engine.getWindow().getSize().y,
|
||||
inputLocked ? nullptr : &engine.getInput(),
|
||||
paused
|
||||
);
|
||||
|
||||
hud->update(hudVisible);
|
||||
|
||||
@ -241,8 +245,7 @@ void LevelScreen::update(float delta) {
|
||||
void LevelScreen::draw(float delta) {
|
||||
auto camera = playerController->getPlayer()->currentCamera;
|
||||
|
||||
Viewport viewport(Window::width, Window::height);
|
||||
DrawContext ctx(nullptr, viewport, batch.get());
|
||||
DrawContext ctx(nullptr, engine.getWindow(), batch.get());
|
||||
|
||||
if (!hud->isPause()) {
|
||||
scripting::on_entities_render(engine.getTime().getDelta());
|
||||
|
||||
@ -16,6 +16,11 @@ class ContentPackRuntime;
|
||||
class Decorator;
|
||||
class Level;
|
||||
class World;
|
||||
class Input;
|
||||
|
||||
namespace gui {
|
||||
class GUI;
|
||||
}
|
||||
|
||||
class LevelScreen : public Screen {
|
||||
World& world;
|
||||
@ -27,6 +32,8 @@ class LevelScreen : public Screen {
|
||||
std::unique_ptr<PostProcessing> postProcessing;
|
||||
std::unique_ptr<Decorator> decorator;
|
||||
std::unique_ptr<Hud> hud;
|
||||
gui::GUI& gui;
|
||||
Input& input;
|
||||
|
||||
void saveWorldPreview();
|
||||
|
||||
|
||||
@ -1,29 +1,31 @@
|
||||
#include "MenuScreen.hpp"
|
||||
|
||||
#include "content/ContentControl.hpp"
|
||||
#include "graphics/ui/GUI.hpp"
|
||||
#include "graphics/ui/elements/Menu.hpp"
|
||||
#include "graphics/core/Batch2D.hpp"
|
||||
#include "graphics/core/Shader.hpp"
|
||||
#include "graphics/core/Texture.hpp"
|
||||
#include "assets/Assets.hpp"
|
||||
#include "maths/UVRegion.hpp"
|
||||
#include "window/Window.hpp"
|
||||
#include "window/Camera.hpp"
|
||||
#include "engine/Engine.hpp"
|
||||
|
||||
MenuScreen::MenuScreen(Engine& engine) : Screen(engine) {
|
||||
engine.resetContent();
|
||||
engine.getContentControl().resetContent();
|
||||
|
||||
auto menu = engine.getGUI()->getMenu();
|
||||
auto menu = engine.getGUI().getMenu();
|
||||
menu->reset();
|
||||
menu->setPage("main");
|
||||
|
||||
uicamera = std::make_unique<Camera>(glm::vec3(), Window::height);
|
||||
uicamera =
|
||||
std::make_unique<Camera>(glm::vec3(), engine.getWindow().getSize().y);
|
||||
uicamera->perspective = false;
|
||||
uicamera->flipped = true;
|
||||
}
|
||||
|
||||
MenuScreen::~MenuScreen() {
|
||||
}
|
||||
MenuScreen::~MenuScreen() = default;
|
||||
|
||||
void MenuScreen::update(float delta) {
|
||||
}
|
||||
@ -31,24 +33,26 @@ void MenuScreen::update(float delta) {
|
||||
void MenuScreen::draw(float delta) {
|
||||
auto assets = engine.getAssets();
|
||||
|
||||
Window::clear();
|
||||
Window::setBgColor(glm::vec3(0.2f));
|
||||
display::clear();
|
||||
display::setBgColor(glm::vec3(0.2f));
|
||||
|
||||
uicamera->setFov(Window::height);
|
||||
const auto& size = engine.getWindow().getSize();
|
||||
uint width = size.x;
|
||||
uint height = size.y;
|
||||
|
||||
uicamera->setFov(height);
|
||||
uicamera->setAspectRatio(width / static_cast<float>(height));
|
||||
auto uishader = assets->get<Shader>("ui");
|
||||
uishader->use();
|
||||
uishader->uniformMatrix("u_projview", uicamera->getProjView());
|
||||
|
||||
uint width = Window::width;
|
||||
uint height = Window::height;
|
||||
|
||||
auto bg = assets->get<Texture>("gui/menubg");
|
||||
batch->begin();
|
||||
batch->texture(bg);
|
||||
batch->rect(
|
||||
0, 0,
|
||||
width, height, 0, 0, 0,
|
||||
UVRegion(0, 0, width/bg->getWidth(), height/bg->getHeight()),
|
||||
UVRegion(0, 0, width / bg->getWidth(), height / bg->getHeight()),
|
||||
false, false, glm::vec4(1.0f)
|
||||
);
|
||||
batch->flush();
|
||||
|
||||
@ -25,10 +25,11 @@ static void set_blend_mode(BlendMode mode) {
|
||||
|
||||
DrawContext::DrawContext(
|
||||
const DrawContext* parent,
|
||||
Viewport viewport,
|
||||
Window& window,
|
||||
Batch2D* g2d
|
||||
) : parent(parent),
|
||||
viewport(std::move(viewport)),
|
||||
) : window(window),
|
||||
parent(parent),
|
||||
viewport(window.getSize()),
|
||||
g2d(g2d),
|
||||
flushable(g2d)
|
||||
{}
|
||||
@ -39,7 +40,7 @@ DrawContext::~DrawContext() {
|
||||
}
|
||||
|
||||
while (scissorsCount--) {
|
||||
Window::popScissor();
|
||||
window.popScissor();
|
||||
}
|
||||
|
||||
if (parent == nullptr)
|
||||
@ -54,11 +55,7 @@ DrawContext::~DrawContext() {
|
||||
}
|
||||
}
|
||||
|
||||
Window::viewport(
|
||||
0, 0,
|
||||
parent->viewport.getWidth(),
|
||||
parent->viewport.getHeight()
|
||||
);
|
||||
glViewport(0, 0, parent->viewport.x, parent->viewport.y);
|
||||
|
||||
if (depthMask != parent->depthMask) {
|
||||
glDepthMask(parent->depthMask);
|
||||
@ -79,7 +76,7 @@ DrawContext::~DrawContext() {
|
||||
}
|
||||
}
|
||||
|
||||
const Viewport& DrawContext::getViewport() const {
|
||||
const glm::uvec2& DrawContext::getViewport() const {
|
||||
return viewport;
|
||||
}
|
||||
|
||||
@ -98,13 +95,9 @@ DrawContext DrawContext::sub(Flushable* flushable) const {
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void DrawContext::setViewport(const Viewport& viewport) {
|
||||
void DrawContext::setViewport(const glm::uvec2& viewport) {
|
||||
this->viewport = viewport;
|
||||
Window::viewport(
|
||||
0, 0,
|
||||
viewport.getWidth(),
|
||||
viewport.getHeight()
|
||||
);
|
||||
glViewport(0, 0, viewport.x, viewport.y);
|
||||
}
|
||||
|
||||
void DrawContext::setFramebuffer(Framebuffer* fbo) {
|
||||
@ -153,7 +146,7 @@ void DrawContext::setBlendMode(BlendMode mode) {
|
||||
}
|
||||
|
||||
void DrawContext::setScissors(const glm::vec4& area) {
|
||||
Window::pushScissor(area);
|
||||
window.pushScissor(area);
|
||||
scissorsCount++;
|
||||
}
|
||||
|
||||
|
||||
@ -1,15 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <glm/vec2.hpp>
|
||||
#include <glm/vec4.hpp>
|
||||
|
||||
#include "commons.hpp"
|
||||
#include "Viewport.hpp"
|
||||
#include "typedefs.hpp"
|
||||
|
||||
class Window;
|
||||
class Batch2D;
|
||||
class Framebuffer;
|
||||
|
||||
class DrawContext {
|
||||
Window& window;
|
||||
const DrawContext* parent;
|
||||
Viewport viewport;
|
||||
glm::uvec2 viewport;
|
||||
Batch2D* g2d;
|
||||
Flushable* flushable = nullptr;
|
||||
Framebuffer* fbo = nullptr;
|
||||
@ -20,15 +24,19 @@ class DrawContext {
|
||||
int scissorsCount = 0;
|
||||
float lineWidth = 1.0f;
|
||||
public:
|
||||
DrawContext(const DrawContext* parent, Viewport viewport, Batch2D* g2d);
|
||||
DrawContext(
|
||||
const DrawContext* parent,
|
||||
Window& window,
|
||||
Batch2D* g2d
|
||||
);
|
||||
~DrawContext();
|
||||
|
||||
Batch2D* getBatch2D() const;
|
||||
|
||||
const Viewport& getViewport() const;
|
||||
const glm::uvec2& getViewport() const;
|
||||
DrawContext sub(Flushable* flushable=nullptr) const;
|
||||
|
||||
void setViewport(const Viewport& viewport);
|
||||
void setViewport(const glm::uvec2& viewport);
|
||||
void setFramebuffer(Framebuffer* fbo);
|
||||
void setDepthMask(bool flag);
|
||||
void setDepthTest(bool flag);
|
||||
|
||||
@ -3,7 +3,6 @@
|
||||
#include "Shader.hpp"
|
||||
#include "Texture.hpp"
|
||||
#include "Framebuffer.hpp"
|
||||
#include "Viewport.hpp"
|
||||
#include "DrawContext.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
@ -23,9 +22,9 @@ PostProcessing::~PostProcessing() = default;
|
||||
void PostProcessing::use(DrawContext& context) {
|
||||
const auto& vp = context.getViewport();
|
||||
if (fbo) {
|
||||
fbo->resize(vp.getWidth(), vp.getHeight());
|
||||
fbo->resize(vp.x, vp.y);
|
||||
} else {
|
||||
fbo = std::make_unique<Framebuffer>(vp.getWidth(), vp.getHeight());
|
||||
fbo = std::make_unique<Framebuffer>(vp.x, vp.y);
|
||||
}
|
||||
context.setFramebuffer(fbo.get());
|
||||
}
|
||||
@ -37,7 +36,7 @@ void PostProcessing::render(const DrawContext& context, Shader* screenShader) {
|
||||
|
||||
const auto& viewport = context.getViewport();
|
||||
screenShader->use();
|
||||
screenShader->uniform2i("u_screenSize", viewport.size());
|
||||
screenShader->uniform2i("u_screenSize", viewport);
|
||||
fbo->getTexture()->bind();
|
||||
quadMesh->draw();
|
||||
}
|
||||
|
||||
@ -1,13 +0,0 @@
|
||||
#include "Viewport.hpp"
|
||||
|
||||
Viewport::Viewport(uint width, uint height)
|
||||
: width(width), height(height) {
|
||||
}
|
||||
|
||||
uint Viewport::getWidth() const {
|
||||
return width;
|
||||
}
|
||||
|
||||
uint Viewport::getHeight() const {
|
||||
return height;
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include "typedefs.hpp"
|
||||
|
||||
class Viewport {
|
||||
uint width;
|
||||
uint height;
|
||||
public:
|
||||
Viewport(uint width, uint height);
|
||||
|
||||
virtual uint getWidth() const;
|
||||
virtual uint getHeight() const;
|
||||
|
||||
glm::ivec2 size() const {
|
||||
return glm::ivec2(width, height);
|
||||
}
|
||||
};
|
||||
@ -11,7 +11,6 @@
|
||||
#include "objects/Player.hpp"
|
||||
#include "voxels/Block.hpp"
|
||||
#include "voxels/Chunks.hpp"
|
||||
#include "window/Window.hpp"
|
||||
#include "world/Level.hpp"
|
||||
|
||||
BlockWrapsRenderer::BlockWrapsRenderer(
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
#include "graphics/core/DrawContext.hpp"
|
||||
#include "graphics/core/Shader.hpp"
|
||||
#include "graphics/core/Texture.hpp"
|
||||
#include "graphics/core/Viewport.hpp"
|
||||
#include "graphics/commons/Model.hpp"
|
||||
|
||||
#include <glm/ext.hpp>
|
||||
|
||||
@ -25,7 +25,7 @@ std::unique_ptr<ImageData> BlocksPreview::draw(
|
||||
const Block& def,
|
||||
int size
|
||||
){
|
||||
Window::clear();
|
||||
display::clear();
|
||||
blockid_t id = def.rt.id;
|
||||
const UVRegion texfaces[6]{cache.getRegion(id, 0), cache.getRegion(id, 1),
|
||||
cache.getRegion(id, 2), cache.getRegion(id, 3),
|
||||
@ -97,6 +97,7 @@ std::unique_ptr<ImageData> BlocksPreview::draw(
|
||||
}
|
||||
|
||||
std::unique_ptr<Atlas> BlocksPreview::build(
|
||||
Window& window,
|
||||
const ContentGfxCache& cache,
|
||||
const Assets& assets,
|
||||
const ContentIndices& indices
|
||||
@ -107,8 +108,7 @@ std::unique_ptr<Atlas> BlocksPreview::build(
|
||||
auto& shader = assets.require<Shader>("ui3d");
|
||||
const auto& atlas = assets.require<Atlas>("blocks");
|
||||
|
||||
Viewport viewport(iconSize, iconSize);
|
||||
DrawContext pctx(nullptr, viewport, nullptr);
|
||||
DrawContext pctx(nullptr, window, nullptr);
|
||||
DrawContext ctx = pctx.sub();
|
||||
ctx.setCullFace(true);
|
||||
ctx.setDepthTest(true);
|
||||
@ -126,8 +126,8 @@ std::unique_ptr<Atlas> BlocksPreview::build(
|
||||
glm::vec3(0, 1, 0)));
|
||||
|
||||
AtlasBuilder builder;
|
||||
Window::viewport(0, 0, iconSize, iconSize);
|
||||
Window::setBgColor(glm::vec4(0.0f));
|
||||
ctx.setViewport({iconSize, iconSize});
|
||||
display::setBgColor(glm::vec4(0.0f));
|
||||
|
||||
fbo.bind();
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
@ -136,7 +136,5 @@ std::unique_ptr<Atlas> BlocksPreview::build(
|
||||
builder.add(def.name, draw(cache, shader, fbo, batch, def, iconSize));
|
||||
}
|
||||
fbo.unbind();
|
||||
|
||||
Window::viewport(0, 0, Window::width, Window::height);
|
||||
return builder.build(2);
|
||||
}
|
||||
|
||||
@ -13,6 +13,7 @@ class Batch3D;
|
||||
class Block;
|
||||
class ContentIndices;
|
||||
class Shader;
|
||||
class Window;
|
||||
class ContentGfxCache;
|
||||
|
||||
class BlocksPreview {
|
||||
@ -26,6 +27,7 @@ class BlocksPreview {
|
||||
);
|
||||
public:
|
||||
static std::unique_ptr<Atlas> build(
|
||||
Window& window,
|
||||
const ContentGfxCache& cache,
|
||||
const Assets& assets,
|
||||
const ContentIndices& indices
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
#include "WorldRenderer.hpp"
|
||||
#include "TextsRenderer.hpp"
|
||||
#include "TextNote.hpp"
|
||||
#include "assets/Assets.hpp"
|
||||
#include "assets/assets_util.hpp"
|
||||
#include "content/Content.hpp"
|
||||
#include "voxels/Chunks.hpp"
|
||||
@ -60,7 +61,7 @@ Decorator::Decorator(
|
||||
player->getPosition()
|
||||
));
|
||||
}
|
||||
playerNamePreset.deserialize(engine.getResPaths()->readCombinedObject(
|
||||
playerNamePreset.deserialize(engine.getResPaths().readCombinedObject(
|
||||
"presets/text3d/player_name.toml"
|
||||
));
|
||||
}
|
||||
|
||||
@ -64,8 +64,6 @@ void GuidesRenderer::renderDebugLines(
|
||||
) {
|
||||
DrawContext ctx = pctx.sub(&batch);
|
||||
const auto& viewport = ctx.getViewport();
|
||||
uint displayWidth = viewport.getWidth();
|
||||
uint displayHeight = viewport.getHeight();
|
||||
|
||||
ctx.setDepthTest(true);
|
||||
|
||||
@ -91,15 +89,15 @@ void GuidesRenderer::renderDebugLines(
|
||||
}
|
||||
|
||||
float length = 40.f;
|
||||
glm::vec3 tsl(displayWidth / 2, displayHeight / 2, 0.f);
|
||||
glm::vec3 tsl(viewport.x / 2, viewport.y / 2, 0.f);
|
||||
glm::mat4 model(glm::translate(glm::mat4(1.f), tsl));
|
||||
linesShader.uniformMatrix(
|
||||
"u_projview",
|
||||
glm::ortho(
|
||||
0.f,
|
||||
static_cast<float>(displayWidth),
|
||||
static_cast<float>(viewport.x),
|
||||
0.f,
|
||||
static_cast<float>(displayHeight),
|
||||
static_cast<float>(viewport.y),
|
||||
-length,
|
||||
length
|
||||
) * model *
|
||||
|
||||
@ -6,7 +6,6 @@
|
||||
#include "graphics/core/Atlas.hpp"
|
||||
#include "graphics/core/Texture.hpp"
|
||||
#include "assets/Assets.hpp"
|
||||
#include "window/Window.hpp"
|
||||
#include "voxels/Chunks.hpp"
|
||||
#include "lighting/Lightmap.hpp"
|
||||
#include "settings.hpp"
|
||||
|
||||
@ -48,6 +48,30 @@ static inline UVRegion get_region_for(
|
||||
return texreg.region;
|
||||
}
|
||||
|
||||
void ModelsGenerator::prepare(Content& content, Assets& assets) {
|
||||
for (auto& [name, def] : content.blocks.getDefs()) {
|
||||
if (def->model == BlockModel::custom && def->modelName.empty()) {
|
||||
assets.store(
|
||||
std::make_unique<model::Model>(
|
||||
loadCustomBlockModel(
|
||||
def->customModelRaw, assets, !def->shadeless
|
||||
)
|
||||
),
|
||||
name + ".model"
|
||||
);
|
||||
def->modelName = def->name + ".model";
|
||||
}
|
||||
}
|
||||
for (auto& [name, def] : content.items.getDefs()) {
|
||||
assets.store(
|
||||
std::make_unique<model::Model>(
|
||||
generate(*def, content, assets)
|
||||
),
|
||||
name + ".model"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
model::Model ModelsGenerator::fromCustom(
|
||||
const Assets& assets,
|
||||
const std::vector<BoxModel>& modelBoxes,
|
||||
|
||||
@ -11,6 +11,8 @@ class Block;
|
||||
|
||||
class ModelsGenerator {
|
||||
public:
|
||||
static void prepare(Content& content, Assets& assets);
|
||||
|
||||
static model::Model generate(
|
||||
const ItemDef& def, const Content& content, const Assets& assets
|
||||
);
|
||||
|
||||
@ -101,11 +101,9 @@ void Skybox::draw(
|
||||
float daytime,
|
||||
float fog)
|
||||
{
|
||||
const Viewport& viewport = pctx.getViewport();
|
||||
int width = viewport.getWidth();
|
||||
int height = viewport.getHeight();
|
||||
const glm::uvec2& viewport = pctx.getViewport();
|
||||
|
||||
drawBackground(camera, assets, width, height);
|
||||
drawBackground(camera, assets, viewport.x, viewport.y);
|
||||
|
||||
DrawContext ctx = pctx.sub();
|
||||
ctx.setBlendMode(BlendMode::addition);
|
||||
@ -145,7 +143,7 @@ void Skybox::refresh(const DrawContext& pctx, float t, float mie, uint quality)
|
||||
ctx.setDepthMask(false);
|
||||
ctx.setDepthTest(false);
|
||||
ctx.setFramebuffer(fbo.get());
|
||||
ctx.setViewport(Viewport(size, size));
|
||||
ctx.setViewport({size, size});
|
||||
|
||||
auto cubemap = dynamic_cast<Cubemap*>(fbo->getTexture());
|
||||
assert(cubemap != nullptr);
|
||||
|
||||
@ -4,11 +4,11 @@
|
||||
#include "maths/util.hpp"
|
||||
#include "assets/Assets.hpp"
|
||||
#include "window/Camera.hpp"
|
||||
#include "window/Window.hpp"
|
||||
#include "maths/FrustumCulling.hpp"
|
||||
#include "graphics/core/Font.hpp"
|
||||
#include "graphics/core/Batch3D.hpp"
|
||||
#include "graphics/core/Shader.hpp"
|
||||
#include "graphics/core/DrawContext.hpp"
|
||||
#include "presets/NotePreset.hpp"
|
||||
#include "constants.hpp"
|
||||
|
||||
@ -66,6 +66,7 @@ void TextsRenderer::renderNote(
|
||||
xvec *= 1.0f + scale;
|
||||
yvec *= 1.0f + scale;
|
||||
}
|
||||
const auto& viewport = context.getViewport();
|
||||
if (preset.displayMode == NoteDisplayMode::PROJECTED) {
|
||||
float scale = 1.0f;
|
||||
if (glm::abs(preset.perspective) > 0.0001f) {
|
||||
@ -84,14 +85,14 @@ void TextsRenderer::renderNote(
|
||||
}
|
||||
pos /= projpos.w;
|
||||
pos.z = 0;
|
||||
xvec = {2.0f/Window::width*scale, 0, 0};
|
||||
yvec = {0, 2.0f/Window::height*scale, 0};
|
||||
xvec = {2.0f / viewport.x * scale, 0, 0};
|
||||
yvec = {0, 2.0f / viewport.y * scale, 0};
|
||||
} else {
|
||||
auto matrix = camera.getProjView();
|
||||
auto screenPos = matrix * glm::vec4(pos, 1.0f);
|
||||
|
||||
xvec = glm::vec3(2.0f/Window::width*scale, 0, 0);
|
||||
yvec = glm::vec3(0, 2.0f/Window::height*scale, 0);
|
||||
xvec = glm::vec3(2.0f / viewport.x * scale, 0, 0);
|
||||
yvec = glm::vec3(0, 2.0f / viewport.y * scale, 0);
|
||||
|
||||
pos = screenPos / screenPos.w;
|
||||
}
|
||||
|
||||
@ -316,7 +316,7 @@ void WorldRenderer::renderHands(
|
||||
assets.get<model::Model>(def.modelName),
|
||||
nullptr
|
||||
);
|
||||
Window::clearDepth();
|
||||
display::clearDepth();
|
||||
setupWorldShader(entityShader, hudcam, engine.getSettings(), 0.0f);
|
||||
skybox->bind();
|
||||
modelBatch->render();
|
||||
@ -338,8 +338,8 @@ void WorldRenderer::draw(
|
||||
|
||||
auto world = level.getWorld();
|
||||
|
||||
const Viewport& vp = pctx.getViewport();
|
||||
camera.aspect = vp.getWidth() / static_cast<float>(vp.getHeight());
|
||||
const auto& vp = pctx.getViewport();
|
||||
camera.setAspectRatio(vp.x / static_cast<float>(vp.y));
|
||||
|
||||
const auto& settings = engine.getSettings();
|
||||
const auto& worldInfo = world->getInfo();
|
||||
@ -359,7 +359,7 @@ void WorldRenderer::draw(
|
||||
DrawContext wctx = pctx.sub();
|
||||
postProcessing.use(wctx);
|
||||
|
||||
Window::clearDepth();
|
||||
display::clearDepth();
|
||||
|
||||
// Drawing background sky plane
|
||||
skybox->draw(pctx, camera, assets, worldInfo.daytime, clouds);
|
||||
|
||||
@ -1,13 +1,15 @@
|
||||
#include "GUI.hpp"
|
||||
|
||||
#include "gui_util.hpp"
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <utility>
|
||||
|
||||
#include "elements/UINode.hpp"
|
||||
#include "assets/Assets.hpp"
|
||||
#include "elements/Label.hpp"
|
||||
#include "elements/Menu.hpp"
|
||||
#include "elements/Panel.hpp"
|
||||
|
||||
#include "assets/Assets.hpp"
|
||||
#include "elements/UINode.hpp"
|
||||
#include "engine/Engine.hpp"
|
||||
#include "frontend/UiDocument.hpp"
|
||||
#include "frontend/locale.hpp"
|
||||
#include "graphics/core/Batch2D.hpp"
|
||||
@ -15,31 +17,36 @@
|
||||
#include "graphics/core/Shader.hpp"
|
||||
#include "graphics/core/Font.hpp"
|
||||
#include "graphics/core/DrawContext.hpp"
|
||||
#include "window/Events.hpp"
|
||||
#include "graphics/core/Shader.hpp"
|
||||
#include "gui_util.hpp"
|
||||
#include "window/Camera.hpp"
|
||||
#include "window/Window.hpp"
|
||||
#include "window/input.hpp"
|
||||
#include "window/Camera.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
|
||||
using namespace gui;
|
||||
|
||||
GUI::GUI()
|
||||
: batch2D(std::make_unique<Batch2D>(1024)),
|
||||
container(std::make_shared<Container>(glm::vec2(1000))) {
|
||||
GUI::GUI(Engine& engine)
|
||||
: engine(engine),
|
||||
input(engine.getInput()),
|
||||
batch2D(std::make_unique<Batch2D>(1024)),
|
||||
container(std::make_shared<Container>(*this, glm::vec2(1000))) {
|
||||
container->setId("root");
|
||||
uicamera = std::make_unique<Camera>(glm::vec3(), Window::height);
|
||||
uicamera =
|
||||
std::make_unique<Camera>(glm::vec3(), engine.getWindow().getSize().y);
|
||||
uicamera->perspective = false;
|
||||
uicamera->flipped = true;
|
||||
|
||||
menu = std::make_shared<Menu>();
|
||||
menu = std::make_shared<Menu>(*this);
|
||||
menu->setId("menu");
|
||||
menu->setZIndex(10);
|
||||
container->add(menu);
|
||||
container->setScrollable(false);
|
||||
|
||||
tooltip = guiutil::create(
|
||||
*this,
|
||||
"<container color='#000000A0' interactive='false' z-index='999'>"
|
||||
"<label id='tooltip.label' pos='2' autoresize='true' multiline='true' text-wrap='false'></label>"
|
||||
"</container>"
|
||||
@ -65,12 +72,15 @@ std::shared_ptr<Menu> GUI::getMenu() {
|
||||
}
|
||||
|
||||
void GUI::onAssetsLoad(Assets* assets) {
|
||||
assets->store(std::make_unique<UiDocument>(
|
||||
"core:root",
|
||||
uidocscript {},
|
||||
std::dynamic_pointer_cast<gui::UINode>(container),
|
||||
nullptr
|
||||
), "core:root");
|
||||
assets->store(
|
||||
std::make_unique<UiDocument>(
|
||||
"core:root",
|
||||
uidocscript {},
|
||||
std::dynamic_pointer_cast<gui::UINode>(container),
|
||||
nullptr
|
||||
),
|
||||
"core:root"
|
||||
);
|
||||
}
|
||||
|
||||
void GUI::resetTooltip() {
|
||||
@ -79,11 +89,13 @@ void GUI::resetTooltip() {
|
||||
}
|
||||
|
||||
void GUI::updateTooltip(float delta) {
|
||||
if (hover == nullptr || !hover->isInside(Events::cursor)) {
|
||||
const auto& cursor = input.getCursor();
|
||||
if (hover == nullptr || !hover->isInside(cursor.pos)) {
|
||||
return resetTooltip();
|
||||
}
|
||||
if (tooltipTimer + delta >= hover->getTooltipDelay()) {
|
||||
auto label = std::dynamic_pointer_cast<gui::Label>(get("tooltip.label"));
|
||||
auto label =
|
||||
std::dynamic_pointer_cast<gui::Label>(get("tooltip.label"));
|
||||
const auto& text = hover->getTooltip();
|
||||
if (text.empty() && tooltip->isVisible()) {
|
||||
return resetTooltip();
|
||||
@ -91,11 +103,11 @@ void GUI::updateTooltip(float delta) {
|
||||
if (label && !text.empty()) {
|
||||
tooltip->setVisible(true);
|
||||
label->setText(langs::get(text));
|
||||
auto size = label->getSize()+glm::vec2(4.0f);
|
||||
auto pos = Events::cursor+glm::vec2(10.0f);
|
||||
auto size = label->getSize() + glm::vec2(4.0f);
|
||||
auto pos = cursor.pos + glm::vec2(10.0f);
|
||||
auto rootSize = container->getSize();
|
||||
pos.x = glm::min(pos.x, rootSize.x-size.x);
|
||||
pos.y = glm::min(pos.y, rootSize.y-size.y);
|
||||
pos.x = glm::min(pos.x, rootSize.x - size.x);
|
||||
pos.y = glm::min(pos.y, rootSize.y - size.y);
|
||||
tooltip->setSize(size);
|
||||
tooltip->setPos(pos);
|
||||
}
|
||||
@ -104,31 +116,33 @@ void GUI::updateTooltip(float delta) {
|
||||
}
|
||||
|
||||
/// @brief Mouse related input and logic handling
|
||||
void GUI::actMouse(float delta) {
|
||||
float mouseDelta = glm::length(Events::delta);
|
||||
void GUI::actMouse(float delta, const CursorState& cursor) {
|
||||
float mouseDelta = glm::length(cursor.delta);
|
||||
doubleClicked = false;
|
||||
doubleClickTimer += delta + mouseDelta * 0.1f;
|
||||
|
||||
auto hover = container->getAt(Events::cursor);
|
||||
auto hover = container->getAt(cursor.pos);
|
||||
if (this->hover && this->hover != hover) {
|
||||
this->hover->setHover(false);
|
||||
}
|
||||
if (hover) {
|
||||
hover->setHover(true);
|
||||
if (Events::scroll) {
|
||||
hover->scrolled(Events::scroll);
|
||||
|
||||
int scroll = input.getScroll();
|
||||
if (scroll) {
|
||||
hover->scrolled(scroll);
|
||||
}
|
||||
}
|
||||
this->hover = hover;
|
||||
|
||||
if (Events::jclicked(mousecode::BUTTON_1)) {
|
||||
if (input.jclicked(Mousecode::BUTTON_1)) {
|
||||
if (pressed == nullptr && this->hover) {
|
||||
pressed = hover;
|
||||
if (doubleClickTimer < doubleClickDelay) {
|
||||
pressed->doubleClick(this, Events::cursor.x, Events::cursor.y);
|
||||
pressed->doubleClick(cursor.pos.x, cursor.pos.y);
|
||||
doubleClicked = true;
|
||||
} else {
|
||||
pressed->click(this, Events::cursor.x, Events::cursor.y);
|
||||
pressed->click(cursor.pos.x, cursor.pos.y);
|
||||
}
|
||||
doubleClickTimer = 0.0f;
|
||||
if (focus && focus != pressed) {
|
||||
@ -136,7 +150,7 @@ void GUI::actMouse(float delta) {
|
||||
}
|
||||
if (focus != pressed) {
|
||||
focus = pressed;
|
||||
focus->onFocus(this);
|
||||
focus->onFocus();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -144,59 +158,61 @@ void GUI::actMouse(float delta) {
|
||||
focus->defocus();
|
||||
focus = nullptr;
|
||||
}
|
||||
} else if (!Events::clicked(mousecode::BUTTON_1) && pressed) {
|
||||
pressed->mouseRelease(this, Events::cursor.x, Events::cursor.y);
|
||||
} else if (!input.clicked(Mousecode::BUTTON_1) && pressed) {
|
||||
pressed->mouseRelease(cursor.pos.x, cursor.pos.y);
|
||||
pressed = nullptr;
|
||||
}
|
||||
|
||||
if (hover) {
|
||||
for (mousecode code : MOUSECODES_ALL) {
|
||||
if (Events::jclicked(code)) {
|
||||
hover->clicked(this, code);
|
||||
for (Mousecode code : MOUSECODES_ALL) {
|
||||
if (input.jclicked(code)) {
|
||||
hover->clicked(code);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GUI::actFocused() {
|
||||
if (Events::jpressed(keycode::ESCAPE)) {
|
||||
if (input.jpressed(Keycode::ESCAPE)) {
|
||||
focus->defocus();
|
||||
focus = nullptr;
|
||||
return;
|
||||
}
|
||||
for (auto codepoint : Events::codepoints) {
|
||||
for (auto codepoint : input.getCodepoints()) {
|
||||
focus->typed(codepoint);
|
||||
}
|
||||
for (auto key : Events::pressedKeys) {
|
||||
for (auto key : input.getPressedKeys()) {
|
||||
focus->keyPressed(key);
|
||||
}
|
||||
|
||||
if (!Events::isCursorLocked()) {
|
||||
if (Events::clicked(mousecode::BUTTON_1) &&
|
||||
(Events::jclicked(mousecode::BUTTON_1) || Events::delta.x || Events::delta.y))
|
||||
{
|
||||
const auto& cursor = input.getCursor();
|
||||
if (!cursor.locked) {
|
||||
if (input.clicked(Mousecode::BUTTON_1) &&
|
||||
(input.jclicked(Mousecode::BUTTON_1) || cursor.delta.x ||
|
||||
cursor.delta.y)) {
|
||||
if (!doubleClicked) {
|
||||
focus->mouseMove(this, Events::cursor.x, Events::cursor.y);
|
||||
focus->mouseMove(cursor.pos.x, cursor.pos.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GUI::act(float delta, const Viewport& vp) {
|
||||
container->setSize(vp.size());
|
||||
void GUI::act(float delta, const glm::uvec2& vp) {
|
||||
container->setSize(vp);
|
||||
container->act(delta);
|
||||
auto prevfocus = focus;
|
||||
|
||||
updateTooltip(delta);
|
||||
if (!Events::isCursorLocked()) {
|
||||
actMouse(delta);
|
||||
|
||||
const auto& cursor = input.getCursor();
|
||||
if (!cursor.locked) {
|
||||
actMouse(delta, cursor);
|
||||
} else {
|
||||
if (hover) {
|
||||
hover->setHover(false);
|
||||
hover = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (focus) {
|
||||
actFocused();
|
||||
}
|
||||
@ -217,7 +233,6 @@ void GUI::draw(const DrawContext& pctx, const Assets& assets) {
|
||||
auto ctx = pctx.sub(batch2D.get());
|
||||
|
||||
auto& viewport = ctx.getViewport();
|
||||
glm::vec2 wsize = viewport.size();
|
||||
|
||||
auto& page = menu->getCurrent();
|
||||
if (page.panel) {
|
||||
@ -227,8 +242,9 @@ void GUI::draw(const DrawContext& pctx, const Assets& assets) {
|
||||
panel->cropToContent();
|
||||
}
|
||||
}
|
||||
menu->setPos((wsize - menu->getSize()) / 2.0f);
|
||||
uicamera->setFov(wsize.y);
|
||||
menu->setPos((glm::vec2(viewport) - menu->getSize()) / 2.0f);
|
||||
uicamera->setFov(viewport.y);
|
||||
uicamera->setAspectRatio(viewport.x / static_cast<float>(viewport.y));
|
||||
|
||||
auto uishader = assets.get<Shader>("ui");
|
||||
uishader->use();
|
||||
@ -238,7 +254,7 @@ void GUI::draw(const DrawContext& pctx, const Assets& assets) {
|
||||
container->draw(ctx, assets);
|
||||
|
||||
if (hover) {
|
||||
Window::setCursor(hover->getCursor());
|
||||
engine.getWindow().setCursor(hover->getCursor());
|
||||
}
|
||||
if (hover && debug) {
|
||||
auto pos = hover->calcPos();
|
||||
@ -260,11 +276,11 @@ void GUI::draw(const DrawContext& pctx, const Assets& assets) {
|
||||
batch2D->untexture();
|
||||
auto node = hover->getParent();
|
||||
while (node) {
|
||||
auto pos = node->calcPos();
|
||||
auto parentPos = node->calcPos();
|
||||
auto size = node->getSize();
|
||||
|
||||
batch2D->setColor(0, 255, 255);
|
||||
batch2D->lineRect(pos.x, pos.y, size.x-1, size.y-1);
|
||||
batch2D->lineRect(parentPos.x, parentPos.y, size.x-1, size.y-1);
|
||||
|
||||
node = node->getParent();
|
||||
}
|
||||
@ -313,7 +329,7 @@ void GUI::setFocus(std::shared_ptr<UINode> node) {
|
||||
}
|
||||
focus = std::move(node);
|
||||
if (focus) {
|
||||
focus->onFocus(this);
|
||||
focus->onFocus();
|
||||
}
|
||||
}
|
||||
|
||||
@ -336,3 +352,15 @@ float GUI::getDoubleClickDelay() const {
|
||||
void GUI::toggleDebug() {
|
||||
debug = !debug;
|
||||
}
|
||||
|
||||
const Input& GUI::getInput() const {
|
||||
return engine.getInput();
|
||||
}
|
||||
|
||||
Input& GUI::getInput() {
|
||||
return engine.getInput();
|
||||
}
|
||||
|
||||
Window& GUI::getWindow() {
|
||||
return engine.getWindow();
|
||||
}
|
||||
|
||||
@ -9,12 +9,14 @@
|
||||
#include <glm/glm.hpp>
|
||||
#include <unordered_map>
|
||||
|
||||
class Viewport;
|
||||
class DrawContext;
|
||||
class Assets;
|
||||
class Camera;
|
||||
class Batch2D;
|
||||
class LineBatch;
|
||||
struct CursorState;
|
||||
class Engine;
|
||||
class Input;
|
||||
class Window;
|
||||
|
||||
/*
|
||||
Some info about padding and margin.
|
||||
@ -56,6 +58,8 @@ namespace gui {
|
||||
|
||||
/// @brief The main UI controller
|
||||
class GUI {
|
||||
Engine& engine;
|
||||
Input& input;
|
||||
std::unique_ptr<Batch2D> batch2D;
|
||||
std::shared_ptr<Container> container;
|
||||
std::shared_ptr<UINode> hover;
|
||||
@ -76,12 +80,12 @@ namespace gui {
|
||||
bool doubleClicked = false;
|
||||
bool debug = false;
|
||||
|
||||
void actMouse(float delta);
|
||||
void actMouse(float delta, const CursorState& cursor);
|
||||
void actFocused();
|
||||
void updateTooltip(float delta);
|
||||
void resetTooltip();
|
||||
public:
|
||||
GUI();
|
||||
GUI(Engine& engine);
|
||||
~GUI();
|
||||
|
||||
void setPageLoader(PageLoaderFunc pageLoader);
|
||||
@ -101,7 +105,7 @@ namespace gui {
|
||||
/// @brief Main input handling and logic update method
|
||||
/// @param delta delta time
|
||||
/// @param viewport window size
|
||||
void act(float delta, const Viewport& viewport);
|
||||
void act(float delta, const glm::uvec2& viewport);
|
||||
|
||||
/// @brief Draw all visible elements on main container
|
||||
/// @param pctx parent graphics context
|
||||
@ -152,5 +156,8 @@ namespace gui {
|
||||
float getDoubleClickDelay() const;
|
||||
|
||||
void toggleDebug();
|
||||
const Input& getInput() const;
|
||||
Input& getInput();
|
||||
Window& getWindow();
|
||||
};
|
||||
}
|
||||
|
||||
@ -26,12 +26,13 @@ namespace gui {
|
||||
}
|
||||
protected:
|
||||
BasePanel(
|
||||
GUI& gui,
|
||||
glm::vec2 size,
|
||||
glm::vec4 padding = glm::vec4(0.0f),
|
||||
float interval = 2.0f,
|
||||
Orientation orientation = Orientation::vertical
|
||||
)
|
||||
: Container(std::move(size)),
|
||||
: Container(gui, std::move(size)),
|
||||
padding(std::move(padding)),
|
||||
interval(interval) {
|
||||
}
|
||||
|
||||
@ -3,17 +3,23 @@
|
||||
#include <utility>
|
||||
|
||||
#include "Label.hpp"
|
||||
#include "graphics/core/DrawContext.hpp"
|
||||
#include "graphics/core/Batch2D.hpp"
|
||||
#include "graphics/core/DrawContext.hpp"
|
||||
|
||||
using namespace gui;
|
||||
|
||||
Button::Button(const std::shared_ptr<UINode>& content, glm::vec4 padding)
|
||||
: Panel(glm::vec2(), padding, 0) {
|
||||
Button::Button(
|
||||
GUI& gui, const std::shared_ptr<UINode>& content, glm::vec4 padding
|
||||
)
|
||||
: Panel(gui, glm::vec2(), padding, 0) {
|
||||
glm::vec4 margin = getMargin();
|
||||
setSize(content->getSize()+
|
||||
glm::vec2(padding[0]+padding[2]+margin[0]+margin[2],
|
||||
padding[1]+padding[3]+margin[1]+margin[3]));
|
||||
setSize(
|
||||
content->getSize() +
|
||||
glm::vec2(
|
||||
padding[0] + padding[2] + margin[0] + margin[2],
|
||||
padding[1] + padding[3] + margin[1] + margin[3]
|
||||
)
|
||||
);
|
||||
add(content);
|
||||
setScrollable(false);
|
||||
setHoverColor(glm::vec4(0.05f, 0.1f, 0.15f, 0.75f));
|
||||
@ -22,15 +28,16 @@ Button::Button(const std::shared_ptr<UINode>& content, glm::vec4 padding)
|
||||
}
|
||||
|
||||
Button::Button(
|
||||
GUI& gui,
|
||||
const std::wstring& text,
|
||||
glm::vec4 padding,
|
||||
const onaction& action,
|
||||
glm::vec2 size
|
||||
) : Panel(size, padding, 0)
|
||||
{
|
||||
)
|
||||
: Panel(gui, size, padding, 0) {
|
||||
if (size.y < 0.0f) {
|
||||
size = glm::vec2(
|
||||
glm::max(padding.x + padding.z + text.length()*8, size.x),
|
||||
glm::max(padding.x + padding.z + text.length() * 8, size.x),
|
||||
glm::max(padding.y + padding.w + 16, size.y)
|
||||
);
|
||||
}
|
||||
@ -41,9 +48,11 @@ Button::Button(
|
||||
}
|
||||
setScrollable(false);
|
||||
|
||||
label = std::make_shared<Label>(text);
|
||||
label = std::make_shared<Label>(gui, text);
|
||||
label->setAlign(Align::center);
|
||||
label->setSize(size-glm::vec2(padding.z+padding.x, padding.w+padding.y));
|
||||
label->setSize(
|
||||
size - glm::vec2(padding.z + padding.x, padding.w + padding.y)
|
||||
);
|
||||
label->setInteractive(false);
|
||||
add(label);
|
||||
setHoverColor(glm::vec4(0.05f, 0.1f, 0.15f, 0.75f));
|
||||
@ -73,7 +82,9 @@ Button* Button::textSupplier(wstringsupplier supplier) {
|
||||
void Button::refresh() {
|
||||
Panel::refresh();
|
||||
if (label) {
|
||||
label->setSize(size-glm::vec2(padding.z+padding.x, padding.w+padding.y));
|
||||
label->setSize(
|
||||
size - glm::vec2(padding.z + padding.x, padding.w + padding.y)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -9,13 +9,19 @@ namespace gui {
|
||||
protected:
|
||||
std::shared_ptr<Label> label;
|
||||
public:
|
||||
Button(const std::shared_ptr<UINode>& content,
|
||||
glm::vec4 padding=glm::vec4(2.0f));
|
||||
Button(
|
||||
GUI& gui,
|
||||
const std::shared_ptr<UINode>& content,
|
||||
glm::vec4 padding = glm::vec4(2.0f)
|
||||
);
|
||||
|
||||
Button(const std::wstring& text,
|
||||
glm::vec4 padding,
|
||||
const onaction& action,
|
||||
glm::vec2 size=glm::vec2(-1));
|
||||
Button(
|
||||
GUI& gui,
|
||||
const std::wstring& text,
|
||||
glm::vec4 padding,
|
||||
const onaction& action,
|
||||
glm::vec2 size = glm::vec2(-1)
|
||||
);
|
||||
|
||||
virtual void drawBackground(
|
||||
const DrawContext& pctx, const Assets& assets
|
||||
|
||||
@ -4,7 +4,8 @@
|
||||
#include "graphics/core/DrawContext.hpp"
|
||||
#include "graphics/core/Texture.hpp"
|
||||
|
||||
gui::Canvas::Canvas(ImageFormat inFormat, glm::uvec2 inSize) : UINode(inSize) {
|
||||
gui::Canvas::Canvas(GUI& gui, ImageFormat inFormat, glm::uvec2 inSize)
|
||||
: UINode(gui, inSize) {
|
||||
auto data = std::make_shared<ImageData>(inFormat, inSize.x, inSize.y);
|
||||
mTexture = Texture::from(data.get());
|
||||
mData = std::move(data);
|
||||
|
||||
@ -9,7 +9,7 @@ class Texture;
|
||||
namespace gui {
|
||||
class Canvas final : public UINode {
|
||||
public:
|
||||
explicit Canvas(ImageFormat inFormat, glm::uvec2 inSize);
|
||||
explicit Canvas(GUI& gui, ImageFormat inFormat, glm::uvec2 inSize);
|
||||
|
||||
~Canvas() override = default;
|
||||
|
||||
|
||||
@ -2,13 +2,14 @@
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "graphics/core/DrawContext.hpp"
|
||||
#include "graphics/core/Batch2D.hpp"
|
||||
#include "Label.hpp"
|
||||
#include "graphics/core/Batch2D.hpp"
|
||||
#include "graphics/core/DrawContext.hpp"
|
||||
|
||||
using namespace gui;
|
||||
|
||||
CheckBox::CheckBox(bool checked) : UINode(glm::vec2(32.0f)), checked(checked) {
|
||||
CheckBox::CheckBox(GUI& gui, bool checked)
|
||||
: UINode(gui, glm::vec2(32.0f)), checked(checked) {
|
||||
setColor({0.0f, 0.0f, 0.0f, 0.5f});
|
||||
setHoverColor({0.05f, 0.1f, 0.2f, 0.75f});
|
||||
}
|
||||
@ -24,7 +25,7 @@ void CheckBox::draw(const DrawContext& pctx, const Assets&) {
|
||||
batch->rect(pos.x, pos.y, size.x, size.y);
|
||||
}
|
||||
|
||||
void CheckBox::mouseRelease(GUI*, int, int) {
|
||||
void CheckBox::mouseRelease(int, int) {
|
||||
checked = !checked;
|
||||
if (consumer) {
|
||||
consumer(checked);
|
||||
@ -44,10 +45,12 @@ CheckBox* CheckBox::setChecked(bool flag) {
|
||||
return this;
|
||||
}
|
||||
|
||||
FullCheckBox::FullCheckBox(const std::wstring& text, glm::vec2 size, bool checked)
|
||||
: Panel(size),
|
||||
checkbox(std::make_shared<CheckBox>(checked)),
|
||||
label(std::make_shared<Label>(text)) {
|
||||
FullCheckBox::FullCheckBox(
|
||||
GUI& gui, const std::wstring& text, glm::vec2 size, bool checked
|
||||
)
|
||||
: Panel(gui, size),
|
||||
checkbox(std::make_shared<CheckBox>(gui, checked)),
|
||||
label(std::make_shared<Label>(gui, text)) {
|
||||
setColor(glm::vec4(0.0f));
|
||||
setOrientation(Orientation::horizontal);
|
||||
|
||||
|
||||
@ -2,8 +2,8 @@
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "Panel.hpp"
|
||||
#include "Label.hpp"
|
||||
#include "Panel.hpp"
|
||||
|
||||
namespace gui {
|
||||
class CheckBox : public UINode {
|
||||
@ -13,11 +13,12 @@ namespace gui {
|
||||
boolconsumer consumer = nullptr;
|
||||
bool checked = false;
|
||||
public:
|
||||
CheckBox(bool checked=false);
|
||||
explicit CheckBox(GUI& gui, bool checked = false);
|
||||
|
||||
virtual void draw(const DrawContext& pctx, const Assets& assets) override;
|
||||
virtual void draw(const DrawContext& pctx, const Assets& assets)
|
||||
override;
|
||||
|
||||
virtual void mouseRelease(GUI*, int x, int y) override;
|
||||
virtual void mouseRelease(int x, int y) override;
|
||||
|
||||
virtual void setSupplier(boolsupplier supplier);
|
||||
virtual void setConsumer(boolconsumer consumer);
|
||||
@ -25,8 +26,7 @@ namespace gui {
|
||||
virtual CheckBox* setChecked(bool flag);
|
||||
|
||||
virtual bool isChecked() const {
|
||||
if (supplier)
|
||||
return supplier();
|
||||
if (supplier) return supplier();
|
||||
return checked;
|
||||
}
|
||||
};
|
||||
@ -36,7 +36,12 @@ namespace gui {
|
||||
std::shared_ptr<CheckBox> checkbox;
|
||||
std::shared_ptr<Label> label;
|
||||
public:
|
||||
FullCheckBox(const std::wstring& text, glm::vec2 size, bool checked=false);
|
||||
explicit FullCheckBox(
|
||||
GUI& gui,
|
||||
const std::wstring& text,
|
||||
glm::vec2 size,
|
||||
bool checked = false
|
||||
);
|
||||
|
||||
virtual void setSupplier(boolsupplier supplier) {
|
||||
checkbox->setSupplier(std::move(supplier));
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
|
||||
using namespace gui;
|
||||
|
||||
Container::Container(glm::vec2 size) : UINode(size) {
|
||||
Container::Container(GUI& gui, glm::vec2 size) : UINode(gui, size) {
|
||||
actualLength = size.y;
|
||||
setColor(glm::vec4());
|
||||
}
|
||||
@ -41,8 +41,8 @@ std::shared_ptr<UINode> Container::getAt(const glm::vec2& pos) {
|
||||
return UINode::getAt(pos);
|
||||
}
|
||||
|
||||
void Container::mouseMove(GUI* gui, int x, int y) {
|
||||
UINode::mouseMove(gui, x, y);
|
||||
void Container::mouseMove(int x, int y) {
|
||||
UINode::mouseMove(x, y);
|
||||
if (!scrollable) {
|
||||
return;
|
||||
}
|
||||
@ -65,8 +65,8 @@ void Container::mouseMove(GUI* gui, int x, int y) {
|
||||
prevScrollY = y;
|
||||
}
|
||||
|
||||
void Container::mouseRelease(GUI* gui, int x, int y) {
|
||||
UINode::mouseRelease(gui, x, y);
|
||||
void Container::mouseRelease(int x, int y) {
|
||||
UINode::mouseRelease(x, y);
|
||||
prevScrollY = -1;
|
||||
}
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
#include <vector>
|
||||
|
||||
namespace gui {
|
||||
class Container : public UINode, public util::ObjectsKeeper {
|
||||
class Container : public UINode, public ::util::ObjectsKeeper {
|
||||
int prevScrollY = -1;
|
||||
protected:
|
||||
std::vector<std::shared_ptr<UINode>> nodes;
|
||||
@ -22,7 +22,7 @@ namespace gui {
|
||||
return prevScrollY != -1;
|
||||
}
|
||||
public:
|
||||
Container(glm::vec2 size);
|
||||
Container(GUI& gui, glm::vec2 size);
|
||||
virtual ~Container();
|
||||
|
||||
virtual void act(float delta) override;
|
||||
@ -44,8 +44,8 @@ namespace gui {
|
||||
virtual void refresh() override;
|
||||
void setScroll(int scroll);
|
||||
|
||||
virtual void mouseMove(GUI*, int x, int y) override;
|
||||
virtual void mouseRelease(GUI*, int x, int y) override;
|
||||
virtual void mouseMove(int x, int y) override;
|
||||
virtual void mouseRelease(int x, int y) override;
|
||||
|
||||
const std::vector<std::shared_ptr<UINode>>& getNodes() const;
|
||||
};
|
||||
|
||||
@ -2,16 +2,17 @@
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "graphics/core/DrawContext.hpp"
|
||||
#include "graphics/core/Batch2D.hpp"
|
||||
#include "graphics/core/Texture.hpp"
|
||||
#include "graphics/core/Atlas.hpp"
|
||||
#include "assets/Assets.hpp"
|
||||
#include "graphics/core/Atlas.hpp"
|
||||
#include "graphics/core/Batch2D.hpp"
|
||||
#include "graphics/core/DrawContext.hpp"
|
||||
#include "graphics/core/Texture.hpp"
|
||||
#include "maths/UVRegion.hpp"
|
||||
|
||||
using namespace gui;
|
||||
|
||||
Image::Image(std::string texture, glm::vec2 size) : UINode(size), texture(std::move(texture)) {
|
||||
Image::Image(GUI& gui, std::string texture, glm::vec2 size)
|
||||
: UINode(gui, size), texture(std::move(texture)) {
|
||||
setInteractive(false);
|
||||
}
|
||||
|
||||
@ -30,14 +31,16 @@ void Image::draw(const DrawContext& pctx, const Assets& assets) {
|
||||
} else {
|
||||
auto atlasName = this->texture.substr(0, separator);
|
||||
if (auto atlas = assets.get<Atlas>(atlasName)) {
|
||||
if (auto region = atlas->getIf(this->texture.substr(separator+1))) {
|
||||
if (auto region =
|
||||
atlas->getIf(this->texture.substr(separator + 1))) {
|
||||
texture = atlas->getTexture();
|
||||
batch->texture(atlas->getTexture());
|
||||
batch->setRegion(*region);
|
||||
if (autoresize) {
|
||||
setSize(glm::vec2(
|
||||
texture->getWidth()*region->getWidth(),
|
||||
texture->getHeight()*region->getHeight()));
|
||||
texture->getWidth() * region->getWidth(),
|
||||
texture->getHeight() * region->getHeight()
|
||||
));
|
||||
}
|
||||
} else {
|
||||
batch->texture(nullptr);
|
||||
@ -45,8 +48,17 @@ void Image::draw(const DrawContext& pctx, const Assets& assets) {
|
||||
}
|
||||
}
|
||||
batch->rect(
|
||||
pos.x, pos.y, size.x, size.y,
|
||||
0, 0, 0, UVRegion(), false, true, calcColor()
|
||||
pos.x,
|
||||
pos.y,
|
||||
size.x,
|
||||
size.y,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
UVRegion(),
|
||||
false,
|
||||
true,
|
||||
calcColor()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@ namespace gui {
|
||||
std::string texture;
|
||||
bool autoresize = false;
|
||||
public:
|
||||
Image(std::string texture, glm::vec2 size=glm::vec2(32,32));
|
||||
Image(GUI& gui, std::string texture, glm::vec2 size=glm::vec2(32,32));
|
||||
|
||||
virtual void draw(const DrawContext& pctx, const Assets& assets) override;
|
||||
|
||||
|
||||
@ -7,10 +7,10 @@
|
||||
|
||||
using namespace gui;
|
||||
|
||||
InputBindBox::InputBindBox(Binding& binding, glm::vec4 padding)
|
||||
: Panel(glm::vec2(100,32), padding, 0),
|
||||
InputBindBox::InputBindBox(GUI& gui, Binding& binding, glm::vec4 padding)
|
||||
: Panel(gui, glm::vec2(100,32), padding, 0),
|
||||
binding(binding),
|
||||
label(std::make_shared<Label>(L"")) {
|
||||
label(std::make_shared<Label>(gui, L"")) {
|
||||
add(label);
|
||||
setScrollable(false);
|
||||
hoverColor = glm::vec4(0.05f, 0.1f, 0.2f, 0.75f);
|
||||
@ -25,15 +25,15 @@ void InputBindBox::drawBackground(const DrawContext& pctx, const Assets&) {
|
||||
label->setText(util::str2wstr_utf8(binding.text()));
|
||||
}
|
||||
|
||||
void InputBindBox::clicked(GUI*, mousecode button) {
|
||||
void InputBindBox::clicked(Mousecode button) {
|
||||
if (isFocused()) {
|
||||
binding.reset(button);
|
||||
defocus();
|
||||
}
|
||||
}
|
||||
|
||||
void InputBindBox::keyPressed(keycode key) {
|
||||
if (key != keycode::ESCAPE) {
|
||||
void InputBindBox::keyPressed(Keycode key) {
|
||||
if (key != Keycode::ESCAPE) {
|
||||
binding.reset(key);
|
||||
}
|
||||
defocus();
|
||||
|
||||
@ -11,14 +11,18 @@ namespace gui {
|
||||
glm::vec4 focusedColor {0.1f, 0.15f, 0.35f, 0.75f};
|
||||
std::shared_ptr<Label> label;
|
||||
public:
|
||||
InputBindBox(Binding& binding, glm::vec4 padding=glm::vec4(6.0f));
|
||||
explicit InputBindBox(
|
||||
GUI& gui, Binding& binding, glm::vec4 padding = glm::vec4(6.0f)
|
||||
);
|
||||
|
||||
virtual void drawBackground(
|
||||
const DrawContext& pctx, const Assets& assets
|
||||
) override;
|
||||
|
||||
virtual void clicked(GUI*, mousecode button) override;
|
||||
virtual void keyPressed(keycode key) override;
|
||||
virtual bool isFocuskeeper() const override {return true;}
|
||||
virtual void clicked(Mousecode button) override;
|
||||
virtual void keyPressed(Keycode key) override;
|
||||
virtual bool isFocuskeeper() const override {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -13,7 +13,6 @@
|
||||
#include "objects/Player.hpp"
|
||||
#include "util/stringutil.hpp"
|
||||
#include "voxels/Block.hpp"
|
||||
#include "window/Events.hpp"
|
||||
#include "window/input.hpp"
|
||||
#include "world/Level.hpp"
|
||||
#include "graphics/core/Atlas.hpp"
|
||||
@ -46,8 +45,8 @@ SlotLayout::SlotLayout(
|
||||
shareFunc(std::move(shareFunc)),
|
||||
rightClick(std::move(rightClick)) {}
|
||||
|
||||
InventoryBuilder::InventoryBuilder() {
|
||||
view = std::make_shared<InventoryView>();
|
||||
InventoryBuilder::InventoryBuilder(GUI& gui) : gui(gui) {
|
||||
view = std::make_shared<InventoryView>(gui);
|
||||
}
|
||||
|
||||
void InventoryBuilder::addGrid(
|
||||
@ -75,7 +74,8 @@ void InventoryBuilder::addGrid(
|
||||
view->setSize(vsize);
|
||||
|
||||
if (addpanel) {
|
||||
auto panel = std::make_shared<gui::Container>(glm::vec2(width, height));
|
||||
auto panel =
|
||||
std::make_shared<gui::Container>(gui, glm::vec2(width, height));
|
||||
view->setColor(glm::vec4(0.122f, 0.122f, 0.122f, 0.878f));
|
||||
view->add(panel, pos);
|
||||
}
|
||||
@ -106,8 +106,8 @@ std::shared_ptr<InventoryView> InventoryBuilder::build() {
|
||||
}
|
||||
|
||||
SlotView::SlotView(
|
||||
SlotLayout layout
|
||||
) : UINode(glm::vec2(InventoryView::SLOT_SIZE)),
|
||||
GUI& gui, SlotLayout layout
|
||||
) : UINode(gui, glm::vec2(InventoryView::SLOT_SIZE)),
|
||||
layout(std::move(layout))
|
||||
{
|
||||
setColor(glm::vec4(0, 0, 0, 0.2f));
|
||||
@ -280,7 +280,8 @@ bool SlotView::isHighlighted() const {
|
||||
}
|
||||
|
||||
void SlotView::performLeftClick(ItemStack& stack, ItemStack& grabbed) {
|
||||
if (layout.taking && Events::pressed(keycode::LEFT_SHIFT)) {
|
||||
const auto& input = gui.getInput();
|
||||
if (layout.taking && input.pressed(Keycode::LEFT_SHIFT)) {
|
||||
if (layout.shareFunc) {
|
||||
layout.shareFunc(layout.index, stack);
|
||||
}
|
||||
@ -347,20 +348,20 @@ void SlotView::performRightClick(ItemStack& stack, ItemStack& grabbed) {
|
||||
}
|
||||
}
|
||||
|
||||
void SlotView::clicked(gui::GUI* gui, mousecode button) {
|
||||
void SlotView::clicked(Mousecode button) {
|
||||
if (bound == nullptr)
|
||||
return;
|
||||
auto exchangeSlot =
|
||||
std::dynamic_pointer_cast<SlotView>(gui->get(EXCHANGE_SLOT_NAME));
|
||||
std::dynamic_pointer_cast<SlotView>(gui.get(EXCHANGE_SLOT_NAME));
|
||||
if (exchangeSlot == nullptr) {
|
||||
return;
|
||||
}
|
||||
ItemStack& grabbed = exchangeSlot->getStack();
|
||||
ItemStack& stack = *bound;
|
||||
|
||||
if (button == mousecode::BUTTON_1) {
|
||||
if (button == Mousecode::BUTTON_1) {
|
||||
performLeftClick(stack, grabbed);
|
||||
} else if (button == mousecode::BUTTON_2) {
|
||||
} else if (button == Mousecode::BUTTON_2) {
|
||||
performRightClick(stack, grabbed);
|
||||
}
|
||||
if (layout.updateFunc) {
|
||||
@ -368,8 +369,8 @@ void SlotView::clicked(gui::GUI* gui, mousecode button) {
|
||||
}
|
||||
}
|
||||
|
||||
void SlotView::onFocus(gui::GUI* gui) {
|
||||
clicked(gui, mousecode::BUTTON_1);
|
||||
void SlotView::onFocus() {
|
||||
clicked(Mousecode::BUTTON_1);
|
||||
}
|
||||
|
||||
const std::wstring& SlotView::getTooltip() const {
|
||||
@ -398,7 +399,7 @@ ItemStack& SlotView::getStack() {
|
||||
return *bound;
|
||||
}
|
||||
|
||||
InventoryView::InventoryView() : Container(glm::vec2()) {
|
||||
InventoryView::InventoryView(GUI& gui) : Container(gui, glm::vec2()) {
|
||||
setColor(glm::vec4(0, 0, 0, 0.0f));
|
||||
}
|
||||
|
||||
@ -419,7 +420,7 @@ std::shared_ptr<SlotView> InventoryView::addSlot(const SlotLayout& layout) {
|
||||
}
|
||||
setSize(vsize);
|
||||
|
||||
auto slot = std::make_shared<SlotView>(layout);
|
||||
auto slot = std::make_shared<SlotView>(gui, layout);
|
||||
if (!layout.background) {
|
||||
slot->setColor(glm::vec4());
|
||||
}
|
||||
|
||||
@ -86,15 +86,15 @@ namespace gui {
|
||||
|
||||
void refreshTooltip(const ItemStack& stack, const ItemDef& item);
|
||||
public:
|
||||
SlotView(SlotLayout layout);
|
||||
SlotView(GUI& gui, SlotLayout layout);
|
||||
|
||||
virtual void draw(const DrawContext& pctx, const Assets& assets) override;
|
||||
|
||||
void setHighlighted(bool flag);
|
||||
bool isHighlighted() const;
|
||||
|
||||
virtual void clicked(gui::GUI*, mousecode) override;
|
||||
virtual void onFocus(gui::GUI*) override;
|
||||
virtual void clicked(Mousecode) override;
|
||||
virtual void onFocus() override;
|
||||
virtual const std::wstring& getTooltip() const override;
|
||||
|
||||
void bind(
|
||||
@ -117,7 +117,7 @@ namespace gui {
|
||||
std::vector<SlotView*> slots;
|
||||
glm::vec2 origin {};
|
||||
public:
|
||||
InventoryView();
|
||||
InventoryView(GUI& gui);
|
||||
virtual ~InventoryView();
|
||||
|
||||
virtual void setPos(glm::vec2 pos) override;
|
||||
@ -145,9 +145,10 @@ namespace gui {
|
||||
};
|
||||
|
||||
class InventoryBuilder {
|
||||
GUI& gui;
|
||||
std::shared_ptr<InventoryView> view;
|
||||
public:
|
||||
InventoryBuilder();
|
||||
InventoryBuilder(GUI& gui);
|
||||
|
||||
/// @brief Add slots grid to inventory view
|
||||
/// @param cols grid columns
|
||||
|
||||
@ -83,8 +83,8 @@ void LabelCache::update(std::wstring_view text, bool multiline, bool wrap) {
|
||||
}
|
||||
}
|
||||
|
||||
Label::Label(const std::string& text, std::string fontName)
|
||||
: UINode(glm::vec2(text.length() * 8, 16)),
|
||||
Label::Label(GUI& gui, const std::string& text, std::string fontName)
|
||||
: UINode(gui, glm::vec2(text.length() * 8, 16)),
|
||||
text(util::str2wstr_utf8(text)),
|
||||
fontName(std::move(fontName))
|
||||
{
|
||||
@ -93,8 +93,8 @@ Label::Label(const std::string& text, std::string fontName)
|
||||
}
|
||||
|
||||
|
||||
Label::Label(const std::wstring& text, std::string fontName)
|
||||
: UINode(glm::vec2(text.length() * 8, 16)),
|
||||
Label::Label(GUI& gui, const std::wstring& text, std::string fontName)
|
||||
: UINode(gui, glm::vec2(text.length() * 8, 16)),
|
||||
text(text),
|
||||
fontName(std::move(fontName))
|
||||
{
|
||||
@ -237,8 +237,8 @@ void Label::draw(const DrawContext& pctx, const Assets& assets) {
|
||||
textYOffset = pos.y-calcPos().y;
|
||||
totalLineHeight = lineHeight;
|
||||
|
||||
auto& viewport = pctx.getViewport();
|
||||
glm::vec4 bounds {0, 0, viewport.getWidth(), viewport.getHeight()};
|
||||
const auto& viewport = pctx.getViewport();
|
||||
glm::vec4 bounds {0, 0, viewport.x, viewport.y};
|
||||
if (parent) {
|
||||
auto ppos = parent->calcPos();
|
||||
auto psize = parent->getSize();
|
||||
|
||||
@ -63,8 +63,8 @@ namespace gui {
|
||||
|
||||
std::unique_ptr<FontStylesScheme> styles;
|
||||
public:
|
||||
Label(const std::string& text, std::string fontName=FONT_DEFAULT);
|
||||
Label(const std::wstring& text, std::string fontName=FONT_DEFAULT);
|
||||
Label(GUI& gui, const std::string& text, std::string fontName="normal");
|
||||
Label(GUI& gui, const std::wstring& text, std::string fontName="normal");
|
||||
|
||||
virtual ~Label();
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
|
||||
using namespace gui;
|
||||
|
||||
Menu::Menu() : Container(glm::vec2(1)){
|
||||
Menu::Menu(GUI& gui) : Container(gui, glm::vec2(1)){
|
||||
}
|
||||
|
||||
bool Menu::has(const std::string& name) {
|
||||
|
||||
@ -21,7 +21,7 @@ namespace gui {
|
||||
std::unordered_map<std::string, supplier<std::shared_ptr<UINode>>> pageSuppliers;
|
||||
PageLoaderFunc pagesLoader = nullptr;
|
||||
public:
|
||||
Menu();
|
||||
explicit Menu(GUI& gui);
|
||||
|
||||
/// @brief Check menu have page or page supplier
|
||||
/// @param name page name
|
||||
|
||||
@ -4,14 +4,12 @@
|
||||
|
||||
using namespace gui;
|
||||
|
||||
Panel::Panel(glm::vec2 size, glm::vec4 padding, float interval)
|
||||
: BasePanel(size, padding, interval, Orientation::vertical)
|
||||
{
|
||||
Panel::Panel(GUI& gui, glm::vec2 size, glm::vec4 padding, float interval)
|
||||
: BasePanel(gui, size, padding, interval) {
|
||||
setColor(glm::vec4(0.0f, 0.0f, 0.0f, 0.75f));
|
||||
}
|
||||
|
||||
Panel::~Panel() {
|
||||
}
|
||||
Panel::~Panel() = default;
|
||||
|
||||
void Panel::setMaxLength(int value) {
|
||||
maxLength = value;
|
||||
@ -46,7 +44,7 @@ void Panel::fullRefresh() {
|
||||
Container::fullRefresh();
|
||||
}
|
||||
|
||||
void Panel::add(const std::shared_ptr<UINode> &node) {
|
||||
void Panel::add(const std::shared_ptr<UINode>& node) {
|
||||
node->setResizing(true);
|
||||
Container::add(node);
|
||||
fullRefresh();
|
||||
@ -80,7 +78,7 @@ void Panel::refresh() {
|
||||
node->refresh();
|
||||
glm::vec2 nodeSize = node->getSize();
|
||||
y += nodeSize.y + margin.w + interval;
|
||||
maxw = fmax(maxw, ex+nodeSize.x+margin.z+padding.z);
|
||||
maxw = fmax(maxw, ex + nodeSize.x + margin.z + padding.z);
|
||||
}
|
||||
actualLength = y + padding.w;
|
||||
} else {
|
||||
@ -89,11 +87,13 @@ void Panel::refresh() {
|
||||
glm::vec2 nodesize = node->getSize();
|
||||
const glm::vec4 margin = node->getMargin();
|
||||
x += margin.x;
|
||||
node->setPos(glm::vec2(x, y+margin.y));
|
||||
node->setPos(glm::vec2(x, y + margin.y));
|
||||
x += nodesize.x + margin.z + interval;
|
||||
|
||||
node->refresh();
|
||||
maxh = fmax(maxh, y+margin.y+node->getSize().y+margin.w+padding.w);
|
||||
maxh = fmax(
|
||||
maxh, y + margin.y + node->getSize().y + margin.w + padding.w
|
||||
);
|
||||
}
|
||||
actualLength = size.y;
|
||||
}
|
||||
|
||||
@ -1,15 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include "commons.hpp"
|
||||
#include "BasePanel.hpp"
|
||||
#include "commons.hpp"
|
||||
|
||||
namespace gui {
|
||||
class Panel : public BasePanel {
|
||||
public:
|
||||
Panel(
|
||||
GUI& gui,
|
||||
glm::vec2 size,
|
||||
glm::vec4 padding=glm::vec4(0.0f),
|
||||
float interval=2.0f
|
||||
glm::vec4 padding = glm::vec4(2.0f),
|
||||
float interval = 2.0f
|
||||
);
|
||||
virtual ~Panel();
|
||||
|
||||
|
||||
@ -1,15 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <memory>
|
||||
|
||||
#include "UINode.hpp"
|
||||
#include "typedefs.hpp"
|
||||
|
||||
#include <memory>
|
||||
|
||||
class Assets;
|
||||
class DrawContext;
|
||||
|
||||
namespace gui {
|
||||
class Plotter : public gui::UINode {
|
||||
class Plotter : public UINode {
|
||||
std::unique_ptr<int[]> points;
|
||||
float multiplier;
|
||||
int index = 0;
|
||||
@ -17,13 +18,18 @@ namespace gui {
|
||||
int dmheight;
|
||||
int labelsInterval;
|
||||
public:
|
||||
Plotter(uint width, uint height, float multiplier, int labelsInterval)
|
||||
: gui::UINode(glm::vec2(width, height)),
|
||||
multiplier(multiplier),
|
||||
dmwidth(width-50),
|
||||
dmheight(height),
|
||||
labelsInterval(labelsInterval)
|
||||
{
|
||||
Plotter(
|
||||
GUI& gui,
|
||||
uint width,
|
||||
uint height,
|
||||
float multiplier,
|
||||
int labelsInterval
|
||||
)
|
||||
: UINode(gui, glm::vec2(width, height)),
|
||||
multiplier(multiplier),
|
||||
dmwidth(width - 50),
|
||||
dmheight(height),
|
||||
labelsInterval(labelsInterval) {
|
||||
points = std::make_unique<int[]>(dmwidth);
|
||||
}
|
||||
|
||||
|
||||
@ -2,15 +2,15 @@
|
||||
|
||||
using namespace gui;
|
||||
|
||||
SplitBox::SplitBox(const glm::vec2& size, float splitPos, Orientation orientation)
|
||||
: BasePanel(size, glm::vec4(), 4.0f, orientation), splitPos(splitPos) {
|
||||
SplitBox::SplitBox(GUI& gui, const glm::vec2& size, float splitPos, Orientation orientation)
|
||||
: BasePanel(gui, size, glm::vec4(), 4.0f, orientation), splitPos(splitPos) {
|
||||
setCursor(
|
||||
orientation == Orientation::vertical ? CursorShape::NS_RESIZE
|
||||
: CursorShape::EW_RESIZE
|
||||
);
|
||||
}
|
||||
|
||||
void SplitBox::mouseMove(GUI*, int x, int y) {
|
||||
void SplitBox::mouseMove(int x, int y) {
|
||||
auto pos = calcPos();
|
||||
auto size = getSize();
|
||||
|
||||
@ -59,7 +59,7 @@ void SplitBox::refresh() {
|
||||
}
|
||||
}
|
||||
|
||||
void SplitBox::doubleClick(GUI*, int x, int y) {
|
||||
void SplitBox::doubleClick(int x, int y) {
|
||||
if (nodes.size() < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -5,12 +5,12 @@
|
||||
namespace gui {
|
||||
class SplitBox : public BasePanel {
|
||||
public:
|
||||
SplitBox(const glm::vec2& size, float splitPos, Orientation orientation);
|
||||
SplitBox(GUI& gui, const glm::vec2& size, float splitPos, Orientation orientation);
|
||||
|
||||
virtual void mouseMove(GUI*, int x, int y) override;
|
||||
virtual void mouseMove(int x, int y) override;
|
||||
virtual void refresh() override;
|
||||
virtual void fullRefresh() override;
|
||||
virtual void doubleClick(GUI*, int x, int y) override;
|
||||
virtual void doubleClick(int x, int y) override;
|
||||
private:
|
||||
float splitPos;
|
||||
};
|
||||
|
||||
@ -4,15 +4,17 @@
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
|
||||
#include "../GUI.hpp"
|
||||
#include "../markdown.hpp"
|
||||
#include "Label.hpp"
|
||||
#include "assets/Assets.hpp"
|
||||
#include "devtools/syntax_highlighting.hpp"
|
||||
#include "engine/Engine.hpp"
|
||||
#include "graphics/core/Batch2D.hpp"
|
||||
#include "graphics/core/DrawContext.hpp"
|
||||
#include "graphics/core/Font.hpp"
|
||||
#include "graphics/ui/markdown.hpp"
|
||||
#include "util/stringutil.hpp"
|
||||
#include "window/Events.hpp"
|
||||
#include "window/Window.hpp"
|
||||
#include "devtools/actions.hpp"
|
||||
#include "../markdown.hpp"
|
||||
@ -186,8 +188,9 @@ namespace gui {
|
||||
};
|
||||
}
|
||||
|
||||
TextBox::TextBox(std::wstring placeholder, glm::vec4 padding)
|
||||
: Container(glm::vec2(200, 32)),
|
||||
TextBox::TextBox(GUI& gui, std::wstring placeholder, glm::vec4 padding)
|
||||
: Container(gui, glm::vec2(200, 32)),
|
||||
inputEvents(gui.getInput()),
|
||||
history(std::make_shared<ActionsHistory>()),
|
||||
historian(std::make_unique<TextBoxHistorian>(*this, *history)),
|
||||
padding(padding),
|
||||
@ -197,16 +200,21 @@ TextBox::TextBox(std::wstring placeholder, glm::vec4 padding)
|
||||
setOnUpPressed(nullptr);
|
||||
setOnDownPressed(nullptr);
|
||||
setColor(glm::vec4(0.0f, 0.0f, 0.0f, 0.75f));
|
||||
label = std::make_shared<Label>(L"");
|
||||
label->setSize(size-glm::vec2(padding.z+padding.x, padding.w+padding.y));
|
||||
|
||||
label = std::make_shared<Label>(gui, L"");
|
||||
label->setSize(
|
||||
size - glm::vec2(padding.z + padding.x, padding.w + padding.y)
|
||||
);
|
||||
label->setPos(glm::vec2(
|
||||
padding.x + LINE_NUMBERS_PANE_WIDTH * showLineNumbers, padding.y
|
||||
));
|
||||
add(label);
|
||||
|
||||
lineNumbersLabel = std::make_shared<Label>(L"");
|
||||
lineNumbersLabel = std::make_shared<Label>(gui, L"");
|
||||
lineNumbersLabel->setMultiline(true);
|
||||
lineNumbersLabel->setSize(size-glm::vec2(padding.z+padding.x, padding.w+padding.y));
|
||||
lineNumbersLabel->setSize(
|
||||
size - glm::vec2(padding.z + padding.x, padding.w + padding.y)
|
||||
);
|
||||
lineNumbersLabel->setVerticalAlign(Align::top);
|
||||
add(lineNumbersLabel);
|
||||
|
||||
@ -242,7 +250,9 @@ void TextBox::draw(const DrawContext& pctx, const Assets& assets) {
|
||||
batch->texture(nullptr);
|
||||
batch->setColor(glm::vec4(1.0f));
|
||||
|
||||
if (editable && int((Window::time() - caretLastMove) * 2) % 2 == 0) {
|
||||
float time = gui.getWindow().time();
|
||||
|
||||
if (editable && static_cast<int>((time - caretLastMove) * 2) % 2 == 0) {
|
||||
uint line = rawTextCache.getLineByTextIndex(caret);
|
||||
uint lcaret = caret - rawTextCache.getTextLineOffset(line);
|
||||
int width = font->calcWidth(input, lcaret);
|
||||
@ -342,7 +352,7 @@ void TextBox::drawBackground(const DrawContext& pctx, const Assets&) {
|
||||
batch->texture(nullptr);
|
||||
|
||||
auto subctx = pctx.sub();
|
||||
subctx.setScissors(glm::vec4(pos.x, pos.y-0.5, size.x, size.y+1));
|
||||
subctx.setScissors(glm::vec4(pos.x, pos.y - 0.5, size.x, size.y + 1));
|
||||
|
||||
if (valid) {
|
||||
if (isFocused() && !multiline) {
|
||||
@ -371,7 +381,8 @@ void TextBox::refreshLabel() {
|
||||
|
||||
const auto& displayText = input.empty() && !hint.empty() ? hint : getText();
|
||||
if (markup == "md") {
|
||||
auto [processedText, styles] = markdown::process(displayText, !focused || !editable);
|
||||
auto [processedText, styles] =
|
||||
markdown::process(displayText, !focused || !editable);
|
||||
label->setText(std::move(processedText));
|
||||
label->setStyles(std::move(styles));
|
||||
} else {
|
||||
@ -386,7 +397,7 @@ void TextBox::refreshLabel() {
|
||||
std::wstringstream ss;
|
||||
int n = 1;
|
||||
for (int i = 1; i <= label->getLinesNumber(); i++) {
|
||||
if (!label->isFakeLine(i-1)) {
|
||||
if (!label->isFakeLine(i - 1)) {
|
||||
ss << n;
|
||||
n++;
|
||||
}
|
||||
@ -402,11 +413,12 @@ void TextBox::refreshLabel() {
|
||||
|
||||
if (autoresize && font) {
|
||||
auto size = getSize();
|
||||
int newy = glm::min(static_cast<int>(parent->getSize().y),
|
||||
static_cast<int>(
|
||||
label->getLinesNumber() *
|
||||
label->getLineInterval() *
|
||||
font->getLineHeight()) + 1
|
||||
int newy = glm::min(
|
||||
static_cast<int>(parent->getSize().y),
|
||||
static_cast<int>(
|
||||
label->getLinesNumber() * label->getLineInterval() *
|
||||
font->getLineHeight()
|
||||
) + 1
|
||||
);
|
||||
if (newy != static_cast<int>(size.y)) {
|
||||
size.y = newy;
|
||||
@ -475,7 +487,7 @@ bool TextBox::eraseSelected() {
|
||||
input.substr(selectionStart, selectionEnd - selectionStart),
|
||||
true
|
||||
);
|
||||
erase(selectionStart, selectionEnd-selectionStart);
|
||||
erase(selectionStart, selectionEnd - selectionStart);
|
||||
resetSelection();
|
||||
onInput();
|
||||
return true;
|
||||
@ -495,7 +507,7 @@ void TextBox::extendSelection(int index) {
|
||||
|
||||
size_t TextBox::getLineLength(uint line) const {
|
||||
size_t position = label->getTextLineOffset(line);
|
||||
size_t lineLength = label->getTextLineOffset(line+1)-position;
|
||||
size_t lineLength = label->getTextLineOffset(line + 1) - position;
|
||||
if (lineLength == 0) {
|
||||
lineLength = label->getText().length() - position + 1;
|
||||
}
|
||||
@ -593,9 +605,9 @@ bool TextBox::isAutoResize() const {
|
||||
return autoresize;
|
||||
}
|
||||
|
||||
void TextBox::onFocus(GUI* gui) {
|
||||
Container::onFocus(gui);
|
||||
if (onEditStart){
|
||||
void TextBox::onFocus() {
|
||||
Container::onFocus();
|
||||
if (onEditStart) {
|
||||
setCaret(input.size());
|
||||
onEditStart();
|
||||
resetSelection();
|
||||
@ -609,7 +621,9 @@ void TextBox::reposition() {
|
||||
|
||||
void TextBox::refresh() {
|
||||
Container::refresh();
|
||||
label->setSize(size-glm::vec2(padding.z+padding.x, padding.w+padding.y));
|
||||
label->setSize(
|
||||
size - glm::vec2(padding.z + padding.x, padding.w + padding.y)
|
||||
);
|
||||
label->setPos(glm::vec2(
|
||||
padding.x + LINE_NUMBERS_PANE_WIDTH * showLineNumbers + textInitX -
|
||||
static_cast<int>(textOffset),
|
||||
@ -629,24 +643,27 @@ size_t TextBox::normalizeIndex(int index) {
|
||||
/// @param y screen Y position
|
||||
/// @return non-normalized character index
|
||||
int TextBox::calcIndexAt(int x, int y) const {
|
||||
if (font == nullptr)
|
||||
return 0;
|
||||
if (font == nullptr) return 0;
|
||||
const auto& labelText = label->getText();
|
||||
glm::vec2 lcoord = label->calcPos();
|
||||
uint line = label->getLineByYOffset(y-lcoord.y);
|
||||
line = std::min(line, label->getLinesNumber()-1);
|
||||
uint line = label->getLineByYOffset(y - lcoord.y);
|
||||
line = std::min(line, label->getLinesNumber() - 1);
|
||||
size_t lineLength = getLineLength(line);
|
||||
uint offset = 0;
|
||||
while (lcoord.x + font->calcWidth(labelText, offset) < x && offset < lineLength-1) {
|
||||
while (lcoord.x + font->calcWidth(labelText, offset) < x &&
|
||||
offset < lineLength - 1) {
|
||||
offset++;
|
||||
}
|
||||
return std::min(offset+label->getTextLineOffset(line), labelText.length());
|
||||
return std::min(
|
||||
offset + label->getTextLineOffset(line), labelText.length()
|
||||
);
|
||||
}
|
||||
|
||||
static inline std::wstring get_alphabet(wchar_t c) {
|
||||
std::wstring alphabet {c};
|
||||
if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_') {
|
||||
return L"abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
return L"abcdefghijklmnopqrstuvwxyz_"
|
||||
L"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
} else if (c >= '0' && c <= '9') {
|
||||
return L"0123456789";
|
||||
}
|
||||
@ -674,23 +691,23 @@ void TextBox::tokenSelectAt(int index) {
|
||||
}
|
||||
right++;
|
||||
}
|
||||
select(left+1, right);
|
||||
select(left + 1, right);
|
||||
}
|
||||
|
||||
void TextBox::doubleClick(GUI* gui, int x, int y) {
|
||||
UINode::doubleClick(gui, x, y);
|
||||
tokenSelectAt(normalizeIndex(calcIndexAt(x, y)-1));
|
||||
void TextBox::doubleClick(int x, int y) {
|
||||
UINode::doubleClick(x, y);
|
||||
tokenSelectAt(normalizeIndex(calcIndexAt(x, y) - 1));
|
||||
}
|
||||
|
||||
void TextBox::click(GUI*, int x, int y) {
|
||||
void TextBox::click(int x, int y) {
|
||||
int index = normalizeIndex(calcIndexAt(x, y));
|
||||
selectionStart = index;
|
||||
selectionEnd = index;
|
||||
selectionOrigin = index;
|
||||
}
|
||||
|
||||
void TextBox::mouseMove(GUI* gui, int x, int y) {
|
||||
Container::mouseMove(gui, x, y);
|
||||
void TextBox::mouseMove(int x, int y) {
|
||||
Container::mouseMove(x, y);
|
||||
if (isScrolling()) {
|
||||
return;
|
||||
}
|
||||
@ -701,7 +718,8 @@ void TextBox::mouseMove(GUI* gui, int x, int y) {
|
||||
}
|
||||
|
||||
void TextBox::resetMaxLocalCaret() {
|
||||
maxLocalCaret = caret - label->getTextLineOffset(label->getLineByTextIndex(caret));
|
||||
maxLocalCaret =
|
||||
caret - label->getTextLineOffset(label->getLineByTextIndex(caret));
|
||||
}
|
||||
|
||||
void TextBox::stepLeft(bool shiftPressed, bool breakSelection) {
|
||||
@ -709,9 +727,9 @@ void TextBox::stepLeft(bool shiftPressed, bool breakSelection) {
|
||||
size_t caret = breakSelection ? selectionStart : this->caret;
|
||||
if (caret > 0) {
|
||||
if (caret > input.length()) {
|
||||
setCaret(input.length()-1);
|
||||
setCaret(input.length() - 1);
|
||||
} else {
|
||||
setCaret(caret-1);
|
||||
setCaret(caret - 1);
|
||||
}
|
||||
if (shiftPressed) {
|
||||
if (selectionStart == selectionEnd) {
|
||||
@ -732,8 +750,8 @@ void TextBox::stepRight(bool shiftPressed, bool breakSelection) {
|
||||
uint previousCaret = this->caret;
|
||||
size_t caret = breakSelection ? selectionEnd : this->caret;
|
||||
if (caret < input.length()) {
|
||||
setCaret(caret+1);
|
||||
caretLastMove = Window::time();
|
||||
setCaret(caret + 1);
|
||||
caretLastMove = gui.getWindow().time();
|
||||
if (shiftPressed) {
|
||||
if (selectionStart == selectionEnd) {
|
||||
selectionOrigin = previousCaret;
|
||||
@ -753,9 +771,10 @@ void TextBox::stepDefaultDown(bool shiftPressed, bool breakSelection) {
|
||||
uint previousCaret = this->caret;
|
||||
uint caret = breakSelection ? selectionEnd : this->caret;
|
||||
uint caretLine = label->getLineByTextIndex(caret);
|
||||
if (caretLine < label->getLinesNumber()-1) {
|
||||
uint offset = std::min(size_t(maxLocalCaret), getLineLength(caretLine+1)-1);
|
||||
setCaret(label->getTextLineOffset(caretLine+1) + offset);
|
||||
if (caretLine < label->getLinesNumber() - 1) {
|
||||
uint offset =
|
||||
std::min(size_t(maxLocalCaret), getLineLength(caretLine + 1) - 1);
|
||||
setCaret(label->getTextLineOffset(caretLine + 1) + offset);
|
||||
} else {
|
||||
setCaret(input.length());
|
||||
}
|
||||
@ -774,8 +793,9 @@ void TextBox::stepDefaultUp(bool shiftPressed, bool breakSelection) {
|
||||
uint caret = breakSelection ? selectionStart : this->caret;
|
||||
uint caretLine = label->getLineByTextIndex(caret);
|
||||
if (caretLine > 0) {
|
||||
uint offset = std::min(size_t(maxLocalCaret), getLineLength(caretLine-1)-1);
|
||||
setCaret(label->getTextLineOffset(caretLine-1) + offset);
|
||||
uint offset =
|
||||
std::min(size_t(maxLocalCaret), getLineLength(caretLine - 1) - 1);
|
||||
setCaret(label->getTextLineOffset(caretLine - 1) + offset);
|
||||
} else {
|
||||
setCaret(static_cast<size_t>(0));
|
||||
}
|
||||
@ -804,22 +824,22 @@ void TextBox::onInput() {
|
||||
refreshSyntax();
|
||||
}
|
||||
|
||||
void TextBox::performEditingKeyboardEvents(keycode key) {
|
||||
bool shiftPressed = Events::pressed(keycode::LEFT_SHIFT);
|
||||
void TextBox::performEditingKeyboardEvents(Keycode key) {
|
||||
bool shiftPressed = gui.getInput().pressed(Keycode::LEFT_SHIFT);
|
||||
bool breakSelection = getSelectionLength() != 0 && !shiftPressed;
|
||||
if (key == keycode::BACKSPACE) {
|
||||
if (key == Keycode::BACKSPACE) {
|
||||
if (!eraseSelected() && caret > 0 && input.length() > 0) {
|
||||
if (caret > input.length()) {
|
||||
caret = input.length();
|
||||
}
|
||||
historian->onErase(caret - 1, input.substr(caret - 1, 1));
|
||||
input = input.substr(0, caret-1) + input.substr(caret);
|
||||
setCaret(caret-1);
|
||||
input = input.substr(0, caret - 1) + input.substr(caret);
|
||||
setCaret(caret - 1);
|
||||
if (validate()) {
|
||||
onInput();
|
||||
}
|
||||
}
|
||||
} else if (key == keycode::DELETE) {
|
||||
} else if (key == Keycode::DELETE) {
|
||||
if (!eraseSelected() && caret < input.length()) {
|
||||
historian->onErase(caret, input.substr(caret, 1));
|
||||
input = input.substr(0, caret) + input.substr(caret + 1);
|
||||
@ -827,7 +847,7 @@ void TextBox::performEditingKeyboardEvents(keycode key) {
|
||||
onInput();
|
||||
}
|
||||
}
|
||||
} else if (key == keycode::ENTER) {
|
||||
} else if (key == Keycode::ENTER) {
|
||||
if (multiline) {
|
||||
paste(L"\n");
|
||||
} else {
|
||||
@ -836,42 +856,43 @@ void TextBox::performEditingKeyboardEvents(keycode key) {
|
||||
consumer(getText());
|
||||
}
|
||||
}
|
||||
} else if (key == keycode::TAB) {
|
||||
} else if (key == Keycode::TAB) {
|
||||
paste(L" ");
|
||||
} else if (key == keycode::LEFT) {
|
||||
} else if (key == Keycode::LEFT) {
|
||||
stepLeft(shiftPressed, breakSelection);
|
||||
} else if (key == keycode::RIGHT) {
|
||||
} else if (key == Keycode::RIGHT) {
|
||||
stepRight(shiftPressed, breakSelection);
|
||||
} else if (key == keycode::UP && onUpPressed) {
|
||||
} else if (key == Keycode::UP && onUpPressed) {
|
||||
onUpPressed();
|
||||
} else if (key == keycode::DOWN && onDownPressed) {
|
||||
} else if (key == Keycode::DOWN && onDownPressed) {
|
||||
onDownPressed();
|
||||
}
|
||||
}
|
||||
|
||||
void TextBox::keyPressed(keycode key) {
|
||||
void TextBox::keyPressed(Keycode key) {
|
||||
const auto& inputEvents = gui.getInput();
|
||||
if (editable) {
|
||||
performEditingKeyboardEvents(key);
|
||||
}
|
||||
if (Events::pressed(keycode::LEFT_CONTROL) && key != keycode::LEFT_CONTROL) {
|
||||
if (inputEvents.pressed(Keycode::LEFT_CONTROL) && key != Keycode::LEFT_CONTROL) {
|
||||
if (controlCombinationsHandler) {
|
||||
if (controlCombinationsHandler(static_cast<int>(key))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Copy selected text to clipboard
|
||||
if (key == keycode::C || key == keycode::X) {
|
||||
if (key == Keycode::C || key == Keycode::X) {
|
||||
std::string text = util::wstr2str_utf8(getSelection());
|
||||
if (!text.empty()) {
|
||||
Window::setClipboardText(text.c_str());
|
||||
gui.getInput().setClipboardText(text.c_str());
|
||||
}
|
||||
if (editable && key == keycode::X) {
|
||||
if (editable && key == Keycode::X) {
|
||||
eraseSelected();
|
||||
}
|
||||
}
|
||||
// Paste text from clipboard
|
||||
if (key == keycode::V && editable) {
|
||||
const char* text = Window::getClipboardText();
|
||||
if (key == Keycode::V && editable) {
|
||||
const char* text = inputEvents.getClipboardText();
|
||||
if (text) {
|
||||
historian->sync(); // flush buffer before combination
|
||||
// Combine deleting selected text and pasing a clipboard content
|
||||
@ -881,18 +902,18 @@ void TextBox::keyPressed(keycode key) {
|
||||
}
|
||||
}
|
||||
// Select/deselect all
|
||||
if (key == keycode::A) {
|
||||
if (key == Keycode::A) {
|
||||
if (selectionStart == selectionEnd) {
|
||||
select(0, input.length());
|
||||
} else {
|
||||
resetSelection();
|
||||
}
|
||||
}
|
||||
if (key == keycode::Z) {
|
||||
if (key == Keycode::Z) {
|
||||
historian->undo();
|
||||
refreshSyntax();
|
||||
}
|
||||
if (key == keycode::Y) {
|
||||
if (key == Keycode::Y) {
|
||||
historian->redo();
|
||||
refreshSyntax();
|
||||
}
|
||||
@ -924,14 +945,14 @@ std::shared_ptr<UINode> TextBox::getAt(const glm::vec2& pos) {
|
||||
return UINode::getAt(pos);
|
||||
}
|
||||
|
||||
void TextBox::setOnUpPressed(const runnable &callback) {
|
||||
void TextBox::setOnUpPressed(const runnable& callback) {
|
||||
if (callback == nullptr) {
|
||||
onUpPressed = [this]() {
|
||||
if (Events::pressed(keycode::LEFT_CONTROL)) {
|
||||
if (inputEvents.pressed(Keycode::LEFT_CONTROL)) {
|
||||
scrolled(1);
|
||||
return;
|
||||
}
|
||||
bool shiftPressed = Events::pressed(keycode::LEFT_SHIFT);
|
||||
bool shiftPressed = inputEvents.pressed(Keycode::LEFT_SHIFT);
|
||||
bool breakSelection = getSelectionLength() != 0 && !shiftPressed;
|
||||
stepDefaultUp(shiftPressed, breakSelection);
|
||||
};
|
||||
@ -940,14 +961,14 @@ void TextBox::setOnUpPressed(const runnable &callback) {
|
||||
}
|
||||
}
|
||||
|
||||
void TextBox::setOnDownPressed(const runnable &callback) {
|
||||
void TextBox::setOnDownPressed(const runnable& callback) {
|
||||
if (callback == nullptr) {
|
||||
onDownPressed = [this]() {
|
||||
if (Events::pressed(keycode::LEFT_CONTROL)) {
|
||||
if (inputEvents.pressed(Keycode::LEFT_CONTROL)) {
|
||||
scrolled(-1);
|
||||
return;
|
||||
}
|
||||
bool shiftPressed = Events::pressed(keycode::LEFT_SHIFT);
|
||||
bool shiftPressed = inputEvents.pressed(Keycode::LEFT_SHIFT);
|
||||
bool breakSelection = getSelectionLength() != 0 && !shiftPressed;
|
||||
stepDefaultDown(shiftPressed, breakSelection);
|
||||
};
|
||||
@ -984,7 +1005,6 @@ glm::vec4 TextBox::getFocusedColor() const {
|
||||
return focusedColor;
|
||||
}
|
||||
|
||||
|
||||
void TextBox::setTextColor(glm::vec4 color) {
|
||||
this->textColor = color;
|
||||
}
|
||||
@ -1002,8 +1022,7 @@ glm::vec4 TextBox::getErrorColor() const {
|
||||
}
|
||||
|
||||
const std::wstring& TextBox::getText() const {
|
||||
if (input.empty())
|
||||
return placeholder;
|
||||
if (input.empty()) return placeholder;
|
||||
return input;
|
||||
}
|
||||
|
||||
@ -1024,7 +1043,6 @@ void TextBox::setPlaceholder(const std::wstring& placeholder) {
|
||||
this->placeholder = placeholder;
|
||||
}
|
||||
|
||||
|
||||
const std::wstring& TextBox::getHint() const {
|
||||
return hint;
|
||||
}
|
||||
@ -1035,7 +1053,7 @@ void TextBox::setHint(const std::wstring& text) {
|
||||
|
||||
std::wstring TextBox::getSelection() const {
|
||||
const auto& text = label->getText();
|
||||
return text.substr(selectionStart, selectionEnd-selectionStart);
|
||||
return text.substr(selectionStart, selectionEnd - selectionStart);
|
||||
}
|
||||
|
||||
size_t TextBox::getCaret() const {
|
||||
@ -1053,28 +1071,29 @@ void TextBox::setCaret(size_t position) {
|
||||
rawTextCache.prepare(font, width);
|
||||
rawTextCache.update(input, multiline, label->isTextWrapping());
|
||||
|
||||
caretLastMove = Window::time();
|
||||
caretLastMove = gui.getWindow().time();
|
||||
|
||||
uint line = rawTextCache.getLineByTextIndex(caret);
|
||||
int offset = label->getLineYOffset(line) + getContentOffset().y;
|
||||
uint lineHeight = font->getLineHeight()*label->getLineInterval();
|
||||
uint lineHeight = font->getLineHeight() * label->getLineInterval();
|
||||
if (scrollStep == 0) {
|
||||
scrollStep = lineHeight;
|
||||
}
|
||||
if (offset < 0) {
|
||||
scrolled(-glm::floor(offset / static_cast<double>(scrollStep)+0.5f));
|
||||
scrolled(-glm::floor(offset / static_cast<double>(scrollStep) + 0.5f));
|
||||
} else if (offset >= getSize().y) {
|
||||
offset -= getSize().y;
|
||||
scrolled(-glm::ceil(offset / static_cast<double>(scrollStep)+0.5f));
|
||||
scrolled(-glm::ceil(offset / static_cast<double>(scrollStep) + 0.5f));
|
||||
}
|
||||
int lcaret = caret - rawTextCache.getTextLineOffset(line);
|
||||
int realoffset =
|
||||
font->calcWidth(labelText, lcaret) - static_cast<int>(textOffset) + 2;
|
||||
|
||||
if (realoffset-width > 0) {
|
||||
setTextOffset(textOffset + realoffset-width);
|
||||
if (realoffset - width > 0) {
|
||||
setTextOffset(textOffset + realoffset - width);
|
||||
} else if (realoffset < 0) {
|
||||
setTextOffset(std::max(textOffset + realoffset, static_cast<size_t>(0)));
|
||||
setTextOffset(std::max(textOffset + realoffset, static_cast<size_t>(0))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -9,6 +9,7 @@ class ActionsHistory;
|
||||
namespace gui {
|
||||
class TextBoxHistorian;
|
||||
class TextBox : public Container {
|
||||
const Input& inputEvents;
|
||||
LabelCache rawTextCache;
|
||||
std::shared_ptr<ActionsHistory> history;
|
||||
std::unique_ptr<TextBoxHistorian> historian;
|
||||
@ -86,7 +87,7 @@ namespace gui {
|
||||
/// @brief Set maxLocalCaret to local (line) caret position
|
||||
void resetMaxLocalCaret();
|
||||
|
||||
void performEditingKeyboardEvents(keycode key);
|
||||
void performEditingKeyboardEvents(Keycode key);
|
||||
|
||||
void refreshLabel();
|
||||
|
||||
@ -94,7 +95,8 @@ namespace gui {
|
||||
|
||||
void refreshSyntax();
|
||||
public:
|
||||
TextBox(
|
||||
explicit TextBox(
|
||||
GUI& gui,
|
||||
std::wstring placeholder,
|
||||
glm::vec4 padding=glm::vec4(4.0f)
|
||||
);
|
||||
@ -227,16 +229,16 @@ namespace gui {
|
||||
virtual bool isShowLineNumbers() const;
|
||||
|
||||
virtual void reposition() override;
|
||||
virtual void onFocus(GUI*) override;
|
||||
virtual void onFocus() override;
|
||||
virtual void refresh() override;
|
||||
virtual void doubleClick(GUI*, int x, int y) override;
|
||||
virtual void click(GUI*, int, int) override;
|
||||
virtual void mouseMove(GUI*, int x, int y) override;
|
||||
virtual void doubleClick(int x, int y) override;
|
||||
virtual void click(int, int) override;
|
||||
virtual void mouseMove(int x, int y) override;
|
||||
virtual bool isFocuskeeper() const override {return true;}
|
||||
virtual void draw(const DrawContext& pctx, const Assets& assets) override;
|
||||
virtual void drawBackground(const DrawContext& pctx, const Assets& assets) override;
|
||||
virtual void typed(unsigned int codepoint) override;
|
||||
virtual void keyPressed(keycode key) override;
|
||||
virtual void keyPressed(Keycode key) override;
|
||||
virtual std::shared_ptr<UINode> getAt(const glm::vec2& pos) override;
|
||||
virtual void setOnUpPressed(const runnable &callback);
|
||||
virtual void setOnDownPressed(const runnable &callback);
|
||||
|
||||
@ -9,12 +9,13 @@
|
||||
using namespace gui;
|
||||
|
||||
TrackBar::TrackBar(
|
||||
GUI& gui,
|
||||
double min,
|
||||
double max,
|
||||
double value,
|
||||
double step,
|
||||
int trackWidth
|
||||
) : UINode(glm::vec2(26)),
|
||||
) : UINode(gui, glm::vec2(26)),
|
||||
min(min),
|
||||
max(max),
|
||||
value(value),
|
||||
@ -54,7 +55,7 @@ void TrackBar::setSubConsumer(doubleconsumer consumer) {
|
||||
this->subconsumer = std::move(consumer);
|
||||
}
|
||||
|
||||
void TrackBar::mouseMove(GUI*, int x, int) {
|
||||
void TrackBar::mouseMove(int x, int) {
|
||||
glm::vec2 pos = calcPos();
|
||||
value = x - trackWidth/2;
|
||||
value -= pos.x;
|
||||
@ -62,7 +63,7 @@ void TrackBar::mouseMove(GUI*, int x, int) {
|
||||
value += min;
|
||||
value = (value > max) ? max : value;
|
||||
value = (value < min) ? min : value;
|
||||
value = (int64_t)round(value / step) * step;
|
||||
value = static_cast<int64_t>(std::round(value / step)) * step;
|
||||
|
||||
if (consumer && !changeOnRelease) {
|
||||
consumer(value);
|
||||
@ -72,7 +73,7 @@ void TrackBar::mouseMove(GUI*, int x, int) {
|
||||
}
|
||||
}
|
||||
|
||||
void TrackBar::mouseRelease(GUI*, int, int) {
|
||||
void TrackBar::mouseRelease(int, int) {
|
||||
if (consumer && changeOnRelease) {
|
||||
consumer(value);
|
||||
}
|
||||
|
||||
@ -16,19 +16,22 @@ namespace gui {
|
||||
int trackWidth;
|
||||
bool changeOnRelease = false;
|
||||
public:
|
||||
TrackBar(double min,
|
||||
double max,
|
||||
double value,
|
||||
double step=1.0,
|
||||
int trackWidth=12);
|
||||
TrackBar(
|
||||
GUI& gui,
|
||||
double min,
|
||||
double max,
|
||||
double value,
|
||||
double step = 1.0,
|
||||
int trackWidth = 12
|
||||
);
|
||||
virtual void draw(const DrawContext& pctx, const Assets& assets) override;
|
||||
|
||||
virtual void setSupplier(doublesupplier);
|
||||
virtual void setConsumer(doubleconsumer);
|
||||
virtual void setSubConsumer(doubleconsumer);
|
||||
|
||||
virtual void mouseMove(GUI*, int x, int y) override;
|
||||
virtual void mouseRelease(GUI*, int x, int y) override;
|
||||
virtual void mouseMove(int x, int y) override;
|
||||
virtual void mouseRelease(int x, int y) override;
|
||||
|
||||
virtual double getValue() const;
|
||||
virtual double getMin() const;
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
using gui::UINode;
|
||||
using gui::Align;
|
||||
|
||||
UINode::UINode(glm::vec2 size) : size(size) {
|
||||
UINode::UINode(GUI& gui, glm::vec2 size) : gui(gui), size(size) {
|
||||
}
|
||||
|
||||
UINode::~UINode() {
|
||||
@ -74,18 +74,18 @@ UINode* UINode::listenDoubleClick(const onaction& action) {
|
||||
return this;
|
||||
}
|
||||
|
||||
void UINode::click(GUI*, int, int) {
|
||||
void UINode::click(int, int) {
|
||||
pressed = true;
|
||||
}
|
||||
|
||||
void UINode::doubleClick(GUI* gui, int x, int y) {
|
||||
void UINode::doubleClick(int x, int y) {
|
||||
pressed = true;
|
||||
if (isInside(glm::vec2(x, y))) {
|
||||
doubleClickCallbacks.notify(gui);
|
||||
}
|
||||
}
|
||||
|
||||
void UINode::mouseRelease(GUI* gui, int x, int y) {
|
||||
void UINode::mouseRelease(int x, int y) {
|
||||
pressed = false;
|
||||
if (isInside(glm::vec2(x, y))) {
|
||||
actions.notify(gui);
|
||||
|
||||
@ -19,8 +19,8 @@ namespace gui {
|
||||
class GUI;
|
||||
class Container;
|
||||
|
||||
using onaction = std::function<void(GUI*)>;
|
||||
using onnumberchange = std::function<void(GUI*, double)>;
|
||||
using onaction = std::function<void(GUI&)>;
|
||||
using onnumberchange = std::function<void(GUI&, double)>;
|
||||
|
||||
class ActionsSet {
|
||||
std::unique_ptr<std::vector<onaction>> callbacks;
|
||||
@ -32,7 +32,7 @@ namespace gui {
|
||||
callbacks->push_back(callback);
|
||||
}
|
||||
|
||||
void notify(GUI* gui) {
|
||||
void notify(GUI& gui) {
|
||||
if (callbacks) {
|
||||
for (auto& callback : *callbacks) {
|
||||
callback(gui);
|
||||
@ -64,6 +64,9 @@ namespace gui {
|
||||
|
||||
/// @brief Base abstract class for all UI elements
|
||||
class UINode : public std::enable_shared_from_this<UINode> {
|
||||
protected:
|
||||
GUI& gui;
|
||||
private:
|
||||
/// @brief element identifier used for direct access in UiDocument
|
||||
std::string id = "";
|
||||
/// @brief element enabled state
|
||||
@ -118,7 +121,7 @@ namespace gui {
|
||||
/// @brief cursor shape when mouse is over the element
|
||||
CursorShape cursor = CursorShape::ARROW;
|
||||
|
||||
UINode(glm::vec2 size);
|
||||
UINode(GUI& gui, glm::vec2 size);
|
||||
public:
|
||||
virtual ~UINode();
|
||||
|
||||
@ -169,12 +172,12 @@ namespace gui {
|
||||
virtual UINode* listenAction(const onaction &action);
|
||||
virtual UINode* listenDoubleClick(const onaction &action);
|
||||
|
||||
virtual void onFocus(GUI*) {focused = true;}
|
||||
virtual void doubleClick(GUI*, int x, int y);
|
||||
virtual void click(GUI*, int x, int y);
|
||||
virtual void clicked(GUI*, mousecode button) {}
|
||||
virtual void mouseMove(GUI*, int x, int y) {};
|
||||
virtual void mouseRelease(GUI*, int x, int y);
|
||||
virtual void onFocus() {focused = true;}
|
||||
virtual void doubleClick(int x, int y);
|
||||
virtual void click(int x, int y);
|
||||
virtual void clicked(Mousecode button) {}
|
||||
virtual void mouseMove(int x, int y) {};
|
||||
virtual void mouseRelease(int x, int y);
|
||||
virtual void scrolled(int value);
|
||||
|
||||
bool isPressed() const;
|
||||
@ -185,7 +188,7 @@ namespace gui {
|
||||
virtual bool isFocuskeeper() const {return false;}
|
||||
|
||||
virtual void typed(unsigned int codepoint) {};
|
||||
virtual void keyPressed(keycode key) {};
|
||||
virtual void keyPressed(Keycode key) {};
|
||||
|
||||
/// @brief Check if screen position is inside of the element
|
||||
/// @param pos screen position
|
||||
@ -222,11 +225,11 @@ namespace gui {
|
||||
virtual glm::vec2 calcPos() const;
|
||||
virtual void setPos(glm::vec2 pos);
|
||||
virtual glm::vec2 getPos() const;
|
||||
virtual glm::vec2 getSize() const;
|
||||
glm::vec2 getSize() const;
|
||||
virtual void setSize(glm::vec2 size);
|
||||
virtual glm::vec2 getMinSize() const;
|
||||
glm::vec2 getMinSize() const;
|
||||
virtual void setMinSize(glm::vec2 size);
|
||||
virtual glm::vec2 getMaxSize() const;
|
||||
glm::vec2 getMaxSize() const;
|
||||
virtual void setMaxSize(glm::vec2 size);
|
||||
/// @brief Called in containers when new element added
|
||||
virtual void refresh() {};
|
||||
|
||||
@ -1,37 +1,36 @@
|
||||
#include "gui_util.hpp"
|
||||
|
||||
#include "elements/Label.hpp"
|
||||
#include "elements/Menu.hpp"
|
||||
#include "elements/Button.hpp"
|
||||
#include "elements/TextBox.hpp"
|
||||
#include "gui_xml.hpp"
|
||||
|
||||
#include "logic/scripting/scripting.hpp"
|
||||
#include "frontend/locale.hpp"
|
||||
#include "util/stringutil.hpp"
|
||||
#include "delegates.hpp"
|
||||
|
||||
#include "window/Events.hpp"
|
||||
#include "engine/Engine.hpp"
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include "delegates.hpp"
|
||||
#include "elements/Button.hpp"
|
||||
#include "elements/Label.hpp"
|
||||
#include "elements/Menu.hpp"
|
||||
#include "elements/TextBox.hpp"
|
||||
#include "engine/Engine.hpp"
|
||||
#include "frontend/locale.hpp"
|
||||
#include "gui_xml.hpp"
|
||||
#include "logic/scripting/scripting.hpp"
|
||||
#include "util/stringutil.hpp"
|
||||
|
||||
using namespace gui;
|
||||
|
||||
std::shared_ptr<gui::UINode> guiutil::create(const std::string& source, scriptenv env) {
|
||||
std::shared_ptr<gui::UINode> guiutil::create(
|
||||
GUI& gui, const std::string& source, scriptenv env
|
||||
) {
|
||||
if (env == nullptr) {
|
||||
env = scripting::get_root_environment();
|
||||
}
|
||||
UiXmlReader reader(env);
|
||||
UiXmlReader reader(gui, env);
|
||||
return reader.readXML("[string]", source);
|
||||
}
|
||||
|
||||
void guiutil::alert(
|
||||
Engine& engine,
|
||||
const std::wstring& text,
|
||||
const runnable& on_hidden
|
||||
Engine& engine, const std::wstring& text, const runnable& on_hidden
|
||||
) {
|
||||
GUI& gui = engine.getGUI();
|
||||
auto panel = std::make_shared<Panel>(
|
||||
gui,
|
||||
glm::vec2(
|
||||
glm::min(
|
||||
static_cast<size_t>(650),
|
||||
@ -44,7 +43,7 @@ void guiutil::alert(
|
||||
);
|
||||
panel->setColor(glm::vec4(0.0f, 0.0f, 0.0f, 0.5f));
|
||||
|
||||
auto menuPtr = engine.getGUI()->getMenu();
|
||||
auto menuPtr = gui.getMenu();
|
||||
auto& menu = *menuPtr;
|
||||
runnable on_hidden_final = [on_hidden, &menu]() {
|
||||
menu.removePage("<alert>");
|
||||
@ -55,24 +54,25 @@ void guiutil::alert(
|
||||
}
|
||||
};
|
||||
|
||||
auto label = std::make_shared<Label>(text);
|
||||
auto label = std::make_shared<Label>(gui, text);
|
||||
label->setMultiline(true);
|
||||
label->setSize(glm::vec2(1, 24));
|
||||
label->setAutoResize(true);
|
||||
panel->add(label);
|
||||
panel->add(std::make_shared<Button>(
|
||||
langs::get(L"Ok"), glm::vec4(10.f),
|
||||
[on_hidden_final](GUI*) {
|
||||
on_hidden_final();
|
||||
}
|
||||
gui,
|
||||
langs::get(L"Ok"),
|
||||
glm::vec4(10.f),
|
||||
[on_hidden_final](GUI&) { on_hidden_final(); }
|
||||
));
|
||||
panel->refresh();
|
||||
|
||||
panel->keepAlive(Events::keyCallbacks[keycode::ENTER].add([on_hidden_final](){
|
||||
auto& input = engine.getInput();
|
||||
panel->keepAlive(input.addKeyCallback(Keycode::ENTER, [on_hidden_final]() {
|
||||
on_hidden_final();
|
||||
return true;
|
||||
}));
|
||||
panel->keepAlive(Events::keyCallbacks[keycode::ESCAPE].add([on_hidden_final](){
|
||||
panel->keepAlive(input.addKeyCallback(Keycode::ESCAPE, [on_hidden_final]() {
|
||||
on_hidden_final();
|
||||
return true;
|
||||
}));
|
||||
@ -91,17 +91,25 @@ void guiutil::confirm(
|
||||
if (yestext.empty()) yestext = langs::get(L"Yes");
|
||||
if (notext.empty()) notext = langs::get(L"No");
|
||||
|
||||
auto container = std::make_shared<Container>(glm::vec2(5000, 5000));
|
||||
auto& gui = engine.getGUI();
|
||||
auto& input = engine.getInput();
|
||||
|
||||
auto container = std::make_shared<Container>(gui, glm::vec2(5000, 5000));
|
||||
container->setColor(glm::vec4(0.05f, 0.05f, 0.05f, 0.7f));
|
||||
auto panel = std::make_shared<Panel>(glm::vec2(600, 200), glm::vec4(8.0f), 8.0f);
|
||||
|
||||
auto panel = std::make_shared<Panel>(
|
||||
gui, glm::vec2(600, 200), glm::vec4(8.0f), 8.0f
|
||||
);
|
||||
|
||||
panel->setGravity(Gravity::center_center);
|
||||
container->add(panel);
|
||||
|
||||
panel->setColor(glm::vec4(0.0f, 0.0f, 0.0f, 0.5f));
|
||||
panel->add(std::make_shared<Label>(text));
|
||||
auto subpanel = std::make_shared<Panel>(glm::vec2(600, 53));
|
||||
panel->add(std::make_shared<Label>(gui, text));
|
||||
auto subpanel = std::make_shared<Panel>(gui, glm::vec2(600, 53));
|
||||
subpanel->setColor(glm::vec4(0));
|
||||
|
||||
auto menu = engine.getGUI()->getMenu();
|
||||
auto menu = gui.getMenu();
|
||||
|
||||
runnable on_confirm_final = [on_confirm, menu]() {
|
||||
menu->removePage("<confirm>");
|
||||
@ -121,20 +129,20 @@ void guiutil::confirm(
|
||||
}
|
||||
};
|
||||
|
||||
subpanel->add(std::make_shared<Button>(yestext, glm::vec4(8.f), [=](GUI*){
|
||||
subpanel->add(std::make_shared<Button>(gui, yestext, glm::vec4(8.f), [=](GUI&) {
|
||||
on_confirm_final();
|
||||
}));
|
||||
|
||||
subpanel->add(std::make_shared<Button>(notext, glm::vec4(8.f), [=](GUI*){
|
||||
subpanel->add(std::make_shared<Button>(gui, notext, glm::vec4(8.f), [=](GUI&) {
|
||||
on_deny_final();
|
||||
}));
|
||||
|
||||
panel->add(subpanel);
|
||||
panel->keepAlive(Events::keyCallbacks[keycode::ENTER].add([=](){
|
||||
panel->keepAlive(input.addKeyCallback(Keycode::ENTER, [=]() {
|
||||
on_confirm_final();
|
||||
return true;
|
||||
}));
|
||||
panel->keepAlive(Events::keyCallbacks[keycode::ESCAPE].add([=](){
|
||||
panel->keepAlive(input.addKeyCallback(Keycode::ESCAPE, [=]() {
|
||||
on_deny_final();
|
||||
return true;
|
||||
}));
|
||||
@ -145,21 +153,25 @@ void guiutil::confirm(
|
||||
}
|
||||
|
||||
void guiutil::confirm_with_memo(
|
||||
const std::shared_ptr<gui::Menu>& menu,
|
||||
const std::wstring& text,
|
||||
const std::wstring& memo,
|
||||
const runnable& on_confirm,
|
||||
std::wstring yestext,
|
||||
std::wstring notext) {
|
||||
|
||||
Engine& engine,
|
||||
const std::wstring& text,
|
||||
const std::wstring& memo,
|
||||
const runnable& on_confirm,
|
||||
std::wstring yestext,
|
||||
std::wstring notext
|
||||
) {
|
||||
auto& gui = engine.getGUI();
|
||||
auto menu = gui.getMenu();
|
||||
if (yestext.empty()) yestext = langs::get(L"Yes");
|
||||
if (notext.empty()) notext = langs::get(L"No");
|
||||
|
||||
auto panel = std::make_shared<Panel>(glm::vec2(600, 500), glm::vec4(8.0f), 8.0f);
|
||||
auto panel = std::make_shared<Panel>(
|
||||
gui, glm::vec2(600, 500), glm::vec4(8.0f), 8.0f
|
||||
);
|
||||
panel->setColor(glm::vec4(0.0f, 0.0f, 0.0f, 0.5f));
|
||||
panel->add(std::make_shared<Label>(text));
|
||||
panel->add(std::make_shared<Label>(gui, text));
|
||||
|
||||
auto textbox = std::make_shared<TextBox>(L"");
|
||||
auto textbox = std::make_shared<TextBox>(gui, L"");
|
||||
textbox->setMultiline(true);
|
||||
textbox->setTextWrapping(true);
|
||||
textbox->setSize(glm::vec2(600, 300));
|
||||
@ -167,16 +179,15 @@ void guiutil::confirm_with_memo(
|
||||
textbox->setEditable(false);
|
||||
panel->add(textbox);
|
||||
|
||||
auto subpanel = std::make_shared<Panel>(glm::vec2(600, 53));
|
||||
auto subpanel = std::make_shared<Panel>(gui, glm::vec2(600, 53));
|
||||
subpanel->setColor(glm::vec4(0));
|
||||
|
||||
subpanel->add(std::make_shared<Button>(yestext, glm::vec4(8.f), [=](GUI*){
|
||||
if (on_confirm)
|
||||
on_confirm();
|
||||
subpanel->add(std::make_shared<Button>(gui, yestext, glm::vec4(8.f), [=](GUI&) {
|
||||
if (on_confirm) on_confirm();
|
||||
menu->back();
|
||||
}));
|
||||
|
||||
subpanel->add(std::make_shared<Button>(notext, glm::vec4(8.f), [=](GUI*){
|
||||
subpanel->add(std::make_shared<Button>(gui, notext, glm::vec4(8.f), [=](GUI&) {
|
||||
menu->back();
|
||||
}));
|
||||
|
||||
|
||||
@ -1,38 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
#include "GUI.hpp"
|
||||
#include "typedefs.hpp"
|
||||
#include "delegates.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "delegates.hpp"
|
||||
#include "typedefs.hpp"
|
||||
|
||||
class Engine;
|
||||
|
||||
namespace gui {
|
||||
class GUI;
|
||||
class UINode;
|
||||
}
|
||||
|
||||
namespace guiutil {
|
||||
/// @brief Create element from XML
|
||||
/// @param source XML
|
||||
std::shared_ptr<gui::UINode> create(const std::string& source, scriptenv env=0);
|
||||
std::shared_ptr<gui::UINode> create(
|
||||
gui::GUI& gui, const std::string& source, scriptenv env = 0
|
||||
);
|
||||
|
||||
void alert(
|
||||
Engine& engine,
|
||||
const std::wstring& text,
|
||||
const runnable& on_hidden=nullptr
|
||||
const runnable& on_hidden = nullptr
|
||||
);
|
||||
|
||||
void confirm(
|
||||
Engine& engine,
|
||||
const std::wstring& text,
|
||||
const runnable& on_confirm=nullptr,
|
||||
const runnable& on_deny=nullptr,
|
||||
std::wstring yestext=L"",
|
||||
std::wstring notext=L"");
|
||||
const runnable& on_confirm = nullptr,
|
||||
const runnable& on_deny = nullptr,
|
||||
std::wstring yestext = L"",
|
||||
std::wstring notext = L""
|
||||
);
|
||||
|
||||
void confirm_with_memo(
|
||||
const std::shared_ptr<gui::Menu>& menu,
|
||||
Engine& engine,
|
||||
const std::wstring& text,
|
||||
const std::wstring& memo,
|
||||
const runnable& on_confirm=nullptr,
|
||||
std::wstring yestext=L"",
|
||||
std::wstring notext=L"");
|
||||
const runnable& on_confirm = nullptr,
|
||||
std::wstring yestext = L"",
|
||||
std::wstring notext = L""
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,29 +1,29 @@
|
||||
#include "gui_xml.hpp"
|
||||
|
||||
#include "elements/Panel.hpp"
|
||||
#include "elements/Image.hpp"
|
||||
#include "elements/Menu.hpp"
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
|
||||
#include "GUI.hpp"
|
||||
#include "elements/Button.hpp"
|
||||
#include "elements/Canvas.hpp"
|
||||
#include "elements/CheckBox.hpp"
|
||||
#include "elements/TextBox.hpp"
|
||||
#include "elements/SplitBox.hpp"
|
||||
#include "elements/TrackBar.hpp"
|
||||
#include "elements/Image.hpp"
|
||||
#include "elements/InputBindBox.hpp"
|
||||
#include "elements/InventoryView.hpp"
|
||||
#include "GUI.hpp"
|
||||
#include "elements/Menu.hpp"
|
||||
#include "elements/Panel.hpp"
|
||||
#include "elements/TextBox.hpp"
|
||||
#include "elements/TrackBar.hpp"
|
||||
#include "engine/Engine.hpp"
|
||||
|
||||
#include "frontend/menu.hpp"
|
||||
#include "frontend/locale.hpp"
|
||||
#include "frontend/menu.hpp"
|
||||
#include "items/Inventory.hpp"
|
||||
#include "logic/scripting/scripting.hpp"
|
||||
#include "maths/voxmaths.hpp"
|
||||
#include "util/stringutil.hpp"
|
||||
#include "window/Events.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
|
||||
using namespace gui;
|
||||
|
||||
@ -80,7 +80,7 @@ static onaction create_action(
|
||||
if (callback == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
return [callback](GUI*) {callback();};
|
||||
return [callback](GUI&) { callback(); };
|
||||
}
|
||||
|
||||
/// @brief Read basic UINode properties
|
||||
@ -152,9 +152,7 @@ static void read_uinode(
|
||||
node.setAlign(align_from_string(alignName, node.getAlign()));
|
||||
|
||||
if (element.has("gravity")) {
|
||||
node.setGravity(gravity_from_string(
|
||||
element.attr("gravity").getText()
|
||||
));
|
||||
node.setGravity(gravity_from_string(element.attr("gravity").getText()));
|
||||
}
|
||||
|
||||
if (element.has("tooltip")) {
|
||||
@ -184,7 +182,9 @@ static void read_uinode(
|
||||
}
|
||||
}
|
||||
|
||||
static void read_container_impl(UiXmlReader& reader, const xml::xmlelement& element, Container& container) {
|
||||
static void read_container_impl(
|
||||
UiXmlReader& reader, const xml::xmlelement& element, Container& container
|
||||
) {
|
||||
read_uinode(reader, element, container);
|
||||
|
||||
if (element.has("scrollable")) {
|
||||
@ -194,8 +194,7 @@ static void read_container_impl(UiXmlReader& reader, const xml::xmlelement& elem
|
||||
container.setScrollStep(element.attr("scroll-step").asInt());
|
||||
}
|
||||
for (auto& sub : element.getElements()) {
|
||||
if (sub->isText())
|
||||
continue;
|
||||
if (sub->isText()) continue;
|
||||
auto subnode = reader.readUINode(*sub);
|
||||
if (subnode) {
|
||||
container.add(subnode);
|
||||
@ -203,7 +202,9 @@ static void read_container_impl(UiXmlReader& reader, const xml::xmlelement& elem
|
||||
}
|
||||
}
|
||||
|
||||
void UiXmlReader::readUINode(UiXmlReader& reader, const xml::xmlelement& element, Container& container) {
|
||||
void UiXmlReader::readUINode(
|
||||
UiXmlReader& reader, const xml::xmlelement& element, Container& container
|
||||
) {
|
||||
read_container_impl(reader, element, container);
|
||||
}
|
||||
|
||||
@ -225,8 +226,7 @@ static void read_base_panel_impl(
|
||||
panel.setPadding(padding);
|
||||
glm::vec2 size = panel.getSize();
|
||||
panel.setSize(glm::vec2(
|
||||
size.x + padding.x + padding.z,
|
||||
size.y + padding.y + padding.w
|
||||
size.x + padding.x + padding.z, size.y + padding.y + padding.w
|
||||
));
|
||||
}
|
||||
if (element.has("orientation")) {
|
||||
@ -254,10 +254,15 @@ static void read_panel_impl(
|
||||
if (element.has("min-length")) {
|
||||
panel.setMinLength(element.attr("min-length").asInt());
|
||||
}
|
||||
if (element.has("orientation")) {
|
||||
auto& oname = element.attr("orientation").getText();
|
||||
if (oname == "horizontal") {
|
||||
panel.setOrientation(Orientation::horizontal);
|
||||
}
|
||||
}
|
||||
if (subnodes) {
|
||||
for (auto& sub : element.getElements()) {
|
||||
if (sub->isText())
|
||||
continue;
|
||||
if (sub->isText()) continue;
|
||||
auto subnode = reader.readUINode(*sub);
|
||||
if (subnode) {
|
||||
panel.add(subnode);
|
||||
@ -289,12 +294,12 @@ static std::shared_ptr<UINode> readLabel(
|
||||
const UiXmlReader& reader, const xml::xmlelement& element
|
||||
) {
|
||||
std::wstring text = parse_inner_text(element, reader.getContext());
|
||||
auto label = std::make_shared<Label>(text);
|
||||
auto label = std::make_shared<Label>(reader.getGUI(), text);
|
||||
read_uinode(reader, element, *label);
|
||||
if (element.has("valign")) {
|
||||
label->setVerticalAlign(
|
||||
align_from_string(element.attr("valign").getText(), label->getVerticalAlign())
|
||||
);
|
||||
label->setVerticalAlign(align_from_string(
|
||||
element.attr("valign").getText(), label->getVerticalAlign()
|
||||
));
|
||||
}
|
||||
if (element.has("supplier")) {
|
||||
label->textSupplier(scripting::create_wstring_supplier(
|
||||
@ -324,7 +329,7 @@ static std::shared_ptr<UINode> readLabel(
|
||||
static std::shared_ptr<UINode> read_container(
|
||||
UiXmlReader& reader, const xml::xmlelement& element
|
||||
) {
|
||||
auto container = std::make_shared<Container>(glm::vec2());
|
||||
auto container = std::make_shared<Container>(reader.getGUI(), glm::vec2());
|
||||
read_container_impl(reader, element, *container);
|
||||
return container;
|
||||
}
|
||||
@ -337,8 +342,9 @@ static std::shared_ptr<UINode> read_split_box(
|
||||
element.attr("orientation", "vertical").getText() == "horizontal"
|
||||
? Orientation::horizontal
|
||||
: Orientation::vertical;
|
||||
auto splitBox =
|
||||
std::make_shared<SplitBox>(glm::vec2(), splitPos, orientation);
|
||||
auto splitBox = std::make_shared<SplitBox>(
|
||||
reader.getGUI(), glm::vec2(), splitPos, orientation
|
||||
);
|
||||
read_base_panel_impl(reader, element, *splitBox);
|
||||
for (auto& sub : element.getElements()) {
|
||||
if (sub->isText())
|
||||
@ -355,7 +361,9 @@ static std::shared_ptr<UINode> read_panel(
|
||||
UiXmlReader& reader, const xml::xmlelement& element
|
||||
) {
|
||||
float interval = element.attr("interval", "2").asFloat();
|
||||
auto panel = std::make_shared<Panel>(glm::vec2(), glm::vec4(), interval);
|
||||
auto panel = std::make_shared<Panel>(
|
||||
reader.getGUI(), glm::vec2(), glm::vec4(), interval
|
||||
);
|
||||
read_panel_impl(reader, element, *panel);
|
||||
return panel;
|
||||
}
|
||||
@ -363,6 +371,7 @@ static std::shared_ptr<UINode> read_panel(
|
||||
static std::shared_ptr<UINode> read_button(
|
||||
UiXmlReader& reader, const xml::xmlelement& element
|
||||
) {
|
||||
auto& gui = reader.getGUI();
|
||||
glm::vec4 padding = element.attr("padding", "10").asVec4();
|
||||
|
||||
std::shared_ptr<Button> button;
|
||||
@ -370,14 +379,14 @@ static std::shared_ptr<UINode> read_button(
|
||||
if (!elements.empty() && elements[0]->getTag() != "#") {
|
||||
auto inner = reader.readUINode(*elements.at(0));
|
||||
if (inner != nullptr) {
|
||||
button = std::make_shared<Button>(inner, padding);
|
||||
button = std::make_shared<Button>(gui, inner, padding);
|
||||
} else {
|
||||
button = std::make_shared<Button>(L"", padding, nullptr);
|
||||
button = std::make_shared<Button>(gui, L"", padding, nullptr);
|
||||
}
|
||||
read_panel_impl(reader, element, *button, false);
|
||||
} else {
|
||||
std::wstring text = parse_inner_text(element, reader.getContext());
|
||||
button = std::make_shared<Button>(text, padding, nullptr);
|
||||
button = std::make_shared<Button>(gui, text, padding, nullptr);
|
||||
read_panel_impl(reader, element, *button, true);
|
||||
}
|
||||
if (element.has("text-align")) {
|
||||
@ -393,7 +402,9 @@ static std::shared_ptr<UINode> read_check_box(
|
||||
) {
|
||||
auto text = parse_inner_text(element, reader.getContext());
|
||||
bool checked = element.attr("checked", "false").asBool();
|
||||
auto checkbox = std::make_shared<FullCheckBox>(text, glm::vec2(32), checked);
|
||||
auto checkbox = std::make_shared<FullCheckBox>(
|
||||
reader.getGUI(), text, glm::vec2(32), checked
|
||||
);
|
||||
read_panel_impl(reader, element, *checkbox);
|
||||
|
||||
if (element.has("consumer")) {
|
||||
@ -417,10 +428,13 @@ static std::shared_ptr<UINode> read_check_box(
|
||||
static std::shared_ptr<UINode> read_text_box(
|
||||
UiXmlReader& reader, const xml::xmlelement& element
|
||||
) {
|
||||
auto placeholder = util::str2wstr_utf8(element.attr("placeholder", "").getText());
|
||||
auto placeholder =
|
||||
util::str2wstr_utf8(element.attr("placeholder", "").getText());
|
||||
auto hint = util::str2wstr_utf8(element.attr("hint", "").getText());
|
||||
auto text = parse_inner_text(element, reader.getContext());
|
||||
auto textbox = std::make_shared<TextBox>(placeholder, glm::vec4(0.0f));
|
||||
auto textbox = std::make_shared<TextBox>(
|
||||
reader.getGUI(), placeholder, glm::vec4(0.0f)
|
||||
);
|
||||
textbox->setHint(hint);
|
||||
|
||||
read_container_impl(reader, element, *textbox);
|
||||
@ -429,8 +443,7 @@ static std::shared_ptr<UINode> read_text_box(
|
||||
textbox->setPadding(padding);
|
||||
glm::vec2 size = textbox->getSize();
|
||||
textbox->setSize(glm::vec2(
|
||||
size.x + padding.x + padding.z,
|
||||
size.y + padding.y + padding.w
|
||||
size.x + padding.x + padding.z, size.y + padding.y + padding.w
|
||||
));
|
||||
}
|
||||
textbox->setText(text);
|
||||
@ -513,7 +526,7 @@ static std::shared_ptr<UINode> read_image(
|
||||
const UiXmlReader& reader, const xml::xmlelement& element
|
||||
) {
|
||||
std::string src = element.attr("src", "").getText();
|
||||
auto image = std::make_shared<Image>(src);
|
||||
auto image = std::make_shared<Image>(reader.getGUI(), src);
|
||||
read_uinode(reader, element, *image);
|
||||
return image;
|
||||
}
|
||||
@ -521,11 +534,12 @@ static std::shared_ptr<UINode> read_image(
|
||||
static std::shared_ptr<UINode> read_canvas(
|
||||
const UiXmlReader& reader, const xml::xmlelement& element
|
||||
) {
|
||||
auto size = glm::uvec2{32, 32};
|
||||
auto size = glm::uvec2 {32, 32};
|
||||
if (element.has("size")) {
|
||||
size = element.attr("size").asVec2();
|
||||
}
|
||||
auto image = std::make_shared<Canvas>(ImageFormat::rgba8888, size);
|
||||
auto image =
|
||||
std::make_shared<Canvas>(reader.getGUI(), ImageFormat::rgba8888, size);
|
||||
read_uinode(reader, element, *image);
|
||||
return image;
|
||||
}
|
||||
@ -540,19 +554,24 @@ static std::shared_ptr<UINode> read_track_bar(
|
||||
float def = element.attr("value", "0.0").asFloat();
|
||||
float step = element.attr("step", "1.0").asFloat();
|
||||
int trackWidth = element.attr("track-width", "12").asInt();
|
||||
auto bar = std::make_shared<TrackBar>(minv, maxv, def, step, trackWidth);
|
||||
auto bar = std::make_shared<TrackBar>(
|
||||
reader.getGUI(), minv, maxv, def, step, trackWidth
|
||||
);
|
||||
read_uinode(reader, element, *bar);
|
||||
if (element.has("consumer")) {
|
||||
bar->setConsumer(scripting::create_number_consumer(
|
||||
env, element.attr("consumer").getText(), file));
|
||||
env, element.attr("consumer").getText(), file
|
||||
));
|
||||
}
|
||||
if (element.has("sub-consumer")) {
|
||||
bar->setSubConsumer(scripting::create_number_consumer(
|
||||
env, element.attr("sub-consumer").getText(), file));
|
||||
env, element.attr("sub-consumer").getText(), file
|
||||
));
|
||||
}
|
||||
if (element.has("supplier")) {
|
||||
bar->setSupplier(scripting::create_number_supplier(
|
||||
env, element.attr("supplier").getText(), file));
|
||||
env, element.attr("supplier").getText(), file
|
||||
));
|
||||
}
|
||||
if (element.has("track-color")) {
|
||||
bar->setTrackColor(element.attr("track-color").asColor());
|
||||
@ -567,14 +586,11 @@ static std::shared_ptr<UINode> read_input_bind_box(
|
||||
UiXmlReader& reader, const xml::xmlelement& element
|
||||
) {
|
||||
auto bindname = element.attr("binding").getText();
|
||||
auto found = Events::bindings.find(bindname);
|
||||
if (found == Events::bindings.end()) {
|
||||
throw std::runtime_error("binding does not exists "+util::quote(bindname));
|
||||
}
|
||||
auto& found = reader.getGUI().getInput().getBindings().require(bindname);
|
||||
glm::vec4 padding = element.attr("padding", "6").asVec4();
|
||||
auto bindbox = std::make_shared<InputBindBox>(found->second, padding);
|
||||
auto bindbox =
|
||||
std::make_shared<InputBindBox>(reader.getGUI(), found, padding);
|
||||
read_panel_impl(reader, element, *bindbox);
|
||||
|
||||
return bindbox;
|
||||
}
|
||||
|
||||
@ -585,11 +601,12 @@ static slotcallback read_slot_func(
|
||||
const std::string& attr
|
||||
) {
|
||||
auto consumer = scripting::create_int_array_consumer(
|
||||
reader.getEnvironment(),
|
||||
element.attr(attr).getText()
|
||||
reader.getEnvironment(), element.attr(attr).getText()
|
||||
);
|
||||
return [=](uint slot, ItemStack&) {
|
||||
int args[] {int(view->getInventory()->getId()), int(slot)};
|
||||
int args[] {
|
||||
static_cast<int>(view->getInventory()->getId()),
|
||||
static_cast<int>(slot)};
|
||||
consumer(args, 2);
|
||||
};
|
||||
}
|
||||
@ -601,7 +618,9 @@ static void readSlot(
|
||||
bool itemSource = element.attr("item-source", "false").asBool();
|
||||
bool taking = element.attr("taking", "true").asBool();
|
||||
bool placing = element.attr("placing", "true").asBool();
|
||||
SlotLayout layout(index, glm::vec2(), true, itemSource, nullptr, nullptr, nullptr);
|
||||
SlotLayout layout(
|
||||
index, glm::vec2(), true, itemSource, nullptr, nullptr, nullptr
|
||||
);
|
||||
if (element.has("pos")) {
|
||||
layout.position = element.attr("pos").asVec2();
|
||||
}
|
||||
@ -612,7 +631,8 @@ static void readSlot(
|
||||
layout.shareFunc = read_slot_func(view, reader, element, "sharefunc");
|
||||
}
|
||||
if (element.has("onrightclick")) {
|
||||
layout.rightClick = read_slot_func(view, reader, element, "onrightclick");
|
||||
layout.rightClick =
|
||||
read_slot_func(view, reader, element, "onrightclick");
|
||||
}
|
||||
layout.taking = taking;
|
||||
layout.placing = placing;
|
||||
@ -622,7 +642,9 @@ static void readSlot(
|
||||
}
|
||||
|
||||
static void readSlotsGrid(
|
||||
InventoryView* view, const UiXmlReader& reader, const xml::xmlelement& element
|
||||
InventoryView* view,
|
||||
const UiXmlReader& reader,
|
||||
const xml::xmlelement& element
|
||||
) {
|
||||
int startIndex = element.attr("start-index", "0").asInt();
|
||||
int rows = element.attr("rows", "0").asInt();
|
||||
@ -647,7 +669,9 @@ static void readSlotsGrid(
|
||||
count = rows * cols;
|
||||
}
|
||||
bool itemSource = element.attr("item-source", "false").asBool();
|
||||
SlotLayout layout(-1, glm::vec2(), true, itemSource, nullptr, nullptr, nullptr);
|
||||
SlotLayout layout(
|
||||
-1, glm::vec2(), true, itemSource, nullptr, nullptr, nullptr
|
||||
);
|
||||
if (element.has("pos")) {
|
||||
layout.position = element.attr("pos").asVec2();
|
||||
}
|
||||
@ -658,7 +682,8 @@ static void readSlotsGrid(
|
||||
layout.shareFunc = read_slot_func(view, reader, element, "sharefunc");
|
||||
}
|
||||
if (element.has("onrightclick")) {
|
||||
layout.rightClick = read_slot_func(view, reader, element, "onrightclick");
|
||||
layout.rightClick =
|
||||
read_slot_func(view, reader, element, "onrightclick");
|
||||
}
|
||||
layout.padding = padding;
|
||||
layout.taking = taking;
|
||||
@ -674,7 +699,7 @@ static void readSlotsGrid(
|
||||
slotLayout.index = startIndex + idx;
|
||||
slotLayout.position += glm::vec2(
|
||||
padding + col * (slotSize + interval),
|
||||
padding + (rows-row-1) * (slotSize + interval)
|
||||
padding + (rows - row - 1) * (slotSize + interval)
|
||||
);
|
||||
auto slot = view->addSlot(slotLayout);
|
||||
view->add(slot, slotLayout.position);
|
||||
@ -685,8 +710,8 @@ static void readSlotsGrid(
|
||||
static std::shared_ptr<UINode> read_inventory(
|
||||
UiXmlReader& reader, const xml::xmlelement& element
|
||||
) {
|
||||
auto view = std::make_shared<InventoryView>();
|
||||
view->setColor(glm::vec4(0.122f, 0.122f, 0.122f, 0.878f)); // todo: fixme
|
||||
auto view = std::make_shared<InventoryView>(reader.getGUI());
|
||||
view->setColor(glm::vec4(0.122f, 0.122f, 0.122f, 0.878f)); // TODO: fixme
|
||||
reader.addIgnore("slot");
|
||||
reader.addIgnore("slots-grid");
|
||||
reader.readUINode(reader, element, *view);
|
||||
@ -704,16 +729,15 @@ static std::shared_ptr<UINode> read_inventory(
|
||||
static std::shared_ptr<UINode> read_page_box(
|
||||
UiXmlReader& reader, const xml::xmlelement& element
|
||||
) {
|
||||
auto menu = std::make_shared<Menu>();
|
||||
menu->setPageLoader(
|
||||
Engine::getInstance().getGUI()->getMenu()->getPageLoader()
|
||||
);
|
||||
auto& gui = reader.getGUI();
|
||||
auto menu = std::make_shared<Menu>(gui);
|
||||
menu->setPageLoader(gui.getMenu()->getPageLoader());
|
||||
read_container_impl(reader, element, *menu);
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
UiXmlReader::UiXmlReader(const scriptenv& env) : env(env) {
|
||||
UiXmlReader::UiXmlReader(gui::GUI& gui, const scriptenv& env) : gui(gui), env(env) {
|
||||
contextStack.emplace("");
|
||||
add("image", read_image);
|
||||
add("canvas", read_canvas);
|
||||
@ -742,16 +766,15 @@ void UiXmlReader::addIgnore(const std::string& tag) {
|
||||
ignored.insert(tag);
|
||||
}
|
||||
|
||||
std::shared_ptr<UINode> UiXmlReader::readUINode(const xml::xmlelement& element) {
|
||||
std::shared_ptr<UINode> UiXmlReader::readUINode(const xml::xmlelement& element
|
||||
) {
|
||||
if (element.has("if")) {
|
||||
const auto& cond = element.attr("if").getText();
|
||||
if (cond.empty() || cond == "false" || cond == "nil")
|
||||
return nullptr;
|
||||
if (cond.empty() || cond == "false" || cond == "nil") return nullptr;
|
||||
}
|
||||
if (element.has("ifnot")) {
|
||||
const auto& cond = element.attr("ifnot").getText();
|
||||
if (!(cond.empty() || cond == "false" || cond == "nil"))
|
||||
return nullptr;
|
||||
if (!(cond.empty() || cond == "false" || cond == "nil")) return nullptr;
|
||||
}
|
||||
|
||||
const std::string& tag = element.getTag();
|
||||
@ -760,7 +783,7 @@ std::shared_ptr<UINode> UiXmlReader::readUINode(const xml::xmlelement& element)
|
||||
if (ignored.find(tag) != ignored.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
throw std::runtime_error("unsupported element '"+tag+"'");
|
||||
throw std::runtime_error("unsupported element '" + tag + "'");
|
||||
}
|
||||
|
||||
bool hascontext = element.has("context");
|
||||
@ -775,8 +798,7 @@ std::shared_ptr<UINode> UiXmlReader::readUINode(const xml::xmlelement& element)
|
||||
}
|
||||
|
||||
std::shared_ptr<UINode> UiXmlReader::readXML(
|
||||
const std::string& filename,
|
||||
const std::string& source
|
||||
const std::string& filename, const std::string& source
|
||||
) {
|
||||
this->filename = filename;
|
||||
auto document = xml::parse(filename, source);
|
||||
@ -784,8 +806,7 @@ std::shared_ptr<UINode> UiXmlReader::readXML(
|
||||
}
|
||||
|
||||
std::shared_ptr<UINode> UiXmlReader::readXML(
|
||||
const std::string& filename,
|
||||
const xml::xmlelement& root
|
||||
const std::string& filename, const xml::xmlelement& root
|
||||
) {
|
||||
this->filename = filename;
|
||||
return readUINode(root);
|
||||
@ -802,3 +823,7 @@ const std::string& UiXmlReader::getFilename() const {
|
||||
const scriptenv& UiXmlReader::getEnvironment() const {
|
||||
return env;
|
||||
}
|
||||
|
||||
gui::GUI& UiXmlReader::getGUI() const {
|
||||
return gui;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user