This commit is contained in:
commit
f599ed7fe7
7
.github/workflows/appimage.yml
vendored
7
.github/workflows/appimage.yml
vendored
@ -9,7 +9,12 @@ on:
|
||||
jobs:
|
||||
build-appimage:
|
||||
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
@ -45,7 +45,7 @@ if(MSVC)
|
||||
endif()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /source-charset:UTF-8")
|
||||
else()
|
||||
target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -lstdc++fs
|
||||
target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra
|
||||
# additional warnings
|
||||
-Wformat-nonliteral -Wcast-align
|
||||
-Wpointer-arith -Wundef
|
||||
@ -114,7 +114,7 @@ if(UNIX)
|
||||
endif()
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -no-pie")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -no-pie -lstdc++fs")
|
||||
endif()
|
||||
|
||||
include_directories(${LUA_INCLUDE_DIR})
|
||||
|
||||
@ -50,20 +50,20 @@ void AssetsLoader::createDefaults(AssetsLoader& loader) {
|
||||
loader.addLoader(ASSET_ATLAS, assetload::atlas);
|
||||
}
|
||||
|
||||
void AssetsLoader::addDefaults(AssetsLoader& loader, bool allAssets) {
|
||||
if (allAssets) {
|
||||
loader.add(ASSET_SHADER, SHADERS_FOLDER"/main", "main");
|
||||
loader.add(ASSET_SHADER, SHADERS_FOLDER"/lines", "lines");
|
||||
loader.add(ASSET_SHADER, SHADERS_FOLDER"/ui", "ui");
|
||||
void AssetsLoader::addDefaults(AssetsLoader& loader, bool world) {
|
||||
loader.add(ASSET_FONT, FONTS_FOLDER"/font", "normal");
|
||||
loader.add(ASSET_SHADER, SHADERS_FOLDER"/ui", "ui");
|
||||
loader.add(ASSET_SHADER, SHADERS_FOLDER"/main", "main");
|
||||
loader.add(ASSET_SHADER, SHADERS_FOLDER"/lines", "lines");
|
||||
loader.add(ASSET_TEXTURE, TEXTURES_FOLDER"/gui/menubg.png", "gui/menubg");
|
||||
loader.add(ASSET_TEXTURE, TEXTURES_FOLDER"/gui/delete_icon.png", "gui/delete_icon");
|
||||
loader.add(ASSET_TEXTURE, TEXTURES_FOLDER"/gui/no_icon.png", "gui/no_icon");
|
||||
if (world) {
|
||||
loader.add(ASSET_SHADER, SHADERS_FOLDER"/ui3d", "ui3d");
|
||||
loader.add(ASSET_SHADER, SHADERS_FOLDER"/background", "background");
|
||||
loader.add(ASSET_SHADER, SHADERS_FOLDER"/skybox_gen", "skybox_gen");
|
||||
loader.add(ASSET_TEXTURE, TEXTURES_FOLDER"/gui/menubg.png", "gui/menubg");
|
||||
loader.add(ASSET_TEXTURE, TEXTURES_FOLDER"/gui/delete_icon.png", "gui/delete_icon");
|
||||
loader.add(ASSET_TEXTURE, TEXTURES_FOLDER"/gui/no_icon.png", "gui/no_icon");
|
||||
loader.add(ASSET_TEXTURE, TEXTURES_FOLDER"/misc/moon.png", "misc/moon");
|
||||
loader.add(ASSET_TEXTURE, TEXTURES_FOLDER"/misc/sun.png", "misc/sun");
|
||||
loader.add(ASSET_FONT, FONTS_FOLDER"/font", "normal");
|
||||
}
|
||||
loader.add(ASSET_ATLAS, TEXTURES_FOLDER"/blocks", "blocks");
|
||||
loader.add(ASSET_ATLAS, TEXTURES_FOLDER"/items", "items");
|
||||
|
||||
@ -36,7 +36,7 @@ public:
|
||||
bool loadNext();
|
||||
|
||||
static void createDefaults(AssetsLoader& loader);
|
||||
static void addDefaults(AssetsLoader& loader, bool allAssets);
|
||||
static void addDefaults(AssetsLoader& loader, bool world);
|
||||
|
||||
const ResPaths* getPaths() const;
|
||||
};
|
||||
|
||||
@ -20,12 +20,14 @@ bool assetload::texture(Assets* assets,
|
||||
const ResPaths* paths,
|
||||
const std::string filename,
|
||||
const std::string name) {
|
||||
Texture* texture = png::load_texture(paths->find(filename).string());
|
||||
std::unique_ptr<Texture> texture(
|
||||
png::load_texture(paths->find(filename).string())
|
||||
);
|
||||
if (texture == nullptr) {
|
||||
std::cerr << "failed to load texture '" << name << "'" << std::endl;
|
||||
return false;
|
||||
}
|
||||
assets->store(texture, name);
|
||||
assets->store(texture.release(), name);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -92,21 +94,21 @@ bool assetload::font(Assets* assets,
|
||||
const ResPaths* paths,
|
||||
const std::string filename,
|
||||
const std::string name) {
|
||||
std::vector<Texture*> pages;
|
||||
std::vector<std::unique_ptr<Texture>> pages;
|
||||
for (size_t i = 0; i <= 4; i++) {
|
||||
std::string name = filename + "_" + std::to_string(i) + ".png";
|
||||
name = paths->find(name).string();
|
||||
Texture* texture = png::load_texture(name);
|
||||
std::unique_ptr<Texture> texture (png::load_texture(name));
|
||||
if (texture == nullptr) {
|
||||
std::cerr << "failed to load bitmap font '" << name;
|
||||
std::cerr << "' (missing page " << std::to_string(i) << ")";
|
||||
std::cerr << std::endl;
|
||||
return false;
|
||||
}
|
||||
pages.push_back(texture);
|
||||
pages.push_back(std::move(texture));
|
||||
}
|
||||
Font* font = new Font(pages, pages[0]->height / 16);
|
||||
assets->store(font, name);
|
||||
int res = pages[0]->height / 16;
|
||||
assets->store(new Font(std::move(pages), res, 4), name);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -135,7 +137,6 @@ bool assetload::animation(Assets* assets,
|
||||
|
||||
auto frameArr = root->list("frames");
|
||||
|
||||
Frame temp;
|
||||
float frameDuration = DEFAULT_FRAME_DURATION;
|
||||
std::string frameName;
|
||||
|
||||
@ -164,7 +165,7 @@ bool assetload::animation(Assets* assets,
|
||||
if (!appendAtlas(builder, file)) continue;
|
||||
}
|
||||
|
||||
Atlas* srcAtlas = builder.build(2);
|
||||
std::unique_ptr<Atlas> srcAtlas (builder.build(2));
|
||||
|
||||
Texture* srcTex = srcAtlas->getTexture();
|
||||
Texture* dstTex = dstAtlas->getTexture();
|
||||
@ -196,7 +197,7 @@ bool assetload::animation(Assets* assets,
|
||||
}
|
||||
}
|
||||
|
||||
assets->store(srcAtlas, name + "_animation");
|
||||
assets->store(srcAtlas.release(), name + "_animation");
|
||||
assets->store(animation);
|
||||
|
||||
return true;
|
||||
|
||||
@ -4,19 +4,6 @@
|
||||
#include <stdexcept>
|
||||
#include <math.h>
|
||||
|
||||
inline int char2int(int c) {
|
||||
if (c >= '0' && c <= '9') {
|
||||
return c - '0';
|
||||
}
|
||||
if (c >= 'a' && c <= 'f') {
|
||||
return 10 + c - 'a';
|
||||
}
|
||||
if (c >= 'A' && c <= 'F') {
|
||||
return 10 + c - 'A';
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
inline double power(double base, int64_t power) {
|
||||
double result = 1.0;
|
||||
for (int64_t i = 0; i < power; i++) {
|
||||
@ -98,6 +85,18 @@ void BasicParser::skipWhitespace() {
|
||||
}
|
||||
}
|
||||
|
||||
void BasicParser::skip(size_t n) {
|
||||
n = std::min(n, source.length()-pos);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char next = source[pos++];
|
||||
if (next == '\n') {
|
||||
line++;
|
||||
linestart = pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BasicParser::skipLine() {
|
||||
while (hasNext()) {
|
||||
if (source[pos] == '\n') {
|
||||
@ -110,10 +109,28 @@ void BasicParser::skipLine() {
|
||||
}
|
||||
}
|
||||
|
||||
bool BasicParser::skipTo(const std::string& substring) {
|
||||
size_t idx = source.find(substring, pos);
|
||||
if (idx == std::string::npos) {
|
||||
skip(source.length()-pos);
|
||||
return false;
|
||||
} else {
|
||||
skip(idx-pos);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool BasicParser::hasNext() {
|
||||
return pos < source.length();
|
||||
}
|
||||
|
||||
bool BasicParser::isNext(const std::string& substring) {
|
||||
if (source.length() - pos < substring.length()) {
|
||||
return false;
|
||||
}
|
||||
return source.substr(pos, substring.length()) == substring;
|
||||
}
|
||||
|
||||
char BasicParser::nextChar() {
|
||||
if (!hasNext()) {
|
||||
throw error("unexpected end");
|
||||
@ -129,6 +146,17 @@ void BasicParser::expect(char expected) {
|
||||
pos++;
|
||||
}
|
||||
|
||||
void BasicParser::expect(const std::string& substring) {
|
||||
if (substring.empty())
|
||||
return;
|
||||
for (uint i = 0; i < substring.length(); i++) {
|
||||
if (source.length() <= pos + i || source[pos+i] != substring[i]) {
|
||||
throw error(escape_string(substring)+" expected");
|
||||
}
|
||||
}
|
||||
pos += substring.length();
|
||||
}
|
||||
|
||||
void BasicParser::expectNewLine() {
|
||||
while (hasNext()) {
|
||||
char next = source[pos];
|
||||
@ -145,6 +173,10 @@ void BasicParser::expectNewLine() {
|
||||
}
|
||||
}
|
||||
|
||||
void BasicParser::goBack() {
|
||||
if (pos) pos--;
|
||||
}
|
||||
|
||||
char BasicParser::peek() {
|
||||
skipWhitespace();
|
||||
if (pos >= source.length()) {
|
||||
@ -171,7 +203,7 @@ std::string BasicParser::parseName() {
|
||||
|
||||
int64_t BasicParser::parseSimpleInt(int base) {
|
||||
char c = peek();
|
||||
int index = char2int(c);
|
||||
int index = hexchar2int(c);
|
||||
if (index == -1 || index >= base) {
|
||||
throw error("invalid number literal");
|
||||
}
|
||||
@ -182,7 +214,7 @@ int64_t BasicParser::parseSimpleInt(int base) {
|
||||
while (c == '_') {
|
||||
c = source[++pos];
|
||||
}
|
||||
index = char2int(c);
|
||||
index = hexchar2int(c);
|
||||
if (index == -1 || index >= base) {
|
||||
return value;
|
||||
}
|
||||
|
||||
@ -41,6 +41,19 @@ inline bool is_identifier_part(int c) {
|
||||
return is_identifier_start(c) || is_digit(c);
|
||||
}
|
||||
|
||||
inline int hexchar2int(int c) {
|
||||
if (c >= '0' && c <= '9') {
|
||||
return c - '0';
|
||||
}
|
||||
if (c >= 'a' && c <= 'f') {
|
||||
return 10 + c - 'a';
|
||||
}
|
||||
if (c >= 'A' && c <= 'F') {
|
||||
return 10 + c - 'A';
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern std::string escape_string(std::string s);
|
||||
|
||||
class parsing_error : public std::runtime_error {
|
||||
@ -70,12 +83,17 @@ protected:
|
||||
uint linestart = 0;
|
||||
|
||||
virtual void skipWhitespace();
|
||||
void skip(size_t n);
|
||||
void skipLine();
|
||||
bool skipTo(const std::string& substring);
|
||||
void expect(char expected);
|
||||
void expect(const std::string& substring);
|
||||
char peek();
|
||||
char nextChar();
|
||||
bool hasNext();
|
||||
bool isNext(const std::string& substring);
|
||||
void expectNewLine();
|
||||
void goBack();
|
||||
|
||||
std::string parseName();
|
||||
int64_t parseSimpleInt(int base);
|
||||
|
||||
@ -34,7 +34,7 @@ std::vector<ubyte> gzip::compress(const ubyte* src, size_t size) {
|
||||
|
||||
std::vector<ubyte> gzip::decompress(const ubyte* src, size_t size) {
|
||||
// getting uncompressed data length from gzip footer
|
||||
size_t decompressed_size = *(uint32_t*)(src+size-4);
|
||||
size_t decompressed_size = *reinterpret_cast<const uint32_t*>(src+size-4);
|
||||
std::vector<ubyte> buffer;
|
||||
buffer.resize(decompressed_size);
|
||||
|
||||
|
||||
354
src/coders/xml.cpp
Normal file
354
src/coders/xml.cpp
Normal file
@ -0,0 +1,354 @@
|
||||
#include "xml.h"
|
||||
|
||||
#include <charconv>
|
||||
#include <stdexcept>
|
||||
#include <sstream>
|
||||
#include "../util/stringutil.h"
|
||||
|
||||
using namespace xml;
|
||||
|
||||
Attribute::Attribute(std::string name, std::string text)
|
||||
: name(name),
|
||||
text(text) {
|
||||
}
|
||||
|
||||
const std::string& Attribute::getName() const {
|
||||
return name;
|
||||
}
|
||||
|
||||
const std::string& Attribute::getText() const {
|
||||
return text;
|
||||
}
|
||||
|
||||
int64_t Attribute::asInt() const {
|
||||
return std::stoll(text);
|
||||
}
|
||||
|
||||
double Attribute::asFloat() const {
|
||||
return util::parse_double(text);
|
||||
}
|
||||
|
||||
bool Attribute::asBool() const {
|
||||
return text == "true" || text == "1";
|
||||
}
|
||||
|
||||
Node::Node(std::string tag) : tag(tag) {
|
||||
}
|
||||
|
||||
void Node::add(xmlelement element) {
|
||||
elements.push_back(element);
|
||||
}
|
||||
|
||||
void Node::set(std::string name, std::string text) {
|
||||
attrs[name] = Attribute(name, text);
|
||||
}
|
||||
|
||||
const std::string& Node::getTag() const {
|
||||
return tag;
|
||||
}
|
||||
|
||||
const xmlattribute Node::attr(const std::string& name) const {
|
||||
auto found = attrs.find(name);
|
||||
if (found == attrs.end()) {
|
||||
throw std::runtime_error("element <"+tag+" ...> missing attribute "+name);
|
||||
}
|
||||
return found->second;
|
||||
}
|
||||
|
||||
const xmlattribute Node::attr(const std::string& name, const std::string& def) const {
|
||||
auto found = attrs.find(name);
|
||||
if (found == attrs.end()) {
|
||||
return Attribute(name, def);
|
||||
}
|
||||
return found->second;
|
||||
}
|
||||
|
||||
bool Node::has(const std::string& name) const {
|
||||
auto found = attrs.find(name);
|
||||
return found != attrs.end();
|
||||
}
|
||||
|
||||
xmlelement Node::sub(size_t index) {
|
||||
return elements.at(index);
|
||||
}
|
||||
|
||||
size_t Node::size() const {
|
||||
return elements.size();
|
||||
}
|
||||
|
||||
const std::vector<xmlelement>& Node::getElements() const {
|
||||
return elements;
|
||||
}
|
||||
|
||||
const xmlelements_map& Node::getAttributes() const {
|
||||
return attrs;
|
||||
}
|
||||
|
||||
Document::Document(std::string version, std::string encoding)
|
||||
: version(version),
|
||||
encoding(encoding) {
|
||||
}
|
||||
|
||||
void Document::setRoot(xmlelement element) {
|
||||
this->root = element;
|
||||
}
|
||||
|
||||
xmlelement Document::getRoot() const {
|
||||
return root;
|
||||
}
|
||||
|
||||
const std::string& Document::getVersion() const {
|
||||
return version;
|
||||
}
|
||||
|
||||
const std::string& Document::getEncoding() const {
|
||||
return encoding;
|
||||
}
|
||||
|
||||
Parser::Parser(std::string filename, std::string source)
|
||||
: BasicParser(filename, source) {
|
||||
}
|
||||
|
||||
xmlelement Parser::parseOpenTag() {
|
||||
std::string tag = parseXMLName();
|
||||
auto node = std::make_shared<Node>(tag);
|
||||
|
||||
char c;
|
||||
while (true) {
|
||||
skipWhitespace();
|
||||
c = peek();
|
||||
if (c == '/' || c == '>' || c == '?')
|
||||
break;
|
||||
std::string attrname = parseXMLName();
|
||||
std::string attrtext = "";
|
||||
skipWhitespace();
|
||||
if (peek() == '=') {
|
||||
nextChar();
|
||||
skipWhitespace();
|
||||
expect('"');
|
||||
attrtext = parseString('"');
|
||||
}
|
||||
node->set(attrname, attrtext);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
void Parser::parseDeclaration() {
|
||||
std::string version = "1.0";
|
||||
std::string encoding = "UTF-8";
|
||||
expect('<');
|
||||
if (peek() == '?') {
|
||||
nextChar();
|
||||
xmlelement node = parseOpenTag();
|
||||
expect("?>");
|
||||
if (node->getTag() != "xml") {
|
||||
throw error("invalid declaration");
|
||||
}
|
||||
version = node->attr("version", version).getText();
|
||||
encoding = node->attr("encoding", encoding).getText();
|
||||
if (encoding != "utf-8" && encoding != "UTF-8") {
|
||||
throw error("UTF-8 encoding is only supported");
|
||||
}
|
||||
} else {
|
||||
goBack();
|
||||
}
|
||||
document = std::make_shared<Document>(version, encoding);
|
||||
}
|
||||
|
||||
void Parser::parseComment() {
|
||||
expect("!--");
|
||||
if (skipTo("-->")) {
|
||||
skip(3);
|
||||
} else {
|
||||
throw error("comment close missing");
|
||||
}
|
||||
}
|
||||
|
||||
std::string Parser::parseText() {
|
||||
size_t start = pos;
|
||||
while (hasNext()) {
|
||||
char c = peek();
|
||||
if (c == '<') {
|
||||
break;
|
||||
}
|
||||
nextChar();
|
||||
}
|
||||
return source.substr(start, pos-start);
|
||||
}
|
||||
|
||||
inline bool is_xml_identifier_start(char c) {
|
||||
return is_identifier_start(c) || c == ':';
|
||||
}
|
||||
|
||||
inline bool is_xml_identifier_part(char c) {
|
||||
return is_identifier_part(c) || c == '-' || c == '.' || c == ':';
|
||||
}
|
||||
|
||||
std::string Parser::parseXMLName() {
|
||||
char c = peek();
|
||||
if (!is_xml_identifier_start(c)) {
|
||||
throw error("identifier expected");
|
||||
}
|
||||
int start = pos;
|
||||
while (hasNext() && is_xml_identifier_part(source[pos])) {
|
||||
pos++;
|
||||
}
|
||||
return source.substr(start, pos-start);
|
||||
}
|
||||
|
||||
xmlelement Parser::parseElement() {
|
||||
// text element
|
||||
if (peek() != '<') {
|
||||
auto element = std::make_shared<Node>("#");
|
||||
auto text = parseText();
|
||||
util::replaceAll(text, """, "\"");
|
||||
util::replaceAll(text, "'", "'");
|
||||
util::replaceAll(text, "<", "<");
|
||||
util::replaceAll(text, ">", ">");
|
||||
util::replaceAll(text, "&", "&");
|
||||
element->set("#", text);
|
||||
return element;
|
||||
}
|
||||
nextChar();
|
||||
|
||||
// <!--element-->
|
||||
if (peek() == '!') {
|
||||
if (isNext("!DOCTYPE ")) {
|
||||
throw error("XML DTD is not supported yet");
|
||||
}
|
||||
parseComment();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto element = parseOpenTag();
|
||||
char c = nextChar();
|
||||
|
||||
// <element/>
|
||||
if (c == '/') {
|
||||
expect('>');
|
||||
}
|
||||
// <element>...</element>
|
||||
else if (c == '>') {
|
||||
skipWhitespace();
|
||||
while (!isNext("</")) {
|
||||
auto sub = parseElement();
|
||||
if (sub) {
|
||||
element->add(sub);
|
||||
}
|
||||
skipWhitespace();
|
||||
}
|
||||
skip(2);
|
||||
expect(element->getTag());
|
||||
expect('>');
|
||||
}
|
||||
// <element?>
|
||||
else {
|
||||
throw error("invalid syntax");
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
xmldocument Parser::parse() {
|
||||
parseDeclaration();
|
||||
|
||||
xmlelement root = nullptr;
|
||||
while (root == nullptr) {
|
||||
root = parseElement();
|
||||
}
|
||||
document->setRoot(root);
|
||||
return document;
|
||||
}
|
||||
|
||||
xmldocument xml::parse(std::string filename, std::string source) {
|
||||
Parser parser(filename, source);
|
||||
return parser.parse();
|
||||
}
|
||||
|
||||
inline void newline(
|
||||
std::stringstream& ss,
|
||||
bool nice,
|
||||
const std::string& indentStr,
|
||||
int indent
|
||||
) {
|
||||
if (!nice)
|
||||
return;
|
||||
ss << '\n';
|
||||
for (int i = 0; i < indent; i++) {
|
||||
ss << indentStr;
|
||||
}
|
||||
}
|
||||
|
||||
static void stringifyElement(
|
||||
std::stringstream& ss,
|
||||
const xmlelement element,
|
||||
bool nice,
|
||||
const std::string& indentStr,
|
||||
int indent
|
||||
) {
|
||||
if (element->isText()) {
|
||||
std::string text = element->attr("#").getText();
|
||||
util::replaceAll(text, "&", "&");
|
||||
util::replaceAll(text, "\"",""");
|
||||
util::replaceAll(text, "'", "'");
|
||||
util::replaceAll(text, "<", "<");
|
||||
util::replaceAll(text, ">", ">");
|
||||
ss << text;
|
||||
return;
|
||||
}
|
||||
const std::string& tag = element->getTag();
|
||||
|
||||
ss << '<' << tag;
|
||||
auto& attrs = element->getAttributes();
|
||||
if (!attrs.empty()) {
|
||||
ss << ' ';
|
||||
int count = 0;
|
||||
for (auto& entry : attrs) {
|
||||
auto attr = entry.second;
|
||||
ss << attr.getName();
|
||||
if (!attr.getText().empty()) {
|
||||
ss << "=" << escape_string(attr.getText());
|
||||
}
|
||||
if (count + 1 < int(attrs.size())) {
|
||||
ss << " ";
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
auto& elements = element->getElements();
|
||||
if (elements.size() == 1 && elements[0]->isText()) {
|
||||
ss << ">";
|
||||
stringifyElement(ss, elements[0], nice, indentStr, indent+1);
|
||||
ss << "</" << tag << ">";
|
||||
return;
|
||||
}
|
||||
if (!elements.empty()) {
|
||||
ss << '>';
|
||||
for (auto& sub : elements) {
|
||||
newline(ss, nice, indentStr, indent+1);
|
||||
stringifyElement(ss, sub, nice, indentStr, indent+1);
|
||||
}
|
||||
newline(ss, nice, indentStr, indent);
|
||||
ss << "</" << tag << ">";
|
||||
|
||||
} else {
|
||||
ss << "/>";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::string xml::stringify(
|
||||
const xmldocument document,
|
||||
bool nice,
|
||||
const std::string& indentStr
|
||||
) {
|
||||
std::stringstream ss;
|
||||
|
||||
// XML declaration
|
||||
ss << "<?xml version=\"" << document->getVersion();
|
||||
ss << "\" encoding=\"UTF-8\" ?>";
|
||||
newline(ss, nice, indentStr, 0);
|
||||
|
||||
stringifyElement(ss, document->getRoot(), nice, indentStr, 0);
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
134
src/coders/xml.h
Normal file
134
src/coders/xml.h
Normal file
@ -0,0 +1,134 @@
|
||||
#ifndef CODERS_XML_H_
|
||||
#define CODERS_XML_H_
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "commons.h"
|
||||
|
||||
namespace xml {
|
||||
class Node;
|
||||
class Attribute;
|
||||
class Document;
|
||||
|
||||
typedef Attribute xmlattribute;
|
||||
typedef std::shared_ptr<Node> xmlelement;
|
||||
typedef std::shared_ptr<Document> xmldocument;
|
||||
typedef std::unordered_map<std::string, xmlattribute> xmlelements_map;
|
||||
|
||||
class Attribute {
|
||||
std::string name;
|
||||
std::string text;
|
||||
public:
|
||||
Attribute() {};
|
||||
Attribute(std::string name, std::string text);
|
||||
|
||||
const std::string& getName() const;
|
||||
const std::string& getText() const;
|
||||
int64_t asInt() const;
|
||||
double asFloat() const;
|
||||
bool asBool() const;
|
||||
};
|
||||
|
||||
/* XML element class. Text element has tag 'text' and attribute 'text' */
|
||||
class Node {
|
||||
std::string tag;
|
||||
std::unordered_map<std::string, xmlattribute> attrs;
|
||||
std::vector<xmlelement> elements;
|
||||
public:
|
||||
Node(std::string tag);
|
||||
|
||||
/* Add sub-element */
|
||||
void add(xmlelement element);
|
||||
|
||||
/* Set attribute value. Creates attribute if does not exists */
|
||||
void set(std::string name, std::string text);
|
||||
|
||||
/* Get element tag */
|
||||
const std::string& getTag() const;
|
||||
|
||||
inline bool isText() const {
|
||||
return getTag() == "#";
|
||||
}
|
||||
|
||||
inline const std::string& text() const {
|
||||
return attr("#").getText();
|
||||
}
|
||||
|
||||
/* Get attribute by name
|
||||
@param name attribute name
|
||||
@throws std::runtime_error if element has no attribute
|
||||
@return xmlattribute - {name, value} */
|
||||
const xmlattribute attr(const std::string& name) const;
|
||||
/* Get attribute by name
|
||||
@param name name
|
||||
@param def default value will be returned wrapped in xmlattribute
|
||||
if element has no attribute
|
||||
@return xmlattribute - {name, value} or {name, def} if not found*/
|
||||
const xmlattribute attr(const std::string& name, const std::string& def) const;
|
||||
|
||||
/* Check if element has attribute
|
||||
@param name attribute name */
|
||||
bool has(const std::string& name) const;
|
||||
|
||||
/* Get sub-element by index
|
||||
@throws std::out_of_range if an invalid index given */
|
||||
xmlelement sub(size_t index);
|
||||
|
||||
/* Get number of sub-elements */
|
||||
size_t size() const;
|
||||
|
||||
const std::vector<xmlelement>& getElements() const;
|
||||
const xmlelements_map& getAttributes() const;
|
||||
};
|
||||
|
||||
class Document {
|
||||
xmlelement root = nullptr;
|
||||
std::string version;
|
||||
std::string encoding;
|
||||
public:
|
||||
Document(std::string version, std::string encoding);
|
||||
|
||||
void setRoot(xmlelement element);
|
||||
xmlelement getRoot() const;
|
||||
|
||||
const std::string& getVersion() const;
|
||||
const std::string& getEncoding() const;
|
||||
};
|
||||
|
||||
class Parser : public BasicParser {
|
||||
xmldocument document;
|
||||
|
||||
xmlelement parseOpenTag();
|
||||
xmlelement parseElement();
|
||||
void parseDeclaration();
|
||||
void parseComment();
|
||||
std::string parseText();
|
||||
std::string parseXMLName();
|
||||
public:
|
||||
Parser(std::string filename, std::string source);
|
||||
|
||||
xmldocument parse();
|
||||
};
|
||||
|
||||
/* Serialize XML Document to string
|
||||
@param document serializing document
|
||||
@param nice use human readable format
|
||||
(with indents and line-separators)
|
||||
@param indentStr indentation characters sequence
|
||||
(default - 4 spaces)*/
|
||||
extern std::string stringify(
|
||||
const xmldocument document,
|
||||
bool nice=true,
|
||||
const std::string& indentStr=" "
|
||||
);
|
||||
|
||||
/* Read XML Document from string
|
||||
@param filename file name will be shown in error messages
|
||||
@param source xml source code string */
|
||||
extern xmldocument parse(std::string filename, std::string source);
|
||||
}
|
||||
|
||||
#endif // CODERS_XML_H_
|
||||
@ -71,7 +71,7 @@ Content* ContentBuilder::build() {
|
||||
|
||||
// Generating runtime info
|
||||
def->rt.id = blockDefsIndices.size();
|
||||
def->rt.emissive = *((uint32_t*)def->emission);
|
||||
def->rt.emissive = *reinterpret_cast<uint32_t*>(def->emission);
|
||||
def->rt.solid = def->model == BlockModel::block;
|
||||
|
||||
if (def->rotatable) {
|
||||
@ -95,7 +95,7 @@ Content* ContentBuilder::build() {
|
||||
|
||||
// Generating runtime info
|
||||
def->rt.id = itemDefsIndices.size();
|
||||
def->rt.emissive = *((uint32_t*)def->emission);
|
||||
def->rt.emissive = *reinterpret_cast<uint32_t*>(def->emission);
|
||||
itemDefsIndices.push_back(def);
|
||||
}
|
||||
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
#include <set>
|
||||
#include "../typedefs.h"
|
||||
|
||||
typedef std::set<unsigned char> DrawGroups;
|
||||
using DrawGroups = std::set<unsigned char>;
|
||||
|
||||
class Block;
|
||||
class ItemDef;
|
||||
|
||||
@ -74,7 +74,7 @@ void ContentLoader::fixPackIndices() {
|
||||
|
||||
std::unique_ptr<dynamic::Map> root;
|
||||
if (fs::is_regular_file(indexFile)) {
|
||||
root = std::move(files::read_json(indexFile));
|
||||
root = files::read_json(indexFile);
|
||||
} else {
|
||||
root.reset(new dynamic::Map());
|
||||
}
|
||||
|
||||
@ -8,7 +8,7 @@ namespace fs = std::filesystem;
|
||||
|
||||
class Block;
|
||||
class ItemDef;
|
||||
class ContentPack;
|
||||
struct ContentPack;
|
||||
class ContentBuilder;
|
||||
|
||||
namespace dynamic {
|
||||
|
||||
@ -1,48 +1,43 @@
|
||||
#include "definitions.h"
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include "items/ItemDef.h"
|
||||
#include "content/Content.h"
|
||||
#include "window/Window.h"
|
||||
#include "window/Events.h"
|
||||
#include "window/input.h"
|
||||
#include "voxels/Block.h"
|
||||
|
||||
using glm::vec3;
|
||||
|
||||
// All in-game definitions (blocks, items, etc..)
|
||||
void setup_definitions(ContentBuilder* builder) { // Strange function, need to REDO ?
|
||||
Block* block = new Block("core:air", "air");
|
||||
block->replaceable = true;
|
||||
block->drawGroup = 1;
|
||||
block->lightPassing = true;
|
||||
block->skyLightPassing = true;
|
||||
block->obstacle = false;
|
||||
block->selectable = false;
|
||||
block->model = BlockModel::none;
|
||||
block->pickingItem = "core:empty";
|
||||
builder->add(block);
|
||||
|
||||
ItemDef* item = builder->createItem("core:empty");
|
||||
item->iconType = item_icon_type::none;
|
||||
}
|
||||
|
||||
void setup_bindings() {
|
||||
Events::bind(BIND_MOVE_FORWARD, inputtype::keyboard, keycode::W);
|
||||
Events::bind(BIND_MOVE_BACK, inputtype::keyboard, keycode::S);
|
||||
Events::bind(BIND_MOVE_RIGHT, inputtype::keyboard, keycode::D);
|
||||
Events::bind(BIND_MOVE_LEFT, inputtype::keyboard, keycode::A);
|
||||
Events::bind(BIND_MOVE_JUMP, inputtype::keyboard, keycode::SPACE);
|
||||
Events::bind(BIND_MOVE_SPRINT, inputtype::keyboard, keycode::LEFT_CONTROL);
|
||||
Events::bind(BIND_MOVE_CROUCH, inputtype::keyboard, keycode::LEFT_SHIFT);
|
||||
Events::bind(BIND_MOVE_CHEAT, inputtype::keyboard, keycode::R);
|
||||
Events::bind(BIND_CAM_ZOOM, inputtype::keyboard, keycode::C);
|
||||
Events::bind(BIND_CAM_MODE, inputtype::keyboard, keycode::F4);
|
||||
Events::bind(BIND_PLAYER_NOCLIP, inputtype::keyboard, keycode::N);
|
||||
Events::bind(BIND_PLAYER_FLIGHT, inputtype::keyboard, keycode::F);
|
||||
Events::bind(BIND_PLAYER_ATTACK, inputtype::mouse, mousecode::BUTTON_1);
|
||||
Events::bind(BIND_PLAYER_BUILD, inputtype::mouse, mousecode::BUTTON_2);
|
||||
Events::bind(BIND_PLAYER_PICK, inputtype::mouse, mousecode::BUTTON_3);
|
||||
Events::bind(BIND_HUD_INVENTORY, inputtype::keyboard, keycode::TAB);
|
||||
#include "core_defs.h"
|
||||
|
||||
#include "items/ItemDef.h"
|
||||
#include "content/Content.h"
|
||||
#include "window/Window.h"
|
||||
#include "window/Events.h"
|
||||
#include "window/input.h"
|
||||
#include "voxels/Block.h"
|
||||
|
||||
// All in-game definitions (blocks, items, etc..)
|
||||
void corecontent::setup(ContentBuilder* builder) {
|
||||
Block* block = builder->createBlock("core:air");
|
||||
block->replaceable = true;
|
||||
block->drawGroup = 1;
|
||||
block->lightPassing = true;
|
||||
block->skyLightPassing = true;
|
||||
block->obstacle = false;
|
||||
block->selectable = false;
|
||||
block->model = BlockModel::none;
|
||||
block->pickingItem = "core:empty";
|
||||
|
||||
ItemDef* item = builder->createItem("core:empty");
|
||||
item->iconType = item_icon_type::none;
|
||||
}
|
||||
|
||||
void corecontent::setup_bindings() {
|
||||
Events::bind(BIND_MOVE_FORWARD, inputtype::keyboard, keycode::W);
|
||||
Events::bind(BIND_MOVE_BACK, inputtype::keyboard, keycode::S);
|
||||
Events::bind(BIND_MOVE_RIGHT, inputtype::keyboard, keycode::D);
|
||||
Events::bind(BIND_MOVE_LEFT, inputtype::keyboard, keycode::A);
|
||||
Events::bind(BIND_MOVE_JUMP, inputtype::keyboard, keycode::SPACE);
|
||||
Events::bind(BIND_MOVE_SPRINT, inputtype::keyboard, keycode::LEFT_CONTROL);
|
||||
Events::bind(BIND_MOVE_CROUCH, inputtype::keyboard, keycode::LEFT_SHIFT);
|
||||
Events::bind(BIND_MOVE_CHEAT, inputtype::keyboard, keycode::R);
|
||||
Events::bind(BIND_CAM_ZOOM, inputtype::keyboard, keycode::C);
|
||||
Events::bind(BIND_CAM_MODE, inputtype::keyboard, keycode::F4);
|
||||
Events::bind(BIND_PLAYER_NOCLIP, inputtype::keyboard, keycode::N);
|
||||
Events::bind(BIND_PLAYER_FLIGHT, inputtype::keyboard, keycode::F);
|
||||
Events::bind(BIND_PLAYER_ATTACK, inputtype::mouse, mousecode::BUTTON_1);
|
||||
Events::bind(BIND_PLAYER_BUILD, inputtype::mouse, mousecode::BUTTON_2);
|
||||
Events::bind(BIND_PLAYER_PICK, inputtype::mouse, mousecode::BUTTON_3);
|
||||
Events::bind(BIND_HUD_INVENTORY, inputtype::keyboard, keycode::TAB);
|
||||
}
|
||||
@ -3,7 +3,6 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
|
||||
const std::string TEXTURE_NOTFOUND = "notfound";
|
||||
|
||||
/* bindings used in engine code */
|
||||
@ -24,4 +23,11 @@ const std::string BIND_PLAYER_BUILD = "player.build";
|
||||
const std::string BIND_PLAYER_PICK = "player.pick";
|
||||
const std::string BIND_HUD_INVENTORY = "hud.inventory";
|
||||
|
||||
class ContentBuilder;
|
||||
|
||||
namespace corecontent {
|
||||
extern void setup_bindings();
|
||||
extern void setup(ContentBuilder* builder);
|
||||
}
|
||||
|
||||
#endif // SRC_CORE_DEFS_H_
|
||||
@ -1,13 +0,0 @@
|
||||
#ifndef DECLARATIONS_H
|
||||
#define DECLARATIONS_H
|
||||
|
||||
#include <iostream>
|
||||
#include "core_defs.h"
|
||||
|
||||
class ContentBuilder;
|
||||
|
||||
extern void setup_bindings();
|
||||
extern void setup_definitions(ContentBuilder* builder);
|
||||
|
||||
#endif // DECLARATIONS_H
|
||||
|
||||
10
src/delegates.h
Normal file
10
src/delegates.h
Normal file
@ -0,0 +1,10 @@
|
||||
#ifndef DELEGATES_H_
|
||||
#define DELEGATES_H_
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
typedef std::function<void()> runnable;
|
||||
typedef std::function<void(const std::string&)> stringconsumer;
|
||||
|
||||
#endif // DELEGATES_H_
|
||||
@ -37,7 +37,7 @@
|
||||
#include "frontend/locale/langs.h"
|
||||
#include "logic/scripting/scripting.h"
|
||||
|
||||
#include "definitions.h"
|
||||
#include "core_defs.h"
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
@ -56,7 +56,7 @@ Engine::Engine(EngineSettings& settings, EnginePaths* paths)
|
||||
assets.reset(new Assets());
|
||||
AssetsLoader loader(assets.get(), resPaths.get());
|
||||
AssetsLoader::createDefaults(loader);
|
||||
AssetsLoader::addDefaults(loader, true);
|
||||
AssetsLoader::addDefaults(loader, false);
|
||||
|
||||
Shader::preprocessor->setPaths(resPaths.get());
|
||||
while (loader.hasNext()) {
|
||||
@ -148,7 +148,7 @@ inline const std::string checkPacks(const std::unordered_set<std::string>& packs
|
||||
void Engine::loadContent() {
|
||||
auto resdir = paths->getResources();
|
||||
ContentBuilder contentBuilder;
|
||||
setup_definitions(&contentBuilder);
|
||||
corecontent::setup(&contentBuilder);
|
||||
paths->setContentPacks(&contentPacks);
|
||||
|
||||
std::vector<fs::path> resRoots;
|
||||
@ -183,7 +183,7 @@ void Engine::loadContent() {
|
||||
std::cout << "-- loading assets" << std::endl;
|
||||
AssetsLoader loader(new_assets.get(), resPaths.get());
|
||||
AssetsLoader::createDefaults(loader);
|
||||
AssetsLoader::addDefaults(loader, false);
|
||||
AssetsLoader::addDefaults(loader, true);
|
||||
while (loader.hasNext()) {
|
||||
if (!loader.loadNext()) {
|
||||
new_assets.reset();
|
||||
@ -214,7 +214,7 @@ void Engine::setScreen(std::shared_ptr<Screen> screen) {
|
||||
void Engine::setLanguage(std::string locale) {
|
||||
settings.ui.language = locale;
|
||||
langs::setup(paths->getResources(), locale, contentPacks);
|
||||
menus::create_menus(this, gui->getMenu());
|
||||
menus::create_menus(this);
|
||||
}
|
||||
|
||||
gui::GUI* Engine::getGUI() {
|
||||
|
||||
@ -30,10 +30,10 @@ fs::path EnginePaths::getScreenshotFile(std::string ext) {
|
||||
ss << std::put_time(&tm, format);
|
||||
std::string datetimestr = ss.str();
|
||||
|
||||
fs::path filename = folder/fs::path("screenshot-"+datetimestr+"."+ext);
|
||||
fs::path filename = folder/fs::u8path("screenshot-"+datetimestr+"."+ext);
|
||||
uint index = 0;
|
||||
while (fs::exists(filename)) {
|
||||
filename = folder/fs::path("screenshot-"+datetimestr+"-"+std::to_string(index)+"."+ext);
|
||||
filename = folder/fs::u8path("screenshot-"+datetimestr+"-"+std::to_string(index)+"."+ext);
|
||||
index++;
|
||||
}
|
||||
return filename;
|
||||
@ -59,7 +59,7 @@ std::vector<fs::path> EnginePaths::scanForWorlds() {
|
||||
continue;
|
||||
}
|
||||
fs::path worldFolder = entry.path();
|
||||
fs::path worldFile = worldFolder/fs::path(WorldFiles::WORLD_FILE);
|
||||
fs::path worldFile = worldFolder/fs::u8path(WorldFiles::WORLD_FILE);
|
||||
if (!fs::is_regular_file(worldFile)) {
|
||||
continue;
|
||||
}
|
||||
@ -91,31 +91,31 @@ void EnginePaths::setContentPacks(std::vector<ContentPack>* contentPacks) {
|
||||
fs::path EnginePaths::resolve(std::string path) {
|
||||
size_t separator = path.find(':');
|
||||
if (separator == std::string::npos) {
|
||||
return fs::path(path);
|
||||
return fs::u8path(path);
|
||||
}
|
||||
std::string prefix = path.substr(0, separator);
|
||||
std::string filename = path.substr(separator+1);
|
||||
|
||||
if (prefix == "res" || prefix == "core") {
|
||||
return resources/fs::path(filename);
|
||||
return resources/fs::u8path(filename);
|
||||
}
|
||||
|
||||
if (prefix == "user") {
|
||||
return userfiles/fs::path(filename);
|
||||
return userfiles/fs::u8path(filename);
|
||||
}
|
||||
|
||||
if (prefix == "world") {
|
||||
return worldFolder/fs::path(filename);
|
||||
return worldFolder/fs::u8path(filename);
|
||||
}
|
||||
|
||||
if (contentPacks) {
|
||||
for (auto& pack : *contentPacks) {
|
||||
if (pack.id == prefix) {
|
||||
return pack.folder/fs::path(filename);
|
||||
return pack.folder/fs::u8path(filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
return fs::path("./"+filename);
|
||||
return fs::u8path("./"+filename);
|
||||
}
|
||||
|
||||
ResPaths::ResPaths(fs::path mainRoot, std::vector<fs::path> roots)
|
||||
@ -125,19 +125,19 @@ ResPaths::ResPaths(fs::path mainRoot, std::vector<fs::path> roots)
|
||||
fs::path ResPaths::find(const std::string& filename) const {
|
||||
for (int i = roots.size()-1; i >= 0; i--) {
|
||||
auto& root = roots[i];
|
||||
fs::path file = root / fs::path(filename);
|
||||
fs::path file = root / fs::u8path(filename);
|
||||
if (fs::exists(file)) {
|
||||
return file;
|
||||
}
|
||||
}
|
||||
return mainRoot / fs::path(filename);
|
||||
return mainRoot / fs::u8path(filename);
|
||||
}
|
||||
|
||||
std::vector<fs::path> ResPaths::listdir(const std::string& folderName) const {
|
||||
std::vector<fs::path> entries;
|
||||
for (int i = roots.size()-1; i >= 0; i--) {
|
||||
auto& root = roots[i];
|
||||
fs::path folder = root / fs::path(folderName);
|
||||
fs::path folder = root / fs::u8path(folderName);
|
||||
if (!fs::is_directory(folder))
|
||||
continue;
|
||||
for (const auto& entry : fs::directory_iterator(folder)) {
|
||||
@ -145,7 +145,7 @@ std::vector<fs::path> ResPaths::listdir(const std::string& folderName) const {
|
||||
}
|
||||
}
|
||||
{
|
||||
fs::path folder = mainRoot / fs::path(folderName);
|
||||
fs::path folder = mainRoot / fs::u8path(folderName);
|
||||
if (!fs::is_directory(folder))
|
||||
return entries;
|
||||
for (const auto& entry : fs::directory_iterator(folder)) {
|
||||
|
||||
@ -289,10 +289,11 @@ void SlotView::clicked(gui::GUI* gui, int button) {
|
||||
if (stack.isEmpty()) {
|
||||
stack.set(grabbed);
|
||||
stack.setCount(1);
|
||||
} else {
|
||||
grabbed.setCount(grabbed.getCount()-1);
|
||||
} else if (stack.accepts(grabbed)){
|
||||
stack.setCount(stack.getCount()+1);
|
||||
grabbed.setCount(grabbed.getCount()-1);
|
||||
}
|
||||
grabbed.setCount(grabbed.getCount()-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -120,8 +120,6 @@ class InventoryView : public gui::Container {
|
||||
InventoryInteraction* interaction;
|
||||
|
||||
std::vector<SlotView*> slots;
|
||||
|
||||
int scroll = 0;
|
||||
public:
|
||||
InventoryView(
|
||||
const Content* content,
|
||||
|
||||
@ -106,7 +106,7 @@ void WorldRenderer::drawChunks(Chunks* chunks,
|
||||
}
|
||||
float px = camera->position.x / (float)CHUNK_W;
|
||||
float pz = camera->position.z / (float)CHUNK_D;
|
||||
std::sort(indices.begin(), indices.end(), [this, chunks, px, pz](size_t i, size_t j) {
|
||||
std::sort(indices.begin(), indices.end(), [chunks, px, pz](size_t i, size_t j) {
|
||||
auto a = chunks->chunks[i];
|
||||
auto b = chunks->chunks[j];
|
||||
return ((a->x + 0.5f - px)*(a->x + 0.5f - px) +
|
||||
|
||||
@ -39,7 +39,7 @@ Skybox::Skybox(uint size, Shader* shader)
|
||||
-1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f,
|
||||
-1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f
|
||||
};
|
||||
vattr attrs[] {2, 0};
|
||||
vattr attrs[] {{2}, {0}};
|
||||
mesh = std::make_unique<Mesh>(vertices, 6, attrs);
|
||||
|
||||
sprites.push_back(skysprite {
|
||||
|
||||
@ -13,30 +13,23 @@
|
||||
#include "../../window/input.h"
|
||||
#include "../../window/Camera.h"
|
||||
|
||||
using glm::vec2;
|
||||
using glm::vec3;
|
||||
using std::string;
|
||||
using std::shared_ptr;
|
||||
using namespace gui;
|
||||
|
||||
GUI::GUI() {
|
||||
container = new Container(vec2(0, 0), vec2(1000));
|
||||
|
||||
uicamera = new Camera(vec3(), Window::height);
|
||||
container = std::make_shared<Container>(glm::vec2(0, 0), glm::vec2(1000));
|
||||
uicamera = std::make_unique<Camera>(glm::vec3(), Window::height);
|
||||
uicamera->perspective = false;
|
||||
uicamera->flipped = true;
|
||||
|
||||
menu = new PagesControl();
|
||||
menu = std::make_shared<PagesControl>();
|
||||
container->add(menu);
|
||||
container->scrollable(false);
|
||||
}
|
||||
|
||||
GUI::~GUI() {
|
||||
delete uicamera;
|
||||
delete container;
|
||||
}
|
||||
|
||||
PagesControl* GUI::getMenu() {
|
||||
std::shared_ptr<PagesControl> GUI::getMenu() {
|
||||
return menu;
|
||||
}
|
||||
|
||||
@ -85,7 +78,7 @@ void GUI::actMouse(float delta) {
|
||||
}
|
||||
|
||||
void GUI::act(float delta) {
|
||||
container->setSize(vec2(Window::width, Window::height));
|
||||
container->setSize(glm::vec2(Window::width, Window::height));
|
||||
container->act(delta);
|
||||
auto prevfocus = focus;
|
||||
|
||||
@ -132,7 +125,7 @@ void GUI::draw(const GfxContext* pctx, Assets* assets) {
|
||||
container->draw(pctx, assets);
|
||||
}
|
||||
|
||||
shared_ptr<UINode> GUI::getFocused() const {
|
||||
std::shared_ptr<UINode> GUI::getFocused() const {
|
||||
return focus;
|
||||
}
|
||||
|
||||
@ -144,19 +137,19 @@ void GUI::addBack(std::shared_ptr<UINode> panel) {
|
||||
container->addBack(panel);
|
||||
}
|
||||
|
||||
void GUI::add(shared_ptr<UINode> panel) {
|
||||
void GUI::add(std::shared_ptr<UINode> panel) {
|
||||
container->add(panel);
|
||||
}
|
||||
|
||||
void GUI::remove(shared_ptr<UINode> panel) {
|
||||
void GUI::remove(std::shared_ptr<UINode> panel) {
|
||||
container->remove(panel);
|
||||
}
|
||||
|
||||
void GUI::store(string name, shared_ptr<UINode> node) {
|
||||
void GUI::store(std::string name, std::shared_ptr<UINode> node) {
|
||||
storage[name] = node;
|
||||
}
|
||||
|
||||
shared_ptr<UINode> GUI::get(string name) {
|
||||
std::shared_ptr<UINode> GUI::get(std::string name) {
|
||||
auto found = storage.find(name);
|
||||
if (found == storage.end()) {
|
||||
return nullptr;
|
||||
@ -164,11 +157,11 @@ shared_ptr<UINode> GUI::get(string name) {
|
||||
return found->second;
|
||||
}
|
||||
|
||||
void GUI::remove(string name) {
|
||||
void GUI::remove(std::string name) {
|
||||
storage.erase(name);
|
||||
}
|
||||
|
||||
void GUI::setFocus(shared_ptr<UINode> node) {
|
||||
void GUI::setFocus(std::shared_ptr<UINode> node) {
|
||||
if (focus) {
|
||||
focus->defocus();
|
||||
}
|
||||
|
||||
@ -44,28 +44,25 @@ class Camera;
|
||||
*/
|
||||
|
||||
namespace gui {
|
||||
typedef std::function<void()> runnable;
|
||||
typedef std::function<void(const std::string&)> stringconsumer;
|
||||
|
||||
class UINode;
|
||||
class Container;
|
||||
class PagesControl;
|
||||
|
||||
class GUI {
|
||||
Container* container;
|
||||
std::shared_ptr<Container> container;
|
||||
std::shared_ptr<UINode> hover = nullptr;
|
||||
std::shared_ptr<UINode> pressed = nullptr;
|
||||
std::shared_ptr<UINode> focus = nullptr;
|
||||
std::unordered_map<std::string, std::shared_ptr<UINode>> storage;
|
||||
|
||||
Camera* uicamera;
|
||||
PagesControl* menu;
|
||||
std::unique_ptr<Camera> uicamera;
|
||||
std::shared_ptr<PagesControl> menu;
|
||||
void actMouse(float delta);
|
||||
public:
|
||||
GUI();
|
||||
~GUI();
|
||||
|
||||
PagesControl* getMenu();
|
||||
std::shared_ptr<PagesControl> getMenu();
|
||||
|
||||
std::shared_ptr<UINode> getFocused() const;
|
||||
bool isFocusCaught() const;
|
||||
|
||||
@ -88,6 +88,14 @@ void UINode::setInteractive(bool flag) {
|
||||
interactive = flag;
|
||||
}
|
||||
|
||||
void UINode::setResizing(bool flag) {
|
||||
resizing = flag;
|
||||
}
|
||||
|
||||
bool UINode::isResizing() const {
|
||||
return resizing;
|
||||
}
|
||||
|
||||
vec2 UINode::calcCoord() const {
|
||||
if (parent) {
|
||||
return coord + parent->calcCoord() + parent->contentOffset();
|
||||
@ -115,6 +123,15 @@ void UINode::setSize(vec2 size) {
|
||||
|
||||
void UINode::setColor(vec4 color) {
|
||||
this->color = color;
|
||||
this->hoverColor = color;
|
||||
}
|
||||
|
||||
void UINode::setHoverColor(glm::vec4 newColor) {
|
||||
this->hoverColor = newColor;
|
||||
}
|
||||
|
||||
glm::vec4 UINode::getHoverColor() const {
|
||||
return hoverColor;
|
||||
}
|
||||
|
||||
vec4 UINode::getColor() const {
|
||||
|
||||
@ -13,23 +13,26 @@ namespace gui {
|
||||
class UINode;
|
||||
class GUI;
|
||||
|
||||
typedef std::function<void(GUI*)> onaction;
|
||||
typedef std::function<void(GUI*, double)> onnumberchange;
|
||||
using onaction = std::function<void(GUI*)>;
|
||||
using onnumberchange = std::function<void(GUI*, double)>;
|
||||
|
||||
enum class Align {
|
||||
left, center, right
|
||||
};
|
||||
|
||||
class UINode {
|
||||
protected:
|
||||
glm::vec2 coord;
|
||||
glm::vec2 size;
|
||||
glm::vec4 color {1.0f};
|
||||
glm::vec4 hoverColor {1.0f};
|
||||
glm::vec4 margin {1.0f};
|
||||
bool visible = true;
|
||||
bool hover = false;
|
||||
bool pressed = false;
|
||||
bool focused = false;
|
||||
bool interactive = true;
|
||||
bool resizing = true;
|
||||
Align align = Align::left;
|
||||
UINode* parent = nullptr;
|
||||
UINode(glm::vec2 coord, glm::vec2 size);
|
||||
@ -50,9 +53,16 @@ namespace gui {
|
||||
virtual void setParent(UINode* node);
|
||||
UINode* getParent() const;
|
||||
|
||||
/* Set element color (doesn't affect inner elements).
|
||||
Also replaces hover color to avoid adding extra properties. */
|
||||
virtual void setColor(glm::vec4 newColor);
|
||||
|
||||
/* Get element color */
|
||||
glm::vec4 getColor() const;
|
||||
|
||||
virtual void setHoverColor(glm::vec4 newColor);
|
||||
glm::vec4 getHoverColor() const;
|
||||
|
||||
virtual void setMargin(glm::vec4 margin);
|
||||
glm::vec4 getMargin() const;
|
||||
|
||||
@ -66,18 +76,34 @@ namespace gui {
|
||||
bool isPressed() const;
|
||||
void defocus();
|
||||
bool isFocused() const;
|
||||
|
||||
/* Check if elements catches all user input when focused */
|
||||
virtual bool isFocuskeeper() const {return false;}
|
||||
|
||||
virtual void typed(unsigned int codepoint) {};
|
||||
virtual void keyPressed(int key) {};
|
||||
|
||||
/* Check if screen position is inside of the element
|
||||
@param pos screen position */
|
||||
virtual bool isInside(glm::vec2 pos);
|
||||
|
||||
/* Get element under the cursor.
|
||||
@param pos cursor screen position
|
||||
@param self shared pointer to element
|
||||
@return self, sub-element or nullptr if element is not interractive */
|
||||
virtual std::shared_ptr<UINode> getAt(glm::vec2 pos, std::shared_ptr<UINode> self);
|
||||
|
||||
/* Check if element is opaque for cursor */
|
||||
virtual bool isInteractive() const;
|
||||
/* Make the element opaque (true) or transparent (false) for cursor */
|
||||
virtual void setInteractive(bool flag);
|
||||
|
||||
virtual void setResizing(bool flag);
|
||||
virtual bool isResizing() const;
|
||||
|
||||
/* Get inner content offset. Used for scroll */
|
||||
virtual glm::vec2 contentOffset() {return glm::vec2(0.0f);};
|
||||
/* Calculate screen position of the element */
|
||||
virtual glm::vec2 calcCoord() const;
|
||||
virtual void setCoord(glm::vec2 coord);
|
||||
virtual glm::vec2 getSize() const;
|
||||
|
||||
@ -20,6 +20,7 @@ Label::Label(std::string text, std::string fontName)
|
||||
: UINode(vec2(), vec2(text.length() * 8, 15)),
|
||||
text(util::str2wstr_utf8(text)),
|
||||
fontName_(fontName) {
|
||||
setInteractive(false);
|
||||
}
|
||||
|
||||
|
||||
@ -27,6 +28,7 @@ Label::Label(std::wstring text, std::string fontName)
|
||||
: UINode(vec2(), vec2(text.length() * 8, 15)),
|
||||
text(text),
|
||||
fontName_(fontName) {
|
||||
setInteractive(false);
|
||||
}
|
||||
|
||||
void Label::setText(std::wstring text) {
|
||||
@ -46,12 +48,23 @@ void Label::draw(const GfxContext* pctx, Assets* assets) {
|
||||
batch->color = getColor();
|
||||
Font* font = assets->getFont(fontName_);
|
||||
vec2 size = getSize();
|
||||
vec2 newsize = vec2(font->calcWidth(text), font->lineHeight());
|
||||
if (newsize.x > size.x) {
|
||||
setSize(newsize);
|
||||
size = newsize;
|
||||
}
|
||||
vec2 newsize = vec2(
|
||||
font->calcWidth(text),
|
||||
font->getLineHeight()+font->getYOffset()
|
||||
);
|
||||
|
||||
vec2 coord = calcCoord();
|
||||
switch (align) {
|
||||
case Align::left:
|
||||
break;
|
||||
case Align::center:
|
||||
coord.x += (size.x-newsize.x)*0.5f;
|
||||
break;
|
||||
case Align::right:
|
||||
coord.x += size.x-newsize.x;
|
||||
break;
|
||||
}
|
||||
coord.y += (size.y-newsize.y)*0.5f;
|
||||
font->draw(batch, text, coord.x, coord.y);
|
||||
}
|
||||
|
||||
@ -60,10 +73,6 @@ Label* Label::textSupplier(wstringsupplier supplier) {
|
||||
return this;
|
||||
}
|
||||
|
||||
void Label::setSize(vec2 sizenew) {
|
||||
UINode::setSize(vec2(UINode::getSize().x, sizenew.y));
|
||||
}
|
||||
|
||||
// ================================= Image ====================================
|
||||
Image::Image(std::string texture, vec2 size) : UINode(vec2(), size), texture(texture) {
|
||||
setInteractive(false);
|
||||
@ -87,17 +96,34 @@ Button::Button(std::shared_ptr<UINode> content, glm::vec4 padding)
|
||||
padding[1]+padding[3]+margin[1]+margin[3]));
|
||||
add(content);
|
||||
scrollable(false);
|
||||
setHoverColor(glm::vec4(0.05f, 0.1f, 0.15f, 0.75f));
|
||||
}
|
||||
|
||||
Button::Button(std::wstring text, glm::vec4 padding, glm::vec4 margin)
|
||||
: Panel(vec2(32,32), padding, 0)
|
||||
Button::Button(
|
||||
std::wstring text,
|
||||
vec4 padding,
|
||||
onaction action,
|
||||
vec2 size
|
||||
) : Panel(size, padding, 0)
|
||||
{
|
||||
setMargin(margin);
|
||||
if (size.y < 0.0f) {
|
||||
size = vec2(
|
||||
glm::max(padding.x + padding.z + text.length()*8, size.x),
|
||||
glm::max(padding.y + padding.w + 16, size.y)
|
||||
);
|
||||
}
|
||||
setSize(size);
|
||||
|
||||
if (action) {
|
||||
listenAction(action);
|
||||
}
|
||||
scrollable(false);
|
||||
|
||||
label = std::make_shared<Label>(text);
|
||||
label->setAlign(Align::center);
|
||||
label->setSize(size-vec2(padding.z+padding.x, padding.w+padding.y));
|
||||
add(label);
|
||||
setHoverColor(glm::vec4(0.05f, 0.1f, 0.15f, 0.75f));
|
||||
}
|
||||
|
||||
void Button::setText(std::wstring text) {
|
||||
@ -120,8 +146,11 @@ Button* Button::textSupplier(wstringsupplier supplier) {
|
||||
return this;
|
||||
}
|
||||
|
||||
void Button::setHoverColor(glm::vec4 color) {
|
||||
hoverColor = color;
|
||||
void Button::refresh() {
|
||||
Panel::refresh();
|
||||
if (label) {
|
||||
label->setSize(size-vec2(padding.z+padding.x, padding.w+padding.y));
|
||||
}
|
||||
}
|
||||
|
||||
void Button::drawBackground(const GfxContext* pctx, Assets* assets) {
|
||||
@ -159,6 +188,7 @@ void Button::textAlign(Align align) {
|
||||
|
||||
// ============================== RichButton ==================================
|
||||
RichButton::RichButton(vec2 size) : Container(vec2(), size) {
|
||||
setHoverColor(glm::vec4(0.05f, 0.1f, 0.15f, 0.75f));
|
||||
}
|
||||
|
||||
void RichButton::mouseRelease(GUI* gui, int x, int y) {
|
||||
@ -175,10 +205,6 @@ RichButton* RichButton::listenAction(onaction action) {
|
||||
return this;
|
||||
}
|
||||
|
||||
void RichButton::setHoverColor(glm::vec4 color) {
|
||||
hoverColor = color;
|
||||
}
|
||||
|
||||
void RichButton::drawBackground(const GfxContext* pctx, Assets* assets) {
|
||||
vec2 coord = calcCoord();
|
||||
auto batch = pctx->getBatch2D();
|
||||
@ -189,11 +215,12 @@ void RichButton::drawBackground(const GfxContext* pctx, Assets* assets) {
|
||||
|
||||
// ================================ TextBox ===================================
|
||||
TextBox::TextBox(std::wstring placeholder, vec4 padding)
|
||||
: Panel(vec2(200,32), padding, 0, false),
|
||||
: Panel(vec2(200,32), padding, 0),
|
||||
input(L""),
|
||||
placeholder(placeholder) {
|
||||
label = std::make_shared<Label>(L"");
|
||||
add(label);
|
||||
setHoverColor(glm::vec4(0.05f, 0.1f, 0.2f, 0.75f));
|
||||
}
|
||||
|
||||
void TextBox::drawBackground(const GfxContext* pctx, Assets* assets) {
|
||||
@ -251,7 +278,7 @@ bool TextBox::isValid() const {
|
||||
return valid;
|
||||
}
|
||||
|
||||
void TextBox::setOnEditStart(gui::runnable oneditstart) {
|
||||
void TextBox::setOnEditStart(runnable oneditstart) {
|
||||
onEditStart = oneditstart;
|
||||
}
|
||||
|
||||
@ -312,9 +339,9 @@ void TextBox::text(std::wstring value) {
|
||||
|
||||
// ============================== InputBindBox ================================
|
||||
InputBindBox::InputBindBox(Binding& binding, vec4 padding)
|
||||
: Panel(vec2(100,32), padding, 0, false),
|
||||
: Panel(vec2(100,32), padding, 0),
|
||||
binding(binding) {
|
||||
label = new Label(L"");
|
||||
label = std::make_shared<Label>(L"");
|
||||
add(label);
|
||||
scrollable(false);
|
||||
}
|
||||
@ -437,7 +464,7 @@ FullCheckBox::FullCheckBox(std::wstring text, glm::vec2 size, bool checked)
|
||||
: Panel(size),
|
||||
checkbox(std::make_shared<CheckBox>(checked)){
|
||||
setColor(vec4(0.0f));
|
||||
orientation(Orientation::horizontal);
|
||||
setOrientation(Orientation::horizontal);
|
||||
|
||||
add(checkbox);
|
||||
|
||||
|
||||
@ -6,25 +6,27 @@
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include "GUI.h"
|
||||
#include "UINode.h"
|
||||
#include "panels.h"
|
||||
#include "../../window/input.h"
|
||||
#include "../../delegates.h"
|
||||
|
||||
class Batch2D;
|
||||
class Assets;
|
||||
|
||||
namespace gui {
|
||||
typedef std::function<std::wstring()> wstringsupplier;
|
||||
typedef std::function<void(std::wstring)> wstringconsumer;
|
||||
using wstringsupplier = std::function<std::wstring()>;
|
||||
using wstringconsumer = std::function<void(std::wstring)>;
|
||||
|
||||
typedef std::function<double()> doublesupplier;
|
||||
typedef std::function<void(double)> doubleconsumer;
|
||||
using doublesupplier = std::function<double()>;
|
||||
using doubleconsumer = std::function<void(double)>;
|
||||
|
||||
typedef std::function<bool()> boolsupplier;
|
||||
typedef std::function<void(bool)> boolconsumer;
|
||||
using boolsupplier = std::function<bool()>;
|
||||
using boolconsumer = std::function<void(bool)>;
|
||||
|
||||
typedef std::function<bool(const std::wstring&)> wstringchecker;
|
||||
using wstringchecker = std::function<bool(const std::wstring&)>;
|
||||
|
||||
class Label : public UINode {
|
||||
protected:
|
||||
@ -41,7 +43,6 @@ namespace gui {
|
||||
virtual void draw(const GfxContext* pctx, Assets* assets) override;
|
||||
|
||||
virtual Label* textSupplier(wstringsupplier supplier);
|
||||
virtual void setSize(glm::vec2 size) override;
|
||||
};
|
||||
|
||||
class Image : public UINode {
|
||||
@ -55,15 +56,17 @@ namespace gui {
|
||||
|
||||
class Button : public Panel {
|
||||
protected:
|
||||
glm::vec4 hoverColor {0.05f, 0.1f, 0.15f, 0.75f};
|
||||
glm::vec4 pressedColor {0.0f, 0.0f, 0.0f, 0.95f};
|
||||
std::vector<onaction> actions;
|
||||
std::shared_ptr<Label> label = nullptr;
|
||||
public:
|
||||
Button(std::shared_ptr<UINode> content, glm::vec4 padding=glm::vec4(2.0f));
|
||||
Button(std::shared_ptr<UINode> content,
|
||||
glm::vec4 padding=glm::vec4(2.0f));
|
||||
|
||||
Button(std::wstring text,
|
||||
glm::vec4 padding=glm::vec4(2.0f),
|
||||
glm::vec4 margin=glm::vec4(1.0f));
|
||||
glm::vec4 padding,
|
||||
onaction action,
|
||||
glm::vec2 size=glm::vec2(-1));
|
||||
|
||||
virtual void drawBackground(const GfxContext* pctx, Assets* assets) override;
|
||||
|
||||
@ -79,12 +82,11 @@ namespace gui {
|
||||
|
||||
virtual Button* textSupplier(wstringsupplier supplier);
|
||||
|
||||
virtual void setHoverColor(glm::vec4 color);
|
||||
virtual void refresh() override;
|
||||
};
|
||||
|
||||
class RichButton : public Container {
|
||||
protected:
|
||||
glm::vec4 hoverColor {0.05f, 0.1f, 0.15f, 0.75f};
|
||||
glm::vec4 pressedColor {0.0f, 0.0f, 0.0f, 0.95f};
|
||||
std::vector<onaction> actions;
|
||||
public:
|
||||
@ -94,13 +96,10 @@ namespace gui {
|
||||
|
||||
virtual void mouseRelease(GUI*, int x, int y) override;
|
||||
virtual RichButton* listenAction(onaction action);
|
||||
|
||||
virtual void setHoverColor(glm::vec4 color);
|
||||
};
|
||||
|
||||
class TextBox : public Panel {
|
||||
protected:
|
||||
glm::vec4 hoverColor {0.05f, 0.1f, 0.2f, 0.75f};
|
||||
glm::vec4 focusedColor {0.0f, 0.0f, 0.0f, 1.0f};
|
||||
glm::vec4 invalidColor {0.1f, 0.05f, 0.03f, 1.0f};
|
||||
std::shared_ptr<Label> label;
|
||||
@ -113,7 +112,7 @@ namespace gui {
|
||||
bool valid = true;
|
||||
public:
|
||||
TextBox(std::wstring placeholder,
|
||||
glm::vec4 padding=glm::vec4(2.0f));
|
||||
glm::vec4 padding=glm::vec4(4.0f));
|
||||
|
||||
virtual std::shared_ptr<UINode> getAt(glm::vec2 pos, std::shared_ptr<UINode> self) override;
|
||||
|
||||
@ -137,7 +136,7 @@ namespace gui {
|
||||
protected:
|
||||
glm::vec4 hoverColor {0.05f, 0.1f, 0.2f, 0.75f};
|
||||
glm::vec4 focusedColor {0.0f, 0.0f, 0.0f, 1.0f};
|
||||
Label* label;
|
||||
std::shared_ptr<Label> label;
|
||||
Binding& binding;
|
||||
public:
|
||||
InputBindBox(Binding& binding, glm::vec4 padding=glm::vec4(6.0f));
|
||||
|
||||
@ -5,30 +5,34 @@
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include "../locale/langs.h"
|
||||
#include "../../delegates.h"
|
||||
|
||||
using namespace gui;
|
||||
using glm::vec2;
|
||||
using glm::vec4;
|
||||
|
||||
Button* guiutil::backButton(PagesControl* menu) {
|
||||
return (new Button(langs::get(L"Back"), vec4(10.f)))->listenAction([=](GUI* gui) {
|
||||
menu->back();
|
||||
});
|
||||
std::shared_ptr<Button> guiutil::backButton(std::shared_ptr<PagesControl> menu) {
|
||||
return std::make_shared<Button>(
|
||||
langs::get(L"Back"), vec4(10.f), [=](GUI*) {
|
||||
menu->back();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
Button* guiutil::gotoButton(
|
||||
std::wstring text,
|
||||
const std::string& page,
|
||||
PagesControl* menu) {
|
||||
std::shared_ptr<Button> guiutil::gotoButton(
|
||||
std::wstring text,
|
||||
const std::string& page,
|
||||
std::shared_ptr<PagesControl> menu
|
||||
) {
|
||||
text = langs::get(text, L"menu");
|
||||
return (new Button(text, vec4(10.f)))->listenAction([=](GUI* gui) {
|
||||
menu->set(page);
|
||||
return std::make_shared<Button>(text, vec4(10.f), [=](GUI* gui) {
|
||||
menu->setPage(page);
|
||||
});
|
||||
}
|
||||
|
||||
void guiutil::alert(GUI* gui, const std::wstring& text, gui::runnable on_hidden) {
|
||||
PagesControl* menu = gui->getMenu();
|
||||
Panel* panel = new Panel(vec2(500, 200), vec4(8.0f), 8.0f);
|
||||
void guiutil::alert(GUI* gui, const std::wstring& text, runnable on_hidden) {
|
||||
auto menu = gui->getMenu();
|
||||
auto panel = std::make_shared<Panel>(vec2(500, 200), vec4(8.0f), 8.0f);
|
||||
panel->setColor(vec4(0.0f, 0.0f, 0.0f, 0.5f));
|
||||
|
||||
// TODO: implement built-in text wrapping
|
||||
@ -43,48 +47,55 @@ void guiutil::alert(GUI* gui, const std::wstring& text, gui::runnable on_hidden)
|
||||
}
|
||||
extra = std::min(extra, wrap_length);
|
||||
std::wstring part = text.substr(offset, extra);
|
||||
panel->add(new Label(part));
|
||||
panel->add(std::make_shared<Label>(part));
|
||||
offset += extra;
|
||||
}
|
||||
} else {
|
||||
panel->add(new Label(text));
|
||||
panel->add(std::make_shared<Label>(text));
|
||||
}
|
||||
panel->add((new Button(langs::get(L"Ok"), vec4(10.f)))->listenAction([=](GUI* gui) {
|
||||
if (on_hidden)
|
||||
on_hidden();
|
||||
menu->back();
|
||||
}));
|
||||
panel->add(std::make_shared<Button>(
|
||||
langs::get(L"Ok"), vec4(10.f),
|
||||
[=](GUI* gui) {
|
||||
if (on_hidden) {
|
||||
on_hidden();
|
||||
}
|
||||
menu->back();
|
||||
}
|
||||
));
|
||||
panel->refresh();
|
||||
menu->add("<alert>", panel);
|
||||
menu->set("<alert>");
|
||||
menu->addPage("<alert>", panel);
|
||||
menu->setPage("<alert>");
|
||||
}
|
||||
|
||||
void guiutil::confirm(
|
||||
GUI* gui,
|
||||
const std::wstring& text,
|
||||
gui::runnable on_confirm,
|
||||
runnable on_confirm,
|
||||
std::wstring yestext,
|
||||
std::wstring notext) {
|
||||
if (yestext.empty()) yestext = langs::get(L"Yes");
|
||||
if (notext.empty()) notext = langs::get(L"No");
|
||||
|
||||
PagesControl* menu = gui->getMenu();
|
||||
Panel* panel = new Panel(vec2(600, 200), vec4(8.0f), 8.0f);
|
||||
auto menu = gui->getMenu();
|
||||
auto panel = std::make_shared<Panel>(vec2(600, 200), vec4(8.0f), 8.0f);
|
||||
panel->setColor(vec4(0.0f, 0.0f, 0.0f, 0.5f));
|
||||
panel->add(new Label(text));
|
||||
Panel* subpanel = new Panel(vec2(600, 53));
|
||||
panel->add(std::make_shared<Label>(text));
|
||||
auto subpanel = std::make_shared<Panel>(vec2(600, 53));
|
||||
subpanel->setColor(vec4(0));
|
||||
subpanel->add((new Button(yestext, vec4(8.0f)))->listenAction([=](GUI*){
|
||||
|
||||
subpanel->add(std::make_shared<Button>(yestext, vec4(8.f), [=](GUI*){
|
||||
if (on_confirm)
|
||||
on_confirm();
|
||||
menu->back();
|
||||
}));
|
||||
subpanel->add((new Button(notext, vec4(8.0f)))->listenAction([=](GUI*){
|
||||
|
||||
subpanel->add(std::make_shared<Button>(notext, vec4(8.f), [=](GUI*){
|
||||
menu->back();
|
||||
}));
|
||||
|
||||
panel->add(subpanel);
|
||||
|
||||
panel->refresh();
|
||||
menu->add("<confirm>", panel);
|
||||
menu->set("<confirm>");
|
||||
menu->addPage("<confirm>", panel);
|
||||
menu->setPage("<confirm>");
|
||||
}
|
||||
|
||||
@ -1,19 +1,38 @@
|
||||
#ifndef FRONTEND_GUI_GUI_UTIL_H_
|
||||
#define FRONTEND_GUI_GUI_UTIL_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include "GUI.h"
|
||||
#include "../../delegates.h"
|
||||
|
||||
namespace gui {
|
||||
class Button;
|
||||
}
|
||||
|
||||
namespace guiutil {
|
||||
gui::Button* backButton(gui::PagesControl* menu);
|
||||
gui::Button* gotoButton(std::wstring text, const std::string& page, gui::PagesControl* menu);
|
||||
void alert(gui::GUI* gui, const std::wstring& text, gui::runnable on_hidden=nullptr);
|
||||
void confirm(gui::GUI* gui, const std::wstring& text, gui::runnable on_confirm=nullptr,
|
||||
std::wstring yestext=L"", std::wstring notext=L"");
|
||||
std::shared_ptr<gui::Button> backButton(
|
||||
std::shared_ptr<gui::PagesControl> menu
|
||||
);
|
||||
|
||||
std::shared_ptr<gui::Button> gotoButton(
|
||||
std::wstring text,
|
||||
const std::string& page,
|
||||
std::shared_ptr<gui::PagesControl> menu
|
||||
);
|
||||
|
||||
void alert(
|
||||
gui::GUI* gui,
|
||||
const std::wstring& text,
|
||||
runnable on_hidden=nullptr
|
||||
);
|
||||
|
||||
void confirm(
|
||||
gui::GUI* gui,
|
||||
const std::wstring& text,
|
||||
runnable on_confirm=nullptr,
|
||||
std::wstring yestext=L"",
|
||||
std::wstring notext=L"");
|
||||
}
|
||||
|
||||
#endif // FRONTEND_GUI_GUI_UTIL_H_
|
||||
|
||||
@ -14,6 +14,7 @@ using glm::vec4;
|
||||
|
||||
Container::Container(vec2 coord, vec2 size) : UINode(coord, size) {
|
||||
actualLength = size.y;
|
||||
setColor(glm::vec4());
|
||||
}
|
||||
|
||||
std::shared_ptr<UINode> Container::getAt(vec2 pos, std::shared_ptr<UINode> self) {
|
||||
@ -96,6 +97,17 @@ void Container::draw(const GfxContext* pctx, Assets* assets) {
|
||||
}
|
||||
}
|
||||
|
||||
void Container::drawBackground(const GfxContext* pctx, Assets* assets) {
|
||||
if (color.a <= 0.0f)
|
||||
return;
|
||||
vec2 coord = calcCoord();
|
||||
|
||||
auto batch = pctx->getBatch2D();
|
||||
batch->texture(nullptr);
|
||||
batch->color = color;
|
||||
batch->rect(coord.x, coord.y, size.x, size.y);
|
||||
}
|
||||
|
||||
void Container::addBack(std::shared_ptr<UINode> node) {
|
||||
nodes.insert(nodes.begin(), node);
|
||||
node->setParent(this);
|
||||
@ -108,10 +120,6 @@ void Container::add(std::shared_ptr<UINode> node) {
|
||||
refresh();
|
||||
}
|
||||
|
||||
void Container::add(UINode* node) {
|
||||
add(std::shared_ptr<UINode>(node));
|
||||
}
|
||||
|
||||
void Container::add(std::shared_ptr<UINode> node, glm::vec2 coord) {
|
||||
node->setCoord(coord);
|
||||
add(node);
|
||||
@ -131,71 +139,74 @@ void Container::listenInterval(float interval, ontimeout callback, int repeat) {
|
||||
intervalEvents.push_back({callback, interval, 0.0f, repeat});
|
||||
}
|
||||
|
||||
Panel::Panel(vec2 size, glm::vec4 padding, float interval, bool resizing)
|
||||
void Container::setSize(glm::vec2 size) {
|
||||
UINode::setSize(size);
|
||||
refresh();
|
||||
}
|
||||
|
||||
Panel::Panel(vec2 size, glm::vec4 padding, float interval)
|
||||
: Container(vec2(), size),
|
||||
padding(padding),
|
||||
interval(interval),
|
||||
resizing_(resizing) {
|
||||
interval(interval) {
|
||||
setColor(vec4(0.0f, 0.0f, 0.0f, 0.75f));
|
||||
}
|
||||
|
||||
Panel::~Panel() {
|
||||
}
|
||||
|
||||
void Panel::drawBackground(const GfxContext* pctx, Assets* assets) {
|
||||
vec2 coord = calcCoord();
|
||||
|
||||
auto batch = pctx->getBatch2D();
|
||||
batch->texture(nullptr);
|
||||
batch->color = color;
|
||||
batch->rect(coord.x, coord.y, size.x, size.y);
|
||||
void Panel::setMaxLength(int value) {
|
||||
maxLength = value;
|
||||
}
|
||||
|
||||
void Panel::maxLength(int value) {
|
||||
maxLength_ = value;
|
||||
int Panel::getMaxLength() const {
|
||||
return maxLength;
|
||||
}
|
||||
|
||||
int Panel::maxLength() const {
|
||||
return maxLength_;
|
||||
void Panel::setPadding(glm::vec4 padding) {
|
||||
this->padding = padding;
|
||||
refresh();
|
||||
}
|
||||
|
||||
glm::vec4 Panel::getPadding() const {
|
||||
return padding;
|
||||
}
|
||||
|
||||
void Panel::cropToContent() {
|
||||
if (maxLength > 0.0f) {
|
||||
setSize(vec2(getSize().x, glm::min(maxLength, actualLength)));
|
||||
} else {
|
||||
setSize(vec2(getSize().x, actualLength));
|
||||
}
|
||||
}
|
||||
|
||||
void Panel::add(std::shared_ptr<UINode> node) {
|
||||
Container::add(node);
|
||||
refresh();
|
||||
cropToContent();
|
||||
}
|
||||
|
||||
void Panel::refresh() {
|
||||
float x = padding.x;
|
||||
float y = padding.y;
|
||||
vec2 size = getSize();
|
||||
if (orientation_ == Orientation::vertical) {
|
||||
if (orientation == Orientation::vertical) {
|
||||
float maxw = size.x;
|
||||
for (auto& node : nodes) {
|
||||
vec2 nodesize = node->getSize();
|
||||
const vec4 margin = node->getMargin();
|
||||
y += margin.y;
|
||||
|
||||
float ex;
|
||||
float spacex = size.x - margin.z - padding.z;
|
||||
switch (node->getAlign()) {
|
||||
case Align::center:
|
||||
ex = x + fmax(0.0f, spacex - nodesize.x) / 2.0f;
|
||||
break;
|
||||
case Align::right:
|
||||
ex = x + spacex - nodesize.x;
|
||||
break;
|
||||
default:
|
||||
ex = x + margin.x;
|
||||
}
|
||||
float ex = x + margin.x;
|
||||
node->setCoord(vec2(ex, y));
|
||||
y += nodesize.y + margin.w + interval;
|
||||
|
||||
float width = size.x - padding.x - padding.z - margin.x - margin.z;
|
||||
node->setSize(vec2(width, nodesize.y));;
|
||||
if (node->isResizing()) {
|
||||
node->setSize(vec2(width, nodesize.y));
|
||||
}
|
||||
node->refresh();
|
||||
maxw = fmax(maxw, ex+node->getSize().x+margin.z+padding.z);
|
||||
}
|
||||
if (resizing_) {
|
||||
if (maxLength_)
|
||||
setSize(vec2(size.x, glm::min(maxLength_, (int)(y+padding.w))));
|
||||
else
|
||||
setSize(vec2(size.x, y+padding.w));
|
||||
}
|
||||
actualLength = y + padding.w;
|
||||
} else {
|
||||
float maxh = size.y;
|
||||
@ -206,27 +217,19 @@ void Panel::refresh() {
|
||||
node->setCoord(vec2(x, y+margin.y));
|
||||
x += nodesize.x + margin.z + interval;
|
||||
|
||||
float height = size.y - padding.y - padding.w - margin.y - margin.w;
|
||||
node->setSize(vec2(nodesize.x, height));
|
||||
node->refresh();
|
||||
maxh = fmax(maxh, y+margin.y+node->getSize().y+margin.w+padding.w);
|
||||
}
|
||||
if (resizing_) {
|
||||
if (maxLength_)
|
||||
setSize(vec2(glm::min(maxLength_, (int)(x+padding.z)), size.y));
|
||||
else
|
||||
setSize(vec2(x+padding.z, size.y));
|
||||
}
|
||||
actualLength = size.y;
|
||||
}
|
||||
}
|
||||
|
||||
void Panel::orientation(Orientation orientation) {
|
||||
this->orientation_ = orientation;
|
||||
void Panel::setOrientation(Orientation orientation) {
|
||||
this->orientation = orientation;
|
||||
}
|
||||
|
||||
Orientation Panel::orientation() const {
|
||||
return orientation_;
|
||||
Orientation Panel::getOrientation() const {
|
||||
return orientation;
|
||||
}
|
||||
|
||||
PagesControl::PagesControl() : Container(vec2(), vec2(1)){
|
||||
@ -236,15 +239,11 @@ bool PagesControl::has(std::string name) {
|
||||
return pages.find(name) != pages.end();
|
||||
}
|
||||
|
||||
void PagesControl::add(std::string name, std::shared_ptr<UINode> panel) {
|
||||
void PagesControl::addPage(std::string name, std::shared_ptr<UINode> panel) {
|
||||
pages[name] = Page{panel};
|
||||
}
|
||||
|
||||
void PagesControl::add(std::string name, UINode* panel) {
|
||||
add(name, std::shared_ptr<UINode>(panel));
|
||||
}
|
||||
|
||||
void PagesControl::set(std::string name, bool history) {
|
||||
void PagesControl::setPage(std::string name, bool history) {
|
||||
auto found = pages.find(name);
|
||||
if (found == pages.end()) {
|
||||
throw std::runtime_error("no page found");
|
||||
@ -266,7 +265,7 @@ void PagesControl::back() {
|
||||
return;
|
||||
std::string name = pageStack.top();
|
||||
pageStack.pop();
|
||||
set(name, false);
|
||||
setPage(name, false);
|
||||
}
|
||||
|
||||
Page& PagesControl::current() {
|
||||
|
||||
@ -12,7 +12,8 @@ class Batch2D;
|
||||
class Assets;
|
||||
|
||||
namespace gui {
|
||||
typedef std::function<void()> ontimeout;
|
||||
using ontimeout = std::function<void()>;
|
||||
|
||||
struct IntervalEvent {
|
||||
ontimeout callback;
|
||||
float interval;
|
||||
@ -34,40 +35,48 @@ namespace gui {
|
||||
Container(glm::vec2 coord, glm::vec2 size);
|
||||
|
||||
virtual void act(float delta) override;
|
||||
virtual void drawBackground(const GfxContext* pctx, Assets* assets) {};
|
||||
virtual void drawBackground(const GfxContext* pctx, Assets* assets);
|
||||
virtual void draw(const GfxContext* pctx, Assets* assets) override;
|
||||
virtual std::shared_ptr<UINode> getAt(glm::vec2 pos, std::shared_ptr<UINode> self) override;
|
||||
virtual void addBack(std::shared_ptr<UINode> node);
|
||||
virtual void add(std::shared_ptr<UINode> node);
|
||||
virtual void add(UINode* node);
|
||||
virtual void add(std::shared_ptr<UINode> node, glm::vec2 coord);
|
||||
virtual void remove(std::shared_ptr<UINode> node);
|
||||
virtual void scrolled(int value) override;
|
||||
virtual void scrollable(bool flag);
|
||||
void listenInterval(float interval, ontimeout callback, int repeat=-1);
|
||||
virtual glm::vec2 contentOffset() override {return glm::vec2(0.0f, scroll);};
|
||||
virtual void setSize(glm::vec2 size);
|
||||
};
|
||||
|
||||
class Panel : public Container {
|
||||
protected:
|
||||
Orientation orientation_ = Orientation::vertical;
|
||||
Orientation orientation = Orientation::vertical;
|
||||
glm::vec4 padding {2.0f};
|
||||
float interval = 2.0f;
|
||||
bool resizing_;
|
||||
int maxLength_ = 0;
|
||||
int maxLength = 0;
|
||||
public:
|
||||
Panel(glm::vec2 size, glm::vec4 padding=glm::vec4(2.0f), float interval=2.0f, bool resizing=true);
|
||||
Panel(
|
||||
glm::vec2 size,
|
||||
glm::vec4 padding=glm::vec4(2.0f),
|
||||
float interval=2.0f
|
||||
);
|
||||
virtual ~Panel();
|
||||
|
||||
virtual void drawBackground(const GfxContext* pctx, Assets* assets) override;
|
||||
virtual void cropToContent();
|
||||
|
||||
virtual void orientation(Orientation orientation);
|
||||
Orientation orientation() const;
|
||||
virtual void setOrientation(Orientation orientation);
|
||||
Orientation getOrientation() const;
|
||||
|
||||
virtual void add(std::shared_ptr<UINode> node) override;
|
||||
|
||||
virtual void refresh() override;
|
||||
|
||||
virtual void maxLength(int value);
|
||||
int maxLength() const;
|
||||
virtual void setMaxLength(int value);
|
||||
int getMaxLength() const;
|
||||
|
||||
virtual void setPadding(glm::vec4 padding);
|
||||
glm::vec4 getPadding() const;
|
||||
};
|
||||
|
||||
struct Page {
|
||||
@ -88,9 +97,8 @@ namespace gui {
|
||||
PagesControl();
|
||||
|
||||
bool has(std::string name);
|
||||
void set(std::string name, bool history=true);
|
||||
void add(std::string name, std::shared_ptr<UINode> panel);
|
||||
void add(std::string name, UINode* panel);
|
||||
void setPage(std::string name, bool history=true);
|
||||
void addPage(std::string name, std::shared_ptr<UINode> panel);
|
||||
void back();
|
||||
void clearHistory();
|
||||
void reset();
|
||||
|
||||
@ -60,7 +60,7 @@ static std::shared_ptr<Label> create_label(gui::wstringsupplier supplier) {
|
||||
std::shared_ptr<UINode> HudRenderer::createDebugPanel(Engine* engine) {
|
||||
auto level = frontend->getLevel();
|
||||
|
||||
auto panel = std::make_shared<Panel>(vec2(250, 200), vec4(5.0f), 1.0f);
|
||||
auto panel = std::make_shared<Panel>(vec2(250, 200), vec4(5.0f), 2.0f);
|
||||
panel->listenInterval(0.5f, [this]() {
|
||||
fpsString = std::to_wstring(fpsMax)+L" / "+std::to_wstring(fpsMin);
|
||||
fpsMin = fps;
|
||||
@ -68,7 +68,7 @@ std::shared_ptr<UINode> HudRenderer::createDebugPanel(Engine* engine) {
|
||||
});
|
||||
panel->setCoord(vec2(10, 10));
|
||||
panel->add(create_label([this](){ return L"fps: "+this->fpsString;}));
|
||||
panel->add(create_label([this](){
|
||||
panel->add(create_label([](){
|
||||
return L"meshes: " + std::to_wstring(Mesh::meshesCount);
|
||||
}));
|
||||
panel->add(create_label([=](){
|
||||
@ -97,18 +97,18 @@ std::shared_ptr<UINode> HudRenderer::createDebugPanel(Engine* engine) {
|
||||
}));
|
||||
|
||||
for (int ax = 0; ax < 3; ax++){
|
||||
Panel* sub = new Panel(vec2(10, 27), vec4(0.0f));
|
||||
sub->orientation(Orientation::horizontal);
|
||||
auto sub = std::make_shared<Panel>(vec2(10, 27), vec4(0.0f));
|
||||
sub->setOrientation(Orientation::horizontal);
|
||||
|
||||
std::wstring str = L"x: ";
|
||||
str[0] += ax;
|
||||
Label* label = new Label(str);
|
||||
auto label = std::make_shared<Label>(str);
|
||||
label->setMargin(vec4(2, 3, 2, 3));
|
||||
sub->add(label);
|
||||
sub->setColor(vec4(0.0f));
|
||||
|
||||
// Coord input
|
||||
TextBox* box = new TextBox(L"");
|
||||
auto box = std::make_shared<TextBox>(L"");
|
||||
box->textSupplier([=]() {
|
||||
Hitbox* hitbox = level->player->hitbox.get();
|
||||
return util::to_wstring(hitbox->position[ax], 2);
|
||||
@ -139,19 +139,21 @@ std::shared_ptr<UINode> HudRenderer::createDebugPanel(Engine* engine) {
|
||||
return L"time: "+timeString;
|
||||
}));
|
||||
{
|
||||
TrackBar* bar = new TrackBar(0.0f, 1.0f, 1.0f, 0.005f, 8);
|
||||
auto bar = std::make_shared<TrackBar>(0.0f, 1.0f, 1.0f, 0.005f, 8);
|
||||
bar->supplier([=]() {return level->world->daytime;});
|
||||
bar->consumer([=](double val) {level->world->daytime = val;});
|
||||
panel->add(bar);
|
||||
}
|
||||
{
|
||||
TrackBar* bar = new TrackBar(0.0f, 1.0f, 0.0f, 0.005f, 8);
|
||||
auto bar = std::make_shared<TrackBar>(0.0f, 1.0f, 0.0f, 0.005f, 8);
|
||||
bar->supplier([=]() {return WorldRenderer::fog;});
|
||||
bar->consumer([=](double val) {WorldRenderer::fog = val;});
|
||||
panel->add(bar);
|
||||
}
|
||||
{
|
||||
auto checkbox = new FullCheckBox(L"Show Chunk Borders", vec2(400, 32));
|
||||
auto checkbox = std::make_shared<FullCheckBox>(
|
||||
L"Show Chunk Borders", vec2(400, 24)
|
||||
);
|
||||
checkbox->supplier([=]() {
|
||||
return engine->getSettings().debug.showChunkBorders;
|
||||
});
|
||||
@ -334,7 +336,7 @@ void HudRenderer::update(bool visible) {
|
||||
closeInventory();
|
||||
} else {
|
||||
pause = true;
|
||||
menu->set("pause");
|
||||
menu->setPage("pause");
|
||||
}
|
||||
}
|
||||
if (visible && Events::jactive(BIND_HUD_INVENTORY)) {
|
||||
|
||||
@ -37,6 +37,8 @@ using glm::vec4;
|
||||
namespace fs = std::filesystem;
|
||||
using namespace gui;
|
||||
|
||||
const int PACKS_PANEL_WIDTH = 550;
|
||||
|
||||
inline uint64_t randU64() {
|
||||
srand(time(NULL));
|
||||
return rand() ^ (rand() << 8) ^
|
||||
@ -46,74 +48,87 @@ inline uint64_t randU64() {
|
||||
((uint64_t)rand() << 56);
|
||||
}
|
||||
|
||||
std::shared_ptr<Panel> create_page(
|
||||
Engine* engine,
|
||||
std::string name,
|
||||
int width,
|
||||
float opacity,
|
||||
int interval) {
|
||||
PagesControl* menu = engine->getGUI()->getMenu();
|
||||
static std::shared_ptr<Label> create_label(gui::wstringsupplier supplier) {
|
||||
auto label = std::make_shared<Label>(L"-");
|
||||
label->textSupplier(supplier);
|
||||
return label;
|
||||
}
|
||||
|
||||
static std::shared_ptr<Panel> create_page(
|
||||
Engine* engine,
|
||||
std::string name,
|
||||
int width,
|
||||
float opacity,
|
||||
int interval
|
||||
) {
|
||||
auto menu = engine->getGUI()->getMenu();
|
||||
auto panel = std::make_shared<Panel>(
|
||||
vec2(width, 200), vec4(8.0f), interval
|
||||
);
|
||||
panel->setColor(vec4(0.0f, 0.0f, 0.0f, opacity));
|
||||
menu->add(name, panel);
|
||||
menu->addPage(name, panel);
|
||||
return panel;
|
||||
}
|
||||
|
||||
Button* create_button(std::wstring text,
|
||||
glm::vec4 padding,
|
||||
glm::vec4 margin,
|
||||
gui::onaction action) {
|
||||
|
||||
auto btn = new Button(langs::get(text, L"menu"),
|
||||
padding, margin);
|
||||
btn->listenAction(action);
|
||||
static std::shared_ptr<Button> create_button(
|
||||
std::wstring text,
|
||||
vec4 padding,
|
||||
vec4 margin,
|
||||
gui::onaction action
|
||||
) {
|
||||
auto btn = std::make_shared<Button>(
|
||||
langs::get(text, L"menu"), padding, action
|
||||
);
|
||||
btn->setMargin(margin);
|
||||
return btn;
|
||||
}
|
||||
|
||||
void show_content_missing(Engine* engine, const Content* content,
|
||||
std::shared_ptr<ContentLUT> lut) {
|
||||
static void show_content_missing(
|
||||
Engine* engine,
|
||||
const Content* content,
|
||||
std::shared_ptr<ContentLUT> lut
|
||||
) {
|
||||
auto* gui = engine->getGUI();
|
||||
auto* menu = gui->getMenu();
|
||||
auto menu = gui->getMenu();
|
||||
auto panel = create_page(engine, "missing-content", 500, 0.5f, 8);
|
||||
|
||||
panel->add(new Label(langs::get(L"menu.missing-content")));
|
||||
panel->add(std::make_shared<Label>(langs::get(L"menu.missing-content")));
|
||||
|
||||
Panel* subpanel = new Panel(vec2(500, 100));
|
||||
auto subpanel = std::make_shared<Panel>(vec2(500, 100));
|
||||
subpanel->setColor(vec4(0.0f, 0.0f, 0.0f, 0.5f));
|
||||
|
||||
for (auto& entry : lut->getMissingContent()) {
|
||||
Panel* hpanel = new Panel(vec2(500, 30));
|
||||
auto hpanel = std::make_shared<Panel>(vec2(500, 30));
|
||||
hpanel->setColor(vec4(0.0f));
|
||||
hpanel->orientation(Orientation::horizontal);
|
||||
hpanel->setOrientation(Orientation::horizontal);
|
||||
|
||||
Label* namelabel = new Label(util::str2wstr_utf8(entry.name));
|
||||
auto namelabel = std::make_shared<Label>(util::str2wstr_utf8(entry.name));
|
||||
namelabel->setColor(vec4(1.0f, 0.2f, 0.2f, 0.5f));
|
||||
|
||||
auto contentname = util::str2wstr_utf8(contenttype_name(entry.type));
|
||||
Label* typelabel = new Label(L"["+contentname+L"]");
|
||||
auto typelabel = std::make_shared<Label>(L"["+contentname+L"]");
|
||||
typelabel->setColor(vec4(0.5f));
|
||||
hpanel->add(typelabel);
|
||||
hpanel->add(namelabel);
|
||||
subpanel->add(hpanel);
|
||||
}
|
||||
subpanel->maxLength(400);
|
||||
subpanel->setMaxLength(400);
|
||||
panel->add(subpanel);
|
||||
|
||||
panel->add((new Button(langs::get(L"Back to Main Menu", L"menu"),
|
||||
vec4(8.0f)))
|
||||
->listenAction([=](GUI*){
|
||||
menu->back();
|
||||
}));
|
||||
menu->set("missing-content");
|
||||
panel->add(std::make_shared<Button>(
|
||||
langs::get(L"Back to Main Menu", L"menu"), vec4(8.0f), [=](GUI*){
|
||||
menu->back();
|
||||
}
|
||||
));
|
||||
menu->setPage("missing-content");
|
||||
}
|
||||
|
||||
void show_convert_request(
|
||||
Engine* engine,
|
||||
const Content* content,
|
||||
std::shared_ptr<ContentLUT> lut,
|
||||
fs::path folder) {
|
||||
fs::path folder
|
||||
) {
|
||||
guiutil::confirm(engine->getGUI(), langs::get(L"world.convert-request"),
|
||||
[=]() {
|
||||
// TODO: add multithreading here
|
||||
@ -125,7 +140,8 @@ void show_convert_request(
|
||||
}, L"", langs::get(L"Cancel"));
|
||||
}
|
||||
|
||||
void create_languages_panel(Engine* engine, PagesControl* menu) {
|
||||
void create_languages_panel(Engine* engine) {
|
||||
auto menu = engine->getGUI()->getMenu();
|
||||
auto panel = create_page(engine, "languages", 400, 0.5f, 1);
|
||||
panel->scrollable(true);
|
||||
|
||||
@ -138,11 +154,14 @@ void create_languages_panel(Engine* engine, PagesControl* menu) {
|
||||
auto& locale = langs::locales_info.at(name);
|
||||
std::string& fullName = locale.name;
|
||||
|
||||
Button* button = new Button(util::str2wstr_utf8(fullName), vec4(10.f));
|
||||
button->listenAction([=](GUI*) {
|
||||
engine->setLanguage(name);
|
||||
menu->back();
|
||||
});
|
||||
auto button = std::make_shared<Button>(
|
||||
util::str2wstr_utf8(fullName),
|
||||
vec4(10.f),
|
||||
[=](GUI*) {
|
||||
engine->setLanguage(name);
|
||||
menu->back();
|
||||
}
|
||||
);
|
||||
panel->add(button);
|
||||
}
|
||||
panel->add(guiutil::backButton(menu));
|
||||
@ -191,10 +210,10 @@ void open_world(std::string name, Engine* engine) {
|
||||
}
|
||||
}
|
||||
|
||||
Panel* create_worlds_panel(Engine* engine) {
|
||||
auto panel = new Panel(vec2(390, 200), vec4(5.0f));
|
||||
std::shared_ptr<Panel> create_worlds_panel(Engine* engine) {
|
||||
auto panel = std::make_shared<Panel>(vec2(390, 200), vec4(5.0f));
|
||||
panel->setColor(vec4(1.0f, 1.0f, 1.0f, 0.07f));
|
||||
panel->maxLength(400);
|
||||
panel->setMaxLength(400);
|
||||
|
||||
auto paths = engine->getPaths();
|
||||
|
||||
@ -205,13 +224,10 @@ Panel* create_worlds_panel(Engine* engine) {
|
||||
auto btn = std::make_shared<RichButton>(vec2(390, 46));
|
||||
btn->setColor(vec4(1.0f, 1.0f, 1.0f, 0.1f));
|
||||
btn->setHoverColor(vec4(1.0f, 1.0f, 1.0f, 0.17f));
|
||||
|
||||
auto label = std::make_shared<Label>(namews);
|
||||
label->setInteractive(false);
|
||||
btn->add(label, vec2(8, 8));
|
||||
btn->listenAction([=](GUI*) {
|
||||
open_world(name, engine);
|
||||
});
|
||||
btn->add(std::make_shared<Label>(namews), vec2(8, 8));
|
||||
|
||||
auto image = std::make_shared<Image>("gui/delete_icon", vec2(32, 32));
|
||||
image->setColor(vec4(1, 1, 1, 0.5f));
|
||||
@ -219,49 +235,49 @@ Panel* create_worlds_panel(Engine* engine) {
|
||||
auto delbtn = std::make_shared<Button>(image, vec4(2));
|
||||
delbtn->setColor(vec4(0.0f));
|
||||
delbtn->setHoverColor(vec4(1.0f, 1.0f, 1.0f, 0.17f));
|
||||
|
||||
btn->add(delbtn, vec2(330, 3));
|
||||
|
||||
delbtn->listenAction([=](GUI* gui) {
|
||||
guiutil::confirm(gui, langs::get(L"delete-confirm", L"world")+
|
||||
L" ("+util::str2wstr_utf8(folder.u8string())+L")", [=]()
|
||||
{
|
||||
std::cout << "deleting " << folder.u8string() << std::endl;
|
||||
fs::remove_all(folder);
|
||||
menus::refresh_menus(engine, gui->getMenu());
|
||||
menus::refresh_menus(engine);
|
||||
});
|
||||
});
|
||||
btn->add(delbtn, vec2(330, 3));
|
||||
|
||||
panel->add(btn);
|
||||
}
|
||||
return panel;
|
||||
}
|
||||
|
||||
void create_main_menu_panel(Engine* engine, PagesControl* menu) {
|
||||
void create_main_menu_panel(Engine* engine) {
|
||||
auto menu = engine->getGUI()->getMenu();
|
||||
|
||||
auto panel = create_page(engine, "main", 400, 0.0f, 1);
|
||||
panel->add(guiutil::gotoButton(L"New World", "new-world", menu));
|
||||
panel->add(create_worlds_panel(engine));
|
||||
panel->add(guiutil::gotoButton(L"Settings", "settings", menu));
|
||||
panel->add((new Button(langs::get(L"Quit", L"menu"), vec4(10.f)))
|
||||
->listenAction([](GUI* gui) {
|
||||
Window::setShouldClose(true);
|
||||
}));
|
||||
|
||||
panel->add(std::make_shared<Button>(
|
||||
langs::get(L"Quit", L"menu"), vec4(10.f), [](GUI*) {
|
||||
Window::setShouldClose(true);
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
typedef std::function<void(const ContentPack& pack)> packconsumer;
|
||||
|
||||
const int PACKS_PANEL_WIDTH = 550;
|
||||
|
||||
std::shared_ptr<Panel> create_packs_panel(
|
||||
const std::vector<ContentPack>& packs,
|
||||
Engine* engine,
|
||||
bool backbutton,
|
||||
packconsumer callback)
|
||||
{
|
||||
packconsumer callback
|
||||
){
|
||||
auto assets = engine->getAssets();
|
||||
auto panel = std::make_shared<Panel>(vec2(PACKS_PANEL_WIDTH, 200), vec4(5.0f));
|
||||
panel->setColor(vec4(1.0f, 1.0f, 1.0f, 0.07f));
|
||||
panel->maxLength(400);
|
||||
panel->setMaxLength(400);
|
||||
panel->scrollable(true);
|
||||
|
||||
for (auto& pack : packs) {
|
||||
@ -298,7 +314,7 @@ std::shared_ptr<Panel> create_packs_panel(
|
||||
descriptionlabel->setColor(vec4(1, 1, 1, 0.7f));
|
||||
packpanel->add(descriptionlabel, vec2(80, 28));
|
||||
|
||||
packpanel->add(std::make_shared<Image>(icon, glm::vec2(64)), vec2(8));
|
||||
packpanel->add(std::make_shared<Image>(icon, vec2(64)), vec2(8));
|
||||
|
||||
packpanel->setColor(vec4(0.06f, 0.12f, 0.18f, 0.7f));
|
||||
panel->add(packpanel);
|
||||
@ -310,7 +326,8 @@ std::shared_ptr<Panel> create_packs_panel(
|
||||
}
|
||||
|
||||
// TODO: refactor
|
||||
void create_content_panel(Engine* engine, PagesControl* menu) {
|
||||
void create_content_panel(Engine* engine) {
|
||||
auto menu = engine->getGUI()->getMenu();
|
||||
auto paths = engine->getPaths();
|
||||
auto mainPanel = create_page(engine, "content", PACKS_PANEL_WIDTH, 0.0f, 5);
|
||||
|
||||
@ -355,8 +372,8 @@ void create_content_panel(Engine* engine, PagesControl* menu) {
|
||||
engine->setScreen(std::make_shared<MenuScreen>(engine));
|
||||
open_world(wname, engine);
|
||||
});
|
||||
menu->add("content-packs", panel);
|
||||
menu->set("content-packs");
|
||||
menu->addPage("content-packs", panel);
|
||||
menu->setPage("content-packs");
|
||||
}));
|
||||
mainPanel->add(guiutil::backButton(menu));
|
||||
}
|
||||
@ -375,7 +392,7 @@ inline uint64_t str2seed(std::wstring seedstr) {
|
||||
}
|
||||
}
|
||||
|
||||
void create_new_world_panel(Engine* engine, PagesControl* menu) {
|
||||
void create_new_world_panel(Engine* engine) {
|
||||
auto panel = create_page(engine, "new-world", 400, 0.0f, 1);
|
||||
|
||||
panel->add(std::make_shared<Label>(langs::get(L"Name", L"world")));
|
||||
@ -398,54 +415,59 @@ void create_new_world_panel(Engine* engine, PagesControl* menu) {
|
||||
if (!nameInput->validate())
|
||||
return;
|
||||
|
||||
std::wstring name = nameInput->text();
|
||||
std::string nameutf8 = util::wstr2str_utf8(name);
|
||||
EnginePaths* paths = engine->getPaths();
|
||||
|
||||
std::wstring seedstr = seedInput->text();
|
||||
uint64_t seed = str2seed(seedstr);
|
||||
std::string name = util::wstr2str_utf8(nameInput->text());
|
||||
uint64_t seed = str2seed(seedInput->text());
|
||||
std::cout << "world seed: " << seed << std::endl;
|
||||
|
||||
auto folder = paths->getWorldsFolder()/fs::u8path(nameutf8);
|
||||
EnginePaths* paths = engine->getPaths();
|
||||
auto folder = paths->getWorldsFolder()/fs::u8path(name);
|
||||
try {
|
||||
engine->loadAllPacks();
|
||||
engine->loadContent();
|
||||
paths->setWorldFolder(folder);
|
||||
} catch (const contentpack_error& error) {
|
||||
guiutil::alert(engine->getGUI(),
|
||||
langs::get(L"Content Error", L"menu")+
|
||||
L":\n"+util::str2wstr_utf8(std::string(error.what())+
|
||||
"\npack '"+error.getPackId()+"' from "+
|
||||
error.getFolder().u8string()));
|
||||
guiutil::alert(
|
||||
engine->getGUI(),
|
||||
langs::get(L"Content Error", L"menu")+L":\n"+
|
||||
util::str2wstr_utf8(
|
||||
std::string(error.what())+
|
||||
"\npack '"+error.getPackId()+"' from "+
|
||||
error.getFolder().u8string()
|
||||
)
|
||||
);
|
||||
return;
|
||||
} catch (const std::runtime_error& error) {
|
||||
guiutil::alert(engine->getGUI(),
|
||||
langs::get(L"Content Error", L"menu")+
|
||||
L": "+util::str2wstr_utf8(error.what()));
|
||||
guiutil::alert(
|
||||
engine->getGUI(),
|
||||
langs::get(L"Content Error", L"menu")+
|
||||
L": "+util::str2wstr_utf8(error.what())
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
Level* level = World::create(
|
||||
nameutf8, folder, seed,
|
||||
name, folder, seed,
|
||||
engine->getSettings(),
|
||||
engine->getContent(),
|
||||
engine->getContentPacks());
|
||||
engine->getContentPacks()
|
||||
);
|
||||
engine->setScreen(std::make_shared<LevelScreen>(engine, level));
|
||||
}));
|
||||
panel->add(guiutil::backButton(menu));
|
||||
panel->add(guiutil::backButton(engine->getGUI()->getMenu()));
|
||||
}
|
||||
|
||||
void create_controls_panel(Engine* engine, PagesControl* menu) {
|
||||
void create_controls_panel(Engine* engine) {
|
||||
auto menu = engine->getGUI()->getMenu();
|
||||
auto panel = create_page(engine, "controls", 400, 0.0f, 1);
|
||||
|
||||
/* Camera sensitivity setting track bar */{
|
||||
panel->add((new Label(L""))->textSupplier([=]() {
|
||||
panel->add(create_label([=]() {
|
||||
float s = engine->getSettings().camera.sensitivity;
|
||||
return langs::get(L"Mouse Sensitivity", L"settings")+L": "+
|
||||
util::to_wstring(s, 1);
|
||||
}));
|
||||
|
||||
TrackBar* trackbar = new TrackBar(0.1, 10.0, 2.0, 0.1, 4);
|
||||
auto trackbar = std::make_shared<TrackBar>(0.1, 10.0, 2.0, 0.1, 4);
|
||||
trackbar->supplier([=]() {
|
||||
return engine->getSettings().camera.sensitivity;
|
||||
});
|
||||
@ -455,19 +477,18 @@ void create_controls_panel(Engine* engine, PagesControl* menu) {
|
||||
panel->add(trackbar);
|
||||
}
|
||||
|
||||
Panel* scrollPanel = new Panel(vec2(400, 200), vec4(2.0f), 1.0f);
|
||||
auto scrollPanel = std::make_shared<Panel>(vec2(400, 200), vec4(2.0f), 1.0f);
|
||||
scrollPanel->setColor(vec4(0.0f, 0.0f, 0.0f, 0.3f));
|
||||
scrollPanel->maxLength(400);
|
||||
scrollPanel->setMaxLength(400);
|
||||
for (auto& entry : Events::bindings){
|
||||
std::string bindname = entry.first;
|
||||
|
||||
Panel* subpanel = new Panel(vec2(400, 40), vec4(5.0f), 1.0f);
|
||||
auto subpanel = std::make_shared<Panel>(vec2(400, 40), vec4(5.0f), 1.0f);
|
||||
subpanel->setColor(vec4(0.0f));
|
||||
subpanel->orientation(Orientation::horizontal);
|
||||
subpanel->setOrientation(Orientation::horizontal);
|
||||
subpanel->add(std::make_shared<InputBindBox>(entry.second));
|
||||
|
||||
InputBindBox* bindbox = new InputBindBox(entry.second);
|
||||
subpanel->add(bindbox);
|
||||
Label* label = new Label(langs::get(util::str2wstr_utf8(bindname)));
|
||||
auto label = std::make_shared<Label>(langs::get(util::str2wstr_utf8(bindname)));
|
||||
label->setMargin(vec4(6.0f));
|
||||
subpanel->add(label);
|
||||
scrollPanel->add(subpanel);
|
||||
@ -476,16 +497,17 @@ void create_controls_panel(Engine* engine, PagesControl* menu) {
|
||||
panel->add(guiutil::backButton(menu));
|
||||
}
|
||||
|
||||
void create_settings_panel(Engine* engine, PagesControl* menu) {
|
||||
void create_settings_panel(Engine* engine) {
|
||||
auto menu = engine->getGUI()->getMenu();
|
||||
auto panel = create_page(engine, "settings", 400, 0.0f, 1);
|
||||
|
||||
/* Load Distance setting track bar */{
|
||||
panel->add((new Label(L""))->textSupplier([=]() {
|
||||
panel->add(create_label([=]() {
|
||||
return langs::get(L"Load Distance", L"settings")+L": " +
|
||||
std::to_wstring(engine->getSettings().chunks.loadDistance);
|
||||
}));
|
||||
|
||||
TrackBar* trackbar = new TrackBar(3, 66, 10, 1, 3);
|
||||
auto trackbar = std::make_shared<TrackBar>(3, 66, 10, 1, 3);
|
||||
trackbar->supplier([=]() {
|
||||
return engine->getSettings().chunks.loadDistance;
|
||||
});
|
||||
@ -496,12 +518,12 @@ void create_settings_panel(Engine* engine, PagesControl* menu) {
|
||||
}
|
||||
|
||||
/* Load Speed setting track bar */{
|
||||
panel->add((new Label(L""))->textSupplier([=]() {
|
||||
panel->add(create_label([=]() {
|
||||
return langs::get(L"Load Speed", L"settings")+L": " +
|
||||
std::to_wstring(engine->getSettings().chunks.loadSpeed);
|
||||
}));
|
||||
|
||||
TrackBar* trackbar = new TrackBar(1, 32, 10, 1, 1);
|
||||
auto trackbar = std::make_shared<TrackBar>(1, 32, 10, 1, 1);
|
||||
trackbar->supplier([=]() {
|
||||
return engine->getSettings().chunks.loadSpeed;
|
||||
});
|
||||
@ -512,13 +534,13 @@ void create_settings_panel(Engine* engine, PagesControl* menu) {
|
||||
}
|
||||
|
||||
/* Fog Curve setting track bar */{
|
||||
panel->add((new Label(L""))->textSupplier([=]() {
|
||||
panel->add(create_label([=]() {
|
||||
float value = engine->getSettings().graphics.fogCurve;
|
||||
return langs::get(L"Fog Curve", L"settings")+L": " +
|
||||
util::to_wstring(value, 1);
|
||||
}));
|
||||
|
||||
TrackBar* trackbar = new TrackBar(1.0, 6.0, 1.0, 0.1, 2);
|
||||
auto trackbar = std::make_shared<TrackBar>(1.0, 6.0, 1.0, 0.1, 2);
|
||||
trackbar->supplier([=]() {
|
||||
return engine->getSettings().graphics.fogCurve;
|
||||
});
|
||||
@ -529,12 +551,12 @@ void create_settings_panel(Engine* engine, PagesControl* menu) {
|
||||
}
|
||||
|
||||
/* Fov setting track bar */{
|
||||
panel->add((new Label(L""))->textSupplier([=]() {
|
||||
panel->add(create_label([=]() {
|
||||
int fov = (int)engine->getSettings().camera.fov;
|
||||
return langs::get(L"FOV", L"settings")+L": "+std::to_wstring(fov)+L"°";
|
||||
}));
|
||||
|
||||
TrackBar* trackbar = new TrackBar(30.0, 120.0, 90, 1, 4);
|
||||
auto trackbar = std::make_shared<TrackBar>(30.0, 120.0, 90, 1, 4);
|
||||
trackbar->supplier([=]() {
|
||||
return engine->getSettings().camera.fov;
|
||||
});
|
||||
@ -545,7 +567,9 @@ void create_settings_panel(Engine* engine, PagesControl* menu) {
|
||||
}
|
||||
|
||||
/* V-Sync checkbox */{
|
||||
auto checkbox = new FullCheckBox(langs::get(L"V-Sync", L"settings"), vec2(400, 32));
|
||||
auto checkbox = std::make_shared<FullCheckBox>(
|
||||
langs::get(L"V-Sync", L"settings"), vec2(400, 32)
|
||||
);
|
||||
checkbox->supplier([=]() {
|
||||
return engine->getSettings().display.swapInterval != 0;
|
||||
});
|
||||
@ -556,9 +580,11 @@ void create_settings_panel(Engine* engine, PagesControl* menu) {
|
||||
}
|
||||
|
||||
/* Backlight checkbox */{
|
||||
auto checkbox = new FullCheckBox(langs::get(L"Backlight", L"settings"), vec2(400, 32));
|
||||
auto checkbox = std::make_shared<FullCheckBox>(
|
||||
langs::get(L"Backlight", L"settings"), vec2(400, 32)
|
||||
);
|
||||
checkbox->supplier([=]() {
|
||||
return engine->getSettings().graphics.backlight != 0;
|
||||
return engine->getSettings().graphics.backlight;
|
||||
});
|
||||
checkbox->consumer([=](bool checked) {
|
||||
engine->getSettings().graphics.backlight = checked;
|
||||
@ -576,15 +602,16 @@ void create_settings_panel(Engine* engine, PagesControl* menu) {
|
||||
panel->add(guiutil::backButton(menu));
|
||||
}
|
||||
|
||||
void create_pause_panel(Engine* engine, PagesControl* menu) {
|
||||
void create_pause_panel(Engine* engine) {
|
||||
auto menu = engine->getGUI()->getMenu();
|
||||
auto panel = create_page(engine, "pause", 400, 0.0f, 1);
|
||||
|
||||
panel->add(create_button(L"Continue", vec4(10.0f), vec4(1), [=](GUI*){
|
||||
menu->reset();
|
||||
}));
|
||||
panel->add(create_button(L"Content", vec4(10.0f), vec4(1), [=](GUI*) {
|
||||
create_content_panel(engine, menu);
|
||||
menu->set("content");
|
||||
create_content_panel(engine);
|
||||
menu->setPage("content");
|
||||
}));
|
||||
panel->add(guiutil::gotoButton(L"Settings", "settings", menu));
|
||||
|
||||
@ -596,16 +623,16 @@ void create_pause_panel(Engine* engine, PagesControl* menu) {
|
||||
}));
|
||||
}
|
||||
|
||||
void menus::create_menus(Engine* engine, PagesControl* menu) {
|
||||
create_new_world_panel(engine, menu);
|
||||
create_settings_panel(engine, menu);
|
||||
create_controls_panel(engine, menu);
|
||||
create_pause_panel(engine, menu);
|
||||
create_languages_panel(engine, menu);
|
||||
create_main_menu_panel(engine, menu);
|
||||
void menus::create_menus(Engine* engine) {
|
||||
create_new_world_panel(engine);
|
||||
create_settings_panel(engine);
|
||||
create_controls_panel(engine);
|
||||
create_pause_panel(engine);
|
||||
create_languages_panel(engine);
|
||||
create_main_menu_panel(engine);
|
||||
}
|
||||
|
||||
void menus::refresh_menus(Engine* engine, PagesControl* menu) {
|
||||
create_main_menu_panel(engine, menu);
|
||||
create_new_world_panel(engine, menu);
|
||||
void menus::refresh_menus(Engine* engine) {
|
||||
create_main_menu_panel(engine);
|
||||
create_new_world_panel(engine);
|
||||
}
|
||||
|
||||
@ -3,13 +3,9 @@
|
||||
|
||||
class Engine;
|
||||
|
||||
namespace gui {
|
||||
class PagesControl;
|
||||
}
|
||||
|
||||
namespace menus {
|
||||
void create_menus(Engine* engine, gui::PagesControl* menu);
|
||||
void refresh_menus(Engine* engine, gui::PagesControl* menu);
|
||||
void create_menus(Engine* engine);
|
||||
void refresh_menus(Engine* engine);
|
||||
}
|
||||
|
||||
#endif // FRONTEND_MENU_H_
|
||||
@ -45,9 +45,9 @@ Screen::~Screen() {
|
||||
|
||||
MenuScreen::MenuScreen(Engine* engine_) : Screen(engine_) {
|
||||
auto menu = engine->getGUI()->getMenu();
|
||||
menus::refresh_menus(engine, menu);
|
||||
menus::refresh_menus(engine);
|
||||
menu->reset();
|
||||
menu->set("main");
|
||||
menu->setPage("main");
|
||||
|
||||
uicamera.reset(new Camera(glm::vec3(), Window::height));
|
||||
uicamera->perspective = false;
|
||||
|
||||
@ -11,17 +11,17 @@ using glm::vec2;
|
||||
using glm::vec3;
|
||||
using glm::vec4;
|
||||
|
||||
Batch2D::Batch2D(size_t capacity) : capacity(capacity), offset(0), color(1.0f, 1.0f, 1.0f, 1.0f){
|
||||
Batch2D::Batch2D(size_t capacity) : capacity(capacity), color(1.0f){
|
||||
const vattr attrs[] = {
|
||||
{2}, {2}, {4}, {0}
|
||||
};
|
||||
|
||||
buffer = new float[capacity * B2D_VERTEX_SIZE];
|
||||
mesh = new Mesh(buffer, 0, attrs);
|
||||
mesh = std::make_unique<Mesh>(buffer, 0, attrs);
|
||||
index = 0;
|
||||
|
||||
unsigned char pixels[] = {
|
||||
255, 255, 255, 255,
|
||||
ubyte pixels[] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF
|
||||
};
|
||||
blank = new Texture(pixels, 1, 1, GL_RGBA);
|
||||
_texture = nullptr;
|
||||
@ -30,7 +30,6 @@ Batch2D::Batch2D(size_t capacity) : capacity(capacity), offset(0), color(1.0f, 1
|
||||
Batch2D::~Batch2D(){
|
||||
delete blank;
|
||||
delete[] buffer;
|
||||
delete mesh;
|
||||
}
|
||||
|
||||
void Batch2D::begin(){
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
#ifndef SRC_GRAPHICS_BATCH2D_H_
|
||||
#define SRC_GRAPHICS_BATCH2D_H_
|
||||
|
||||
#include <memory>
|
||||
#include <stdlib.h>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
@ -13,8 +14,7 @@ class Sprite;
|
||||
class Batch2D {
|
||||
float* buffer;
|
||||
size_t capacity;
|
||||
size_t offset;
|
||||
Mesh* mesh;
|
||||
std::unique_ptr<Mesh> mesh;
|
||||
size_t index;
|
||||
|
||||
Texture* blank;
|
||||
|
||||
@ -13,8 +13,7 @@ using glm::vec3;
|
||||
using glm::vec4;
|
||||
|
||||
Batch3D::Batch3D(size_t capacity)
|
||||
: capacity(capacity),
|
||||
offset(0) {
|
||||
: capacity(capacity) {
|
||||
const vattr attrs[] = {
|
||||
{3}, {2}, {4}, {0}
|
||||
};
|
||||
|
||||
@ -12,7 +12,6 @@ class Texture;
|
||||
class Batch3D {
|
||||
float* buffer;
|
||||
size_t capacity;
|
||||
size_t offset;
|
||||
Mesh* mesh;
|
||||
size_t index;
|
||||
|
||||
|
||||
@ -4,16 +4,19 @@
|
||||
|
||||
using glm::vec4;
|
||||
|
||||
Font::Font(std::vector<Texture*> pages, int lineHeight) : lineHeight_(lineHeight), pages(pages) {
|
||||
Font::Font(std::vector<std::unique_ptr<Texture>> pages, int lineHeight, int yoffset)
|
||||
: lineHeight(lineHeight), yoffset(yoffset), pages(std::move(pages)) {
|
||||
}
|
||||
|
||||
Font::~Font(){
|
||||
for (Texture* texture : pages)
|
||||
delete texture;
|
||||
}
|
||||
|
||||
int Font::lineHeight() const {
|
||||
return lineHeight_;
|
||||
int Font::getYOffset() const {
|
||||
return yoffset;
|
||||
}
|
||||
|
||||
int Font::getLineHeight() const {
|
||||
return lineHeight;
|
||||
}
|
||||
|
||||
bool Font::isPrintableChar(int c) {
|
||||
@ -48,11 +51,11 @@ void Font::draw(Batch2D* batch, std::wstring text, int x, int y, int style) {
|
||||
if (isPrintableChar(c)){
|
||||
int charpage = c >> 8;
|
||||
if (charpage == page){
|
||||
Texture* texture = pages[charpage];
|
||||
Texture* texture = pages[charpage].get();
|
||||
if (texture == nullptr){
|
||||
texture = pages[0];
|
||||
texture = pages[0].get();
|
||||
}
|
||||
batch->texture(pages[charpage]);
|
||||
batch->texture(texture);
|
||||
|
||||
switch (style){
|
||||
case STYLE_SHADOW:
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
#ifndef GRAPHICS_FONT_H_
|
||||
#define GRAPHICS_FONT_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "../typedefs.h"
|
||||
@ -13,13 +14,15 @@ const uint STYLE_SHADOW = 1;
|
||||
const uint STYLE_OUTLINE = 2;
|
||||
|
||||
class Font {
|
||||
int lineHeight_;
|
||||
int lineHeight;
|
||||
int yoffset;
|
||||
public:
|
||||
std::vector<Texture*> pages;
|
||||
Font(std::vector<Texture*> pages, int lineHeight);
|
||||
std::vector<std::unique_ptr<Texture>> pages;
|
||||
Font(std::vector<std::unique_ptr<Texture>> pages, int lineHeight, int yoffset);
|
||||
~Font();
|
||||
|
||||
int lineHeight() const;
|
||||
int getLineHeight() const;
|
||||
int getYOffset() const;
|
||||
int calcWidth(std::wstring text);
|
||||
// int getGlyphWidth(char c);
|
||||
bool isPrintableChar(int c);
|
||||
|
||||
@ -8,17 +8,23 @@ const uint LB_VERTEX_SIZE = (3+4);
|
||||
LineBatch::LineBatch(size_t capacity) : capacity(capacity) {
|
||||
const vattr attrs[] = { {3},{4}, {0} };
|
||||
buffer = new float[capacity * LB_VERTEX_SIZE * 2];
|
||||
mesh = new Mesh(buffer, 0, attrs);
|
||||
mesh = std::make_unique<Mesh>(buffer, 0, attrs);
|
||||
index = 0;
|
||||
}
|
||||
|
||||
LineBatch::~LineBatch(){
|
||||
delete[] buffer;
|
||||
delete mesh;
|
||||
}
|
||||
|
||||
void LineBatch::line(float x1, float y1, float z1, float x2, float y2, float z2,
|
||||
float r, float g, float b, float a) {
|
||||
void LineBatch::line(
|
||||
float x1, float y1,
|
||||
float z1, float x2,
|
||||
float y2, float z2,
|
||||
float r, float g, float b, float a
|
||||
) {
|
||||
if (index + LB_VERTEX_SIZE * 2 >= capacity) {
|
||||
render();
|
||||
}
|
||||
buffer[index] = x1;
|
||||
buffer[index+1] = y1;
|
||||
buffer[index+2] = z1;
|
||||
|
||||
@ -1,13 +1,14 @@
|
||||
#ifndef GRAPHICS_LINEBATCH_H_
|
||||
#define GRAPHICS_LINEBATCH_H_
|
||||
|
||||
#include <memory>
|
||||
#include <stdlib.h>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
class Mesh;
|
||||
|
||||
class LineBatch {
|
||||
Mesh* mesh;
|
||||
std::unique_ptr<Mesh> mesh;
|
||||
float* buffer;
|
||||
size_t index;
|
||||
size_t capacity;
|
||||
|
||||
@ -19,7 +19,7 @@ Texture::Texture(ubyte* data, int width, int height, uint format)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 2);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
|
||||
@ -19,9 +19,6 @@ private:
|
||||
uint padding;
|
||||
std::unique_ptr<WorldGenerator> generator;
|
||||
|
||||
/* Average measured microseconds duration of loadVisible call */
|
||||
int64_t avgDurationMcs = 1000;
|
||||
|
||||
/* Process one chunk: load it or calculate lights for it */
|
||||
bool loadVisible();
|
||||
bool buildLights(std::shared_ptr<Chunk> chunk);
|
||||
|
||||
@ -25,7 +25,7 @@ inline int lua_pushivec3(lua_State* L, int x, int y, int z) {
|
||||
return 3;
|
||||
}
|
||||
|
||||
inline void luaL_openlib(lua_State* L, const char* name, const luaL_Reg* libfuncs, int nup) {
|
||||
inline void openlib(lua_State* L, const char* name, const luaL_Reg* libfuncs, int nup) {
|
||||
lua_newtable(L);
|
||||
luaL_setfuncs(L, libfuncs, nup);
|
||||
lua_setglobal(L, name);
|
||||
@ -409,11 +409,11 @@ static int l_print(lua_State* L) {
|
||||
lua_setglobal(L, NAME))
|
||||
|
||||
void apilua::create_funcs(lua_State* L) {
|
||||
luaL_openlib(L, "pack", packlib, 0);
|
||||
luaL_openlib(L, "world", worldlib, 0);
|
||||
luaL_openlib(L, "player", playerlib, 0);
|
||||
luaL_openlib(L, "time", timelib, 0);
|
||||
luaL_openlib(L, "file", filelib, 0);
|
||||
openlib(L, "pack", packlib, 0);
|
||||
openlib(L, "world", worldlib, 0);
|
||||
openlib(L, "player", playerlib, 0);
|
||||
openlib(L, "time", timelib, 0);
|
||||
openlib(L, "file", filelib, 0);
|
||||
|
||||
lua_addfunc(L, l_print, "print");
|
||||
lua_addfunc(L, l_block_index, "block_index");
|
||||
|
||||
@ -101,6 +101,20 @@ void scripting::initialize(Engine* engine) {
|
||||
load_script(fs::path("stdlib.lua"));
|
||||
}
|
||||
|
||||
// todo: luaL state check
|
||||
runnable scripting::create_runnable(
|
||||
const std::string& filename,
|
||||
const std::string& src
|
||||
) {
|
||||
return [=](){
|
||||
if (luaL_loadbuffer(L, src.c_str(), src.length(), filename.c_str())) {
|
||||
handleError(L);
|
||||
return;
|
||||
}
|
||||
call_func(L, 0, filename);
|
||||
};
|
||||
}
|
||||
|
||||
void scripting::on_world_load(Level* level, BlocksController* blocks) {
|
||||
scripting::level = level;
|
||||
scripting::content = level->content;
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
#include <string>
|
||||
#include <filesystem>
|
||||
|
||||
#include "../../delegates.h"
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
class Engine;
|
||||
@ -20,6 +22,12 @@ namespace scripting {
|
||||
extern BlocksController* blocks;
|
||||
|
||||
void initialize(Engine* engine);
|
||||
|
||||
runnable create_runnable(
|
||||
const std::string& filename,
|
||||
const std::string& source
|
||||
);
|
||||
|
||||
void on_world_load(Level* level, BlocksController* blocks);
|
||||
void on_world_save();
|
||||
void on_world_quit();
|
||||
|
||||
@ -4,18 +4,17 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef unsigned int uint;
|
||||
using uint = unsigned int;
|
||||
|
||||
// use for bytes arrays
|
||||
typedef uint8_t ubyte;
|
||||
using ubyte = uint8_t;
|
||||
|
||||
// content indices
|
||||
typedef uint32_t itemid_t;
|
||||
typedef uint16_t blockid_t;
|
||||
using itemid_t = uint32_t;
|
||||
using blockid_t = uint16_t;
|
||||
|
||||
typedef uint32_t itemcount_t;
|
||||
|
||||
typedef uint16_t blockstate_t;
|
||||
typedef uint16_t light_t;
|
||||
using itemcount_t = uint32_t;
|
||||
using blockstate_t = uint16_t;
|
||||
using light_t = uint16_t;
|
||||
|
||||
#endif
|
||||
|
||||
@ -252,3 +252,30 @@ std::vector<ubyte> util::base64_decode(const char* str, size_t size) {
|
||||
std::vector<ubyte> util::base64_decode(const std::string& str) {
|
||||
return base64_decode(str.c_str(), str.size());
|
||||
}
|
||||
|
||||
int util::replaceAll(std::string& str, const std::string& from, const std::string& to) {
|
||||
int count = 0;
|
||||
size_t offset = 0;
|
||||
while (true) {
|
||||
size_t start_pos = str.find(from, offset);
|
||||
if(start_pos == std::string::npos)
|
||||
break;
|
||||
str.replace(start_pos, from.length(), to);
|
||||
offset = start_pos + to.length();
|
||||
count++;
|
||||
break;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
// replace it with std::from_chars in the far far future
|
||||
double util::parse_double(const std::string& str) {
|
||||
std::istringstream ss(str);
|
||||
ss.imbue(std::locale("C"));
|
||||
double d;
|
||||
ss >> d;
|
||||
if (ss.fail()) {
|
||||
throw std::runtime_error("invalid number format");
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
@ -26,6 +26,10 @@ namespace util {
|
||||
extern std::string base64_encode(const ubyte* data, size_t size);
|
||||
extern std::vector<ubyte> base64_decode(const char* str, size_t size);
|
||||
extern std::vector<ubyte> base64_decode(const std::string& str);
|
||||
|
||||
extern int replaceAll(std::string& str, const std::string& from, const std::string& to);
|
||||
|
||||
extern double parse_double(const std::string& str);
|
||||
}
|
||||
|
||||
#endif // UTIL_STRINGUTIL_H_
|
||||
@ -5,7 +5,7 @@
|
||||
#include <filesystem>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "definitions.h"
|
||||
#include "core_defs.h"
|
||||
#include "engine.h"
|
||||
#include "util/platform.h"
|
||||
#include "coders/toml.h"
|
||||
@ -38,7 +38,7 @@ int main(int argc, char** argv) {
|
||||
toml::Reader reader(wrapper.get(), settings_file.string(), text);
|
||||
reader.read();
|
||||
}
|
||||
setup_bindings();
|
||||
corecontent::setup_bindings();
|
||||
Engine engine(settings, &paths);
|
||||
if (fs::is_regular_file(controls_file)) {
|
||||
std::cout << "-- loading controls" << std::endl;
|
||||
|
||||
@ -13,7 +13,7 @@ struct AABB;
|
||||
class Content;
|
||||
class ContentIndices;
|
||||
class Chunk;
|
||||
class voxel;
|
||||
struct voxel;
|
||||
class WorldFiles;
|
||||
class LevelEvents;
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
|
||||
#include "../typedefs.h"
|
||||
|
||||
class voxel;
|
||||
struct voxel;
|
||||
class Content;
|
||||
|
||||
class WorldGenerator {
|
||||
|
||||
@ -84,6 +84,10 @@ public:
|
||||
uint getNextInventoryId() {
|
||||
return nextInventoryId++;
|
||||
}
|
||||
|
||||
const Content* getContent() const {
|
||||
return content;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* WORLD_WORLD_H_ */
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user