Compare commits

..

13 Commits

53 changed files with 562 additions and 86 deletions

View File

@@ -80,6 +80,7 @@ set(INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include)
add_executable(${PROJECT_NAME}
src/main.cpp
src/app.cpp
src/debug_collector.cpp
src/camera.cpp
src/gameplay/chunk.cpp
src/gameplay/player.cpp
@@ -94,6 +95,7 @@ add_executable(${PROJECT_NAME}
src/tools/font.cpp
src/tools/log.cpp
src/tools/perlin_noise.cpp
src/ui/text.cpp
src/window.cpp
)
@@ -109,6 +111,15 @@ if(CMAKE_BUILD_TYPE STREQUAL "Debug")
target_link_options(${PROJECT_NAME} PRIVATE
-fsanitize=address
)
target_compile_definitions(${PROJECT_NAME} PRIVATE DEBUG_MODE)
target_compile_definitions(${PROJECT_NAME} PRIVATE
ASSETS_PATH="${CMAKE_SOURCE_DIR}/assets/"
)
else()
target_compile_definitions(${PROJECT_NAME} PRIVATE
ASSETS_PATH="./assets/"
)
endif()
target_include_directories(${PROJECT_NAME} PUBLIC ${INCLUDE_DIR})
@@ -140,11 +151,3 @@ if (UNIX AND NOT APPLE)
target_compile_options(${PROJECT_NAME} PRIVATE ${EGL_CFLAGS_OTHER} ${Wayland_CFLAGS_OTHER})
endif()
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
"${PROJECT_SOURCE_DIR}/src/shaders"
"$<TARGET_FILE_DIR:${PROJECT_NAME}>/shaders"
COMMENT "Copying shaders to output directory"
)

View File

@@ -7,9 +7,9 @@ layout (location = 2) in float layer;
out vec2 tc;
flat out int tex_layer;
uniform mat4 projection;
uniform mat4 mv_matrix;
void main(void) {
gl_Position = projection * vec4(pos, 0.0, 1.0);
gl_Position = projection * mv_matrix * vec4(pos, 0.0, 1.0);
tc = texCoord;
tex_layer = int(layer);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 482 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 482 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 482 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 482 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 482 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 482 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 512 B

After

Width:  |  Height:  |  Size: 563 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 362 B

After

Width:  |  Height:  |  Size: 482 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 512 B

After

Width:  |  Height:  |  Size: 563 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 512 B

After

Width:  |  Height:  |  Size: 563 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 512 B

After

Width:  |  Height:  |  Size: 563 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 382 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 382 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 382 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 382 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 382 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 382 B

View File

@@ -29,9 +29,6 @@ private:
Window m_window{m_renderer};
GLuint m_texture_array = 0;
inline static double last_time = glfwGetTime();
inline static double current_time = glfwGetTime();
inline static double delta_time = 0.0f;

View File

@@ -1,6 +1,6 @@
#pragma once
constexpr int WORLD_SIZE_Y = 256;
constexpr int MAX_BLOCK_NUM = 2;
constexpr int MAX_BLOCK_NUM = 4;
constexpr int MAX_UI_NUM = 1;
constexpr int CHUCK_SIZE = 16;

View File

@@ -0,0 +1,20 @@
#pragma once
#include <Cubed/ui/text.hpp>
#include <unordered_map>
class DebugCollector {
public:
static DebugCollector& get();
DebugCollector();
std::unordered_map<std::size_t, Text>& all_texts();
Text& text(std::string_view name);
void report(std::string_view name, std::string_view content);
void init_text();
private:
std::unordered_map<std::size_t, Text> m_texts;
};

View File

@@ -16,9 +16,14 @@ struct MouseState {
bool right = false;
};
struct KeyState {
bool r = false;
};
struct InputState {
MoveState move_state;
MouseState mouse_state;
KeyState key_state;
};
namespace Input {

View File

@@ -2,6 +2,7 @@
#include <Cubed/config.hpp>
#include <Cubed/shader.hpp>
#include <Cubed/ui/text.hpp>
#include <glad/glad.h>
#include <glm/glm.hpp>
@@ -45,6 +46,9 @@ private:
std::unordered_map<std::size_t, Shader> m_shaders;
std::vector<GLuint> m_vao;
std::vector<Vertex2D> m_ui;
void init_text();
void render_outline();
void render_sky();
void render_text();

View File

@@ -6,20 +6,26 @@
class TextureManager {
private:
bool m_need_reload = false;
GLuint m_block_status_array;
GLuint m_texture_array;
GLuint m_ui_array;
void load_block_status(unsigned status_id);
void load_block_texture(unsigned block_id);
void load_ui_texture(unsigned id);
public:
TextureManager();
~TextureManager();
void delet_texture();
GLuint get_block_status_array() const;
GLuint get_texture_array() const;
GLuint get_ui_array() const;
// Must call after MapTable::init_map() and glfwMakeContextCurrent(window);
void init_texture();
void hot_reload();
void need_reload();
void update();
};

View File

@@ -16,10 +16,7 @@ namespace Assert {
}
}
#ifdef NDEBUG
#define CUBED_ASSERT(cond) ((void)0)
#define CUBED_ASSERT_MSG(cond, message) ((void)0)
#else
#ifdef DEBUG_MODE
#define CUBED_ASSERT(cond) \
do { \
if (!(cond)) { \
@@ -32,4 +29,8 @@ namespace Assert {
::Assert::msg(#cond, __FILE__, __LINE__, __func__, message); \
} \
} while (0)
#else
#define CUBED_ASSERT(cond) ((void)0)
#define CUBED_ASSERT_MSG(cond, message) ((void)0)
#endif

View File

@@ -1,8 +1,8 @@
#pragma once
#include <string>
#include <string_view>
namespace HASH {
inline std::size_t str(const std::string& value) {
return std::hash<std::string>{}(value);
inline std::size_t str(std::string_view value) {
return std::hash<std::string_view>{}(value);
}
}

View File

@@ -8,6 +8,8 @@
#include <string>
#include <unordered_map>
#include <Cubed/config.hpp>
struct Character {
glm::vec2 uv_min;
glm::vec2 uv_max;
@@ -23,8 +25,8 @@ public:
Font();
~Font();
static void render_text(const Shader& shader, const std::string& text, float x, float y, float scale, const glm::vec3& color);
static std::vector<Vertex2D> vertices(const std::string& text, float x = 0.0f, float y = 0.0f, float scale = 1.0f);
static GLuint text_texture();
private:
FT_Library m_ft;
FT_Face m_face;
@@ -32,7 +34,7 @@ private:
float m_texture_width = 64;
float m_texture_height = 64;
GLuint m_text_texture;
static inline GLuint m_text_texture;
std::unordered_map<char8_t, Character> m_characters;
void load_character(char8_t c);

View File

@@ -0,0 +1,67 @@
#pragma once
#include <string>
#include <Cubed/tools/log.hpp>
#ifdef _WIN32
#include <windows.h>
typedef LONG (WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW);
inline bool get_os_version(std::string& str) {
HMODULE hntdll = GetModuleHandleW(L"ntdll.dll");
if (!hntdll) return false;
auto prtl_get_version = reinterpret_cast<RtlGetVersionPtr>(
GetProcAddress(hntdll, "RtlGetVersion"));
if (!prtl_get_version) return false;
RTL_OSVERSIONINFOW osvi = { 0 };
osvi.dwOSVersionInfoSize = sizeof(osvi);
if (prtl_get_version(&osvi) != 0) return false;
if (osvi.dwMajorVersion == 10) {
if (osvi.dwBuildNumber >= 22000) {
str = "Windows 11 Build " + std::to_string(osvi.dwBuildNumber);
} else {
str = "Windows 10 Build " + std::to_string(osvi.dwBuildNumber);
}
} else {
str = "Windows Build " + std::to_string(osvi.dwBuildNumber);
}
return true;
}
#elif defined(__linux__)
#include <fstream>
inline bool get_os_version(std::string& str) {
std::ifstream file("/etc/os-release");
if (!file.is_open()) {
Logger::error("Can't Open /etc/os-release");
return false;
}
std::string line;
while (std::getline(file, line)) {
size_t eq_pos = line.find("=");
if (eq_pos == std::string::npos) {
continue;
}
std::string key = line.substr(0, eq_pos);
if (key != "PRETTY_NAME") {
continue;
}
str = line.substr(eq_pos + 1);
if (str.size() >= 2 && str.front() == '"' && str.back() == '"') {
str = str.substr(1, str.size() - 2);
return true;
}
}
return false;
}
#else
inline bool get_os_version(std::string& str) {
str = "Unknown OS";
return false;
}
#endif

View File

@@ -0,0 +1,65 @@
#pragma once
#include <Cubed/tools/cubed_assert.hpp>
#include <glm/glm.hpp>
enum class Color {
BLACK,
WHITE,
RED,
GREEN,
BLUE,
YELLOW,
CYAN,
MAGENTA,
GRAY,
ORANGE,
PURPLE,
PINK,
BROWN
};
inline constexpr glm::vec4 color_value(Color color) {
using glm::vec4;
switch (color) {
case Color::BLACK:
return vec4{0.0f, 0.0f, 0.0f, 1.0f};
case Color::WHITE:
return vec4{1.0f, 1.0f, 1.0f, 1.0f};
case Color::RED:
return vec4{1.0f, 0.0f, 0.0f, 1.0f};
case Color::GREEN:
return vec4{0.0f, 1.0f, 0.0f, 1.0f};
case Color::BLUE:
return vec4{0.0f, 0.0f, 1.0f, 1.0f};
case Color::YELLOW:
return vec4{1.0f, 1.0f, 0.0f, 1.0f};
case Color::CYAN:
return vec4{0.0f, 1.0f, 1.0f, 1.0f};
case Color::MAGENTA:
return vec4{1.0f, 0.0f, 1.0f, 1.0f};
case Color::GRAY:
return vec4{0.5f, 0.5f, 0.5f, 1.0f};
case Color::ORANGE:
return vec4{1.0f, 0.647f, 0.0f, 1.0f};
case Color::PURPLE:
return vec4{0.502f, 0.0f, 0.502f, 1.0f};
case Color::PINK:
return vec4{1.0f, 0.753f, 0.769f, 1.0f};
case Color::BROWN:
return vec4{0.647f, 0.165f, 0.165f, 1.0f};
default:
CUBED_ASSERT_MSG(false, "Unknown Color");
return vec4{1.0f, 1.0f, 1.0f, 1.0f};
}
}
inline glm::vec4 rgb255_to_float(int r, int g, int b, int a) {
float nr = static_cast<float>(r) / 255.0f;
float ng = static_cast<float>(g) / 255.0f;
float nb = static_cast<float>(b) / 255.0f;
float na = static_cast<float>(a) / 255.0f;
return glm::vec4{nr, ng, nb, na};
}

53
include/Cubed/ui/text.hpp Normal file
View File

@@ -0,0 +1,53 @@
#pragma once
#include <glad/glad.h>
#include <glm/glm.hpp>
#include <string>
#include <vector>
#include <Cubed/config.hpp>
#include <Cubed/ui/color.hpp>
class Shader;
class Text {
public:
explicit Text(std::string_view name);
Text(std::string_view name, std::string_view str, glm::vec2 pos = glm::vec2{0.0f, 0.0f}, Color color = Color::BLACK);
~Text();
Text(const Text&) = delete;
Text(Text&&) noexcept;
Text& operator=(const Text&) = delete;
Text& operator=(Text&&) noexcept = delete;
Text& color(Color color);
//Text& color(const glm::vec4& color, int pos);
Text& name(std::string_view name);
Text& position(float x, float y);
Text& scale(float s);
Text& text(std::string_view str);
std::size_t uuid() const;
static void set_loc(const Shader& shader);
void render();
bool operator==(const Text& other) const;
private:
float m_scale = 1.0f;
glm::vec2 m_pos{0.0f, 0.0f};
const std::string NAME;
const std::size_t UUID;
std::string m_text;
glm::vec4 m_color{1.0f, 1.0f, 1.0f, 1.0f};
glm::mat4 m_model_matrix;
std::vector<Vertex2D> m_vertices;
GLuint m_vbo = 0;
static inline GLuint m_color_loc = 0;
static inline GLuint m_mv_loc = 0;
void update_vertices();
void upload_to_gpu();
};

View File

@@ -6,12 +6,16 @@ public:
Window(Renderer& renderer);
~Window();
bool is_mouse_enable() const;
const GLFWwindow* get_glfw_window() const;
GLFWwindow* get_glfw_window();
void init();
void update_viewport();
void toggle_fullscreen();
void toggle_mouse_able();
private:
bool m_mouse_enable = false;
float m_aspect;
GLFWwindow* m_window;
int m_width;

View File

@@ -1,4 +1,5 @@
#include <Cubed/app.hpp>
#include <Cubed/debug_collector.hpp>
#include <Cubed/gameplay/player.hpp>
#include <Cubed/map_table.hpp>
#include <Cubed/tools/cubed_assert.hpp>
@@ -18,7 +19,10 @@ App::~App() {
void App::cursor_position_callback(GLFWwindow* window, double xpos, double ypos) {
App* app = static_cast<App*>(glfwGetWindowUserPointer(window));
CUBED_ASSERT_MSG(app, "nullptr");
app->m_camera.update_cursor_position_camera(xpos, ypos);
if (!app->m_window.is_mouse_enable()) {
app->m_camera.update_cursor_position_camera(xpos, ypos);
}
}
void App::init() {
m_window.init();
@@ -44,7 +48,6 @@ void App::init() {
Logger::info("Texture Load Success");
m_world.init_world();
Logger::info("World Init Success");
m_texture_array = m_texture_manager.get_texture_array();
m_camera.camera_init(&m_world.get_player("TestPlayer"));
@@ -53,7 +56,7 @@ void App::init() {
void App::key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) {
App* app = static_cast<App*>(glfwGetWindowUserPointer(window));
CUBED_ASSERT_MSG(app, "nullptr");
auto& input = Input::get_input_state();
switch(key) {
case GLFW_KEY_Q:
if (action == GLFW_PRESS) {
@@ -77,7 +80,12 @@ void App::key_callback(GLFWwindow* window, int key, int scancode, int action, in
break;
case GLFW_KEY_R:
if (action == GLFW_PRESS) {
app->m_world.need_gen();
app->m_texture_manager.need_reload();
}
break;
case GLFW_KEY_P:
if (action == GLFW_PRESS) {
app->m_window.toggle_mouse_able();
}
break;
@@ -153,10 +161,12 @@ void App::update() {
if (fps_time_count >= 1.0f) {
fps = static_cast<int>(frame_count / fps_time_count);
std::string title = "Cubed FPS: " + std::to_string(fps);
DebugCollector::get().report("fps", std::string{"FPS: " + std::to_string(fps)});
glfwSetWindowTitle(m_window.get_glfw_window(), title.c_str());
frame_count = 0;
fps_time_count = 0.0f;
}
m_texture_manager.update();
m_world.update(delta_time);
m_camera.update_move_camera();
const auto& player= m_world.get_player("TestPlayer");

73
src/debug_collector.cpp Normal file
View File

@@ -0,0 +1,73 @@
#include <Cubed/debug_collector.hpp>
#include <Cubed/tools/system_version.hpp>
#include <Cubed/tools/cubed_hash.hpp>
DebugCollector::DebugCollector() {
}
DebugCollector& DebugCollector::get() {
static DebugCollector instance;
return instance;
}
void DebugCollector::init_text() {
Text version_text("version");
Text fps_text("fps");
Text player_pos_text("player_pos");
Text rendered_chunk_text("rendered_chunk");
version_text
.position(0.0f, 100.0f)
.scale(0.8f)
.color(Color::WHITE)
.text("Version: v0.0.1-Debug");
fps_text
.position(0.0f, 50.0f)
.text("FPS: 0");
player_pos_text
.position(0.0f, 150.0f)
.scale(0.8f)
.text("x: 0.00 y: 0.00 z: 0.00");
rendered_chunk_text
.text("Rendered Chunk: 0")
.scale(0.8f)
.position(0.0, 200.0f);
std::string os;
Text os_text("os");
os_text
.scale(0.8f)
.position(0.0f, 250.0f);
if (get_os_version(os)) {
os_text
.text("OS: " + os);
Logger::info("System: {}", os);
} else {
os_text
.text("OS: Unknown");
}
m_texts.insert({version_text.uuid(), std::move(version_text)});
m_texts.insert({fps_text.uuid(), std::move(fps_text)});
m_texts.insert({player_pos_text.uuid(), std::move(player_pos_text)});
m_texts.insert({rendered_chunk_text.uuid(), std::move(rendered_chunk_text)});
m_texts.insert({os_text.uuid(), std::move(os_text)});
}
std::unordered_map<std::size_t, Text>& DebugCollector::all_texts() {
return m_texts;
}
Text& DebugCollector::text(std::string_view name) {
std::size_t id = HASH::str(name);
auto it = m_texts.find(id);
CUBED_ASSERT_MSG(it != m_texts.end(), "Can't Find Text");
return it->second;
}
void DebugCollector::report(std::string_view name, std::string_view content) {
auto& t = text(name);
t.text(content);
}

View File

@@ -216,7 +216,7 @@ void Chunk::init_chunk() {
for (int x = 0; x < CHUCK_SIZE; x++) {
for (int y = 0; y < 5; y++) {
for (int z = 0; z < CHUCK_SIZE; z++) {
m_blocks[get_index(x, y, z)] = 1;
m_blocks[get_index(x, y, z)] = 3;
}
}
}
@@ -233,10 +233,15 @@ void Chunk::init_chunk() {
0.125f * PerlinNoise::noise(world_x * 0.04f, world_z * 0.04f, 0.5f);
int y_max = height * noise;
for (int y = 5; y < y_max; y++) {
for (int y = 5; y < y_max - 5; y++) {
m_blocks[get_index(x, y, z)] = 3;
}
for (int y = y_max - 5; y < y_max - 1; y++) {
m_blocks[get_index(x, y, z)] = 2;
}
for (int y = y_max - 1; y < y_max; y++) {
m_blocks[get_index(x, y, z)] = 1;
}
}
}

View File

@@ -1,4 +1,6 @@
#include <Cubed/gameplay/player.hpp>
#include <Cubed/debug_collector.hpp>
#include <Cubed/gameplay/world.hpp>
#include <Cubed/map_table.hpp>
#include <Cubed/tools/cubed_assert.hpp>
@@ -138,6 +140,10 @@ void Player::update(float delta_time) {
update_move(delta_time);
update_lookup_block();
check_player_chunk_transition();
std::string player_pos = std::format("x: {:.2f} y: {:.2f} z: {:.2f}", m_player_pos.x, m_player_pos.y, m_player_pos.z);
DebugCollector::get().report("player_pos", player_pos);
}
void Player::update_player_move_state(int key, int action) {

View File

@@ -1,4 +1,6 @@
#include <Cubed/gameplay/world.hpp>
#include <Cubed/debug_collector.hpp>
#include <Cubed/gameplay/player.hpp>
#include <Cubed/map_table.hpp>
#include <Cubed/tools/cubed_assert.hpp>
@@ -128,7 +130,7 @@ void World::init_world() {
void World::render(const glm::mat4& mvp_matrix) {
Math::extract_frustum_planes(mvp_matrix, m_planes);
int rendered_sum = 0;
for (const auto& snapshot : m_render_snapshots) {
if (is_aabb_in_frustum(snapshot.center, snapshot.half_extents)) {
@@ -143,11 +145,13 @@ void World::render(const glm::mat4& mvp_matrix) {
glDrawArrays(GL_TRIANGLES, 0, snapshot.vertex_count);
glBindBuffer(GL_ARRAY_BUFFER, 0);
rendered_sum++;
}
}
DebugCollector::get().report("rendered_chunk", "Rendered Chunk: " + std::to_string(rendered_sum));
}

View File

@@ -3,9 +3,18 @@
#include <Cubed/tools/cubed_assert.hpp>
#include <Cubed/tools/cubed_hash.hpp>
#include <array>
std::unordered_map<unsigned, std::string> MapTable::id_to_name_map;
std::unordered_map<size_t, unsigned> MapTable::name_to_id_map;
constexpr std::array<std::string_view, MAX_BLOCK_NUM> BLOCK_REISTER{
"air",
"grass_block",
"dirt",
"stone"
};
const std::string& MapTable::get_name_from_id(unsigned id) {
auto it = id_to_name_map.find(id);
@@ -17,13 +26,16 @@ const unsigned MapTable::get_id_from_name(const std::string& name) {
CUBED_ASSERT_MSG(it != name_to_id_map.end(), "Name " + name + " is not exist");
return it->second;
}
void MapTable::init_map() {
id_to_name_map.reserve(MAX_BLOCK_NUM);
name_to_id_map.reserve(MAX_BLOCK_NUM);
id_to_name_map[0] = "air";
name_to_id_map[HASH::str("air")] = 0;
id_to_name_map[1] = "grass_block";
name_to_id_map[HASH::str("grass_block")] = 1;
for (int i = 0; i < MAX_BLOCK_NUM; i++) {
id_to_name_map[i] = BLOCK_REISTER[i];
name_to_id_map[HASH::str(BLOCK_REISTER[i])] = i;
}
}

View File

@@ -1,6 +1,7 @@
#include <Cubed/app.hpp>
#include <Cubed/camera.hpp>
#include <Cubed/config.hpp>
#include <Cubed/debug_collector.hpp>
#include <Cubed/gameplay/player.hpp>
#include <Cubed/gameplay/world.hpp>
#include <Cubed/texture_manager.hpp>
@@ -62,7 +63,7 @@ void Renderer::init() {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
#ifndef NDEBUG
#ifdef DEBUG_MODE
glEnable(GL_DEBUG_OUTPUT);
glDebugMessageCallback([](GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* user_param) {
Logger::log(Logger::Level::DEBUG, std::source_location::current(),"GL Debug: {}", reinterpret_cast<const char*>(message));
@@ -104,6 +105,8 @@ void Renderer::init() {
glBindBuffer(GL_ARRAY_BUFFER, m_text_vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)* 6 * 4, NULL, GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
init_text();
}
const Shader& Renderer::get_shader(const std::string& name) const {
@@ -112,6 +115,12 @@ const Shader& Renderer::get_shader(const std::string& name) const {
return it->second;
}
void Renderer::init_text() {
const auto& shader = get_shader("text");
Text::set_loc(shader);
DebugCollector::get().init_text();
}
void Renderer::render() {
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
@@ -192,16 +201,12 @@ void Renderer::render_text() {
m_proj_loc = shader.loc("projection");
glUniformMatrix4fv(m_proj_loc, 1, GL_FALSE, glm::value_ptr(m_ui_proj));
Font::render_text(shader, std::string{"FPS: " + std::to_string(static_cast<int>(App::get_fps()))}, 0.0f, 50.0f, 1.0f, glm::vec3(1.0f, 1.0f, 1.0f));
Font::render_text(shader, "Version: v0.0.1-Debug", 0.0f, 100.0f, 0.8f, glm::vec3(1.0f, 1.0f, 1.0f));
const auto& player = m_world.get_player("TestPlayer");
const auto& pos = player.get_player_pos();
std::string player_pos = std::format("x: {:.2f} y: {:.2f} z: {:.2f}", pos.x, pos.y, pos.z);
Font::render_text(shader, player_pos, 0.0f, 150.0f, 0.8f, glm::vec3(1.0f, 1.0f, 1.0f));
auto& texts = DebugCollector::get().all_texts();
for (auto& t : texts) {
t.second.render();
}
glEnable(GL_DEPTH_TEST);
}

View File

@@ -32,7 +32,7 @@ GLuint TextureManager::get_ui_array() const{
void TextureManager::load_block_status(unsigned id) {
CUBED_ASSERT_MSG(id < MAX_BLOCK_STATUS, "Exceed the max status sum limit");
std::string path = "assets/texture/status/" + std::to_string(id) + ".png";
std::string path = "texture/status/" + std::to_string(id) + ".png";
unsigned char* image_data = nullptr;
image_data = (Tools::load_image_data(path));
glBindTexture(GL_TEXTURE_2D_ARRAY, m_block_status_array);
@@ -54,7 +54,7 @@ void TextureManager::load_block_texture(unsigned id) {
}
unsigned char* image_data[6];
std::string block_texture_path = "assets/texture/block/" + name;
std::string block_texture_path = "texture/block/" + name;
image_data[0] = (Tools::load_image_data(block_texture_path + "/front.png"));
image_data[1] = (Tools::load_image_data(block_texture_path + "/right.png"));
image_data[2] = (Tools::load_image_data(block_texture_path + "/back.png"));
@@ -80,7 +80,7 @@ void TextureManager::load_block_texture(unsigned id) {
void TextureManager::load_ui_texture(unsigned id) {
CUBED_ASSERT_MSG(id < MAX_UI_NUM, "Exceed the max ui sum limit");
std::string path = "assets/texture/ui/" + std::to_string(id) + ".png";
std::string path = "texture/ui/" + std::to_string(id) + ".png";
unsigned char* image_data = nullptr;
image_data = (Tools::load_image_data(path));
glBindTexture(GL_TEXTURE_2D_ARRAY, m_ui_array);
@@ -178,4 +178,20 @@ void TextureManager::init_texture() {
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
void TextureManager::update() {
if (m_need_reload) {
hot_reload();
}
}
void TextureManager::need_reload() {
m_need_reload = true;
}
void TextureManager::hot_reload() {
delet_texture();
init_texture();
m_need_reload = false;
}

View File

@@ -1,18 +1,16 @@
#include <Cubed/config.hpp>
#include <Cubed/shader.hpp>
#include <Cubed/tools/font.hpp>
#include <Cubed/tools/log.hpp>
#include <Cubed/tools/shader_tools.hpp>
Font::Font() {
if (FT_Init_FreeType(&m_ft)) {
Logger::error("FREETYPE: Could not init FreeType Library");
}
if (FT_New_Face(m_ft, "assets/fonts/IBMPlexSans-Regular.ttf", 0, &m_face)) {
if (FT_New_Face(m_ft, ASSETS_PATH "fonts/IBMPlexSans-Regular.ttf", 0, &m_face)) {
Logger::error("FREETYPE: Failed to load font");
}
@@ -24,9 +22,7 @@ Font::~Font() {
FT_Done_Face(m_face);
FT_Done_FreeType(m_ft);
for (const auto& [key, character] : m_characters) {
glDeleteTextures(1, &m_text_texture);
}
glDeleteTextures(1, &m_text_texture);
}
void Font::load_character(char8_t c) {
@@ -36,6 +32,7 @@ void Font::load_character(char8_t c) {
}
const auto& width = m_face->glyph->bitmap.width;
const auto& height = m_face->glyph->bitmap.rows;
glBindTexture(GL_TEXTURE_2D_ARRAY, m_text_texture);
glTexSubImage3D(
GL_TEXTURE_2D_ARRAY,
0,
@@ -90,13 +87,9 @@ void Font::setup_font_character() {
glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
}
void Font::render_text(const Shader& shader, const std::string& text, float x, float y, float scale, const glm::vec3& color) {
std::vector<Vertex2D> Font::vertices(const std::string &text, float x, float y, float scale) {
static Font font;
glUniform3f(shader.loc("textColor"), color.x, color.y, color.z);
glActiveTexture(GL_TEXTURE0);
std::vector<Vertex2D> vertices;
for (char8_t c : text) {
@@ -122,22 +115,10 @@ void Font::render_text(const Shader& shader, const std::string& text, float x, f
x += (ch.advance >> 6) * scale;
}
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex2D), vertices.data(), GL_STATIC_DRAW);
glBindTexture(GL_TEXTURE_2D_ARRAY, font.m_text_texture);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), (void*)0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), (void*)offsetof(Vertex2D, s));
glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), (void*)offsetof(Vertex2D, layer));
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glDrawArrays(GL_TRIANGLES, 0, vertices.size());
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
glDeleteBuffers(1, &vbo);
return vertices;
}
GLuint Font::text_texture() {
return m_text_texture;
}

View File

@@ -1,16 +1,19 @@
#include <fstream>
#include <filesystem>
#include <Cubed/config.hpp>
#include <Cubed/tools/cubed_assert.hpp>
#include <Cubed/tools/shader_tools.hpp>
#include <Cubed/tools/log.hpp>
namespace fs = std::filesystem;
namespace Tools {
GLuint create_shader_program(const std::string& v_shader_path, const std::string& f_shader_path) {
std::string v_shader_str = Tools::read_shader_source(v_shader_path);
std::string f_shader_str = Tools::read_shader_source(f_shader_path);
std::string v_shader_str = Tools::read_shader_source(ASSETS_PATH + v_shader_path);
std::string f_shader_str = Tools::read_shader_source(ASSETS_PATH + f_shader_path);
const char *v_shader_source = v_shader_str.c_str();
const char *f_shader_source = f_shader_str.c_str();
@@ -119,11 +122,12 @@ namespace Tools {
}
unsigned char* load_image_data(const std::string& tex_image_path) {
fs::path path = ASSETS_PATH + tex_image_path;
CUBED_ASSERT_MSG(fs::is_regular_file(path), path.c_str());
unsigned char* data = nullptr;
int width, height, channels;
data = SOIL_load_image(tex_image_path.c_str(), &width, &height, &channels, SOIL_LOAD_AUTO);
std::string error_info = "Could not load texture " + tex_image_path;
CUBED_ASSERT_MSG(data, error_info.c_str());
data = SOIL_load_image(path.string().c_str(), &width, &height, &channels, SOIL_LOAD_AUTO);
CUBED_ASSERT_MSG(data, "Could not load texture" + path.string());
return data;
}

119
src/ui/text.cpp Normal file
View File

@@ -0,0 +1,119 @@
#include <Cubed/ui/text.hpp>
#include <Cubed/shader.hpp>
#include <Cubed/tools/cubed_hash.hpp>
#include <Cubed/tools/font.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
Text::Text(std::string_view name) :
NAME(name),
UUID(HASH::str(name))
{
}
Text::Text(std::string_view name, std::string_view str, glm::vec2 pos, Color color) :
NAME(name),
UUID(HASH::str(name))
{
m_text.assign(str);
m_pos = pos;
m_color = color_value(color);
update_vertices();
}
Text::~Text() {
if (m_vbo != 0) {
glDeleteBuffers(1, &m_vbo);
}
}
Text::Text(Text&& other) noexcept :
UUID(other.UUID),
NAME(other.NAME),
m_scale(other.m_scale),
m_vbo(other.m_vbo),
m_color(other.m_color),
m_model_matrix(other.m_model_matrix),
m_pos(other.m_pos),
m_text(std::move(other.m_text)),
m_vertices(std::move(other.m_vertices))
{
other.m_vbo = 0;
}
Text& Text::color(Color color) {
m_color = color_value(color);
return *this;
}
Text& Text::position(float x, float y) {
m_pos = glm::vec2{x, y};
return *this;
}
Text& Text::scale(float s) {
m_scale = s;
return *this;
}
std::size_t Text::uuid() const {
return UUID;
}
void Text::set_loc(const Shader& shader) {
m_color_loc = shader.loc("textColor");
m_mv_loc = shader.loc("mv_matrix");
}
Text& Text::text(std::string_view str) {
m_text.assign(str);
update_vertices();
return *this;
}
void Text::render() {
CUBED_ASSERT_MSG(m_vbo != 0,"VBO not initialized!");
CUBED_ASSERT_MSG(!m_vertices.empty(), "Text String Not Set");
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D_ARRAY, Font::text_texture());
CUBED_ASSERT_MSG(m_color_loc, "m_color_loc is null");
m_model_matrix = glm::translate(glm::mat4(1.0f), glm::vec3(m_pos.x, m_pos.y, 0.0f)) *
glm::scale(glm::mat4(1.0f), glm::vec3(m_scale, m_scale, 1.0f));
glUniform3f(m_color_loc, m_color.x, m_color.y, m_color.z);
glUniformMatrix4fv(m_mv_loc, 1, GL_FALSE, glm::value_ptr(m_model_matrix));
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), (void*)0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), (void*)offsetof(Vertex2D, s));
glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), (void*)offsetof(Vertex2D, layer));
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glDrawArrays(GL_TRIANGLES, 0, m_vertices.size());
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
}
void Text::update_vertices() {
m_vertices = Font::vertices(m_text);
upload_to_gpu();
}
void Text::upload_to_gpu() {
if (m_vbo == 0) {
glGenBuffers(1, &m_vbo);
}
CUBED_ASSERT_MSG(m_vbo, "Vbo Is Not Gen");
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
glBufferData(GL_ARRAY_BUFFER, m_vertices.size() * sizeof(Vertex2D), m_vertices.data(), GL_DYNAMIC_DRAW);
}
bool Text::operator==(const Text& other) const {
return UUID == other.uuid();
}

View File

@@ -19,6 +19,10 @@ Window::~Window() {
glfwTerminate();
}
bool Window::is_mouse_enable() const {
return m_mouse_enable;
}
const GLFWwindow* Window::get_glfw_window() const {
return m_window;
}
@@ -97,4 +101,14 @@ void Window::toggle_fullscreen() {
);
}
update_viewport();
}
void Window::toggle_mouse_able() {
if (m_mouse_enable) {
glfwSetInputMode(m_window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
m_mouse_enable = false;
} else {
glfwSetInputMode(m_window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
m_mouse_enable = true;
}
}