Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
9d58c8c
rework text instance and type setting
Tehsapper Jun 7, 2025
fb68f8a
implement font stack support
Tehsapper Jun 9, 2025
d0501be
fix text selection
Tehsapper Jun 9, 2025
995a7e7
add support for CJK variant selection in text format
Tehsapper Jun 11, 2025
68f5b78
implement line spacing modifier
Tehsapper Jun 11, 2025
33094d6
fix LightContainer::add
Tehsapper Jun 12, 2025
6e7dffc
add pixel size override for type setter
Tehsapper Jun 16, 2025
1476595
add links support to text instance
Tehsapper Jun 16, 2025
4fcf065
fix includes
Tehsapper Jun 21, 2025
e990091
split composite pass into bloom enabled version
Tehsapper Jul 8, 2025
dd853bc
fix effect shader
Tehsapper Jul 8, 2025
caedf18
fix light removal
Tehsapper Jul 10, 2025
38b4104
fix glb loading
Tehsapper Jul 12, 2025
2541f56
add CPU profiler
Tehsapper Jul 15, 2025
a79c8f1
fix text selection driver crash
Tehsapper Aug 19, 2025
d3f50d2
profile cursor pos retrieval
Tehsapper Aug 25, 2025
2e3e712
support monospace digits
Tehsapper Aug 26, 2025
87de460
expire emitter once particles are dead
Tehsapper Aug 26, 2025
8b0ae1f
simplify camera
Tehsapper Sep 2, 2025
1c33bc1
meme snow
Tehsapper Sep 7, 2025
abee503
fix mutable texture image loading
Tehsapper Sep 8, 2025
a2a5cbf
more profiling
Tehsapper Sep 24, 2025
cff36a7
pass tex loader flags to gltf loader
Tehsapper Oct 12, 2025
58fa0e1
add ASTC compression support
Tehsapper Oct 13, 2025
dcae8e8
remove ASTC compression support as it cannot be used online
Tehsapper Oct 13, 2025
c89a964
improve skeletal rendering
Tehsapper Oct 14, 2025
7c21d04
implement GLTF saver via cgltf plus extension support
Tehsapper Oct 18, 2025
d6b3554
implement fog
Tehsapper Oct 19, 2025
add9b94
try ACES mapping
Tehsapper Oct 20, 2025
371c19e
fix failure on 0x0 framebuffer
Tehsapper Nov 25, 2025
80c68e9
allow loading model variant materials and fix base mesh material
Tehsapper Dec 26, 2025
1b05623
wither for texture loader
Tehsapper Dec 30, 2025
265d9f7
fix instanced buffer lag
Tehsapper Jan 6, 2026
cf0ef0d
reset binds
Tehsapper Jan 21, 2026
42896c5
allow specifying skybox paths
Tehsapper Feb 9, 2026
a697b1f
remove internal format stdio spam
Tehsapper Feb 11, 2026
16cbe42
fix mesh emitter shader and add camera repeat boundary
Tehsapper Mar 12, 2026
d460299
add meshoptimizer support
Tehsapper Mar 13, 2026
89bb628
support vertex lock for mesh simplification
Tehsapper Mar 13, 2026
0e9e5dc
profile context creation
Tehsapper Mar 28, 2026
898300e
allow recreating VAOs
Tehsapper Mar 28, 2026
8d324a4
extras
Tehsapper Mar 29, 2026
39b3e62
lod target index count or factor
Tehsapper Mar 30, 2026
cd23bc7
fix bbs rotation
Tehsapper Mar 31, 2026
f5e7015
update headers
Tehsapper Mar 31, 2026
f080d9c
add snoise, scene depth uniform to translucent pass
Tehsapper Mar 31, 2026
733ec18
comment stdout
Tehsapper Apr 3, 2026
bedef77
simplify models in 2 passes
Tehsapper Apr 11, 2026
25c8333
add min height emitter module
Tehsapper May 17, 2026
98c7b3d
add tracing
Tehsapper May 25, 2026
675ed91
rotate traces every frame
Tehsapper May 26, 2026
d7f2697
add priority for decal rendering
Tehsapper Jun 3, 2026
04c93cf
fix rendering multiple meshes with different blending
Tehsapper Jun 9, 2026
2513bfe
fix multiple uvs again
Tehsapper Jun 9, 2026
1baa1ed
fix conversion warning
Tehsapper Jun 12, 2026
0fbff9a
fix UBs, memory leaks and perf issues
Tehsapper Jun 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,7 @@
url = https://github.com/Perlmint/glew-cmake
[submodule "thirdparty/plog"]
path = thirdparty/plog
url = https://github.com/SergiusTheBest/plog
url = https://github.com/SergiusTheBest/plog
[submodule "thirdparty/meshoptimizer"]
path = thirdparty/meshoptimizer
url = https://github.com/zeux/meshoptimizer
10 changes: 10 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ set(ENGINE_CORE
src/limitless/core/context_observer.cpp
src/limitless/core/state_query.cpp
src/limitless/core/profiler.cpp
src/limitless/core/cpu_profiler.cpp
src/limitless/core/time_query.cpp

src/limitless/core/texture/texture.cpp
Expand Down Expand Up @@ -96,11 +97,14 @@ set(ENGINE_LOADERS
src/limitless/loaders/dds_loader.cpp
src/limitless/loaders/cgltf.c
src/limitless/loaders/gltf_model_loader.cpp
src/limitless/loaders/cgltf_write.c
src/limitless/loaders/gltf_model_saver.cpp
)

set(ENGINE_MODELS
src/limitless/models/elementary_model.cpp
src/limitless/models/text_model.cpp
src/limitless/models/text_selection_model.cpp
src/limitless/models/skeletal_model.cpp
src/limitless/models/abstract_model.cpp
src/limitless/models/cube.cpp
Expand Down Expand Up @@ -141,6 +145,7 @@ set(ENGINE_MS
set(ENGINE_TEXT
src/limitless/text/text_instance.cpp
src/limitless/text/font_atlas.cpp
src/limitless/text/type_setter.cpp
)

set(ENGINE_FX
Expand Down Expand Up @@ -173,6 +178,7 @@ set(ENGINE_RENDERER
src/limitless/renderer/deferred_lighting_pass.cpp
src/limitless/renderer/depth_pass.cpp
src/limitless/renderer/translucent_pass.cpp
src/limitless/renderer/fog_pass.cpp
src/limitless/renderer/bloom_pass.cpp
src/limitless/renderer/composite_pass.cpp
src/limitless/renderer/ssao_pass.cpp
Expand Down Expand Up @@ -219,10 +225,12 @@ set(ENGINE_SRC
add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/thirdparty/freetype")
add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/thirdparty/glew/build/cmake")
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/plog")
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/meshoptimizer")

target_compile_options(glfw PUBLIC -O3)
target_compile_options(freetype PUBLIC -O3)
target_compile_options(glew PUBLIC -O3)
target_compile_options(meshoptimizer PUBLIC -O3)

##########################################
add_library(limitless-engine STATIC ${ENGINE_SRC})
Expand All @@ -233,10 +241,12 @@ target_include_directories(limitless-engine PUBLIC "${CMAKE_CURRENT_LIST_DIR}/th
target_include_directories(limitless-engine PUBLIC "${CMAKE_CURRENT_LIST_DIR}/thirdparty/freetype/include")
target_include_directories(limitless-engine PUBLIC "${CMAKE_CURRENT_LIST_DIR}/thirdparty/glew/include")
target_include_directories(limitless-engine PUBLIC "${CMAKE_CURRENT_LIST_DIR}/thirdparty/plog/include")
target_include_directories(limitless-engine PUBLIC "${CMAKE_CURRENT_LIST_DIR}/thirdparty/meshoptimizer/src")

target_link_libraries(limitless-engine PUBLIC glfw ${GLFW_LIBRARIES})
target_link_libraries(limitless-engine PUBLIC glew ${GLEW_LIBRARIES})
target_link_libraries(limitless-engine PUBLIC freetype)
target_link_libraries(limitless-engine PUBLIC meshoptimizer)

if (UNIX)
target_link_libraries(limitless-engine PUBLIC GL)
Expand Down
37 changes: 14 additions & 23 deletions include/limitless/camera.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,27 @@
#include <glm/gtx/quaternion.hpp>

namespace Limitless {
enum class CameraMovement { Forward, Backward, Left, Right, Up, Down };
enum class CameraMode { Free, Panning };

class Camera {
private:
glm::vec3 position;
glm::vec3 front, up, right, world_up;
glm::vec3 front;
glm::vec3 up;
glm::vec3 right;
glm::vec3 world_up;

glm::mat4 projection;
glm::mat4 view;
glm::mat4 view_to_screen;

CameraMode mode {};

float pitch;
float pitch; // degrees
float yaw;

float fov {90}; // degrees
float near_distance {0.01f};
float far_distance {100.0f};

float move_speed {2.0f};
float mouse_sence {0.5f};
public:
explicit Camera(glm::uvec2 window_size) noexcept;
explicit Camera(glm::uvec2 screen_size) noexcept;

[[nodiscard]] const auto& getViewToScreen() const noexcept { return view_to_screen; }
[[nodiscard]] const auto& getProjection() const noexcept { return projection; }
Expand All @@ -42,21 +38,16 @@ namespace Limitless {
[[nodiscard]] const auto& getNear() const noexcept { return near_distance; }
[[nodiscard]] const auto& getFar() const noexcept { return far_distance; }
[[nodiscard]] const auto& getFov() const noexcept { return fov; }

[[nodiscard]] auto& getMoveSpeed() noexcept { return move_speed; }
[[nodiscard]] auto& getMouseSence() noexcept { return mouse_sence; }
[[nodiscard]] auto& getMode() noexcept { return mode; }
[[nodiscard]] const auto& getPitch() const noexcept { return pitch; }
[[nodiscard]] const auto& getYaw() const noexcept { return yaw; }

void setPosition(const glm::vec3& position) noexcept;
void setFront(const glm::vec3& front) noexcept;
void setFov(glm::uvec2 size, float fov) noexcept;
void setMode(CameraMode mode) noexcept;

void mouseMove(glm::dvec2 offset) noexcept;
void mouseScroll(float yoffset) noexcept;
void movement(CameraMovement move, float delta) noexcept;
void setFov(glm::uvec2 screen_size, float fov) noexcept;
void setPitch(float pitch) noexcept;
void setYaw(float yaw) noexcept;
void setRotation(float pitch, float yaw) noexcept;

void updateView() noexcept;
void updateProjection(glm::uvec2 size) noexcept;
void updateProjection(glm::uvec2 screen_size) noexcept;
};
}
}
2 changes: 2 additions & 0 deletions include/limitless/core/abstract_vertex_stream.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,7 @@ namespace Limitless {

virtual void draw_instanced(std::size_t count) noexcept = 0;
virtual void draw_instanced(VertexStreamDraw draw, std::size_t count) noexcept = 0;

virtual void recreateVAO() noexcept = 0;
};
}
2 changes: 1 addition & 1 deletion include/limitless/core/buffer/buffer_builder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@ namespace Limitless {

std::unique_ptr<Buffer> build();
// builds indexed buffer for specified context
std::shared_ptr<Buffer> build(std::string_view name, ContextState& ctx);
std::shared_ptr<Buffer> build(const std::string& name, ContextState& ctx);
};
}
9 changes: 5 additions & 4 deletions include/limitless/core/buffer/indexed_buffer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <memory>
#include <mutex>
#include <map>
#include <optional>

namespace Limitless {
class Buffer;
Expand All @@ -21,15 +22,15 @@ namespace Limitless {
enum class Type { UniformBuffer = GL_UNIFORM_BLOCK, ShaderStorage = GL_SHADER_STORAGE_BLOCK };
using Identifier = std::pair<Type, std::string>;
private:
std::unordered_multimap<std::string, std::shared_ptr<Buffer>> buffers;
std::map<Identifier, std::shared_ptr<Buffer>> buffers;
std::unordered_map<Type, GLint> current_bind;
std::map<Identifier, GLuint> bound;
public:
GLuint getBindingPoint(Type type, std::string_view name) noexcept;

void add(std::string_view name, std::shared_ptr<Buffer> buffer) noexcept;
void remove(const std::string& name, const std::shared_ptr<Buffer>& buffer);
std::shared_ptr<Buffer> get(std::string_view name);
void add(Type type, const std::string& name, std::shared_ptr<Buffer> buffer) noexcept;
void remove(Type type, const std::string& name);
std::optional<std::shared_ptr<Buffer>> get(Type type, const std::string& name) noexcept;
};

struct IndexedBufferData {
Expand Down
3 changes: 3 additions & 0 deletions include/limitless/core/context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ namespace Limitless {

InputState getKey(int key) const noexcept;
bool isPressed(int key) const noexcept;
bool isNotPressed(int key) const noexcept {
return !isPressed(key);
}

InputState getMouseButton(MouseButton button);

Expand Down
5 changes: 4 additions & 1 deletion include/limitless/core/context_initializer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ namespace Limitless {

static void initializeGLEW();
static void initializeGLFW();
static void getExtensions() noexcept;
static void discoverExtensions() noexcept;
static void getLimits() noexcept;

ContextInitializer();
Expand All @@ -41,6 +41,9 @@ namespace Limitless {
static void printExtensions() noexcept;
static bool isExtensionSupported(std::string_view name) noexcept;
static bool checkMinimumRequirements() noexcept;
static const auto& getExtensions() noexcept {
return extensions;
}

static bool isProgramInterfaceQuerySupported() noexcept;
static bool isBindlessTextureSupported() noexcept;
Expand Down
7 changes: 6 additions & 1 deletion include/limitless/core/context_state.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,8 @@ namespace Limitless {
GLuint shader_id {};

/**
* Vertex array object id
* Currently active vertex array object.
* TODO: map engine VAO ID to real OpenGL VAO ID for each context.
*/
GLuint vertex_array_id {};

Expand Down Expand Up @@ -274,8 +275,12 @@ namespace Limitless {

auto getActiveTexture() const noexcept { return active_texture; }
const auto& getTextureBound() const noexcept { return texture_bound; }
void resetTextureBinds() noexcept;
const auto& getBufferPoints() const noexcept { return buffer_point; }

[[nodiscard]] GLuint getActiveTextureFromGpu() const noexcept;
[[nodiscard]] GLuint getBoundTextureFromGpu(GLenum target) const noexcept;

auto getShaderId() const noexcept { return shader_id; }
auto getVertexArrayId() const noexcept { return vertex_array_id; }
};
Expand Down
100 changes: 100 additions & 0 deletions include/limitless/core/cpu_profiler.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
#pragma once

#include <chrono>
#include <memory>
#include <unordered_map>
#include <vector>

namespace Limitless {
struct CpuProfiler {
using MonotonicTime = std::chrono::steady_clock::time_point;
using Duration = std::chrono::steady_clock::duration;

struct Frame {
void record(Duration period);

Duration getMinDuration() const noexcept;
Duration getMaxDuration() const noexcept;
Duration getAverageDuration() const noexcept;
Duration getLastDuration() const noexcept;
size_t getCount() const noexcept;

Duration getTotalPerFrame() const noexcept;
size_t getCountPerFrame() const noexcept;

void startFrame();

private:
Duration min {Duration::max()};
Duration max {Duration::min()};
Duration avg {Duration::zero()};
Duration last {Duration::zero()};
Duration total_per_frame {Duration::zero()};
size_t n_per_frame {0};
size_t n {0};
};

// A node in the per-thread profile trace tree. Each Span is uniquely
// identified within its parent by its name; entering a CpuProfileScope
// whose parent already has a child with the same name updates the
// existing Span instead of creating a new one. This keeps the trace
// compact when scopes execute in tight loops.
struct Span {
const char* name {nullptr};
Duration total_time {Duration::zero()};
size_t hit_count {0};
std::vector<std::unique_ptr<Span>> children {};
Span* parent {nullptr};

Span() = default;
Span(const Span&) = delete;
Span& operator=(const Span&) = delete;
Span(Span&&) = default;
Span& operator=(Span&&) = default;

Span* findChild(const char* id) noexcept;
};

struct Trace {
std::vector<std::unique_ptr<Span>> roots {};
};

std::unordered_map<const char*, Frame> frames;

// Most recently completed trace snapshot from the recording thread.
// Updated by maybeRotateTrace() at the start of each frame.
Trace previous_trace {};

void startFrame();

// Moves the previous frame's trace into `previous_trace`. Called from
// startFrame() when no scope is currently active on the recording thread.
void maybeRotateTrace();

// Moves any accumulated trace on the recording thread into `previous_trace`.
// Must be called on the thread that records CpuProfileScopes.
void finalizeTrace();

[[nodiscard]] const Trace& getPreviousTrace() const noexcept { return previous_trace; }
};

extern CpuProfiler global_profiler;

struct CpuProfileScope {
CpuProfiler::Frame& frame;
CpuProfiler::Span* span;
CpuProfiler::Span* parent_span;
// Is a const char* to avoid dynamically allocating a std::sting for
// every profile frame.
const char* identifier;
CpuProfiler::MonotonicTime start;

CpuProfileScope(CpuProfiler& profiler, const char* id) noexcept;

~CpuProfileScope();

private:
// TODO: consider taking a clock instance.
static CpuProfiler::MonotonicTime now() noexcept;
};
}
9 changes: 8 additions & 1 deletion include/limitless/core/texture/texture.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,11 @@ namespace Limitless {

// GL_ARB_texture_compression_rgtc
R_RGTC = GL_COMPRESSED_RED_RGTC1,
RG_RGTC = GL_COMPRESSED_RG_RGTC2
RG_RGTC = GL_COMPRESSED_RG_RGTC2,

// GL_KHR_texture_compression_astc_ldr
RGBA_ASTC_4x4 = GL_COMPRESSED_RGBA_ASTC_4x4_KHR,
sRGBA8_ASTC_4x4 = GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR
};

enum class Format {
Expand Down Expand Up @@ -131,6 +135,8 @@ namespace Limitless {
bool mipmap {false};
bool compressed {false};
bool immutable {false};

size_t getBytesPerPixel() const noexcept;
protected:
Texture() = default;
public:
Expand Down Expand Up @@ -164,6 +170,7 @@ namespace Limitless {
[[nodiscard]] auto isCubemapArray() const noexcept { return target == Type::TexCubeMapArray; }
[[nodiscard]] uint32_t getId() const noexcept;
[[nodiscard]] auto& getExtensionTexture() noexcept { return *texture; }
[[nodiscard]] std::vector<std::byte> getPixels() const noexcept;

Texture& setMinFilter(Filter filter);
Texture& setMagFilter(Filter filter);
Expand Down
8 changes: 4 additions & 4 deletions include/limitless/core/texture/texture_builder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,10 @@ namespace Limitless {
Builder& wrap_t(Texture::Wrap wrap);
Builder& wrap_r(Texture::Wrap wrap);

void useStateExtensionTexture();
void useNamedExtensionTexture();
void useBindlessExtensionTexture();
void useBestSupportedExtensionTexture();
Builder& useStateExtensionTexture();
Builder& useNamedExtensionTexture();
Builder& useBindlessExtensionTexture();
Builder& useBestSupportedExtensionTexture();

std::shared_ptr<Texture> buildMutable();
std::shared_ptr<Texture> buildImmutable();
Expand Down
2 changes: 1 addition & 1 deletion include/limitless/core/uniform/uniform_value.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ namespace Limitless {
protected:
T value;

constexpr UniformValueType getUniformValueType();
static constexpr UniformValueType getUniformValueType();

UniformValue(std::string name, UniformType type, const T& value) noexcept;

Expand Down
Loading