Skip to content

Commit

Permalink
feat(ui): add UI text rendering
Browse files Browse the repository at this point in the history
  • Loading branch information
mkuritsu committed Nov 21, 2024
1 parent b5a299b commit 5296e35
Show file tree
Hide file tree
Showing 29 changed files with 929 additions and 52 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Allow identifying assets in code from their path (#1177. **@GalaxyCrush**).
- Added an Audio asset (#230, **@Dageus**, **@diogomsmiranda**).
- Hold function for debug_camera (#1030, **@jdbaracho**).
- Added UIText component (#1300, **@mkuritsu**)

### Changed

Expand Down
1 change: 1 addition & 0 deletions core/include/cubos/core/gl/render_device.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@ namespace cubos::core::gl
R32Float, ///< 1 channel 32 bits floating point.
RG16Float, ///< 2 channel 16 bits floating point.
RG32Float, ///< 2 channel 32 bits floating point.
RGB8UInt, ///< 3 channel 8 bits unsigned integer.
RGB16Float, ///< 3 channel 16 bits floating point.
RGB32Float, ///< 3 channel 32 bits floating point.
RGBA16Float, ///< 4 channel 16 bits floating point.
Expand Down
5 changes: 5 additions & 0 deletions core/src/gl/ogl_render_device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ static bool textureFormatToGL(TextureFormat texFormat, GLenum& internalFormat, G
{
switch (texFormat)
{
case TextureFormat::RGB8UInt:
internalFormat = GL_RGB;
format = GL_RGB;
type = GL_UNSIGNED_BYTE;
break;
case TextureFormat::R8UNorm:
internalFormat = GL_R8;
format = GL_RED;
Expand Down
24 changes: 24 additions & 0 deletions engine/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# engine/CMakeLists.txt
# Cubos engine build configuration

include(FetchContent)

option(BUILD_ENGINE_SAMPLES "Build cubos engine samples" OFF)
option(BUILD_ENGINE_TESTS "Build cubos engine tests?" OFF)
option(BUILD_ENGINE_SHARED "Build cubos engine as shared library?" ON)
Expand Down Expand Up @@ -113,10 +115,19 @@ set(CUBOS_ENGINE_SOURCE
"src/ui/color_rect/color_rect.cpp"
"src/ui/image/plugin.cpp"
"src/ui/image/image.cpp"
"src/ui/text/plugin.cpp"
"src/ui/text/text_stretch.cpp"
"src/ui/text/text.cpp"

"src/fixed_step/plugin.cpp"
"src/fixed_step/fixed_delta_time.cpp"

"src/font/plugin.cpp"
"src/font/font.cpp"
"src/font/bridge.cpp"
"src/font/atlas.cpp"
"src/font/atlas_store.cpp"

"src/render/defaults/plugin.cpp"
"src/render/defaults/target.cpp"
"src/render/shader/plugin.cpp"
Expand Down Expand Up @@ -237,6 +248,19 @@ add_library(stb_image INTERFACE)
target_include_directories(stb_image SYSTEM INTERFACE "lib/stb_image")
target_link_libraries(cubos-engine PUBLIC stb_image)

set(MSDF_ATLAS_USE_VCPKG OFF)
set(MSDF_ATLAS_USE_SKIA OFF)
FetchContent_Declare(msdf-atlas-gen
GIT_REPOSITORY "https://github.com/Chlumsky/msdf-atlas-gen.git"
)
FetchContent_MakeAvailable(msdf-atlas-gen)
set_property(TARGET msdf-atlas-gen PROPERTY POSITION_INDEPENDENT_CODE ON)
set_property(TARGET msdfgen-core PROPERTY POSITION_INDEPENDENT_CODE ON)
# Throwing some compile erros without these
target_compile_options(msdf-atlas-gen PUBLIC "-Wno-float-conversion" "-Wno-unneeded-internal-declaration" "-Wno-unused-function" "-Wno-sign-conversion")
target_link_libraries(cubos-engine PUBLIC msdf-atlas-gen)
target_include_directories(cubos-engine PUBLIC ${msdf-atlas-gen_SOURCE_DIR})

# Add engine tests
if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME AND BUILD_ENGINE_TESTS)
add_subdirectory(tests)
Expand Down
Binary file added engine/assets/font/Roboto-Regular.ttf
Binary file not shown.
3 changes: 3 additions & 0 deletions engine/assets/font/Roboto-Regular.ttf.meta
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"id": "93cbe82e-9c9b-4c25-aa55-5105c1afd0cc"
}
38 changes: 38 additions & 0 deletions engine/assets/ui/text.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#version 330 core

in vec2 texCoord;
out vec4 out_color;
uniform sampler2D fontAtlas;

const float pxRange = 4.0;

layout(std140) uniform PerElement
{
vec2 xRange;
vec2 yRange;
vec4 color;
int depth;
};

float screenPxRange()
{
vec2 unitRange = vec2(pxRange) / vec2(textureSize(fontAtlas, 0));
vec2 screenTexSize = vec2(1.0) / fwidth(texCoord);
return max(0.5 * dot(unitRange, screenTexSize), 1.0);
}

float median(float r, float g, float b)
{
return max(min(r, g), min(max(r, g), b));
}

void main()
{
vec3 msd = texture(fontAtlas, texCoord).rgb;
float sd = median(msd.r, msd.g, msd.b);
float screenPxDistance = screenPxRange() * (sd - 0.5);
float opacity = clamp(screenPxDistance + 0.5, 0.0, 1.0);
if (opacity == 0.0)
discard;
out_color = mix(vec4(0.0), color, opacity);
}
3 changes: 3 additions & 0 deletions engine/assets/ui/text.fs.meta
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"id": "b5b43fcb-0ec3-4f3a-9e90-a7b0b9978cc5"
}
25 changes: 25 additions & 0 deletions engine/assets/ui/text_element.vs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#version 330 core

in vec2 in_position;
in vec2 in_texCoord;

layout(std140) uniform PerElement
{
vec2 xRange;
vec2 yRange;
vec4 color;
int depth;
};

out vec2 texCoord;

uniform MVP
{
mat4 mvp;
};

void main()
{
gl_Position = mvp * (vec4(xRange.x, yRange.x, 0, 0) + vec4(in_position, depth, 1));
texCoord = in_texCoord;
}
3 changes: 3 additions & 0 deletions engine/assets/ui/text_element.vs.meta
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"id": "51c11c57-c819-4a51-806c-853178ec686a"
}
37 changes: 37 additions & 0 deletions engine/include/cubos/engine/font/atlas.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/// @file
/// @brief Struct @ref cubos::engine::FontAtlas.
/// @ingroup font-plugin

#pragma once

#include <unordered_map>

#include <msdf-atlas-gen/msdf-atlas-gen.h>

#include <cubos/core/gl/render_device.hpp>
#include <cubos/core/reflection/reflect.hpp>

#include <cubos/engine/api.hpp>

namespace cubos::engine
{
/// @brief Struct that holds all the necessay data about a font atlas.
///
/// @ingroup font-plugin
struct CUBOS_ENGINE_API FontAtlas
{
CUBOS_REFLECT;

/// @brief The created gpu texture for this font atlas.
cubos::core::gl::Texture2D texture;

/// @brief Map from unicode characters to their respective glyph geometry data.
std::unordered_map<msdf_atlas::unicode_t, msdf_atlas::GlyphGeometry> glyphs;

/// @brief Information about the bitmap used to generate the texture.
msdfgen::BitmapConstRef<msdfgen::byte, 3> bitmap;

FontAtlas(msdfgen::FontHandle* font, core::gl::RenderDevice& rd);
};

} // namespace cubos::engine
37 changes: 37 additions & 0 deletions engine/include/cubos/engine/font/atlas_store.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/// @file
/// @brief Resource @ref cubos::engine::FontAtlasStore.
/// @ingroup font-plugin

#pragma once

#include <memory>
#include <unordered_map>

#include <uuid.h>

#include <cubos/core/reflection/reflect.hpp>

#include <cubos/engine/api.hpp>
#include <cubos/engine/font/atlas.hpp>

namespace cubos::engine
{
struct CUBOS_ENGINE_API FontAtlasStore
{
CUBOS_REFLECT;

std::weak_ptr<FontAtlas> retrieve(const uuids::uuid& assetId);

bool contains(const uuids::uuid& assetId) const;

void store(const uuids::uuid& assetId, const std::shared_ptr<FontAtlas>& atlas);

void remove(const uuids::uuid& assetId);

const std::unordered_map<uuids::uuid, std::weak_ptr<FontAtlas>>& map() const;

private:
std::unordered_map<uuids::uuid, std::weak_ptr<FontAtlas>> mAtlas;
};

} // namespace cubos::engine
33 changes: 33 additions & 0 deletions engine/include/cubos/engine/font/bridge.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/// @file
/// @brief Class @ref cubos::engine::FontBridge.
/// @ingroup font-plugin

#pragma once

#include <cubos/engine/assets/bridges/file.hpp>
#include <cubos/engine/font/font.hpp>

namespace cubos::engine
{
/// @brief Bridge which loads and saves @ref Font assets.
///
/// @ingroup font-plugin
class CUBOS_ENGINE_API FontBridge : public FileBridge
{
public:
FontBridge()
: FileBridge(core::reflection::reflect<Font>())
, mFtHandle(msdfgen::initializeFreetype())
{
}

~FontBridge() override;

protected:
bool loadFromFile(Assets& assets, const AnyAsset& handle, core::memory::Stream& stream) override;
bool saveToFile(const Assets& assets, const AnyAsset& handle, core::memory::Stream& stream) override;

private:
msdfgen::FreetypeHandle* mFtHandle;
};
} // namespace cubos::engine
30 changes: 30 additions & 0 deletions engine/include/cubos/engine/font/font.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/// @file
/// @brief Struct @ref cubos::engine::Font.
/// @ingroup font-plugin

#pragma once

#include <msdf-atlas-gen/msdf-atlas-gen.h>

#include <cubos/core/memory/stream.hpp>
#include <cubos/core/reflection/reflect.hpp>

#include <cubos/engine/api.hpp>

namespace cubos::engine
{
/// @brief Asset containing font data.
///
/// @ingroup font-plugin
struct CUBOS_ENGINE_API Font
{
CUBOS_REFLECT;

/// @brief The handle to the loaded font.
msdfgen::FontHandle* fontHandle{nullptr};

explicit Font(msdfgen::FreetypeHandle* ft, core::memory::Stream& stream);
Font(Font&& other) noexcept;
~Font();
};
} // namespace cubos::engine
28 changes: 28 additions & 0 deletions engine/include/cubos/engine/font/plugin.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/// @dir
/// @brief @ref font-plugin plugin directory.

/// @file
/// @brief Plugin entry point.
/// @ingroup font-plugin

#pragma once

#include <cubos/engine/prelude.hpp>

namespace cubos::engine
{
/// @defgroup font-plugin Font
/// @ingroup engine
/// @brief Adds fonts to @b Cubos using msdfgen.
///
/// ## Bridges
/// - @ref FontBridge - loads @ref Font assets.
///
/// ## Dependencies
/// - @ref assets-plugin

/// @brief Plugin entry function.
/// @param cubos @b Cubos main class.
/// @ingroup font-plugin
CUBOS_ENGINE_API void fontPlugin(Cubos& cubos);
} // namespace cubos::engine
23 changes: 23 additions & 0 deletions engine/include/cubos/engine/ui/text/plugin.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/// @dir
/// @brief @ref ui-text-plugin plugin directory.

/// @file
/// @brief Plugin entry point.
/// @ingroup ui-text-plugin

#pragma once

#include <cubos/engine/prelude.hpp>

namespace cubos::engine
{
/// @defgroup ui-text-plugin
/// @ingroup ui-plugins
/// @brief Adds text element to UI.

/// @brief Plugin entry function.
/// @param cubos @b Cubos main class
/// @ingroup ui-text-plugin
CUBOS_ENGINE_API void uiTextPlugin(Cubos& cubos);

} // namespace cubos::engine
Loading

0 comments on commit 5296e35

Please sign in to comment.