mirror of
https://github.com/MihailRis/voxelcore.git
synced 2026-10-14 23:41:50 +00:00
commit
038811a1e0
34 changed files with 516 additions and 94 deletions
2
.github/workflows/appimage.yml
vendored
2
.github/workflows/appimage.yml
vendored
|
|
@ -31,7 +31,7 @@ jobs:
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install -y build-essential libglfw3-dev libglfw3 libglew-dev libglew2.2 \
|
sudo apt-get install -y build-essential libglfw3-dev libglfw3 libglew-dev libglew2.2 \
|
||||||
libglm-dev libpng-dev libopenal-dev libluajit-5.1-dev libvorbis-dev \
|
libglm-dev libpng-dev libopenal-dev libluajit-5.1-dev libvorbis-dev \
|
||||||
libcurl4-openssl-dev libgtest-dev cmake squashfs-tools valgrind
|
libcurl4-openssl-dev libgtest-dev libfreetype6-dev cmake squashfs-tools valgrind
|
||||||
# fix luajit paths
|
# fix luajit paths
|
||||||
sudo ln -s /usr/lib/x86_64-linux-gnu/libluajit-5.1.a /usr/lib/x86_64-linux-gnu/liblua5.1.a
|
sudo ln -s /usr/lib/x86_64-linux-gnu/libluajit-5.1.a /usr/lib/x86_64-linux-gnu/liblua5.1.a
|
||||||
sudo ln -s /usr/include/luajit-2.1 /usr/include/lua
|
sudo ln -s /usr/include/luajit-2.1 /usr/include/lua
|
||||||
|
|
|
||||||
2
.github/workflows/cmake.yml
vendored
2
.github/workflows/cmake.yml
vendored
|
|
@ -39,7 +39,7 @@ jobs:
|
||||||
# make && make install INSTALL_INC=/usr/include/lua
|
# make && make install INSTALL_INC=/usr/include/lua
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install libglfw3-dev libglfw3 libglew-dev libglm-dev libpng-dev libopenal-dev libluajit-5.1-dev libvorbis-dev libgtest-dev libcurl4-openssl-dev
|
sudo apt-get install libglfw3-dev libglfw3 libglew-dev libglm-dev libpng-dev libopenal-dev libluajit-5.1-dev libvorbis-dev libgtest-dev libcurl4-openssl-dev libfreetype6-dev
|
||||||
# fix luajit paths
|
# fix luajit paths
|
||||||
sudo ln -s /usr/lib/x86_64-linux-gnu/libluajit-5.1.a /usr/lib/x86_64-linux-gnu/liblua-5.1.a
|
sudo ln -s /usr/lib/x86_64-linux-gnu/libluajit-5.1.a /usr/lib/x86_64-linux-gnu/liblua-5.1.a
|
||||||
sudo ln -s /usr/include/luajit-2.1 /usr/include/lua
|
sudo ln -s /usr/include/luajit-2.1 /usr/include/lua
|
||||||
|
|
|
||||||
2
.github/workflows/macos.yml
vendored
2
.github/workflows/macos.yml
vendored
|
|
@ -23,7 +23,7 @@ jobs:
|
||||||
|
|
||||||
- name: Install dependencies from brew
|
- name: Install dependencies from brew
|
||||||
run: |
|
run: |
|
||||||
brew install glfw3 glew libpng openal-soft luajit libvorbis skypjack/entt/entt googletest glm
|
brew install glfw3 glew libpng openal-soft luajit libvorbis skypjack/entt/entt googletest glm freetype
|
||||||
|
|
||||||
- name: Configure
|
- name: Configure
|
||||||
run: |
|
run: |
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ RUN apt-get update && apt-get install --no-install-recommends -y \
|
||||||
libluajit-5.1-dev \
|
libluajit-5.1-dev \
|
||||||
libvorbis-dev \
|
libvorbis-dev \
|
||||||
libcurl4-openssl-dev \
|
libcurl4-openssl-dev \
|
||||||
|
libfreetype6-dev \
|
||||||
ca-certificates \
|
ca-certificates \
|
||||||
wget \
|
wget \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
|
||||||
12
README.md
12
README.md
|
|
@ -30,13 +30,13 @@ sudo make install
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
su -
|
su -
|
||||||
apt-get install entt-devel libglfw3-devel libGLEW-devel libglm-devel libpng-devel libvorbis-devel libopenal-devel libluajit-devel libstdc++13-devel-static libcurl-devel
|
apt-get install entt-devel libglfw3-devel libGLEW-devel libglm-devel libpng-devel libvorbis-devel libopenal-devel libluajit-devel libstdc++13-devel-static libcurl-devel libfreetype-devel
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Debian based distros
|
#### Debian based distros
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
sudo apt install libglfw3 libglfw3-dev libglew-dev libglm-dev libpng-dev libopenal-dev libluajit-5.1-dev libvorbis-dev libcurl4-openssl-dev
|
sudo apt install libglfw3 libglfw3-dev libglew-dev libglm-dev libpng-dev libopenal-dev libluajit-5.1-dev libvorbis-dev libcurl4-openssl-dev libfreetype6-dev
|
||||||
```
|
```
|
||||||
|
|
||||||
> [!TIP]
|
> [!TIP]
|
||||||
|
|
@ -50,7 +50,7 @@ sudo apt install libglfw3 libglfw3-dev libglew-dev libglm-dev libpng-dev libopen
|
||||||
#### RHEL based distros
|
#### RHEL based distros
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
sudo dnf install glfw-devel glew-devel glm-devel libpng-devel libvorbis-devel openal-soft-devel luajit-devel libcurl-devel
|
sudo dnf install glfw-devel glew-devel glm-devel libpng-devel libvorbis-devel openal-soft-devel luajit-devel libcurl-devel libfreetype-devel
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Arch based distros
|
#### Arch based distros
|
||||||
|
|
@ -58,13 +58,13 @@ sudo dnf install glfw-devel glew-devel glm-devel libpng-devel libvorbis-devel op
|
||||||
If you use X11:
|
If you use X11:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
sudo pacman -S glfw-x11 glew glm libpng libvorbis openal luajit libcurl
|
sudo pacman -S glfw-x11 glew glm libpng libvorbis openal luajit libcurl freetype2
|
||||||
```
|
```
|
||||||
|
|
||||||
If you use Wayland:
|
If you use Wayland:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
sudo pacman -S glfw-wayland glew glm libpng libvorbis openal luajit libcurl
|
sudo pacman -S glfw-wayland glew glm libpng libvorbis openal luajit libcurl freetype2
|
||||||
```
|
```
|
||||||
|
|
||||||
And install EnTT:
|
And install EnTT:
|
||||||
|
|
@ -94,7 +94,7 @@ cmake --build . --parallel
|
||||||
### Install libraries
|
### Install libraries
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
brew install glfw3 glew glm libpng libvorbis lua luajit libcurl openal-soft skypjack/entt/entt
|
brew install glfw3 glew glm libpng libvorbis lua luajit libcurl openal-soft skypjack/entt/entt freetype
|
||||||
```
|
```
|
||||||
|
|
||||||
> [!TIP]
|
> [!TIP]
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ AppDir:
|
||||||
- libvorbis0a
|
- libvorbis0a
|
||||||
- libvorbisfile3
|
- libvorbisfile3
|
||||||
- libluajit-5.1-2
|
- libluajit-5.1-2
|
||||||
|
- libfreetype6
|
||||||
exclude:
|
exclude:
|
||||||
- hicolor-icon-theme
|
- hicolor-icon-theme
|
||||||
- sound-theme-freedesktop
|
- sound-theme-freedesktop
|
||||||
|
|
@ -45,6 +46,9 @@ AppDir:
|
||||||
- kwin-style-breeze
|
- kwin-style-breeze
|
||||||
- kde-style-breeze
|
- kde-style-breeze
|
||||||
- plasma-integration
|
- plasma-integration
|
||||||
|
- libllvm15
|
||||||
|
- libicu70
|
||||||
|
- libxml2
|
||||||
files:
|
files:
|
||||||
exclude:
|
exclude:
|
||||||
- usr/share/man
|
- usr/share/man
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<panel id='bind_%{id}' size='400,40' padding='4' color='0' orientation='horizontal'>
|
<panel id='bind_%{id}' size='400,40' padding='4' color='0' orientation='horizontal'>
|
||||||
<bindbox binding='%{id}'/>
|
<bindbox binding='%{id}'/>
|
||||||
<image id="bindmark_%{id}"src='gui/left_half_block' size='4,28' visible="false"/>
|
<image id="bindmark_%{id}" src='gui/left_half_block' size='4,28' visible="false"/>
|
||||||
<label id='bindlabel_%{id}' color="#ffffffff" margin='6'>%{name}</label>
|
<label id='bindlabel_%{id}' color="#ffffffff" margin='6'>%{name}</label>
|
||||||
</panel>
|
</panel>
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ find_package(ZLIB REQUIRED)
|
||||||
find_package(PNG REQUIRED)
|
find_package(PNG REQUIRED)
|
||||||
find_package(CURL REQUIRED)
|
find_package(CURL REQUIRED)
|
||||||
find_package(glfw3 REQUIRED)
|
find_package(glfw3 REQUIRED)
|
||||||
|
find_package(Freetype REQUIRED)
|
||||||
if(NOT APPLE)
|
if(NOT APPLE)
|
||||||
find_package(EnTT REQUIRED)
|
find_package(EnTT REQUIRED)
|
||||||
endif()
|
endif()
|
||||||
|
|
@ -75,6 +76,7 @@ target_link_libraries(
|
||||||
Vorbis::vorbis
|
Vorbis::vorbis
|
||||||
Vorbis::vorbisfile
|
Vorbis::vorbisfile
|
||||||
luajit::luajit
|
luajit::luajit
|
||||||
|
Freetype::Freetype
|
||||||
PUBLIC glm::glm # Need public for src/delegates.hpp, which including to
|
PUBLIC glm::glm # Need public for src/delegates.hpp, which including to
|
||||||
# main.cpp
|
# main.cpp
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -187,6 +187,12 @@ void AssetsLoader::processPreload(
|
||||||
config = std::make_shared<ModelCfg>(squashed);
|
config = std::make_shared<ModelCfg>(squashed);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case AssetType::FONT: {
|
||||||
|
int size = DEFAULT_FONT_SIZE;
|
||||||
|
map.at("size").get(size);
|
||||||
|
config = std::make_unique<FontCfg>(size);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,8 +33,7 @@ struct LayoutCfg : AssetCfg {
|
||||||
gui::GUI* gui;
|
gui::GUI* gui;
|
||||||
scriptenv env;
|
scriptenv env;
|
||||||
|
|
||||||
LayoutCfg(gui::GUI* gui, scriptenv env) : gui(gui), env(std::move(env)) {
|
LayoutCfg(gui::GUI* gui, scriptenv env) : gui(gui), env(std::move(env)) {}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SoundCfg : AssetCfg {
|
struct SoundCfg : AssetCfg {
|
||||||
|
|
@ -43,6 +42,12 @@ struct SoundCfg : AssetCfg {
|
||||||
SoundCfg(bool keepPCM) : keepPCM(keepPCM) {}
|
SoundCfg(bool keepPCM) : keepPCM(keepPCM) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct FontCfg : AssetCfg {
|
||||||
|
int size;
|
||||||
|
|
||||||
|
FontCfg(int size) : size(size) {}
|
||||||
|
};
|
||||||
|
|
||||||
enum class AtlasType {
|
enum class AtlasType {
|
||||||
ATLAS, SEPARATE
|
ATLAS, SEPARATE
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@
|
||||||
#include "coders/obj.hpp"
|
#include "coders/obj.hpp"
|
||||||
#include "coders/vcm.hpp"
|
#include "coders/vcm.hpp"
|
||||||
#include "coders/vec3.hpp"
|
#include "coders/vec3.hpp"
|
||||||
|
#include "coders/vector_fonts.hpp"
|
||||||
#include "constants.hpp"
|
#include "constants.hpp"
|
||||||
#include "debug/Logger.hpp"
|
#include "debug/Logger.hpp"
|
||||||
#include "engine/EnginePaths.hpp"
|
#include "engine/EnginePaths.hpp"
|
||||||
|
|
@ -199,8 +200,24 @@ assetload::postfunc assetload::font(
|
||||||
const ResPaths& paths,
|
const ResPaths& paths,
|
||||||
const std::string& filename,
|
const std::string& filename,
|
||||||
const std::string& name,
|
const std::string& name,
|
||||||
const std::shared_ptr<AssetCfg>&
|
const std::shared_ptr<AssetCfg>& config
|
||||||
) {
|
) {
|
||||||
|
auto cfg = std::dynamic_pointer_cast<FontCfg>(config);
|
||||||
|
auto ext = fs::path(filename).extension().string();
|
||||||
|
if (ext == ".ttf" || ext == ".otf") {
|
||||||
|
logger.info() << "loading vector font " << util::quote(filename);
|
||||||
|
return [=](Assets* assets) {
|
||||||
|
using FontFile = vector_fonts::FontFile;
|
||||||
|
FontFile* fontFile;
|
||||||
|
if ((fontFile = assets->get<FontFile>(filename)) == nullptr) {
|
||||||
|
auto fontFilePtr = vector_fonts::load_font(paths.find(filename).string());
|
||||||
|
fontFile = fontFilePtr.get();
|
||||||
|
assets->store(fontFilePtr, filename);
|
||||||
|
}
|
||||||
|
assets->store(fontFile->createInstance(cfg ? cfg->size : 16), name);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
auto pages = std::make_shared<std::vector<std::unique_ptr<ImageData>>>();
|
auto pages = std::make_shared<std::vector<std::unique_ptr<ImageData>>>();
|
||||||
for (size_t i = 0; i <= 1024; i++) {
|
for (size_t i = 0; i <= 1024; i++) {
|
||||||
std::string pagefile = filename + "_" + std::to_string(i) + ".png";
|
std::string pagefile = filename + "_" + std::to_string(i) + ".png";
|
||||||
|
|
@ -214,20 +231,7 @@ assetload::postfunc assetload::font(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return [=](auto assets) {
|
return [=](auto assets) {
|
||||||
int res = pages->at(0)->getHeight() / 16;
|
assets->store(Font::createBitmapFont(std::move(*pages)), name);
|
||||||
std::vector<std::unique_ptr<Texture>> textures;
|
|
||||||
for (auto& page : *pages) {
|
|
||||||
if (page == nullptr) {
|
|
||||||
textures.emplace_back(nullptr);
|
|
||||||
} else {
|
|
||||||
auto texture = Texture::from(page.get());
|
|
||||||
texture->setMipMapping(false, true);
|
|
||||||
textures.emplace_back(std::move(texture));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assets->store(
|
|
||||||
std::make_unique<Font>(std::move(textures), res, 4), name
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
180
src/coders/vector_fonts.cpp
Normal file
180
src/coders/vector_fonts.cpp
Normal file
|
|
@ -0,0 +1,180 @@
|
||||||
|
#include "vector_fonts.hpp"
|
||||||
|
|
||||||
|
#include "io/io.hpp"
|
||||||
|
#include "debug/Logger.hpp"
|
||||||
|
#include "graphics/core/ImageData.hpp"
|
||||||
|
#include "graphics/core/Texture.hpp"
|
||||||
|
#include "graphics/core/Font.hpp"
|
||||||
|
#include "constants.hpp"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <ft2build.h>
|
||||||
|
#include FT_FREETYPE_H
|
||||||
|
|
||||||
|
static debug::Logger logger("vector_fonts");
|
||||||
|
|
||||||
|
static FT_Library library;
|
||||||
|
|
||||||
|
static const char* get_ft_error_message(FT_Error error) {
|
||||||
|
#undef FTERRORS_H_
|
||||||
|
#define FT_ERRORDEF( e, v, s ) case v: return s;
|
||||||
|
#define FT_ERROR_START_LIST switch (error) {
|
||||||
|
#define FT_ERROR_END_LIST }
|
||||||
|
#include FT_ERRORS_H
|
||||||
|
return "unknown error";
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
class FTFontFile : public vector_fonts::FontFile,
|
||||||
|
public std::enable_shared_from_this<FTFontFile> {
|
||||||
|
public:
|
||||||
|
FTFontFile(FT_Face face, util::Buffer<ubyte> buffer)
|
||||||
|
: face(std::move(face)), buffer(std::move(buffer)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
~FTFontFile() {
|
||||||
|
if (FT_Error error = FT_Done_Face(face)) {
|
||||||
|
logger.error()
|
||||||
|
<< "error on FT_Done_Face: " << get_ft_error_message(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Font> createInstance(int size) override {
|
||||||
|
if (FT_Error error = FT_Set_Pixel_Sizes(face, 0, size)) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
"FT_Set_Pixel_Sizes error: " +
|
||||||
|
std::string(get_ft_error_message(error))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<Texture>> pages;
|
||||||
|
std::vector<Glyph> glyphs;
|
||||||
|
|
||||||
|
int dstSize = size * 16;
|
||||||
|
ImageData canvas(ImageFormat::RGBA8888, dstSize, dstSize);
|
||||||
|
ImageData bitmapDst(ImageFormat::RGBA8888, size, size);
|
||||||
|
|
||||||
|
for (int pageid = 0; pageid < DEFAULT_PRE_RENDER_FONT_PAGES; pageid++) {
|
||||||
|
renderPage(pageid, canvas, bitmapDst, glyphs);
|
||||||
|
pages.push_back(Texture::from(&canvas));
|
||||||
|
}
|
||||||
|
return std::make_unique<Font>(
|
||||||
|
std::move(pages),
|
||||||
|
std::move(glyphs),
|
||||||
|
size,
|
||||||
|
size / 2,
|
||||||
|
shared_from_this()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Texture> renderPage(
|
||||||
|
int pageid, std::vector<Glyph>& glyphs, int size
|
||||||
|
) override {
|
||||||
|
if (FT_Error error = FT_Set_Pixel_Sizes(face, 0, size)) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
"FT_Set_Pixel_Sizes error: " +
|
||||||
|
std::string(get_ft_error_message(error))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
int dstSize = size * 16;
|
||||||
|
ImageData canvas(ImageFormat::RGBA8888, dstSize, dstSize);
|
||||||
|
ImageData bitmapDst(ImageFormat::RGBA8888, size, size);
|
||||||
|
|
||||||
|
renderPage(pageid, canvas, bitmapDst, glyphs);
|
||||||
|
return Texture::from(&canvas);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
FT_Face face;
|
||||||
|
util::Buffer<ubyte> buffer;
|
||||||
|
|
||||||
|
bool renderGlyph(int codepoint, ImageData& bitmapDst) {
|
||||||
|
int width = bitmapDst.getWidth();
|
||||||
|
int height = bitmapDst.getHeight();
|
||||||
|
|
||||||
|
if (FT_Error error = FT_Load_Char(face, codepoint, FT_LOAD_RENDER)) {
|
||||||
|
logger.warning() << get_ft_error_message(error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto dstData = bitmapDst.getData();
|
||||||
|
std::memset(dstData, 0, bitmapDst.getDataSize());
|
||||||
|
if (face->glyph->bitmap.width == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const FT_Bitmap& bitmap = face->glyph->bitmap;
|
||||||
|
for (int row = 0; row < std::min<int>(bitmap.rows, height); row++) {
|
||||||
|
for (int col = 0; col < std::min<int>(bitmap.width, width); col++) {
|
||||||
|
uint8_t value = bitmap.buffer[row * bitmap.pitch + col];
|
||||||
|
dstData[(row * width + col) * 4 + 0] = 255;
|
||||||
|
dstData[(row * width + col) * 4 + 1] = 255;
|
||||||
|
dstData[(row * width + col) * 4 + 2] = 255;
|
||||||
|
dstData[(row * width + col) * 4 + 3] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void renderPage(
|
||||||
|
int pageid,
|
||||||
|
ImageData& canvas,
|
||||||
|
ImageData& bitmapDst,
|
||||||
|
std::vector<Glyph>& glyphs
|
||||||
|
) {
|
||||||
|
int size = canvas.getWidth() / 16;
|
||||||
|
for (int c = 0; c < 256; c++) {
|
||||||
|
int codepoint = pageid << 8 | c;
|
||||||
|
if (!renderGlyph(codepoint, bitmapDst)) {
|
||||||
|
glyphs.push_back(Glyph {0, size / 2});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas.blit(bitmapDst, (c % 16) * size, (c / 16) * size);
|
||||||
|
|
||||||
|
Glyph glyph {
|
||||||
|
face->glyph->bitmap_top - size,
|
||||||
|
static_cast<int>(face->glyph->advance.x >> 6)
|
||||||
|
};
|
||||||
|
if (codepoint < glyphs.size()) {
|
||||||
|
glyphs[codepoint] = std::move(glyph);
|
||||||
|
} else {
|
||||||
|
glyphs.push_back(std::move(glyph));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
canvas.flipY();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void vector_fonts::initialize() {
|
||||||
|
if (FT_Error error = FT_Init_FreeType(&library)) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
"could not initialize freetype: " +
|
||||||
|
std::string(get_ft_error_message(error))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void vector_fonts::finalize() {
|
||||||
|
if (FT_Error error = FT_Done_FreeType(library)) {
|
||||||
|
logger.error() << "error on FT_Done_FreeType: "
|
||||||
|
<< get_ft_error_message(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<vector_fonts::FontFile> vector_fonts::load_font(
|
||||||
|
const std::string& filename
|
||||||
|
) {
|
||||||
|
auto bytes = io::read_bytes_buffer(io::path(filename));
|
||||||
|
|
||||||
|
FT_Face face;
|
||||||
|
|
||||||
|
if (FT_Error error =
|
||||||
|
FT_New_Memory_Face(library, bytes.data(), bytes.size(), 0, &face)) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
"could not load font '" + filename +
|
||||||
|
"': " + std::string(get_ft_error_message(error))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_shared<FTFontFile>(std::move(face), std::move(bytes));
|
||||||
|
}
|
||||||
28
src/coders/vector_fonts.hpp
Normal file
28
src/coders/vector_fonts.hpp
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class Font;
|
||||||
|
struct Glyph;
|
||||||
|
|
||||||
|
class Texture;
|
||||||
|
|
||||||
|
namespace vector_fonts {
|
||||||
|
class FontFile {
|
||||||
|
public:
|
||||||
|
virtual ~FontFile() {}
|
||||||
|
|
||||||
|
virtual std::unique_ptr<Font> createInstance(int size) = 0;
|
||||||
|
|
||||||
|
virtual std::unique_ptr<Texture> renderPage(
|
||||||
|
int pageid, std::vector<Glyph>& glyphs, int size
|
||||||
|
) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
void initialize();
|
||||||
|
void finalize();
|
||||||
|
|
||||||
|
std::shared_ptr<vector_fonts::FontFile> load_font(const std::string& filename);
|
||||||
|
}
|
||||||
|
|
@ -63,6 +63,10 @@ inline constexpr int TRANSLUCENT_BLOCKS_SORT_INTERVAL = 8;
|
||||||
|
|
||||||
inline constexpr int ATLAS_EXTRUSION = 2;
|
inline constexpr int ATLAS_EXTRUSION = 2;
|
||||||
|
|
||||||
|
inline constexpr int DEFAULT_FONT_SIZE = 16;
|
||||||
|
|
||||||
|
inline constexpr int DEFAULT_PRE_RENDER_FONT_PAGES = 1; // must be at least 1
|
||||||
|
|
||||||
inline const std::string SHADERS_FOLDER = "shaders";
|
inline const std::string SHADERS_FOLDER = "shaders";
|
||||||
inline const std::string TEXTURES_FOLDER = "textures";
|
inline const std::string TEXTURES_FOLDER = "textures";
|
||||||
inline const std::string FONTS_FOLDER = "fonts";
|
inline const std::string FONTS_FOLDER = "fonts";
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
#include "coders/commons.hpp"
|
#include "coders/commons.hpp"
|
||||||
#include "coders/GLSLExtension.hpp"
|
#include "coders/GLSLExtension.hpp"
|
||||||
#include "coders/toml.hpp"
|
#include "coders/toml.hpp"
|
||||||
|
#include "coders/vector_fonts.hpp"
|
||||||
#include "content/ContentControl.hpp"
|
#include "content/ContentControl.hpp"
|
||||||
#include "core_defs.hpp"
|
#include "core_defs.hpp"
|
||||||
#include "debug/Logger.hpp"
|
#include "debug/Logger.hpp"
|
||||||
|
|
@ -167,6 +168,8 @@ void Engine::initialize(CoreParameters coreParameters) {
|
||||||
settings.audio
|
settings.audio
|
||||||
);
|
);
|
||||||
|
|
||||||
|
vector_fonts::initialize();
|
||||||
|
|
||||||
if (settings.ui.language.get() == "auto") {
|
if (settings.ui.language.get() == "auto") {
|
||||||
settings.ui.language.set(
|
settings.ui.language.set(
|
||||||
langs::locale_by_envlocale(platform::detect_locale())
|
langs::locale_by_envlocale(platform::detect_locale())
|
||||||
|
|
@ -342,6 +345,9 @@ void Engine::close() {
|
||||||
gui.reset();
|
gui.reset();
|
||||||
logger.info() << "gui finished";
|
logger.info() << "gui finished";
|
||||||
}
|
}
|
||||||
|
if (!isHeadless()) {
|
||||||
|
vector_fonts::finalize();
|
||||||
|
}
|
||||||
audio::close();
|
audio::close();
|
||||||
debuggingServer.reset();
|
debuggingServer.reset();
|
||||||
network.reset();
|
network.reset();
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,31 @@
|
||||||
#include "Font.hpp"
|
#include "Font.hpp"
|
||||||
|
|
||||||
|
#include "Batch2D.hpp"
|
||||||
|
#include "Batch3D.hpp"
|
||||||
|
#include "coders/vector_fonts.hpp"
|
||||||
|
#include "Texture.hpp"
|
||||||
|
#include "window/Camera.hpp"
|
||||||
|
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include "Texture.hpp"
|
|
||||||
#include "Batch2D.hpp"
|
|
||||||
#include "Batch3D.hpp"
|
|
||||||
#include "window/Camera.hpp"
|
|
||||||
|
|
||||||
inline constexpr uint GLYPH_SIZE = 16;
|
inline constexpr uint GLYPH_SIZE = 16;
|
||||||
inline constexpr uint MAX_CODEPAGES = 10000; // idk ho many codepages unicode has
|
inline constexpr uint MAX_CODEPAGES = 10000; // idk ho many codepages unicode has
|
||||||
inline constexpr glm::vec4 SHADOW_TINT(0.0f, 0.0f, 0.0f, 1.0f);
|
inline constexpr glm::vec4 SHADOW_TINT(0.0f, 0.0f, 0.0f, 1.0f);
|
||||||
|
|
||||||
Font::Font(std::vector<std::unique_ptr<Texture>> pages, int lineHeight, int yoffset)
|
Font::Font(
|
||||||
: lineHeight(lineHeight), yoffset(yoffset), pages(std::move(pages)) {
|
std::vector<std::unique_ptr<Texture>> pages,
|
||||||
|
std::vector<Glyph> glyphs,
|
||||||
|
int lineHeight,
|
||||||
|
int yoffset,
|
||||||
|
std::optional<std::weak_ptr<vector_fonts::FontFile>> fontFile
|
||||||
|
)
|
||||||
|
: lineHeight(lineHeight),
|
||||||
|
yoffset(yoffset),
|
||||||
|
glyphInterval(lineHeight / 2),
|
||||||
|
pages(std::move(pages)),
|
||||||
|
glyphs(std::move(glyphs)),
|
||||||
|
fontFile(std::move(fontFile)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Font::~Font() = default;
|
Font::~Font() = default;
|
||||||
|
|
@ -39,7 +52,22 @@ bool Font::isPrintableChar(uint codepoint) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
int FontMetrics::calcWidth(std::wstring_view text, size_t offset, size_t length) const {
|
int FontMetrics::calcWidth(std::wstring_view text, size_t offset, size_t length) const {
|
||||||
return std::min(text.length() - offset, length) * glyphInterval;
|
auto font = this->font.has_value() ? this->font->lock() : nullptr;
|
||||||
|
if (font == nullptr) {
|
||||||
|
return std::min(text.length() - offset, length) * _glyphInterval;
|
||||||
|
}
|
||||||
|
int totalWidth = 0;
|
||||||
|
for (int i = offset; i < offset + length && i < text.length(); i++) {
|
||||||
|
auto codepoint = text[i];
|
||||||
|
if (!font->isPrintableChar(codepoint)) {
|
||||||
|
totalWidth += _glyphInterval;
|
||||||
|
} else if (auto glyph = font->getGlyph(codepoint)) {
|
||||||
|
totalWidth += glyph->xAdvance;
|
||||||
|
} else {
|
||||||
|
totalWidth += _glyphInterval;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return totalWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Font::calcWidth(std::wstring_view text, size_t length) const {
|
int Font::calcWidth(std::wstring_view text, size_t length) const {
|
||||||
|
|
@ -71,7 +99,7 @@ static inline void draw_glyph(
|
||||||
|
|
||||||
batch.sprite(
|
batch.sprite(
|
||||||
pos.x + (offset.x + i / (right.x/glyphInterval/2.0f)) * right.x,
|
pos.x + (offset.x + i / (right.x/glyphInterval/2.0f)) * right.x,
|
||||||
pos.y + offset.y * right.y,
|
pos.y + offset.y * up.y,
|
||||||
right.x / glyphInterval,
|
right.x / glyphInterval,
|
||||||
up.y,
|
up.y,
|
||||||
-0.15f * style.italic,
|
-0.15f * style.italic,
|
||||||
|
|
@ -100,7 +128,6 @@ static inline void draw_glyph(
|
||||||
} else {
|
} else {
|
||||||
color = style.color;
|
color = style.color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
batch.sprite(
|
batch.sprite(
|
||||||
pos + right * (offset.x + i) + up * offset.y,
|
pos + right * (offset.x + i) + up * offset.y,
|
||||||
|
|
@ -116,7 +143,7 @@ static inline void draw_glyph(
|
||||||
|
|
||||||
template <class Batch>
|
template <class Batch>
|
||||||
static inline void draw_text(
|
static inline void draw_text(
|
||||||
const Font& font,
|
Font& font,
|
||||||
Batch& batch,
|
Batch& batch,
|
||||||
std::wstring_view text,
|
std::wstring_view text,
|
||||||
const glm::vec3& pos,
|
const glm::vec3& pos,
|
||||||
|
|
@ -134,10 +161,12 @@ static inline void draw_text(
|
||||||
|
|
||||||
uint page = 0;
|
uint page = 0;
|
||||||
uint next = MAX_CODEPAGES;
|
uint next = MAX_CODEPAGES;
|
||||||
int x = 0;
|
float x = 0;
|
||||||
int y = 0;
|
int y = 0;
|
||||||
bool hasLines = false;
|
bool hasLines = false;
|
||||||
|
|
||||||
|
float baseAdvance = glm::length(right);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
for (size_t i = 0; i < text.length(); i++) {
|
for (size_t i = 0; i < text.length(); i++) {
|
||||||
uint c = text[i];
|
uint c = text[i];
|
||||||
|
|
@ -152,17 +181,23 @@ static inline void draw_text(
|
||||||
x++;
|
x++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
int yOffset = 0;
|
||||||
|
float advance = baseAdvance;
|
||||||
|
if (auto glyph = font.getGlyph(c)) {
|
||||||
|
yOffset = glyph->yOffset;
|
||||||
|
advance = glyph->xAdvance;
|
||||||
|
}
|
||||||
uint charpage = c >> 8;
|
uint charpage = c >> 8;
|
||||||
if (charpage == page){
|
if (charpage == page){
|
||||||
batch.texture(font.getPage(charpage));
|
batch.texture(font.getPage(charpage));
|
||||||
draw_glyph(
|
draw_glyph(
|
||||||
batch, pos, glm::vec2(x, y), c, right, up, interval, style
|
batch, pos, glm::vec2(x, y - yOffset / static_cast<float>(font.getLineHeight())), c, right, up, interval, style
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else if (charpage > page && charpage < next){
|
else if (charpage > page && charpage < next){
|
||||||
next = charpage;
|
next = charpage;
|
||||||
}
|
}
|
||||||
x++;
|
x += advance / baseAdvance;
|
||||||
}
|
}
|
||||||
page = next;
|
page = next;
|
||||||
next = MAX_CODEPAGES;
|
next = MAX_CODEPAGES;
|
||||||
|
|
@ -213,7 +248,7 @@ void Font::draw(
|
||||||
const FontStylesScheme* styles,
|
const FontStylesScheme* styles,
|
||||||
size_t styleMapOffset,
|
size_t styleMapOffset,
|
||||||
float scale
|
float scale
|
||||||
) const {
|
) {
|
||||||
draw_text(
|
draw_text(
|
||||||
*this, batch, text,
|
*this, batch, text,
|
||||||
glm::vec3(x, y, 0),
|
glm::vec3(x, y, 0),
|
||||||
|
|
@ -233,7 +268,7 @@ void Font::draw(
|
||||||
const glm::vec3& pos,
|
const glm::vec3& pos,
|
||||||
const glm::vec3& right,
|
const glm::vec3& right,
|
||||||
const glm::vec3& up
|
const glm::vec3& up
|
||||||
) const {
|
) {
|
||||||
draw_text(
|
draw_text(
|
||||||
*this, batch, text, pos,
|
*this, batch, text, pos,
|
||||||
right * static_cast<float>(glyphInterval),
|
right * static_cast<float>(glyphInterval),
|
||||||
|
|
@ -243,3 +278,50 @@ void Font::draw(
|
||||||
styleMapOffset
|
styleMapOffset
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Font> Font::createBitmapFont(
|
||||||
|
std::vector<std::unique_ptr<ImageData>> pages
|
||||||
|
) {
|
||||||
|
int res = pages.at(0)->getHeight() / 16;
|
||||||
|
std::vector<std::unique_ptr<Texture>> textures;
|
||||||
|
std::vector<Glyph> glyphs(textures.size() * 256);
|
||||||
|
for (auto& glyph : glyphs) {
|
||||||
|
glyph.yOffset = 0;
|
||||||
|
glyph.xAdvance = res / 2;
|
||||||
|
}
|
||||||
|
for (auto& page : pages) {
|
||||||
|
if (page == nullptr) {
|
||||||
|
textures.emplace_back(nullptr);
|
||||||
|
} else {
|
||||||
|
auto texture = Texture::from(page.get());
|
||||||
|
texture->setMipMapping(false, true);
|
||||||
|
textures.emplace_back(std::move(texture));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::make_unique<Font>(std::move(textures), std::move(glyphs), res, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Glyph* Font::getGlyph(int codepoint) {
|
||||||
|
if (codepoint < 0) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
if (codepoint < glyphs.size()) {
|
||||||
|
return &glyphs.at(codepoint);
|
||||||
|
}
|
||||||
|
if (!this->fontFile.has_value() || this->fontFile->expired()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
int codepage = codepoint >> 8;
|
||||||
|
if (codepage >= 1024) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
if (glyphs.size() < (codepage << 8)) {
|
||||||
|
glyphs.resize(codepage << 8);
|
||||||
|
}
|
||||||
|
auto fontFile = this->fontFile->lock();
|
||||||
|
if (pages.size() <= codepage) {
|
||||||
|
pages.resize(codepage);
|
||||||
|
}
|
||||||
|
pages.push_back(fontFile->renderPage(codepage, glyphs, lineHeight));
|
||||||
|
return &glyphs.at(codepoint);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <optional>
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
#include "typedefs.hpp"
|
#include "typedefs.hpp"
|
||||||
|
|
@ -14,14 +15,28 @@ class Texture;
|
||||||
class Batch2D;
|
class Batch2D;
|
||||||
class Batch3D;
|
class Batch3D;
|
||||||
class Camera;
|
class Camera;
|
||||||
|
class ImageData;
|
||||||
|
|
||||||
|
class Font;
|
||||||
|
|
||||||
|
namespace vector_fonts {
|
||||||
|
class FontFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Glyph {
|
||||||
|
int yOffset;
|
||||||
|
int xAdvance;
|
||||||
|
};
|
||||||
|
|
||||||
class Font {
|
class Font {
|
||||||
int lineHeight;
|
|
||||||
int yoffset;
|
|
||||||
int glyphInterval = 8;
|
|
||||||
std::vector<std::unique_ptr<Texture>> pages;
|
|
||||||
public:
|
public:
|
||||||
Font(std::vector<std::unique_ptr<Texture>> pages, int lineHeight, int yoffset);
|
Font(
|
||||||
|
std::vector<std::unique_ptr<Texture>> pages,
|
||||||
|
std::vector<Glyph> glyphs,
|
||||||
|
int lineHeight,
|
||||||
|
int yoffset,
|
||||||
|
std::optional<std::weak_ptr<vector_fonts::FontFile>> fontFile = std::nullopt
|
||||||
|
);
|
||||||
~Font();
|
~Font();
|
||||||
|
|
||||||
int getLineHeight() const;
|
int getLineHeight() const;
|
||||||
|
|
@ -52,7 +67,7 @@ public:
|
||||||
const FontStylesScheme* styles,
|
const FontStylesScheme* styles,
|
||||||
size_t styleMapOffset,
|
size_t styleMapOffset,
|
||||||
float scale = 1
|
float scale = 1
|
||||||
) const;
|
);
|
||||||
|
|
||||||
void draw(
|
void draw(
|
||||||
Batch3D& batch,
|
Batch3D& batch,
|
||||||
|
|
@ -62,11 +77,24 @@ public:
|
||||||
const glm::vec3& pos,
|
const glm::vec3& pos,
|
||||||
const glm::vec3& right={1, 0, 0},
|
const glm::vec3& right={1, 0, 0},
|
||||||
const glm::vec3& up={0, 1, 0}
|
const glm::vec3& up={0, 1, 0}
|
||||||
) const;
|
);
|
||||||
|
|
||||||
const Texture* getPage(int page) const;
|
const Texture* getPage(int page) const;
|
||||||
|
|
||||||
FontMetrics getMetrics() const {
|
FontMetrics getMetrics() const {
|
||||||
return {lineHeight, yoffset, glyphInterval};
|
return {std::nullopt, lineHeight, yoffset, glyphInterval};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Glyph* getGlyph(int codepoint);
|
||||||
|
|
||||||
|
static std::unique_ptr<Font> createBitmapFont(
|
||||||
|
std::vector<std::unique_ptr<ImageData>> pages
|
||||||
|
);
|
||||||
|
private:
|
||||||
|
int lineHeight;
|
||||||
|
int yoffset;
|
||||||
|
int glyphInterval;
|
||||||
|
std::vector<std::unique_ptr<Texture>> pages;
|
||||||
|
std::vector<Glyph> glyphs;
|
||||||
|
std::optional<std::weak_ptr<vector_fonts::FontFile>> fontFile;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,19 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
class Font;
|
||||||
|
|
||||||
struct FontMetrics {
|
struct FontMetrics {
|
||||||
|
std::optional<std::weak_ptr<Font>> font;
|
||||||
|
|
||||||
int lineHeight;
|
int lineHeight;
|
||||||
int yoffset;
|
int yoffset;
|
||||||
int glyphInterval = 8;
|
int _glyphInterval = 8;
|
||||||
|
|
||||||
|
~FontMetrics();
|
||||||
|
|
||||||
int calcWidth(std::wstring_view text, size_t offset=0, size_t length=-1) const;
|
int calcWidth(std::wstring_view text, size_t offset=0, size_t length=-1) const;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
5
src/graphics/core/FontMetrics.cpp
Normal file
5
src/graphics/core/FontMetrics.cpp
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
#include "FontMetics.hpp"
|
||||||
|
|
||||||
|
#include "Font.hpp"
|
||||||
|
|
||||||
|
FontMetrics::~FontMetrics() = default;
|
||||||
|
|
@ -45,7 +45,7 @@ void TextsRenderer::renderNote(
|
||||||
}
|
}
|
||||||
opacity = preset.xrayOpacity;
|
opacity = preset.xrayOpacity;
|
||||||
}
|
}
|
||||||
const auto& font = assets.require<Font>(FONT_DEFAULT);
|
auto& font = assets.require<Font>(FONT_DEFAULT);
|
||||||
|
|
||||||
glm::vec3 xvec = note.getAxisX();
|
glm::vec3 xvec = note.getAxisX();
|
||||||
glm::vec3 yvec = note.getAxisY();
|
glm::vec3 yvec = note.getAxisY();
|
||||||
|
|
|
||||||
|
|
@ -91,6 +91,10 @@ void Button::setTextAlign(Align align) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Label> Button::getLabel() const {
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
Align Button::getTextAlign() const {
|
Align Button::getTextAlign() const {
|
||||||
if (label) {
|
if (label) {
|
||||||
return label->getAlign();
|
return label->getAlign();
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,8 @@ namespace gui {
|
||||||
virtual Align getTextAlign() const;
|
virtual Align getTextAlign() const;
|
||||||
virtual void setTextAlign(Align align);
|
virtual void setTextAlign(Align align);
|
||||||
|
|
||||||
|
std::shared_ptr<Label> getLabel() const;
|
||||||
|
|
||||||
virtual void setText(std::wstring text);
|
virtual void setText(std::wstring text);
|
||||||
virtual std::wstring getText() const;
|
virtual std::wstring getText() const;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,3 +38,7 @@ void InputBindBox::keyPressed(Keycode key) {
|
||||||
}
|
}
|
||||||
defocus();
|
defocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Label> InputBindBox::getLabel() const {
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,5 +24,7 @@ namespace gui {
|
||||||
bool isFocuskeeper() const override {
|
bool isFocuskeeper() const override {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Label> getLabel() const;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -276,13 +276,13 @@ void SlotView::draw(const DrawContext& pctx, const Assets& assets) {
|
||||||
drawItemIcon(batch, stack, item, assets, tint, pos);
|
drawItemIcon(batch, stack, item, assets, tint, pos);
|
||||||
|
|
||||||
if (stack.getCount() > 1 || stack.getFields() != nullptr) {
|
if (stack.getCount() > 1 || stack.getFields() != nullptr) {
|
||||||
const auto& font = assets.require<Font>(FONT_DEFAULT);
|
auto& font = assets.require<Font>(FONT_DEFAULT);
|
||||||
drawItemInfo(batch, stack, item, font, pos);
|
drawItemInfo(batch, stack, item, font, pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void draw_shaded_text(
|
static void draw_shaded_text(
|
||||||
Batch2D& batch, const Font& font, const std::wstring& text, int x, int y
|
Batch2D& batch, Font& font, const std::wstring& text, int x, int y
|
||||||
) {
|
) {
|
||||||
batch.setColor({0, 0, 0, 1.0f});
|
batch.setColor({0, 0, 0, 1.0f});
|
||||||
font.draw(batch, text, x + 1, y + 1, nullptr, 0);
|
font.draw(batch, text, x + 1, y + 1, nullptr, 0);
|
||||||
|
|
@ -294,7 +294,7 @@ void SlotView::drawItemInfo(
|
||||||
Batch2D& batch,
|
Batch2D& batch,
|
||||||
const ItemStack& stack,
|
const ItemStack& stack,
|
||||||
const ItemDef& item,
|
const ItemDef& item,
|
||||||
const Font& font,
|
Font& font,
|
||||||
const glm::vec2& pos
|
const glm::vec2& pos
|
||||||
) {
|
) {
|
||||||
const int SLOT_SIZE = InventoryView::SLOT_SIZE;
|
const int SLOT_SIZE = InventoryView::SLOT_SIZE;
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@ namespace gui {
|
||||||
Batch2D& batch,
|
Batch2D& batch,
|
||||||
const ItemStack& stack,
|
const ItemStack& stack,
|
||||||
const ItemDef& item,
|
const ItemDef& item,
|
||||||
const Font& font,
|
Font& font,
|
||||||
const glm::vec2& pos
|
const glm::vec2& pos
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,11 +11,11 @@
|
||||||
|
|
||||||
using namespace gui;
|
using namespace gui;
|
||||||
|
|
||||||
void LabelCache::prepare(std::ptrdiff_t fontId, FontMetrics metrics, size_t wrapWidth) {
|
void LabelCache::prepare(const std::shared_ptr<Font>& font, FontMetrics metrics, size_t wrapWidth) {
|
||||||
if (fontId != this->fontId) {
|
if (!this->metrics.font.has_value() || font.get() != this->metrics.font.value().lock().get()) {
|
||||||
resetFlag = true;
|
resetFlag = true;
|
||||||
this->fontId = fontId;
|
|
||||||
this->metrics = metrics;
|
this->metrics = metrics;
|
||||||
|
this->metrics.font = font;
|
||||||
}
|
}
|
||||||
if (wrapWidth != this->wrapWidth) {
|
if (wrapWidth != this->wrapWidth) {
|
||||||
resetFlag = true;
|
resetFlag = true;
|
||||||
|
|
@ -42,7 +42,8 @@ void LabelCache::update(std::wstring_view text, bool multiline, bool wrap) {
|
||||||
lines.clear();
|
lines.clear();
|
||||||
lines.push_back(LineScheme {0, false});
|
lines.push_back(LineScheme {0, false});
|
||||||
|
|
||||||
if (fontId == 0) {
|
auto font = metrics.font.has_value() ? metrics.font.value().lock() : nullptr;
|
||||||
|
if (font == nullptr) {
|
||||||
wrap = false;
|
wrap = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -61,26 +62,27 @@ void LabelCache::update(std::wstring_view text, bool multiline, bool wrap) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (fontId != 0) {
|
if (font == nullptr) {
|
||||||
int maxWidth = 0;
|
return;
|
||||||
for (int i = 0; i < lines.size() - 1; i++) {
|
}
|
||||||
const auto& next = lines[i + 1];
|
int maxWidth = 0;
|
||||||
const auto& cur = lines[i];
|
for (int i = 0; i < lines.size() - 1; i++) {
|
||||||
maxWidth = std::max(
|
const auto& next = lines[i + 1];
|
||||||
metrics.calcWidth(
|
const auto& cur = lines[i];
|
||||||
text.substr(cur.offset, next.offset - cur.offset)
|
|
||||||
),
|
|
||||||
maxWidth
|
|
||||||
);
|
|
||||||
}
|
|
||||||
maxWidth = std::max(
|
maxWidth = std::max(
|
||||||
metrics.calcWidth(
|
metrics.calcWidth(
|
||||||
text.substr(lines[lines.size() - 1].offset)
|
text.substr(cur.offset, next.offset - cur.offset)
|
||||||
),
|
),
|
||||||
maxWidth
|
maxWidth
|
||||||
);
|
);
|
||||||
multilineWidth = maxWidth;
|
|
||||||
}
|
}
|
||||||
|
maxWidth = std::max(
|
||||||
|
metrics.calcWidth(
|
||||||
|
text.substr(lines[lines.size() - 1].offset)
|
||||||
|
),
|
||||||
|
maxWidth
|
||||||
|
);
|
||||||
|
multilineWidth = maxWidth;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -136,7 +138,7 @@ void Label::setText(std::wstring text) {
|
||||||
this->text = std::move(text);
|
this->text = std::move(text);
|
||||||
cache.update(this->text, multiline, textWrap);
|
cache.update(this->text, multiline, textWrap);
|
||||||
|
|
||||||
if (cache.fontId != 0 && autoresize) {
|
if (cache.metrics.font.has_value() && !cache.metrics.font->expired() && autoresize) {
|
||||||
setSize(calcSize());
|
setSize(calcSize());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -203,9 +205,9 @@ uint Label::getLinesNumber() const {
|
||||||
|
|
||||||
void Label::draw(const DrawContext& pctx, const Assets& assets) {
|
void Label::draw(const DrawContext& pctx, const Assets& assets) {
|
||||||
auto batch = pctx.getBatch2D();
|
auto batch = pctx.getBatch2D();
|
||||||
auto font = assets.get<Font>(fontName);
|
auto font = assets.getShared<Font>(fontName);
|
||||||
cache.prepare(
|
cache.prepare(
|
||||||
reinterpret_cast<ptrdiff_t>(font),
|
font,
|
||||||
font->getMetrics(),
|
font->getMetrics(),
|
||||||
static_cast<size_t>(glm::abs(getSize().x))
|
static_cast<size_t>(glm::abs(getSize().x))
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@ namespace gui {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LabelCache {
|
struct LabelCache {
|
||||||
ptrdiff_t fontId = 0;
|
|
||||||
FontMetrics metrics;
|
FontMetrics metrics;
|
||||||
|
|
||||||
std::vector<LineScheme> lines;
|
std::vector<LineScheme> lines;
|
||||||
|
|
@ -24,7 +23,7 @@ namespace gui {
|
||||||
size_t wrapWidth = -1;
|
size_t wrapWidth = -1;
|
||||||
int multilineWidth = 0;
|
int multilineWidth = 0;
|
||||||
|
|
||||||
void prepare(std::ptrdiff_t fontId, FontMetrics metrics, size_t wrapWidth);
|
void prepare(const std::shared_ptr<Font>& font, FontMetrics metrics, size_t wrapWidth);
|
||||||
void update(std::wstring_view text, bool multiline, bool wrap);
|
void update(std::wstring_view text, bool multiline, bool wrap);
|
||||||
|
|
||||||
size_t getTextLineOffset(size_t line) const;
|
size_t getTextLineOffset(size_t line) const;
|
||||||
|
|
|
||||||
|
|
@ -86,3 +86,7 @@ void SelectBox::drawBackground(const DrawContext& pctx, const Assets&) {
|
||||||
pos.y + size.y / 2.0f + heightHalf
|
pos.y + size.y / 2.0f + heightHalf
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Label> SelectBox::getLabel() const {
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,5 +35,7 @@ namespace gui {
|
||||||
void setOptions(std::vector<Option>&& options);
|
void setOptions(std::vector<Option>&& options);
|
||||||
|
|
||||||
void drawBackground(const DrawContext& pctx, const Assets&) override;
|
void drawBackground(const DrawContext& pctx, const Assets&) override;
|
||||||
|
|
||||||
|
std::shared_ptr<Label> getLabel() const;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -252,10 +252,12 @@ void TextBox::draw(const DrawContext& pctx, const Assets& assets) {
|
||||||
|
|
||||||
float time = gui.getWindow().time();
|
float time = gui.getWindow().time();
|
||||||
|
|
||||||
|
// drawing caret here
|
||||||
if (isFocused() && editable && static_cast<int>((time - caretLastMove) * 2) % 2 == 0) {
|
if (isFocused() && editable && static_cast<int>((time - caretLastMove) * 2) % 2 == 0) {
|
||||||
uint line = label->getLineByTextIndex(caret);
|
uint line = label->getLineByTextIndex(caret);
|
||||||
|
auto linestart = label->getTextLineOffset(line);
|
||||||
uint lcaret = caret - label->getTextLineOffset(line);
|
uint lcaret = caret - label->getTextLineOffset(line);
|
||||||
int width = rawTextCache.metrics.calcWidth(input, 0, lcaret);
|
int width = rawTextCache.metrics.calcWidth(input.substr(linestart), 0, lcaret);
|
||||||
|
|
||||||
batch->rect(
|
batch->rect(
|
||||||
lcoord.x + width,
|
lcoord.x + width,
|
||||||
|
|
@ -264,6 +266,7 @@ void TextBox::draw(const DrawContext& pctx, const Assets& assets) {
|
||||||
lineHeight
|
lineHeight
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
// drawing selection
|
||||||
if (selectionStart != selectionEnd) {
|
if (selectionStart != selectionEnd) {
|
||||||
auto selectionCtx = subctx.sub(batch);
|
auto selectionCtx = subctx.sub(batch);
|
||||||
selectionCtx.setBlendMode(BlendMode::addition);
|
selectionCtx.setBlendMode(BlendMode::addition);
|
||||||
|
|
@ -349,12 +352,8 @@ void TextBox::draw(const DrawContext& pctx, const Assets& assets) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextBox::drawBackground(const DrawContext& pctx, const Assets& assets) {
|
void TextBox::drawBackground(const DrawContext& pctx, const Assets& assets) {
|
||||||
auto font = assets.get<Font>(label->getFontName());
|
auto font = assets.getShared<Font>(label->getFontName());
|
||||||
rawTextCache.prepare(
|
rawTextCache.prepare(font, font->getMetrics(), label->getSize().x);
|
||||||
reinterpret_cast<ptrdiff_t>(font),
|
|
||||||
font->getMetrics(),
|
|
||||||
label->getSize().x
|
|
||||||
);
|
|
||||||
|
|
||||||
glm::vec2 pos = calcPos();
|
glm::vec2 pos = calcPos();
|
||||||
|
|
||||||
|
|
@ -384,8 +383,11 @@ void TextBox::drawBackground(const DrawContext& pctx, const Assets& assets) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextBox::refreshLabel() {
|
void TextBox::refreshLabel() {
|
||||||
|
if (!rawTextCache.metrics.font.has_value()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
rawTextCache.prepare(
|
rawTextCache.prepare(
|
||||||
rawTextCache.fontId,
|
rawTextCache.metrics.font.value().lock(),
|
||||||
rawTextCache.metrics,
|
rawTextCache.metrics,
|
||||||
static_cast<size_t>(getSize().x)
|
static_cast<size_t>(getSize().x)
|
||||||
);
|
);
|
||||||
|
|
@ -425,7 +427,7 @@ void TextBox::refreshLabel() {
|
||||||
lineNumbersLabel->setColor(glm::vec4(1, 1, 1, 0.25f));
|
lineNumbersLabel->setColor(glm::vec4(1, 1, 1, 0.25f));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (autoresize && rawTextCache.fontId) {
|
if (autoresize) {
|
||||||
auto size = getSize();
|
auto size = getSize();
|
||||||
int newy = glm::min(
|
int newy = glm::min(
|
||||||
static_cast<int>(parent->getSize().y),
|
static_cast<int>(parent->getSize().y),
|
||||||
|
|
@ -443,7 +445,7 @@ void TextBox::refreshLabel() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (multiline && rawTextCache.fontId) {
|
if (multiline) {
|
||||||
setScrollable(true);
|
setScrollable(true);
|
||||||
uint height = label->getLinesNumber() * rawTextCache.metrics.lineHeight *
|
uint height = label->getLinesNumber() * rawTextCache.metrics.lineHeight *
|
||||||
label->getLineInterval();
|
label->getLineInterval();
|
||||||
|
|
@ -665,7 +667,7 @@ size_t TextBox::normalizeIndex(int index) {
|
||||||
/// @param y screen Y position
|
/// @param y screen Y position
|
||||||
/// @return non-normalized character index
|
/// @return non-normalized character index
|
||||||
int TextBox::calcIndexAt(int x, int y) const {
|
int TextBox::calcIndexAt(int x, int y) const {
|
||||||
if (rawTextCache.fontId == 0) return 0;
|
if (!rawTextCache.metrics.font.has_value()) return 0;
|
||||||
const auto& labelText = label->getText();
|
const auto& labelText = label->getText();
|
||||||
glm::vec2 lcoord = label->calcPos();
|
glm::vec2 lcoord = label->calcPos();
|
||||||
uint line = label->getLineByYOffset(y - lcoord.y);
|
uint line = label->getLineByYOffset(y - lcoord.y);
|
||||||
|
|
@ -682,7 +684,7 @@ int TextBox::calcIndexAt(int x, int y) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
int TextBox::getLineYOffset(int line) const {
|
int TextBox::getLineYOffset(int line) const {
|
||||||
if (rawTextCache.fontId == 0) return 0;
|
if (!rawTextCache.metrics.font.has_value()) return 0;
|
||||||
return label->getLineYOffset(line);
|
return label->getLineYOffset(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1205,12 +1207,16 @@ size_t TextBox::getCaret() const {
|
||||||
void TextBox::setCaret(size_t position) {
|
void TextBox::setCaret(size_t position) {
|
||||||
const auto& labelText = label->getText();
|
const auto& labelText = label->getText();
|
||||||
caret = std::min(static_cast<size_t>(position), input.length());
|
caret = std::min(static_cast<size_t>(position), input.length());
|
||||||
if (rawTextCache.fontId == 0) {
|
|
||||||
|
auto font = rawTextCache.metrics.font.has_value()
|
||||||
|
? rawTextCache.metrics.font->lock()
|
||||||
|
: nullptr;
|
||||||
|
if (font == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int width = label->getSize().x;
|
int width = label->getSize().x;
|
||||||
|
|
||||||
rawTextCache.prepare(rawTextCache.fontId, rawTextCache.metrics, width);
|
rawTextCache.prepare(font, rawTextCache.metrics, width);
|
||||||
rawTextCache.update(input, multiline, label->isTextWrapping());
|
rawTextCache.update(input, multiline, label->isTextWrapping());
|
||||||
|
|
||||||
caretLastMove = gui.getWindow().time();
|
caretLastMove = gui.getWindow().time();
|
||||||
|
|
@ -1283,3 +1289,7 @@ void TextBox::setMarkup(std::string_view lang) {
|
||||||
const std::string& TextBox::getMarkup() const {
|
const std::string& TextBox::getMarkup() const {
|
||||||
return markup;
|
return markup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Label> TextBox::getLabel() const {
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -255,5 +255,7 @@ namespace gui {
|
||||||
|
|
||||||
virtual void setMarkup(std::string_view lang);
|
virtual void setMarkup(std::string_view lang);
|
||||||
virtual const std::string& getMarkup() const;
|
virtual const std::string& getMarkup() const;
|
||||||
|
|
||||||
|
std::shared_ptr<Label> getLabel() const;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -309,6 +309,9 @@ static std::shared_ptr<UINode> read_label(
|
||||||
std::wstring text = parse_inner_text(element, reader.getContext());
|
std::wstring text = parse_inner_text(element, reader.getContext());
|
||||||
auto label = std::make_shared<Label>(reader.getGUI(), text);
|
auto label = std::make_shared<Label>(reader.getGUI(), text);
|
||||||
read_uinode(reader, element, *label);
|
read_uinode(reader, element, *label);
|
||||||
|
if (element.has("font")) {
|
||||||
|
label->setFontName(element.attr("font").getText());
|
||||||
|
}
|
||||||
if (element.has("text-align")) {
|
if (element.has("text-align")) {
|
||||||
label->setAlign(align_from_string(
|
label->setAlign(align_from_string(
|
||||||
element.attr("text-align").getText(), label->getAlign()
|
element.attr("text-align").getText(), label->getAlign()
|
||||||
|
|
@ -428,6 +431,12 @@ static std::shared_ptr<UINode> read_button(
|
||||||
element.attr("text-align").getText(), button->getTextAlign()
|
element.attr("text-align").getText(), button->getTextAlign()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
if (element.has("font")) {
|
||||||
|
if (auto label = button->getLabel()) {
|
||||||
|
label->setFontName(element.attr("font").getText());
|
||||||
|
button->setMustRefresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
return button;
|
return button;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -489,6 +498,12 @@ static std::shared_ptr<UINode> read_select(
|
||||||
GUI&, const std::string& value
|
GUI&, const std::string& value
|
||||||
) { callback(value); });
|
) { callback(value); });
|
||||||
}
|
}
|
||||||
|
if (element.has("font")) {
|
||||||
|
if (auto label = selectBox->getLabel()) {
|
||||||
|
label->setFontName(element.attr("font").getText());
|
||||||
|
selectBox->setMustRefresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
read_panel_impl(reader, element, *selectBox, false);
|
read_panel_impl(reader, element, *selectBox, false);
|
||||||
return selectBox;
|
return selectBox;
|
||||||
}
|
}
|
||||||
|
|
@ -625,6 +640,12 @@ static std::shared_ptr<UINode> read_text_box(
|
||||||
if (auto onDownPressed = create_runnable(reader, element, "ondown")) {
|
if (auto onDownPressed = create_runnable(reader, element, "ondown")) {
|
||||||
textbox->setOnDownPressed(onDownPressed);
|
textbox->setOnDownPressed(onDownPressed);
|
||||||
}
|
}
|
||||||
|
if (element.has("font")) {
|
||||||
|
if (auto label = textbox->getLabel()) {
|
||||||
|
label->setFontName(element.attr("font").getText());
|
||||||
|
textbox->setMustRefresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
return textbox;
|
return textbox;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -703,6 +724,12 @@ static std::shared_ptr<UINode> read_input_bind_box(
|
||||||
glm::vec4 padding = element.attr("padding", "6").asVec4();
|
glm::vec4 padding = element.attr("padding", "6").asVec4();
|
||||||
auto bindbox =
|
auto bindbox =
|
||||||
std::make_shared<InputBindBox>(reader.getGUI(), found, padding);
|
std::make_shared<InputBindBox>(reader.getGUI(), found, padding);
|
||||||
|
if (element.has("font")) {
|
||||||
|
if (auto label = bindbox->getLabel()) {
|
||||||
|
label->setFontName(element.attr("font").getText());
|
||||||
|
bindbox->setMustRefresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
read_panel_impl(reader, element, *bindbox);
|
read_panel_impl(reader, element, *bindbox);
|
||||||
return bindbox;
|
return bindbox;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@
|
||||||
"libvorbis",
|
"libvorbis",
|
||||||
"entt",
|
"entt",
|
||||||
"gtest",
|
"gtest",
|
||||||
"curl"
|
"curl",
|
||||||
|
"freetype"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue