17 Commits

Author SHA1 Message Date
80ba6dad89 feat(ui): add Rect widget with fill, color, and parent-relative sizing 2026-07-13 20:48:51 +08:00
acb0b94d7b feat(main_menu): add exit button and refactor layout with ColumnLayout
- Add `should_close_window()` method to force window close from UI.
- Replace standalone button with ColumnLayout for proper centering.
- Add "Exit" button that calls `should_close_window()`.
- Update ESC key handling to only close window when game is not running.
- Fix ColumnLayout to respect parent's anchor instead of hardcoded TOP_LEFT.
- Remove unused parameter name in Image::update for consistency.
2026-07-13 18:15:34 +08:00
e7082bdbe0 feat(ui): introduce ColumnLayout widget and refactor widget parenting
- Add ColumnLayout widget that arranges children vertically with spacing.
- Refactor Widget::add_child to automatically pass `this` as parent.
- Update DebugCollector to use ColumnLayout for consistent spacing.
- Expose children() accessor in Widget for layout management.
2026-07-13 16:01:00 +08:00
f5e53fd13d feat(ui): introduce anchor-based widget positioning system
Replace set_position with anchor and offset for relative positioning. Add parent pointer to widget hierarchy. Remove manual resize logic in UI managers.
2026-07-13 14:52:35 +08:00
0cbb353a2a fix(render): remove duplicate scaling in render_image model matrix 2026-07-13 13:10:44 +08:00
e8157ab549 refactor(ui): move scale property to subclasses and fix resize event handling
Remove scale from base Widget class and add per-type set_scale/scale methods to Button, Image, and Label. Dispatch separate WindowResizeEvent alongside existing FrameBufferResizeEvent. Correct centering calculations from `+` to `-` in main menu and world UI managers.
2026-07-13 13:06:09 +08:00
1fa3b9cce8 feat(ui): support scaling of labels and images
Modify width() and height() methods to multiply by m_scale for both Label and Image. Rename internal dimensions to m_real_width and m_real_height for clarity. Adjust Button foreground position to vertically center when label is scaled.
2026-07-13 11:40:27 +08:00
b5e0bb9290 refactor(font): return TextMesh from Font::vertices to include bounding box
Replace the plain vertex vector with a TextMesh struct that carries width, height, and min coordinates. Update Label to compute and store these values immediately on text change (removing lazy dirty update). Fix Button's width/height to factor in scale and use concrete widget types for background and foreground.
2026-07-13 11:32:52 +08:00
576a2f8072 feat(ui): add button scaling and change square vertices to top-left origin 2026-07-13 11:11:30 +08:00
01c9f61d1c ui: add main menu scene and interactive button widget
- Implement MainMenuScene with a "Start Game" button that pushes the WorldScene.
- Extend Button class with background/foreground, hover detection, and size queries.
- Add virtual width/height and event handlers to Widget base class.
- Update WorldUIManager to propagate mouse move events.
- Adjust Window mouse mode based on game running state.
2026-07-13 10:38:30 +08:00
8bbed7b7b9 feat(client-player): add block cooldown and track mouse state
Introduce a time-based cooldown for block placement (PLACE_BLOCK_INTERVAL) to prevent rapid clicking. Replace the global InputState with per-player MouseState tracking in ClientPlayer. Rename place_block() to get_current_block() for clarity. Remove the old src/input.cpp and the Cubed/input.hpp header, moving input structures to Cubed/input/input.hpp.
2026-07-12 21:03:50 +08:00
674c023228 feat(input): add KeyAction::REPEAT for key repeat events
Add a new REPEAT value to the KeyAction enum and update the input callbacks to map GLFW_REPEAT actions to the new value instead of treating them as press.
2026-07-12 20:43:04 +08:00
d00ada1391 fix(font): use correct texture format and clamp to edge for font atlas 2026-07-12 20:33:24 +08:00
cb1eb25e7b refactor: add framebuffer resize event and separate UI management 2026-07-12 18:38:42 +08:00
5712ba0600 refactor(core): add event system and scene management
- Introduce Event variant and Overloaded helper for input handling
- Move game state (camera, client_world, dev_panel) from App to WorldScene
- Add SceneManager with push/pop/change operations for scene stack
- Refactor input callbacks to dispatch events through scene hierarchy
- Extract Argument struct to separate header
- Update Renderer and WorldRenderer to accept world reference
- Replace global input state with event-driven processing in ClientPlayer, Camera, etc.
2026-07-12 16:05:59 +08:00
2d28488126 refactor(render): replace UI shaders with image shaders and Image widget 2026-07-11 14:54:08 +08:00
09653c318a refactor(ui): replace Text with Label/Widget component system
Replace the old `Text` class with a new component-based UI system consisting of `Widget` and `Label` classes. Key changes:

- Remove `Text` class and its GPU upload logic; introduce `Label` as a `Widget` subclass with dirty-flag vertex update.
- Add `UIVertexData` struct to manage per-label vertex buffer/array and memory.
- Refactor `DebugCollector` to store labels in a `Widget` tree, removing hash-based lookup.
- Simplify `Font::vertices()` signature by removing position/scale parameters; scaling is now applied in the renderer’s model matrix.
- Update `Renderer` with `render_label()` and move UI rendering to a `render_ui()` that renders the widget tree.
- Add new source files `label.cpp`, `widget.cpp`, `ui_vertex_data.cpp` and update CMakeLists.
2026-07-11 11:44:31 +08:00
73 changed files with 3074 additions and 745 deletions

View File

@@ -0,0 +1,11 @@
#version 460
in vec2 tc;
out vec4 color;
layout (binding = 0) uniform sampler2D samp;
void main(void) {
color = texture(samp, tc);
}

View File

@@ -0,0 +1,14 @@
#version 460
layout (location = 0) in vec2 pos;
layout (location = 1) in vec2 texCoord;
out vec2 tc;
uniform mat4 model_matrix;
uniform mat4 proj_matrix;
void main(void) {
gl_Position = proj_matrix * model_matrix * vec4(pos, 0.0, 1.0);
tc = texCoord;
}

View File

@@ -0,0 +1,9 @@
#version 460
out vec4 color;
uniform vec4 inColor;
void main(void) {
color = inColor;
}

View File

@@ -0,0 +1,11 @@
#version 460
layout (location = 0) in vec2 pos;
uniform mat4 model_matrix;
uniform mat4 proj_matrix;
void main(void) {
gl_Position = proj_matrix * model_matrix * vec4(pos, 0.0, 1.0);
}

View File

@@ -1,12 +0,0 @@
#version 460
in vec2 tc;
flat in int tex_layer;
out vec4 color;
layout (binding = 0) uniform sampler2DArray samp;
void main(void) {
color = texture(samp, vec3(tc, tex_layer));
}

View File

@@ -1,18 +0,0 @@
#version 460
layout (location = 0) in vec2 pos;
layout (location = 1) in vec2 texCoord;
layout (location = 2) in float layer;
out vec2 tc;
flat out int tex_layer;
uniform mat4 m_matrix;
uniform mat4 proj_matrix;
void main(void) {
gl_Position = proj_matrix * m_matrix * vec4(pos, 0.0, 1.0);
tc = texCoord;
tex_layer = int(layer);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 B

View File

@@ -1,27 +1,19 @@
#pragma once #pragma once
#include "Cubed/audio/audio_engine.hpp" #include "Cubed/audio/audio_engine.hpp"
#include "Cubed/gameplay/client_world.hpp"
#include "Cubed/gameplay/network_server.hpp" #include "Cubed/gameplay/network_server.hpp"
#include "Cubed/gameplay/server_world.hpp" #include "Cubed/gameplay/server_world.hpp"
#define GLFW_INCLUDE_NONE #define GLFW_INCLUDE_NONE
#include "Cubed/camera.hpp" #include "Cubed/argument.hpp"
#include "Cubed/config.hpp" #include "Cubed/config.hpp"
#include "Cubed/dev_panel.hpp" #include "Cubed/dev_panel.hpp"
#include "Cubed/render/renderer.hpp" #include "Cubed/render/renderer.hpp"
#include "Cubed/scene/scene_manager.hpp"
#include "Cubed/texture_manager.hpp" #include "Cubed/texture_manager.hpp"
#include "Cubed/window.hpp" #include "Cubed/window.hpp"
namespace Cubed { namespace Cubed {
class App { class App {
public: public:
struct Argument {
bool is_client = false;
int port = 25530;
std::string ip{"127.0.0.1"};
std::string player{"Unknown"};
bool debug_on = true;
};
App(); App();
~App(); ~App();
static void cursor_position_callback(GLFWwindow* window, double xpos, static void cursor_position_callback(GLFWwindow* window, double xpos,
@@ -33,6 +25,8 @@ public:
static void window_focus_callback(GLFWwindow* window, int focused); static void window_focus_callback(GLFWwindow* window, int focused);
static void window_reshape_callback(GLFWwindow* window, int new_width, static void window_reshape_callback(GLFWwindow* window, int new_width,
int new_height); int new_height);
static void framebuffer_size_callback(GLFWwindow* window, int new_width,
int new_height);
static void mouse_scroll_callback(GLFWwindow* window, double xoffset, static void mouse_scroll_callback(GLFWwindow* window, double xoffset,
double yoffset); double yoffset);
static void cursor_enter_callback(GLFWwindow* window, int entered); static void cursor_enter_callback(GLFWwindow* window, int entered);
@@ -43,12 +37,9 @@ public:
static float delta_time(); static float delta_time();
static float get_fps(); static float get_fps();
Camera& camera();
DevPanel& dev_panel();
Renderer& renderer(); Renderer& renderer();
TextureManager& texture_manager(); TextureManager& texture_manager();
Window& window(); Window& window();
ClientWorld& client_world();
ServerWorld& server_world(); ServerWorld& server_world();
Config& config(); Config& config();
const Argument& argument() const; const Argument& argument() const;
@@ -56,18 +47,17 @@ public:
private: private:
Config m_game_config; Config m_game_config;
Camera m_camera;
TextureManager m_texture_manager; TextureManager m_texture_manager;
NetworkServer m_server; NetworkServer m_server;
std::shared_ptr<NetworkClient> m_client;
AudioEngine m_audio; AudioEngine m_audio;
ClientWorld m_client_world;
DevPanel m_dev_panel;
Renderer m_renderer; Renderer m_renderer;
Window m_window; Window m_window;
SceneManager m_scene_manager;
inline static double last_time = glfwGetTime(); inline static double last_time = glfwGetTime();
inline static double current_time = glfwGetTime(); inline static double current_time = glfwGetTime();
inline static double dt = 0.0f; inline static double dt = 0.0f;
@@ -86,6 +76,8 @@ private:
void render(); void render();
void run(); void run();
void update(); void update();
void dispatch_event(const Event& e);
}; };
} // namespace Cubed } // namespace Cubed

View File

@@ -0,0 +1,11 @@
#pragma once
#include <string>
namespace Cubed {
struct Argument {
bool is_client = false;
int port = 25530;
std::string ip{"127.0.0.1"};
std::string player{"Unknown"};
bool debug_on = true;
};
} // namespace Cubed

View File

@@ -1,5 +1,6 @@
#pragma once #pragma once
#include "Cubed/input/event.hpp"
#define GLFW_INCLUDE_NONE #define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#include <glm/glm.hpp> #include <glm/glm.hpp>
@@ -28,6 +29,9 @@ private:
glm::vec3 camera_collision(glm::vec3 start, glm::vec3 end, glm::vec3 camera_collision(glm::vec3 start, glm::vec3 end,
float radius = 0.2f); float radius = 0.2f);
bool handle_key_event(const KeyEvent& e);
bool handle_mouse_move_event(const MouseMoveEvent& e);
public: public:
Camera(); Camera();
@@ -45,6 +49,7 @@ public:
glm::vec3 get_camera_front() const; glm::vec3 get_camera_front() const;
void change_perspective(); void change_perspective();
bool is_first_person() const; bool is_first_person() const;
bool handle_event(const Event& e);
}; };
} // namespace Cubed } // namespace Cubed

View File

@@ -1,6 +1,8 @@
#pragma once #pragma once
#include "Cubed/ui/text.hpp" #include "Cubed/ui/column_layout.hpp"
#include "Cubed/ui/label.hpp"
#include "Cubed/ui/widget.hpp"
#include <unordered_map> #include <unordered_map>
@@ -11,14 +13,14 @@ public:
static DebugCollector& get(); static DebugCollector& get();
DebugCollector(); DebugCollector();
std::unordered_map<std::size_t, Text>& all_texts(); void report(const std::string& name, std::string_view content);
void init(int width, int height);
Text& text(std::string_view name); Widget& get_widget();
void report(std::string_view name, std::string_view content); bool handle_event(const Event& e);
void init_text();
private: private:
std::unordered_map<std::size_t, Text> m_texts; ColumnLayout m_widget;
std::unordered_map<std::string, Label*> m_component;
}; };
} // namespace Cubed } // namespace Cubed

View File

@@ -6,8 +6,9 @@
namespace Cubed { namespace Cubed {
class App; class WorldScene;
class ClientPlayer; class ClientPlayer;
class App;
class DevPanel { class DevPanel {
struct ConfigView { struct ConfigView {
float fov = 70.0f; float fov = 70.0f;
@@ -32,12 +33,13 @@ class DevPanel {
}; };
public: public:
DevPanel(App& app); DevPanel(WorldScene& app);
void init(); void init();
void render(); void render();
private: private:
App& m_app; App& m_app;
WorldScene& m_world_scene;
Config& m_config; Config& m_config;
ConfigView m_config_view; ConfigView m_config_view;
ClientPlayer* m_player; ClientPlayer* m_player;

View File

@@ -6,7 +6,8 @@
#include "Cubed/gameplay/game_mode.hpp" #include "Cubed/gameplay/game_mode.hpp"
#include "Cubed/gameplay/game_time.hpp" #include "Cubed/gameplay/game_time.hpp"
#include "Cubed/gameplay/player.hpp" #include "Cubed/gameplay/player.hpp"
#include "Cubed/input.hpp" #include "Cubed/input/event.hpp"
#include "Cubed/input/input.hpp"
#include <absl/container/flat_hash_set.h> #include <absl/container/flat_hash_set.h>
#include <glm/glm.hpp> #include <glm/glm.hpp>
@@ -23,6 +24,14 @@ public:
ClientPlayer(ClientWorld& world); ClientPlayer(ClientWorld& world);
~ClientPlayer(); ~ClientPlayer();
bool handle_mouse_button_event(const MouseButtonEvent& e);
bool handle_key_event(const KeyEvent& e);
bool handle_mouse_wheel_event(const MouseWheelEvent& e);
void update_front_vec(float offset_x, float offset_y);
bool update_player_move_state(Key key, KeyAction action);
bool update_scroll(float yoffset);
void update_chunk_set(const ChunkPosSet& set); void update_chunk_set(const ChunkPosSet& set);
const ChunkPosSet& get_chunk_pos_set() const; const ChunkPosSet& get_chunk_pos_set() const;
ChunkPosSet get_chunk_pos_set(); ChunkPosSet get_chunk_pos_set();
@@ -40,9 +49,6 @@ public:
void set_player_pos(const glm::vec3& pos); void set_player_pos(const glm::vec3& pos);
void set_place_block(unsigned id); void set_place_block(unsigned id);
void update(float delta_time); void update(float delta_time);
void update_front_vec(float offset_x, float offset_y);
void update_player_move_state(int key, int action);
void update_scroll(double yoffset);
float& max_walk_speed(); float& max_walk_speed();
float& max_run_speed(); float& max_run_speed();
@@ -52,7 +58,7 @@ public:
float& g(); float& g();
float& fly_y_speed(); float& fly_y_speed();
unsigned place_block() const; unsigned get_current_block() const;
void set_gait(Gait gait); void set_gait(Gait gait);
GameMode& game_mode(); GameMode& game_mode();
@@ -74,6 +80,7 @@ public:
float distance = 4.0f); float distance = 4.0f);
bool is_underwater() const; bool is_underwater() const;
void set_underwater(bool u); void set_underwater(bool u);
void place_block(float dt);
private: private:
using enum GameMode; using enum GameMode;
@@ -83,7 +90,8 @@ private:
float m_deceleration = DEFAULT_DECELERATION; float m_deceleration = DEFAULT_DECELERATION;
float m_g = DEFAULT_G; float m_g = DEFAULT_G;
constexpr static float MAX_SPACE_ON_TIME = 0.3f; constexpr static float MAX_SPACE_ON_TIME = 0.3f;
constexpr static float PLACE_BLOCK_INTERVAL = 0.2f;
float m_place_time = PLACE_BLOCK_INTERVAL;
std::atomic<float> m_yaw = 0.0f; std::atomic<float> m_yaw = 0.0f;
std::atomic<float> m_pitch = 0.0f; std::atomic<float> m_pitch = 0.0f;
@@ -119,6 +127,7 @@ private:
std::atomic<Gait> m_gait = Gait::STOP; std::atomic<Gait> m_gait = Gait::STOP;
MoveState m_move_state{}; MoveState m_move_state{};
MouseState m_mouse_state{};
GameMode m_game_mode = CREATIVE; GameMode m_game_mode = CREATIVE;
std::optional<LookBlock> m_look_block = std::nullopt; std::optional<LookBlock> m_look_block = std::nullopt;
std::string m_name{}; std::string m_name{};
@@ -137,11 +146,15 @@ private:
void update_direction(); void update_direction();
void update_lookup_block(); void update_lookup_block();
void update_move(float delta_time); void update_move(float delta_time);
void update_x_move(glm::vec3& player_pos); void update_x_move(glm::vec3& player_pos);
void update_y_move(glm::vec3& player_pos); void update_y_move(glm::vec3& player_pos);
void update_z_move(glm::vec3& player_pos); void update_z_move(glm::vec3& player_pos);
void update_player_chunk(); void update_player_chunk();
void play_walk_sound(float dt); void play_walk_sound(float dt);
Gait compute_gait() const; Gait compute_gait() const;
}; };

View File

@@ -7,6 +7,7 @@
#include "Cubed/gameplay/client_player.hpp" #include "Cubed/gameplay/client_player.hpp"
#include "Cubed/gameplay/game_time.hpp" #include "Cubed/gameplay/game_time.hpp"
#include "Cubed/gameplay/network_client.hpp" #include "Cubed/gameplay/network_client.hpp"
#include "Cubed/input/event.hpp"
#include "Cubed/tools/cubed_random.hpp" #include "Cubed/tools/cubed_random.hpp"
#include "Cubed/tools/priority_thread_pool.hpp" #include "Cubed/tools/priority_thread_pool.hpp"
@@ -41,14 +42,15 @@ struct PlayerRenderData {
Gait gait; Gait gait;
float angle; float angle;
}; };
class WorldScene;
class ClientWorld { class ClientWorld {
public: public:
ClientWorld(AudioEngine& auido, Config& config); ClientWorld(AudioEngine& auido, Config& config, WorldScene& scene);
~ClientWorld(); ~ClientWorld();
void init(std::string_view player_name, void init(std::string_view player_name,
std::shared_ptr<NetworkClient> client); std::shared_ptr<NetworkClient> client);
void update(float delta_time); void update(float delta_time);
bool handle_event(const Event& e);
const std::optional<LookBlock>& get_look_block_pos() const; const std::optional<LookBlock>& get_look_block_pos() const;
ClientPlayer& get_player(); ClientPlayer& get_player();
const ClientPlayer& get_player() const; const ClientPlayer& get_player() const;
@@ -97,6 +99,7 @@ public:
static AABB get_block_aabb(const glm::ivec3& pos); static AABB get_block_aabb(const glm::ivec3& pos);
AudioEngine& get_audio(); AudioEngine& get_audio();
Config& get_config(); Config& get_config();
WorldScene& world_scene();
template <typename Fn> template <typename Fn>
void register_ticktimer(std::string_view id, TickType threshold, Fn&& f) { void register_ticktimer(std::string_view id, TickType threshold, Fn&& f) {
m_ticktimers.emplace( m_ticktimers.emplace(
@@ -133,6 +136,7 @@ private:
ChunkHashMap m_chunks; ChunkHashMap m_chunks;
AudioEngine& m_audio; AudioEngine& m_audio;
Config& m_config; Config& m_config;
WorldScene& m_world_scene;
std::vector<glm::vec4> m_planes; std::vector<glm::vec4> m_planes;
std::jthread m_client_thread; std::jthread m_client_thread;

View File

@@ -0,0 +1,61 @@
#pragma once
#include "Cubed/input/key.hpp"
#include "Cubed/input/mouse.hpp"
#include <string>
#include <variant>
namespace Cubed {
struct MouseMoveEvent {
float xpos;
float ypos;
MouseMoveEvent(float x, float y) : xpos(x), ypos(y) {}
};
struct MouseButtonEvent {
MouseKey key;
KeyAction action;
MouseButtonEvent(MouseKey k, KeyAction a) : key(k), action(a) {}
};
struct MouseWheelEvent {
float offset;
MouseWheelEvent(float o) : offset(o) {}
};
struct KeyEvent {
Key key;
KeyAction action;
KeyEvent(Key k, KeyAction a) : key(k), action(a) {}
};
struct TextInputEvent {
std::string text;
TextInputEvent(std::string t) : text(std::move(t)) {}
};
struct WindowResizeEvent {
int width;
int height;
};
struct FrameBufferResizeEvent {
int width;
int height;
};
using Event =
std::variant<MouseMoveEvent, MouseButtonEvent, MouseWheelEvent, KeyEvent,
TextInputEvent, WindowResizeEvent, FrameBufferResizeEvent>;
template <class... T> struct Overloaded : T... {
using T::operator()...;
};
template <class... T> Overloaded(T...) -> Overloaded<T...>;
} // namespace Cubed

View File

@@ -18,19 +18,4 @@ struct MouseState {
bool right = false; bool right = false;
}; };
struct KeyState {
bool r = false;
};
struct InputState {
MoveState move_state;
MouseState mouse_state;
KeyState key_state;
};
namespace Input {
InputState& get_input_state();
}
} // namespace Cubed } // namespace Cubed

127
include/Cubed/input/key.hpp Normal file
View File

@@ -0,0 +1,127 @@
#pragma once
namespace Cubed {
enum class Key {
// Letter keys
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z,
// Digit keys (main keyboard area)
DIGIT_0,
DIGIT_1,
DIGIT_2,
DIGIT_3,
DIGIT_4,
DIGIT_5,
DIGIT_6,
DIGIT_7,
DIGIT_8,
DIGIT_9,
// Function keys
F1,
F2,
F3,
F4,
F5,
F6,
F7,
F8,
F9,
F10,
F11,
F12,
// Control keys
BACKSPACE,
TAB,
ENTER,
ESCAPE,
SPACE,
CAPS_LOCK,
NUM_LOCK,
SCROLL_LOCK,
// Modifier keys
LEFT_SHIFT,
RIGHT_SHIFT,
LEFT_CTRL,
RIGHT_CTRL,
LEFT_ALT,
RIGHT_ALT,
LEFT_SUPER,
RIGHT_SUPER, // Windows / Command 键
// Navigation keys
INSERT,
DELETE,
HOME,
END,
PAGE_UP,
PAGE_DOWN,
LEFT,
RIGHT,
UP,
DOWN,
// Lock and system keys
PRINT_SCREEN,
PAUSE,
// Main keyboard area symbol keys
GRAVE_ACCENT, // `
MINUS, // -
EQUALS, // =
LEFT_BRACKET, // [
RIGHT_BRACKET, // ]
BACKSLASH, // \ /
SEMICOLON, // ;
APOSTROPHE, // '
COMMA, // ,
PERIOD, // .
SLASH, // /
// Numpad area
NUMPAD_0,
NUMPAD_1,
NUMPAD_2,
NUMPAD_3,
NUMPAD_4,
NUMPAD_5,
NUMPAD_6,
NUMPAD_7,
NUMPAD_8,
NUMPAD_9,
NUMPAD_ADD, // +
NUMPAD_SUBTRACT, // -
NUMPAD_MULTIPLY, // *
NUMPAD_DIVIDE, // /
NUMPAD_DECIMAL, // .
NUMPAD_ENTER
};
enum class KeyAction { PRESS, RELEASE, REPEAT };
} // namespace Cubed

View File

@@ -0,0 +1,25 @@
#pragma once
namespace Cubed {
enum class MouseKey {
LEFT_BUTTON,
RIGHT_BUTTON,
MIDDLE_BUTTON,
BACK_BUTTON, // Side button back
FORWARD_BUTTON, // Side button forward
WHEEL_UP,
WHEEL_DOWN,
WHEEL_LEFT,
WHEEL_RIGHT,
EXTRA_BUTTON_1, // Additional programmable buttons
EXTRA_BUTTON_2,
EXTRA_BUTTON_3,
EXTRA_BUTTON_4,
EXTRA_BUTTON_5
};
}

View File

@@ -188,13 +188,14 @@ constexpr float CUBE_VER[24] = {0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0,
constexpr int OUTLINE_CUBE_INDICES[24] = {0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, constexpr int OUTLINE_CUBE_INDICES[24] = {0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6,
6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7}; 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7};
constexpr float SQUARE_VERTICES[6][2] = { constexpr float SQUARE_VERTICES_TOP_LEFT[6][2] = {
{-0.5f, -0.5f}, // bottom left {0.0f, 0.0f}, // top left
{-0.5f, 0.5f}, // top left {0.0f, 1.0f}, // bottom left
{0.5f, 0.5f}, // top right {1.0f, 1.0f}, // bottom right
{0.5f, 0.5f}, // top right
{0.5f, -0.5f}, // bottom right {1.0f, 1.0f}, // bottom right
{-0.5f, -0.5f} // bottom left {1.0f, 0.0f}, // top right
{0.0f, 0.0f} // top left
}; };
constexpr float SQUARE_TEXTURE_POS[6][2] = { constexpr float SQUARE_TEXTURE_POS[6][2] = {

View File

@@ -5,6 +5,7 @@
#include <glad/glad.h> #include <glad/glad.h>
namespace Cubed { namespace Cubed {
class ClientWorld;
class Renderer; class Renderer;
class PlayerRenderer { class PlayerRenderer {
public: public:
@@ -12,8 +13,9 @@ public:
PlayerRenderer(Renderer& renderer); PlayerRenderer(Renderer& renderer);
~PlayerRenderer(); ~PlayerRenderer();
void init(); void init();
void render(const Shader& shader); void render(const Shader& shader, ClientWorld& world);
void shadow_render(const Shader& shader, glm::mat4& light_matrix); void shadow_render(const Shader& shader, glm::mat4& light_matrix,
ClientWorld& world);
private: private:
struct PlayerVertex { struct PlayerVertex {

View File

@@ -2,6 +2,7 @@
#include "Cubed/config.hpp" #include "Cubed/config.hpp"
#include "Cubed/constants.hpp" #include "Cubed/constants.hpp"
#include "Cubed/input/event.hpp"
#include "Cubed/primitive_data.hpp" #include "Cubed/primitive_data.hpp"
#include "Cubed/render/player_renderer.hpp" #include "Cubed/render/player_renderer.hpp"
#include "Cubed/render/shader_manager.hpp" #include "Cubed/render/shader_manager.hpp"
@@ -9,13 +10,13 @@
#include "Cubed/render/vertex_buffer.hpp" #include "Cubed/render/vertex_buffer.hpp"
#include "Cubed/render/world_renderer.hpp" #include "Cubed/render/world_renderer.hpp"
#include "Cubed/shader.hpp" #include "Cubed/shader.hpp"
#include "Cubed/ui/text.hpp" #include "Cubed/ui/image.hpp"
#include "Cubed/ui/label.hpp"
#include "Cubed/ui/rect.hpp"
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <vector> #include <vector>
namespace Cubed { namespace Cubed {
class Camera;
class TextureManager; class TextureManager;
class ClientWorld; class ClientWorld;
class DevPanel; class DevPanel;
@@ -23,18 +24,23 @@ class Renderer {
public: public:
constexpr static int NUM_VAO = 7; constexpr static int NUM_VAO = 7;
Renderer(const Camera& camera, ClientWorld& world, Renderer(TextureManager& texture_manager, Config& config);
const TextureManager& texture_manager, DevPanel& dev_panel,
Config& config);
~Renderer(); ~Renderer();
void hot_reload(); void hot_reload();
void init(bool debug_on); void init(bool debug_on);
const Shader& get_shader(const std::string& name) const; const Shader& get_shader(const std::string& name) const;
void render(); void begin_frame();
void end_frame();
void render_world(ClientWorld& world);
void render_lable(const Label& label);
void render_image(const Image& image);
void render_rect(const Rect& rect);
void begin_render_ui();
void end_render_ui();
void update(float delta_time); void update(float delta_time);
void update_fov(float fov); void update_fov(float fov);
void update_proj_matrix(float aspect, float width, float height);
void updata_framebuffer(int width, int height);
float& ambient_strength(); float& ambient_strength();
bool& discard_transparent(); bool& discard_transparent();
@@ -58,24 +64,23 @@ public:
float& underwater_fog_density(); float& underwater_fog_density();
float& water_density(); float& water_density();
const Camera& camera() const;
const ClientWorld& world() const;
ClientWorld& world();
const glm::mat4& world_proj_matrix() const; const glm::mat4& world_proj_matrix() const;
const TextureManager& texture_mamger() const; const TextureManager& texture_mamger() const;
float delta_time() const; float delta_time() const;
float height() const; float window_height() const;
float width() const; float window_width() const;
float frame_height() const;
float frame_width() const;
const glm::mat4& p_mat() const; const glm::mat4& p_mat() const;
const std::vector<VertexArray>& vao() const; const std::vector<VertexArray>& vao() const;
void render_dev_panel(DevPanel& dev_panel);
bool handle_event(const Event& e);
private: private:
const Camera& m_camera; TextureManager& m_texture_manager;
DevPanel& m_dev_panel;
const TextureManager& m_texture_manager;
ClientWorld& m_world;
bool m_init = false; bool m_init = false;
@@ -84,8 +89,11 @@ private:
float m_delta_time = 0.0f; float m_delta_time = 0.0f;
float m_width = 0.0f; float m_frame_width = 0.0f;
float m_height = 0.0f; float m_frame_height = 0.0f;
float m_window_width = 0.0f;
float m_window_height = 0.0f;
glm::mat4 m_world_proj_matrix; glm::mat4 m_world_proj_matrix;
@@ -97,14 +105,13 @@ private:
std::unique_ptr<VertexBuffer> m_quad_vbo; std::unique_ptr<VertexBuffer> m_quad_vbo;
glm::mat4 m_ui_proj_matrix; glm::mat4 m_ui_proj_matrix;
glm::mat4 m_ui_model_matrix;
ShaderManager m_shaders; ShaderManager m_shaders;
/* /*
0 - quad vao 0 - quad vao (center)
1 - sky vao 1 - sky vao
2 - outline vao 2 - outline vao
3 - ui vao 3 - ui vao (top-left)
4 - text vao 4 - text vao
*/ */
std::vector<VertexArray> m_vao; std::vector<VertexArray> m_vao;
@@ -112,16 +119,12 @@ private:
WorldRenderer m_world_renderer; WorldRenderer m_world_renderer;
Config& m_config; Config& m_config;
bool handle_window_resize_event(const WindowResizeEvent& e);
bool handle_frame_buffer_resize_event(const FrameBufferResizeEvent& e);
void updata_framebuffer(int width, int height);
void init_quad(); void init_quad();
void init_text(); void init_text();
void day_night_calculation();
void render_sky();
void render_text();
void render_ui();
void render_dev_panel();
}; };
} // namespace Cubed } // namespace Cubed

View File

@@ -35,6 +35,7 @@ enum TextureFormat : GLenum {
RGBA16F = GL_RGBA16F, RGBA16F = GL_RGBA16F,
RED = GL_RED, RED = GL_RED,
RGBA = GL_RGBA, RGBA = GL_RGBA,
R8 = GL_R8,
RGB = GL_RGB, RGB = GL_RGB,
RGBA8 = GL_RGBA8, RGBA8 = GL_RGBA8,
@@ -60,12 +61,12 @@ public:
void tex_image_2d(TextureFormat internalformat, TextureFormat format, void tex_image_2d(TextureFormat internalformat, TextureFormat format,
GLenum type, const void* data, GLsizei width, GLenum type, const void* data, GLsizei width,
GLsizei height, GLint level = 0, GLint border = 0) const; GLsizei height, GLint level = 0, GLint border = 0);
void tex_image_3d(TextureFormat internalformat, TextureFormat format, void tex_image_3d(TextureFormat internalformat, TextureFormat format,
GLenum type, const void* data, GLsizei width, GLenum type, const void* data, GLsizei width,
GLsizei height, GLsizei depth, GLint level = 0, GLsizei height, GLsizei depth, GLint level = 0,
GLint border = 0) const; GLint border = 0);
void tex_sub_image_3d(TextureFormat format, GLenum type, const void* data, void tex_sub_image_3d(TextureFormat format, GLenum type, const void* data,
GLint xoffset, GLint yoffset, GLint zoffset, GLint xoffset, GLint yoffset, GLint zoffset,
@@ -84,11 +85,14 @@ public:
void set_clamp_to_edge(bool r = true, bool s = true, bool t = true) const; void set_clamp_to_edge(bool r = true, bool s = true, bool t = true) const;
TextureType type() const; TextureType type() const;
float width() const;
float height() const;
private: private:
GLuint m_id = 0; GLuint m_id = 0;
float m_width = 0;
float m_height = 0;
const TextureType M_TYPE; const TextureType M_TYPE;
GLenum get_gl_texture_type() const; GLenum get_gl_texture_type() const;
}; };
} // namespace Cubed } // namespace Cubed

View File

@@ -39,7 +39,7 @@ public:
WorldRenderer& operator=(const WorldRenderer&) = delete; WorldRenderer& operator=(const WorldRenderer&) = delete;
WorldRenderer& operator=(WorldRenderer&&) = delete; WorldRenderer& operator=(WorldRenderer&&) = delete;
void init(); void init();
void render(); void render(ClientWorld& world);
void updata_framebuffer(int width, int height); void updata_framebuffer(int width, int height);
float& ambient_strength(); float& ambient_strength();
@@ -121,27 +121,26 @@ private:
glm::mat4 view_matrix; glm::mat4 view_matrix;
ClientWorld& m_world;
const Camera& m_camera;
const TextureManager& m_texture_manager; const TextureManager& m_texture_manager;
void day_night_calculation(); void day_night_calculation(ClientWorld& world);
void render_sky(); void render_sky(ClientWorld& world);
void render_world(); void render_world(ClientWorld& world);
void shadow_map_generate(); void shadow_map_generate(ClientWorld& world);
void render_underwater(); void render_underwater(ClientWorld& world);
void render_outline(); void render_outline(ClientWorld& world);
void render_player(); void render_player(ClientWorld& world);
void render_normal_block(const glm::mat4& model_mat, void render_normal_block(const glm::mat4& model_mat,
const glm::mat4& mv_mat, const glm::mat4& mv_mat, const glm::mat4& norm_mat,
const glm::mat4& norm_mat); ClientWorld& world);
void render_transparent_block(const glm::mat4& mv_mat, void render_transparent_block(const glm::mat4& mv_mat,
const glm::mat4& norm_mat); const glm::mat4& norm_mat,
ClientWorld& world);
glm::vec3 quantize_sun_direction(const glm::vec3& sundir, glm::vec3 quantize_sun_direction(const glm::vec3& sundir,
float angle_step_deg) const; float angle_step_deg) const;

View File

@@ -0,0 +1,28 @@
#pragma once
#include "Cubed/scene/scene.hpp"
#include "Cubed/ui/main_menu_ui_manager.hpp"
namespace Cubed {
class SceneManager;
class MainMenuScene : public Scene {
public:
MainMenuScene(const MainMenuScene&) = delete;
MainMenuScene(MainMenuScene&&) = delete;
MainMenuScene& operator=(const MainMenuScene&) = delete;
MainMenuScene& operator=(MainMenuScene&&) = delete;
MainMenuScene(SceneManager& scene_manager);
~MainMenuScene();
void update(float dt) override;
void render(Renderer& renderer) override;
bool handle_event(const Event& e) override;
void on_enter() override;
void on_leave() override;
SceneManager& scene_manager();
private:
SceneManager& m_scene_manager;
MainMenuUIManager m_ui_manager;
};
} // namespace Cubed

View File

@@ -0,0 +1,24 @@
#pragma once
#include "Cubed/input/event.hpp"
namespace Cubed {
class Renderer;
enum class SceneType { MAIN_MENU, WORLD };
class Scene {
public:
Scene() = default;
Scene(const Scene&) = delete;
Scene(Scene&&) = delete;
Scene& operator=(const Scene&) = delete;
Scene& operator=(Scene&&) = delete;
virtual ~Scene() = default;
virtual void update(float dt) = 0;
virtual void render(Renderer& renderer) = 0;
virtual bool handle_event(const Event& e) = 0;
virtual void on_enter() {};
virtual void on_leave() {};
};
} // namespace Cubed

View File

@@ -0,0 +1,47 @@
#pragma once
#include "Cubed/scene/scene.hpp"
#include <memory>
#include <stack>
#include <vector>
namespace Cubed {
class App;
class SceneManager {
public:
SceneManager(const SceneManager&) = delete;
SceneManager(SceneManager&&) = delete;
SceneManager& operator=(const SceneManager&) = delete;
SceneManager& operator=(SceneManager&&) = delete;
SceneManager(App& app);
~SceneManager();
void update(float dt);
void render(Renderer& renderer);
bool handle_event(const Event& e);
void request_change(SceneType type);
void request_push(SceneType type);
void request_pop();
App& app();
private:
enum class OperationType { PUSH, POP, CHANGE };
struct SceneOperation {
OperationType type;
std::optional<SceneType> scene;
};
App& m_app;
std::vector<std::unique_ptr<Scene>> m_pending_delete_scene;
std::optional<SceneOperation> m_operation;
std::stack<std::unique_ptr<Scene>> m_scenes;
void process_operation();
void change(SceneType type);
void push(SceneType type);
void pop();
std::unique_ptr<Scene> create_scene(SceneType);
};
} // namespace Cubed

View File

@@ -0,0 +1,39 @@
#pragma once
#include "Cubed/argument.hpp"
#include "Cubed/camera.hpp"
#include "Cubed/dev_panel.hpp"
#include "Cubed/gameplay/client_world.hpp"
#include "Cubed/scene/scene.hpp"
#include "Cubed/ui/world_ui_manager.hpp"
namespace Cubed {
class SceneManager;
class WorldScene : public Scene {
public:
WorldScene(const WorldScene&) = delete;
WorldScene(WorldScene&&) = delete;
WorldScene& operator=(const WorldScene&) = delete;
WorldScene& operator=(WorldScene&&) = delete;
WorldScene(SceneManager& scene_manager);
~WorldScene();
void update(float dt) override;
void render(Renderer& renderer) override;
bool handle_event(const Event& e) override;
void on_enter() override;
void on_leave() override;
Camera& camera();
SceneManager& scene_manager();
ClientWorld& client_world();
private:
SceneManager& m_scene_manager;
DevPanel m_dev_panel;
Camera m_camera;
std::shared_ptr<NetworkClient> m_client;
ClientWorld m_client_world;
WorldUIManager m_ui_manager;
const Argument& m_argument;
};
} // namespace Cubed

View File

@@ -40,6 +40,9 @@ public:
} else if constexpr (is_same_v<dT, glm::mat4>) { } else if constexpr (is_same_v<dT, glm::mat4>) {
glUniformMatrix4fv(loc(location), 1, GL_FALSE, glUniformMatrix4fv(loc(location), 1, GL_FALSE,
glm::value_ptr(value)); glm::value_ptr(value));
} else if constexpr (is_same_v<dT, glm::vec4>) {
glUniform4fv(loc(location), 1, glm::value_ptr(value));
} else { } else {
static_assert(always_false<dT>::value, "Unknown Type"); static_assert(always_false<dT>::value, "Unknown Type");
} }

View File

@@ -1,6 +1,7 @@
#pragma once #pragma once
#include "Cubed/config.hpp" #include "Cubed/config.hpp"
#include "Cubed/gameplay/block.hpp" #include "Cubed/gameplay/block.hpp"
#include "Cubed/input/event.hpp"
#include "Cubed/render/texture.hpp" #include "Cubed/render/texture.hpp"
#include <glad/glad.h> #include <glad/glad.h>
@@ -15,10 +16,10 @@ private:
std::unique_ptr<Texture> m_block_status_array; std::unique_ptr<Texture> m_block_status_array;
std::unique_ptr<Texture> m_texture_array; std::unique_ptr<Texture> m_texture_array;
std::unique_ptr<Texture> m_cross_plane_array; std::unique_ptr<Texture> m_cross_plane_array;
std::unique_ptr<Texture> m_ui_array;
std::unique_ptr<Texture> m_normal_texture_array; std::unique_ptr<Texture> m_normal_texture_array;
std::unique_ptr<Texture> m_skin; std::unique_ptr<Texture> m_skin;
std::vector<std::unique_ptr<Texture>> m_item_textures; std::vector<std::unique_ptr<Texture>> m_item_textures;
std::unordered_map<std::string, std::unique_ptr<Texture>> m_ui_map;
GLfloat m_max_aniso = 0.0f; GLfloat m_max_aniso = 0.0f;
Config& m_config; Config& m_config;
int m_aniso = 1; int m_aniso = 1;
@@ -27,7 +28,7 @@ private:
void load_block_texture(unsigned block_id); void load_block_texture(unsigned block_id);
void load_block_item_texture(unsigned id); void load_block_item_texture(unsigned id);
void load_cross_plane_texture(unsigned id); void load_cross_plane_texture(unsigned id);
void load_ui_texture(unsigned id); const Texture* load_image_texture(const std::string& path);
void load_pbr_texture(unsigned id); void load_pbr_texture(unsigned id);
void init_item(); void init_item();
void init_block(); void init_block();
@@ -35,6 +36,7 @@ private:
void init_block_status(); void init_block_status();
void init_skin(); void init_skin();
void hot_reload(); void hot_reload();
bool handle_key_event(const KeyEvent& e);
public: public:
TextureManager(Config& config); TextureManager(Config& config);
@@ -44,7 +46,7 @@ public:
const Texture* get_block_status_array() const; const Texture* get_block_status_array() const;
const Texture* get_texture_array() const; const Texture* get_texture_array() const;
const Texture* get_cross_plane_array() const; const Texture* get_cross_plane_array() const;
const Texture* get_ui_array() const; const Texture* get_image_texture(const std::string& path);
const Texture* get_pbr_texture() const; const Texture* get_pbr_texture() const;
const std::vector<std::unique_ptr<Texture>>& item_textures() const; const std::vector<std::unique_ptr<Texture>>& item_textures() const;
const Texture* get_skin() const; const Texture* get_skin() const;
@@ -54,6 +56,7 @@ public:
void need_reload(); void need_reload();
void update(); void update();
int max_aniso() const; int max_aniso() const;
bool handle_event(const Event& e);
}; };
} // namespace Cubed } // namespace Cubed

View File

@@ -22,6 +22,16 @@ struct Character {
GLuint advance; GLuint advance;
}; };
struct TextMesh {
std::vector<Vertex2D> vertices;
float width;
float height;
float min_x;
float min_y;
};
class Shader; class Shader;
class Font { class Font {
@@ -29,9 +39,7 @@ public:
Font(); Font();
~Font(); ~Font();
static std::vector<Vertex2D> vertices(const std::string& text, static TextMesh vertices(const std::string& text);
float x = 0.0f, float y = 0.0f,
float scale = 1.0f);
static const Texture* text_texture(); static const Texture* text_texture();
static const std::string& font_path(); static const std::string& font_path();

View File

@@ -3,9 +3,42 @@
#include <SOIL2.h> #include <SOIL2.h>
#include <glad/glad.h> #include <glad/glad.h>
#include <string> #include <string>
#include <utility>
namespace Cubed { namespace Cubed {
namespace Tools {
void delete_image_data(unsigned char* data);
}
struct ImageData {
unsigned char* data = nullptr;
int width = 0;
int height = 0;
int channels = 0;
ImageData(const ImageData&) = delete;
ImageData(ImageData&& o) noexcept
: data(std::exchange(o.data, nullptr)), width(o.width),
height(o.height), channels(o.channels) {}
ImageData& operator=(const ImageData&) = delete;
ImageData& operator=(ImageData&& o) noexcept {
if (this == &o) {
return *this;
}
if (data) {
Tools::delete_image_data(data);
}
data = std::exchange(o.data, nullptr);
width = o.width;
height = o.height;
channels = o.channels;
return *this;
}
ImageData(unsigned char* d, int w, int h, int c)
: data(d), width(w), height(h), channels(c) {}
ImageData() = default;
~ImageData() { Tools::delete_image_data(data); }
};
namespace Tools { namespace Tools {
GLuint create_shader_program(const std::string& v_shader_path, GLuint create_shader_program(const std::string& v_shader_path,
const std::string& f_shader_path); const std::string& f_shader_path);
@@ -13,9 +46,9 @@ void print_shader_log(GLuint shader);
void print_program_info(int prog); void print_program_info(int prog);
bool check_opengl_error(); bool check_opengl_error();
std::string read_shader_source(const std::string& file_path); std::string read_shader_source(const std::string& file_path);
void delete_image_data(unsigned char* data);
unsigned char* load_image_data(const std::string& tex_image_path, ImageData load_image_data(const std::string& tex_image_path,
bool check_exist = true); bool check_exist = true);
} // namespace Tools } // namespace Tools

View File

@@ -0,0 +1,15 @@
#pragma once
enum class Anchor {
TOP_LEFT,
TOP_CENTER,
TOP_RIGHT,
CENTER_LEFT,
CENTER,
CENTER_RIGHT,
BOTTOM_LEFT,
BOTTOM_CENTER,
BOTTOM_RIGHT,
};

View File

@@ -0,0 +1,58 @@
#pragma once
#include "Cubed/ui/image.hpp"
#include "Cubed/ui/label.hpp"
#include "Cubed/ui/widget.hpp"
#include <functional>
namespace Cubed {
class Button : public Widget {
public:
Button(Widget* parent);
Button(const Button&) = delete;
Button(Button&&) = delete;
Button& operator=(const Button&) = delete;
Button& operator=(Button&&) = delete;
void render(Renderer& renderer) override;
void update(float dt) override;
bool handle_mouse_move_event(const MouseMoveEvent& e) override;
bool handle_mouse_button_event(const MouseButtonEvent& e) override;
void set_window_size(int width, int height) override;
Button& set_scale(float scale);
Widget& set_anchor(Anchor anchor) override;
Widget& set_offset(glm::ivec2 offset) override;
glm::vec2 pos() const override;
float width() const override;
float height() const override;
float scale() const;
template <typename F> Button& set_clicked(F&& f) {
m_clicked = std::forward<F>(f);
return *this;
}
template <typename T, typename... Args> T& set_background(Args&&... args) {
auto w = std::make_unique<T>(std::forward<Args>(args)..., m_parent);
T& ref = *w;
m_background = std::move(w);
return ref;
}
template <typename T, typename... Args> T& set_foreground(Args&&... args) {
auto w = std::make_unique<T>(std::forward<Args>(args)..., this);
T& ref = *w;
m_foreground = std::move(w);
m_foreground->set_anchor(Anchor::CENTER);
return ref;
}
private:
std::function<void()> m_clicked;
std::unique_ptr<Image> m_background;
std::unique_ptr<Label> m_foreground;
bool m_hovered = false;
};
} // namespace Cubed

View File

@@ -0,0 +1,27 @@
#pragma once
#include "Cubed/ui/widget.hpp"
namespace Cubed {
class ColumnLayout : public Widget {
public:
ColumnLayout(const ColumnLayout&) = delete;
ColumnLayout(ColumnLayout&&) = delete;
ColumnLayout& operator=(const ColumnLayout&) = delete;
ColumnLayout& operator=(ColumnLayout&&) = delete;
ColumnLayout(Widget* parent);
~ColumnLayout();
void update(float dt) override;
float width() const override;
float height() const override;
void set_spacing(int spacing);
// No need for parent node pointer; do not modify children's anchors and
// scale.
void layout();
private:
int m_spacing = 0;
};
} // namespace Cubed

View File

@@ -0,0 +1,27 @@
#pragma once
#include "Cubed/render/texture.hpp"
#include "Cubed/ui/widget.hpp"
#include "glm/ext/vector_float2.hpp"
namespace Cubed {
class TextureManager;
class Image : public Widget {
public:
Image(Widget* parent);
void update(float dt) override;
void render(Renderer& renderer) override;
Image& set_image(const std::string& path, TextureManager& texture_manager);
float width() const override;
float height() const override;
const Texture* texture() const;
Image& set_scale(float scale);
float scale() const;
private:
const Texture* m_texture = nullptr;
glm::vec2 m_pos{0.0f, 0.0f};
float m_scale = 1.0f;
};
} // namespace Cubed

View File

@@ -0,0 +1,48 @@
#pragma once
#include "Cubed/ui/text.hpp"
#include "Cubed/ui/ui_vertex_data.hpp"
#include "Cubed/ui/widget.hpp"
namespace Cubed {
class Label : public Widget {
public:
Label(const Label&) = delete;
Label(Label&&) = delete;
Label& operator=(const Label&) = delete;
Label& operator=(Label&&) = delete;
Label(const std::string& id, Widget* parent);
Label(Widget* parent);
virtual ~Label() = default;
Label& set_text(std::string_view text);
Label& set_color(Color color);
Label& set_scale(float scale);
virtual void update(float dt) override;
virtual void render(Renderer& renderer) override;
const UIVertexData& data() const;
const TextStyle& text_style() const;
float width() const override;
float height() const override;
float offset_x() const;
float offset_y() const;
float scale() const;
protected:
virtual void on_update(float dt) override;
virtual void on_render(Renderer& renderer) override;
private:
TextStyle m_text;
UIVertexData m_data;
float m_real_width = 0.0f;
float m_real_height = 0.0f;
float m_offset_x = 0.0f;
float m_offset_y = 0.0f;
float m_scale = 1.0f;
void update_vertices();
};
} // namespace Cubed

View File

@@ -0,0 +1,36 @@
#pragma once
#include "Cubed/input/event.hpp"
#include "Cubed/ui/widget.hpp"
#include <memory>
#include <unordered_map>
namespace Cubed {
class Renderer;
class MainMenuScene;
class MainMenuUIManager {
public:
MainMenuUIManager(MainMenuScene& m_scene);
MainMenuUIManager(const MainMenuUIManager&) = delete;
MainMenuUIManager(MainMenuUIManager&&) = delete;
MainMenuUIManager& operator=(const MainMenuUIManager&) = delete;
MainMenuUIManager& operator=(MainMenuUIManager&&) = delete;
~MainMenuUIManager();
void init();
void render(Renderer& renderer);
void update(float dt);
bool handle_event(const Event& e);
private:
MainMenuScene& m_scene;
std::unique_ptr<Widget> m_root_widget;
std::unordered_map<std::string, Widget*> m_widgets;
bool handle_mouse_move_event(const MouseMoveEvent& e);
bool handle_mouse_button_event(const MouseButtonEvent& e);
bool handle_window_resize_event(const WindowResizeEvent& e);
bool handle_mouse_wheel_event(const MouseWheelEvent& e);
bool handle_key_event(const KeyEvent& e);
};
} // namespace Cubed

41
include/Cubed/ui/rect.hpp Normal file
View File

@@ -0,0 +1,41 @@
#pragma once
#include "Cubed/ui/color.hpp"
#include "Cubed/ui/widget.hpp"
namespace Cubed {
class Rect : public Widget {
public:
Rect(const Rect&) = delete;
Rect(Rect&&) = delete;
Rect& operator=(const Rect&) = delete;
Rect& operator=(Rect&&) = delete;
Rect(Widget* parent);
~Rect();
void update(float dt) override;
void render(Renderer& renderer) override;
float width() const override;
float height() const override;
float alpha() const;
Rect& set_width(float width);
Rect& set_height(float height);
Rect& set_fill(bool fill);
Rect& set_scale(float scale);
Rect& set_color(Color color);
Rect& set_alpha(float alpha);
Color color() const;
private:
Color m_color = Color::WHITE;
float m_width = 0.0f;
float m_height = 0.0f;
float m_scale = 1.0f;
float m_alpha = 1.0f;
bool m_fill = false;
};
} // namespace Cubed

View File

@@ -1,8 +1,5 @@
#pragma once #pragma once
#include "Cubed/primitive_data.hpp"
#include "Cubed/render/vertex_array.hpp"
#include "Cubed/render/vertex_buffer.hpp"
#include "Cubed/ui/color.hpp" #include "Cubed/ui/color.hpp"
#include <glad/glad.h> #include <glad/glad.h>
@@ -10,46 +7,9 @@
#include <string> #include <string>
namespace Cubed { namespace Cubed {
class Shader; struct TextStyle {
std::string text;
class Text { Color color = Color::WHITE;
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& position(float x, float y);
Text& scale(float s);
Text& text(std::string_view str);
std::size_t uuid() const;
void render(const Shader& shader);
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;
std::unique_ptr<VertexBuffer> m_vbo;
std::unique_ptr<VertexArray> m_vao;
void update_vertices();
void upload_to_gpu();
}; };
} // namespace Cubed } // namespace Cubed

View File

@@ -0,0 +1,25 @@
#pragma once
#include "Cubed/primitive_data.hpp"
#include "Cubed/render/vertex_array.hpp"
#include "Cubed/render/vertex_buffer.hpp"
#include <atomic>
#include <memory>
#include <vector>
namespace Cubed {
struct UIVertexData {
std::vector<Vertex2D> m_vertices;
std::unique_ptr<VertexBuffer> m_vbo;
std::unique_ptr<VertexArray> m_vao;
std::atomic<std::size_t> m_sum{0};
UIVertexData();
~UIVertexData();
UIVertexData(const UIVertexData&) = delete;
UIVertexData(UIVertexData&&) noexcept;
UIVertexData& operator=(const UIVertexData&) = delete;
UIVertexData& operator=(UIVertexData&&) noexcept;
void upload();
void update_sum();
};
} // namespace Cubed

View File

@@ -0,0 +1,61 @@
#pragma once
#include "Cubed/input/event.hpp"
#include "Cubed/ui/anchor.hpp"
#include <glm/glm.hpp>
#include <memory>
#include <vector>
namespace Cubed {
class Renderer;
class Widget {
public:
Widget(const std::string& id, Widget* parent);
Widget(Widget* parent);
virtual ~Widget() = default;
virtual void update(float dt);
virtual void render(Renderer& renderer);
virtual const std::string& id() const;
virtual Widget& set_anchor(Anchor anchor);
virtual Widget& set_offset(glm::ivec2 offset);
virtual void set_window_size(int width, int height);
// Returns the final display size
virtual float width() const = 0;
virtual float height() const = 0;
virtual glm::vec2 pos() const;
virtual bool handle_key_event(const KeyEvent& e);
virtual bool handle_mouse_button_event(const MouseButtonEvent& e);
virtual bool handle_mouse_wheel_event(const MouseWheelEvent& e);
virtual bool handle_window_resize_event(const WindowResizeEvent& e);
virtual bool handle_mouse_move_event(const MouseMoveEvent& e);
template <typename T, typename... Args> T& add_child(Args&&... args) {
auto widget = std::make_unique<T>(std::forward<Args>(args)..., this);
T& ref = *widget;
m_children.emplace_back(std::move(widget));
return ref;
};
protected:
Widget* m_parent = nullptr;
std::string m_id;
float m_window_height = 0;
float m_window_width = 0;
// Center is at the top-left corner, position is at the top-left corner
Anchor m_anchor = Anchor::TOP_LEFT;
glm::ivec2 m_offset{0, 0};
std::vector<std::unique_ptr<Widget>>& children();
const std::vector<std::unique_ptr<Widget>>& children() const;
virtual void on_update(float dt);
virtual void on_render(Renderer& renderer);
virtual glm::vec2 compute_position() const;
private:
std::vector<std::unique_ptr<Widget>> m_children;
};
} // namespace Cubed

View File

@@ -0,0 +1,34 @@
#pragma once
#include "Cubed/input/event.hpp"
#include "Cubed/ui/widget.hpp"
#include <string>
#include <unordered_map>
namespace Cubed {
class WorldScene;
class WorldUIManager {
public:
WorldUIManager(const WorldUIManager&) = delete;
WorldUIManager(WorldUIManager&&) = delete;
WorldUIManager& operator=(const WorldUIManager&) = delete;
WorldUIManager& operator=(WorldUIManager&&) = delete;
WorldUIManager(WorldScene& scene);
~WorldUIManager();
void init();
void update(float dt);
void render(Renderer& renderer);
bool handle_event(const Event& e);
private:
WorldScene& m_scene;
std::unordered_map<std::string, std::unique_ptr<Widget>> m_widgets;
bool handle_mouse_move_event(const MouseMoveEvent& e);
bool handle_mouse_button_event(const MouseButtonEvent& e);
bool handle_window_resize_event(const WindowResizeEvent& e);
bool handle_mouse_wheel_event(const MouseWheelEvent& e);
bool handle_key_event(const KeyEvent& e);
};
} // namespace Cubed

View File

@@ -1,15 +1,16 @@
#pragma once #pragma once
#include "Cubed/config.hpp" #include "Cubed/config.hpp"
#include "Cubed/input/event.hpp"
#define GLFW_INCLUDE_NONE #define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
namespace Cubed { namespace Cubed {
class Camera;
class Renderer; class Renderer;
class Window { class Window {
public: public:
Window(Renderer& renderer, Config& config); Window(Config& config);
~Window(); ~Window();
bool is_mouse_enable() const; bool is_mouse_enable() const;
@@ -17,22 +18,34 @@ public:
GLFWwindow* get_glfw_window(); GLFWwindow* get_glfw_window();
void init(); void init();
void imgui_init(); void imgui_init();
void update_viewport();
// end of frame to reload! // end of frame to reload!
bool handle_event(const Event& e);
void hot_reload(); void hot_reload();
void toggle_fullscreen(); void toggle_fullscreen();
void toggle_mouse_able(); void toggle_mouse_able();
void set_camera(Camera* camera);
Camera* camera();
void set_game_running(bool running);
void should_close_window();
private: private:
bool m_mouse_enable = false; bool m_mouse_enable = false;
bool m_imgui_init = false; bool m_imgui_init = false;
float m_aspect; bool m_game_running = false;
GLFWwindow* m_window; GLFWwindow* m_window;
int m_width; int m_window_width;
int m_height; int m_window_height;
Renderer& m_renderer;
Config& m_config; Config& m_config;
Camera* m_camera = nullptr;
bool handle_key_event(const KeyEvent& e);
bool handle_window_resize_event(const WindowResizeEvent& e);
bool handle_mouse_button_event(const MouseButtonEvent& e);
}; };
} // namespace Cubed } // namespace Cubed

View File

@@ -9,7 +9,6 @@ target_sources(${PROJECT_NAME}
gameplay/biome.cpp gameplay/biome.cpp
gameplay/chunk_generator.cpp gameplay/chunk_generator.cpp
gameplay/tree.cpp gameplay/tree.cpp
input.cpp
render/renderer.cpp render/renderer.cpp
shader.cpp shader.cpp
texture_manager.cpp texture_manager.cpp
@@ -17,7 +16,6 @@ target_sources(${PROJECT_NAME}
tools/shader_tools.cpp tools/shader_tools.cpp
tools/font.cpp tools/font.cpp
tools/perlin_noise.cpp tools/perlin_noise.cpp
ui/text.cpp
window.cpp window.cpp
gameplay/builders/biome_builder.cpp gameplay/builders/biome_builder.cpp
gameplay/builders/plain_builder.cpp gameplay/builders/plain_builder.cpp
@@ -59,4 +57,16 @@ target_sources(${PROJECT_NAME}
render/frame_buffer.cpp render/frame_buffer.cpp
render/shader_manager.cpp render/shader_manager.cpp
render/world_renderer.cpp render/world_renderer.cpp
ui/widget.cpp
ui/label.cpp
ui/ui_vertex_data.cpp
ui/image.cpp
ui/button.cpp
scene/world_scene.cpp
scene/scene_manager.cpp
ui/world_ui_manager.cpp
ui/main_menu_ui_manager.cpp
scene/main_menu_scene.cpp
ui/column_layout.cpp
ui/rect.cpp
) )

View File

@@ -1,5 +1,6 @@
#include "Cubed/app.hpp" #include "Cubed/app.hpp"
#include "Cubed/camera.hpp"
#include "Cubed/config.hpp" #include "Cubed/config.hpp"
#include "Cubed/debug_collector.hpp" #include "Cubed/debug_collector.hpp"
#include "Cubed/tools/arg_parser.hpp" #include "Cubed/tools/arg_parser.hpp"
@@ -16,16 +17,10 @@ App::App()
: m_game_config(ASSETS_PATH "config.toml"), : m_game_config(ASSETS_PATH "config.toml"),
m_texture_manager(m_game_config), m_audio(m_game_config), m_texture_manager(m_game_config), m_audio(m_game_config),
m_client_world(m_audio, m_game_config), m_dev_panel(*this), m_renderer(m_texture_manager, m_game_config), m_window(m_game_config),
m_renderer(m_camera, m_client_world, m_texture_manager, m_dev_panel, m_scene_manager(*this) {}
m_game_config),
m_window(m_renderer, m_game_config) {}
App::~App() { App::~App() {}
if (m_client) {
m_client->stop();
}
}
void App::cursor_position_callback(GLFWwindow* window, double xpos, void App::cursor_position_callback(GLFWwindow* window, double xpos,
double ypos) { double ypos) {
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
@@ -38,7 +33,8 @@ void App::cursor_position_callback(GLFWwindow* window, double xpos,
return; return;
} }
if (!app->m_window.is_mouse_enable()) { if (!app->m_window.is_mouse_enable()) {
app->m_camera.update_cursor_position_camera(xpos, ypos); app->m_scene_manager.handle_event(
MouseMoveEvent{static_cast<float>(xpos), static_cast<float>(ypos)});
} }
} }
void App::init(int argc, char** argv) { void App::init(int argc, char** argv) {
@@ -60,6 +56,8 @@ void App::init(int argc, char** argv) {
window_focus_callback); window_focus_callback);
glfwSetWindowSizeCallback(m_window.get_glfw_window(), glfwSetWindowSizeCallback(m_window.get_glfw_window(),
window_reshape_callback); window_reshape_callback);
glfwSetFramebufferSizeCallback(m_window.get_glfw_window(),
framebuffer_size_callback);
glfwSetKeyCallback(m_window.get_glfw_window(), key_callback); glfwSetKeyCallback(m_window.get_glfw_window(), key_callback);
glfwSetScrollCallback(m_window.get_glfw_window(), mouse_scroll_callback); glfwSetScrollCallback(m_window.get_glfw_window(), mouse_scroll_callback);
glfwSetCursorEnterCallback(m_window.get_glfw_window(), glfwSetCursorEnterCallback(m_window.get_glfw_window(),
@@ -72,7 +70,6 @@ void App::init(int argc, char** argv) {
BlockManager::init(); BlockManager::init();
m_renderer.init(m_argument.debug_on); m_renderer.init(m_argument.debug_on);
Logger::info("Renderer Init Success"); Logger::info("Renderer Init Success");
m_window.update_viewport();
// MapTable::init_map(); // MapTable::init_map();
m_texture_manager.init_texture(); m_texture_manager.init_texture();
Logger::info("Texture Load Success"); Logger::info("Texture Load Success");
@@ -80,16 +77,19 @@ void App::init(int argc, char** argv) {
m_server.start_server(m_argument.port); m_server.start_server(m_argument.port);
} }
m_client = std::make_shared<NetworkClient>(m_client_world); m_scene_manager.request_push(SceneType::MAIN_MENU);
m_client->start(m_argument.ip, m_argument.port); {
// init will send packet int w, h;
m_client_world.init(m_argument.player, m_client); glfwGetWindowSize(m_window.get_glfw_window(), &w, &h);
window_reshape_callback(m_window.get_glfw_window(), w, h);
}
Logger::info("World Init Success"); {
int w, h;
m_camera.camera_init(&m_client_world.get_player()); glfwGetFramebufferSize(m_window.get_glfw_window(), &w, &h);
m_dev_panel.init(); framebuffer_size_callback(m_window.get_glfw_window(), w, h);
}
} }
void App::handle_argument(int argc, char** argv) { void App::handle_argument(int argc, char** argv) {
@@ -179,49 +179,357 @@ void App::key_callback(GLFWwindow* window, int key, int scancode, int action,
// ImGui_ImplGlfw_CursorEnterCallback(window, // ImGui_ImplGlfw_CursorEnterCallback(window,
// !app->m_window.is_mouse_enable()); // !app->m_window.is_mouse_enable());
if (io.WantCaptureKeyboard && app->m_window.is_mouse_enable()) { if (io.WantCaptureKeyboard && app->m_window.is_mouse_enable()) {
if ((key == GLFW_KEY_LEFT_ALT || key == GLFW_KEY_ESCAPE) && if ((key == GLFW_KEY_LEFT_ALT) && action == GLFW_PRESS) {
action == GLFW_PRESS) { app->dispatch_event(KeyEvent{Key::LEFT_ALT, KeyAction::PRESS});
app->m_window.toggle_mouse_able();
app->m_camera.reset_camera();
return; return;
} }
ImGui_ImplGlfw_KeyCallback(window, key, scancode, action, mods); ImGui_ImplGlfw_KeyCallback(window, key, scancode, action, mods);
return; return;
} }
Key pkey;
KeyAction act;
switch (key) { switch (key) {
// Letter keys
case GLFW_KEY_A:
pkey = Key::A;
break;
case GLFW_KEY_B:
pkey = Key::B;
break;
case GLFW_KEY_C:
pkey = Key::C;
break;
case GLFW_KEY_D:
pkey = Key::D;
break;
case GLFW_KEY_E:
pkey = Key::E;
break;
case GLFW_KEY_F:
pkey = Key::F;
break;
case GLFW_KEY_G:
pkey = Key::G;
break;
case GLFW_KEY_H:
pkey = Key::H;
break;
case GLFW_KEY_I:
pkey = Key::I;
break;
case GLFW_KEY_J:
pkey = Key::J;
break;
case GLFW_KEY_K:
pkey = Key::K;
break;
case GLFW_KEY_L:
pkey = Key::L;
break;
case GLFW_KEY_M:
pkey = Key::M;
break;
case GLFW_KEY_N:
pkey = Key::N;
break;
case GLFW_KEY_O:
pkey = Key::O;
break;
case GLFW_KEY_P:
pkey = Key::P;
break;
case GLFW_KEY_Q: case GLFW_KEY_Q:
if (action == GLFW_PRESS) { pkey = Key::Q;
}
break;
case GLFW_KEY_ESCAPE:
if (action == GLFW_PRESS) {
glfwSetWindowShouldClose(window, GLFW_TRUE);
}
break;
case GLFW_KEY_F11:
if (action == GLFW_PRESS) {
app->m_window.toggle_fullscreen();
}
break; break;
case GLFW_KEY_R: case GLFW_KEY_R:
if (action == GLFW_PRESS) { pkey = Key::R;
app->m_texture_manager.need_reload();
}
break; break;
case GLFW_KEY_LEFT_ALT: case GLFW_KEY_S:
if (action == GLFW_PRESS) { pkey = Key::S;
app->m_window.toggle_mouse_able(); break;
app->m_camera.reset_camera(); case GLFW_KEY_T:
} pkey = Key::T;
break;
case GLFW_KEY_U:
pkey = Key::U;
break;
case GLFW_KEY_V:
pkey = Key::V;
break;
case GLFW_KEY_W:
pkey = Key::W;
break;
case GLFW_KEY_X:
pkey = Key::X;
break;
case GLFW_KEY_Y:
pkey = Key::Y;
break;
case GLFW_KEY_Z:
pkey = Key::Z;
break;
// Digit keys (main keyboard area)
case GLFW_KEY_0:
pkey = Key::DIGIT_0;
break;
case GLFW_KEY_1:
pkey = Key::DIGIT_1;
break;
case GLFW_KEY_2:
pkey = Key::DIGIT_2;
break;
case GLFW_KEY_3:
pkey = Key::DIGIT_3;
break;
case GLFW_KEY_4:
pkey = Key::DIGIT_4;
break;
case GLFW_KEY_5:
pkey = Key::DIGIT_5;
break;
case GLFW_KEY_6:
pkey = Key::DIGIT_6;
break;
case GLFW_KEY_7:
pkey = Key::DIGIT_7;
break;
case GLFW_KEY_8:
pkey = Key::DIGIT_8;
break;
case GLFW_KEY_9:
pkey = Key::DIGIT_9;
break;
// Function keys
case GLFW_KEY_F1:
pkey = Key::F1;
break;
case GLFW_KEY_F2:
pkey = Key::F2;
break;
case GLFW_KEY_F3:
pkey = Key::F3;
break;
case GLFW_KEY_F4:
pkey = Key::F4;
break; break;
case GLFW_KEY_F5: case GLFW_KEY_F5:
if (action == GLFW_PRESS) { pkey = Key::F5;
app->m_camera.change_perspective();
}
break; break;
case GLFW_KEY_F6:
pkey = Key::F6;
break;
case GLFW_KEY_F7:
pkey = Key::F7;
break;
case GLFW_KEY_F8:
pkey = Key::F8;
break;
case GLFW_KEY_F9:
pkey = Key::F9;
break;
case GLFW_KEY_F10:
pkey = Key::F10;
break;
case GLFW_KEY_F11:
pkey = Key::F11;
break;
case GLFW_KEY_F12:
pkey = Key::F12;
break;
// Control keys
case GLFW_KEY_BACKSPACE:
pkey = Key::BACKSPACE;
break;
case GLFW_KEY_TAB:
pkey = Key::TAB;
break;
case GLFW_KEY_ENTER:
pkey = Key::ENTER;
break;
case GLFW_KEY_ESCAPE:
pkey = Key::ESCAPE;
break;
case GLFW_KEY_SPACE:
pkey = Key::SPACE;
break;
case GLFW_KEY_CAPS_LOCK:
pkey = Key::CAPS_LOCK;
break;
case GLFW_KEY_NUM_LOCK:
pkey = Key::NUM_LOCK;
break;
case GLFW_KEY_SCROLL_LOCK:
pkey = Key::SCROLL_LOCK;
break;
// Modifier keys
case GLFW_KEY_LEFT_SHIFT:
pkey = Key::LEFT_SHIFT;
break;
case GLFW_KEY_RIGHT_SHIFT:
pkey = Key::RIGHT_SHIFT;
break;
case GLFW_KEY_LEFT_CONTROL:
pkey = Key::LEFT_CTRL;
break;
case GLFW_KEY_RIGHT_CONTROL:
pkey = Key::RIGHT_CTRL;
break;
case GLFW_KEY_LEFT_ALT:
pkey = Key::LEFT_ALT;
break;
case GLFW_KEY_RIGHT_ALT:
pkey = Key::RIGHT_ALT;
break;
case GLFW_KEY_LEFT_SUPER:
pkey = Key::LEFT_SUPER;
break;
case GLFW_KEY_RIGHT_SUPER:
pkey = Key::RIGHT_SUPER;
break;
// Navigation keys
case GLFW_KEY_INSERT:
pkey = Key::INSERT;
break;
case GLFW_KEY_DELETE:
pkey = Key::DELETE;
break;
case GLFW_KEY_HOME:
pkey = Key::HOME;
break;
case GLFW_KEY_END:
pkey = Key::END;
break;
case GLFW_KEY_PAGE_UP:
pkey = Key::PAGE_UP;
break;
case GLFW_KEY_PAGE_DOWN:
pkey = Key::PAGE_DOWN;
break;
case GLFW_KEY_LEFT:
pkey = Key::LEFT;
break;
case GLFW_KEY_RIGHT:
pkey = Key::RIGHT;
break;
case GLFW_KEY_UP:
pkey = Key::UP;
break;
case GLFW_KEY_DOWN:
pkey = Key::DOWN;
break;
// Lock and system keys
case GLFW_KEY_PRINT_SCREEN:
pkey = Key::PRINT_SCREEN;
break;
case GLFW_KEY_PAUSE:
pkey = Key::PAUSE;
break;
// Main keyboard area symbol keys
case GLFW_KEY_GRAVE_ACCENT:
pkey = Key::GRAVE_ACCENT;
break;
case GLFW_KEY_MINUS:
pkey = Key::MINUS;
break;
case GLFW_KEY_EQUAL:
pkey = Key::EQUALS;
break;
case GLFW_KEY_LEFT_BRACKET:
pkey = Key::LEFT_BRACKET;
break;
case GLFW_KEY_RIGHT_BRACKET:
pkey = Key::RIGHT_BRACKET;
break;
case GLFW_KEY_BACKSLASH:
pkey = Key::BACKSLASH;
break;
case GLFW_KEY_SEMICOLON:
pkey = Key::SEMICOLON;
break;
case GLFW_KEY_APOSTROPHE:
pkey = Key::APOSTROPHE;
break;
case GLFW_KEY_COMMA:
pkey = Key::COMMA;
break;
case GLFW_KEY_PERIOD:
pkey = Key::PERIOD;
break;
case GLFW_KEY_SLASH:
pkey = Key::SLASH;
break;
// Numpad area
case GLFW_KEY_KP_0:
pkey = Key::NUMPAD_0;
break;
case GLFW_KEY_KP_1:
pkey = Key::NUMPAD_1;
break;
case GLFW_KEY_KP_2:
pkey = Key::NUMPAD_2;
break;
case GLFW_KEY_KP_3:
pkey = Key::NUMPAD_3;
break;
case GLFW_KEY_KP_4:
pkey = Key::NUMPAD_4;
break;
case GLFW_KEY_KP_5:
pkey = Key::NUMPAD_5;
break;
case GLFW_KEY_KP_6:
pkey = Key::NUMPAD_6;
break;
case GLFW_KEY_KP_7:
pkey = Key::NUMPAD_7;
break;
case GLFW_KEY_KP_8:
pkey = Key::NUMPAD_8;
break;
case GLFW_KEY_KP_9:
pkey = Key::NUMPAD_9;
break;
case GLFW_KEY_KP_ADD:
pkey = Key::NUMPAD_ADD;
break;
case GLFW_KEY_KP_SUBTRACT:
pkey = Key::NUMPAD_SUBTRACT;
break;
case GLFW_KEY_KP_MULTIPLY:
pkey = Key::NUMPAD_MULTIPLY;
break;
case GLFW_KEY_KP_DIVIDE:
pkey = Key::NUMPAD_DIVIDE;
break;
case GLFW_KEY_KP_DECIMAL:
pkey = Key::NUMPAD_DECIMAL;
break;
case GLFW_KEY_KP_ENTER:
pkey = Key::NUMPAD_ENTER;
break;
default:
Logger::error("Unknown Key {}", key);
return;
} }
app->m_client_world.get_player().update_player_move_state(key, action); if (action == GLFW_PRESS) {
act = KeyAction::PRESS;
} else if (action == GLFW_RELEASE) {
act = KeyAction::RELEASE;
} else {
act = KeyAction::REPEAT;
}
app->dispatch_event(KeyEvent{pkey, act});
} }
void App::mouse_button_callback(GLFWwindow* window, int button, int action, void App::mouse_button_callback(GLFWwindow* window, int button, int action,
@@ -233,30 +541,46 @@ void App::mouse_button_callback(GLFWwindow* window, int button, int action,
ImGui_ImplGlfw_MouseButtonCallback(window, button, action, mods); ImGui_ImplGlfw_MouseButtonCallback(window, button, action, mods);
return; return;
} }
MouseKey key;
KeyAction act;
switch (button) { switch (button) {
case GLFW_MOUSE_BUTTON_LEFT: case GLFW_MOUSE_BUTTON_LEFT:
if (action == GLFW_PRESS) { key = MouseKey::LEFT_BUTTON;
if (app->m_window.is_mouse_enable()) {
app->m_window.toggle_mouse_able();
app->m_camera.reset_camera();
break;
;
}
Input::get_input_state().mouse_state.left = true;
}
if (action == GLFW_RELEASE) {
Input::get_input_state().mouse_state.left = false;
}
break; break;
case GLFW_MOUSE_BUTTON_RIGHT: case GLFW_MOUSE_BUTTON_RIGHT:
if (action == GLFW_PRESS) { key = MouseKey::RIGHT_BUTTON;
Input::get_input_state().mouse_state.right = true;
}
if (action == GLFW_RELEASE) {
Input::get_input_state().mouse_state.right = false;
}
break; break;
case GLFW_MOUSE_BUTTON_MIDDLE:
key = MouseKey::MIDDLE_BUTTON;
break;
case GLFW_MOUSE_BUTTON_4:
key = MouseKey::BACK_BUTTON;
break;
case GLFW_MOUSE_BUTTON_5:
key = MouseKey::FORWARD_BUTTON;
break;
case GLFW_MOUSE_BUTTON_6:
key = MouseKey::EXTRA_BUTTON_1;
break;
case GLFW_MOUSE_BUTTON_7:
key = MouseKey::EXTRA_BUTTON_2;
break;
case GLFW_MOUSE_BUTTON_8:
key = MouseKey::EXTRA_BUTTON_3;
break;
default:
Logger::error("Unknown Mouse Button {}", button);
return;
} }
if (action == GLFW_PRESS) {
act = KeyAction::PRESS;
} else if (action == GLFW_RELEASE) {
act = KeyAction::RELEASE;
} else {
act = KeyAction::REPEAT;
}
app->dispatch_event(MouseButtonEvent{key, act});
} }
void App::window_focus_callback(GLFWwindow* window, int focused) { void App::window_focus_callback(GLFWwindow* window, int focused) {
@@ -268,17 +592,29 @@ void App::window_focus_callback(GLFWwindow* window, int focused) {
return; return;
} }
if (focused) { if (focused) {
app->m_camera.reset_camera(); auto camera = app->m_window.camera();
if (camera) {
camera->reset_camera();
}
} }
} }
void App::window_reshape_callback(GLFWwindow* window, int, int) { void App::window_reshape_callback(GLFWwindow* window, int width, int height) {
App* app = static_cast<App*>(glfwGetWindowUserPointer(window)); App* app = static_cast<App*>(glfwGetWindowUserPointer(window));
ASSERT_MSG(app, "nullptr"); ASSERT_MSG(app, "nullptr");
app->m_window.update_viewport();
}
app->dispatch_event(WindowResizeEvent{width, height});
Logger::info("Window Reshape W: {} H: {}", width, height);
}
void App::framebuffer_size_callback(GLFWwindow* window, int width, int height) {
App* app = static_cast<App*>(glfwGetWindowUserPointer(window));
ASSERT_MSG(app, "nullptr");
app->dispatch_event(FrameBufferResizeEvent{width, height});
Logger::info("Frame Buffer Reshape W: {} H: {}", width, height);
}
void App::mouse_scroll_callback(GLFWwindow* window, double xoffset, void App::mouse_scroll_callback(GLFWwindow* window, double xoffset,
double yoffset) { double yoffset) {
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
@@ -289,8 +625,7 @@ void App::mouse_scroll_callback(GLFWwindow* window, double xoffset,
ImGui_ImplGlfw_ScrollCallback(window, xoffset, yoffset); ImGui_ImplGlfw_ScrollCallback(window, xoffset, yoffset);
return; return;
} }
auto& player = app->m_client_world.get_player(); app->dispatch_event(MouseWheelEvent(static_cast<float>(yoffset)));
player.update_scroll(yoffset);
} }
void App::cursor_enter_callback(GLFWwindow* window, int entered) { void App::cursor_enter_callback(GLFWwindow* window, int entered) {
@@ -318,8 +653,9 @@ void App::render() {
ImGui_ImplGlfw_Sleep(10); ImGui_ImplGlfw_Sleep(10);
return; return;
} }
m_renderer.render(); m_renderer.begin_frame();
m_scene_manager.render(m_renderer);
m_renderer.end_frame();
glfwSwapBuffers(m_window.get_glfw_window()); glfwSwapBuffers(m_window.get_glfw_window());
} }
@@ -327,20 +663,37 @@ void App::run() {
last_time = glfwGetTime(); last_time = glfwGetTime();
while (!glfwWindowShouldClose(m_window.get_glfw_window())) { while (!glfwWindowShouldClose(m_window.get_glfw_window())) {
if (m_client_world.is_receive_exit()) { // if (m_client_world.is_receive_exit()) {
break; // break;
} // }
update(); update();
render(); render();
} }
m_client_world.request_exit();
if (!m_argument.is_client) { if (!m_argument.is_client) {
m_server.server_world().stop(); m_server.server_world().stop();
} }
} }
static Gait player_gait = Gait::WALK; // static Gait player_gait = Gait::WALK;
void App::update() { void App::update() {
glfwPollEvents(); glfwPollEvents();
{
int w, h;
glfwGetFramebufferSize(m_window.get_glfw_window(), &w, &h);
if (w != m_renderer.frame_width() || h != m_renderer.frame_height()) {
dispatch_event(FrameBufferResizeEvent{w, h});
}
}
{
int w, h;
glfwGetWindowSize(m_window.get_glfw_window(), &w, &h);
if (w != m_renderer.window_width() || h != m_renderer.window_height()) {
dispatch_event(WindowResizeEvent{w, h});
}
}
current_time = glfwGetTime(); current_time = glfwGetTime();
dt = current_time - last_time; dt = current_time - last_time;
last_time = current_time; last_time = current_time;
@@ -359,23 +712,30 @@ void App::update() {
std::format("RSS: {}mb", Tools::get_current_rss() / (1024 * 1024))); std::format("RSS: {}mb", Tools::get_current_rss() / (1024 * 1024)));
} }
m_texture_manager.update(); m_texture_manager.update();
m_client_world.update(dt);
m_camera.update_move_camera();
const auto& player = m_client_world.get_player();
if (player_gait != player.get_gait()) {
player_gait = player.get_gait();
float fov = m_game_config.get("player.fov", 70.0f);
if (player_gait == Gait::WALK) {
m_renderer.update_fov(fov);
}
if (player_gait == Gait::RUN) {
m_renderer.update_fov(fov + 5.0f);
}
}
m_audio.update_listener(m_camera.get_camera_pos(),
m_camera.get_camera_front(), glm::vec3(0, 1, 0));
m_audio.update(); m_audio.update();
DebugCollector::get().get_widget().update(dt);
m_renderer.update(dt); m_renderer.update(dt);
m_scene_manager.update(dt);
}
void App::dispatch_event(const Event& e) {
if (m_window.handle_event(e)) {
return;
}
if (m_texture_manager.handle_event(e)) {
return;
}
if (m_renderer.handle_event(e)) {
return;
}
if (m_scene_manager.handle_event(e)) {
return;
}
} }
int App::start_cubed_application(int argc, char** argv) { int App::start_cubed_application(int argc, char** argv) {
@@ -401,14 +761,11 @@ float App::delta_time() { return dt; }
float App::get_fps() { return fps; } float App::get_fps() { return fps; }
Camera& App::camera() { return m_camera; }
DevPanel& App::dev_panel() { return m_dev_panel; }
Renderer& App::renderer() { return m_renderer; } Renderer& App::renderer() { return m_renderer; }
TextureManager& App::texture_manager() { return m_texture_manager; } TextureManager& App::texture_manager() { return m_texture_manager; }
Window& App::window() { return m_window; } Window& App::window() { return m_window; }
ClientWorld& App::client_world() { return m_client_world; }
ServerWorld& App::server_world() { return m_server.server_world(); } ServerWorld& App::server_world() { return m_server.server_world(); }
Config& App::config() { return m_game_config; } Config& App::config() { return m_game_config; }
const App::Argument& App::argument() const { return m_argument; } const Argument& App::argument() const { return m_argument; }
AudioEngine& App::audio() { return m_audio; } AudioEngine& App::audio() { return m_audio; }
} // namespace Cubed } // namespace Cubed

View File

@@ -115,6 +115,32 @@ bool Camera::is_first_person() const {
return m_perspective == Perspective::FIRST_PERSON; return m_perspective == Perspective::FIRST_PERSON;
} }
bool Camera::handle_event(const Event& e) {
return std::visit(
Overloaded{[this](const MouseMoveEvent& e) {
if (handle_mouse_move_event(e)) {
return true;
}
return false;
},
[](const MouseButtonEvent&) { return false; },
[](const MouseWheelEvent&) { return false; },
[this](const KeyEvent& e) {
if (handle_key_event(e)) {
return true;
}
return false;
},
[](const TextInputEvent&) { return false; },
[](const WindowResizeEvent&) { return false; },
[](const FrameBufferResizeEvent&) { return false; }
} // namespace Cubed
,
e);
}
glm::vec3 Camera::camera_collision(glm::vec3 start, glm::vec3 end, glm::vec3 Camera::camera_collision(glm::vec3 start, glm::vec3 end,
float radius) { float radius) {
constexpr float STEP = 0.05f; constexpr float STEP = 0.05f;
@@ -136,4 +162,20 @@ glm::vec3 Camera::camera_collision(glm::vec3 start, glm::vec3 end,
return end; return end;
} }
bool Camera::handle_key_event(const KeyEvent& e) {
if (e.key == Key::LEFT_ALT && e.action == KeyAction::PRESS) {
reset_camera();
return true;
}
if (e.key == Key::F5 && e.action == KeyAction::PRESS) {
change_perspective();
return true;
}
return false;
}
bool Camera::handle_mouse_move_event(const MouseMoveEvent& e) {
update_cursor_position_camera(e.xpos, e.ypos);
return true;
}
} // namespace Cubed } // namespace Cubed

View File

@@ -1,101 +1,150 @@
#include "Cubed/debug_collector.hpp" #include "Cubed/debug_collector.hpp"
#include "Cubed/tools/cubed_hash.hpp"
#include "Cubed/tools/system_info.hpp" #include "Cubed/tools/system_info.hpp"
#include "version.hpp" #include "version.hpp"
namespace Cubed { namespace Cubed {
DebugCollector::DebugCollector() {} DebugCollector::DebugCollector() : m_widget(nullptr) {}
DebugCollector& DebugCollector::get() { DebugCollector& DebugCollector::get() {
static DebugCollector instance; static DebugCollector instance;
return instance; return instance;
} }
void DebugCollector::init_text() { void DebugCollector::init(int width, int height) {
Text version_text("version"); constexpr float SCALE = 0.6f;
Text fps_text("fps");
Text player_pos_text("player_pos"); m_widget.set_window_size(width, height);
Text rendered_chunk_text("rendered_chunk"); m_widget.set_spacing(15);
Text rss_text("rss"); m_widget.set_anchor(Anchor::TOP_LEFT);
Text cpu_text("cpu"); m_widget.set_offset({0, 5});
Text gpu_text("gpu");
Text opengl_version_text("opengl_version"); // version_text
Text biome_text("biome"); auto& version_text = m_widget.add_child<Label>("version");
Text speed_text("speed");
std::string version{"Version: " CUBED_VERSION}; std::string version{"Version: " CUBED_VERSION};
#ifdef DEBUG_MODE #ifdef DEBUG_MODE
version.append("-debug"); version.append("-debug");
#else #else
version.append("-release"); version.append("-release");
#endif #endif
version_text.position(0.0f, 100.0f)
.scale(0.8f)
.color(Color::WHITE)
.text(version);
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);
rss_text.text("RSS: 0mb").scale(0.8f).position(0.0f, 300.0f);
std::string os;
Text os_text("os"); version_text.set_color(Color::WHITE).set_text(version).set_scale(SCALE);
os_text.scale(0.8f).position(0.0f, 250.0f); m_component.try_emplace(version_text.id(), &version_text);
// fps
auto& fps_text = m_widget.add_child<Label>("fps");
fps_text.set_text("FPS: 0").set_scale(SCALE);
m_component.try_emplace(fps_text.id(), &fps_text);
// player_pos
auto& player_pos_text = m_widget.add_child<Label>("player_pos");
player_pos_text.set_text("x: 0.00 y: 0.00 z: 0.00").set_scale(SCALE);
m_component.try_emplace(player_pos_text.id(), &player_pos_text);
// rendered_chunk
auto& rendered_chunk_text = m_widget.add_child<Label>("rendered_chunk");
rendered_chunk_text.set_text("Rendered Chunk: 0").set_scale(SCALE);
m_component.try_emplace(rendered_chunk_text.id(), &rendered_chunk_text);
// rss
auto& rss_text = m_widget.add_child<Label>("rss");
rss_text.set_text("RSS: 0mb").set_scale(SCALE);
m_component.try_emplace(rss_text.id(), &rss_text);
// os
std::string os;
auto& os_text = m_widget.add_child<Label>("os");
os_text.set_scale(SCALE);
if (Tools::get_os_version(os)) { if (Tools::get_os_version(os)) {
os_text.text("OS: " + os); os_text.set_text("OS: " + os);
Logger::info("System: {}", os); Logger::info("System: {}", os);
} else { } else {
os_text.text("OS: Unknown"); os_text.set_text("OS: Unknown");
} }
cpu_text.text("CPU: " + Tools::get_cpu_info()) m_component.try_emplace(os_text.id(), &os_text);
.scale(0.7f)
.position(0.0f, 350.0f); // cpu
auto& cpu_text = m_widget.add_child<Label>("cpu");
cpu_text.set_text("CPU: " + Tools::get_cpu_info()).set_scale(SCALE);
m_component.try_emplace(cpu_text.id(), &cpu_text);
// gpu
auto& gpu_text = m_widget.add_child<Label>("gpu");
gpu_text gpu_text
.text(std::string{"GPU: "} + .set_text(std::string{"GPU: "} +
reinterpret_cast<const char*>(glGetString(GL_RENDERER))) reinterpret_cast<const char*>(glGetString(GL_RENDERER)))
.scale(0.7f) .set_scale(SCALE);
.position(0.0f, 400.0f); m_component.try_emplace(gpu_text.id(), &gpu_text);
// opengl_version
auto& opengl_version_text = m_widget.add_child<Label>("opengl_version");
opengl_version_text opengl_version_text
.text("OpenGL: " + std::to_string(GLVersion.major) + "." + .set_text("OpenGL: " + std::to_string(GLVersion.major) + "." +
std::to_string(GLVersion.minor)) std::to_string(GLVersion.minor))
.scale(0.7f) .set_scale(SCALE);
.position(0.0f, 450.0f); m_component.try_emplace(opengl_version_text.id(), &opengl_version_text);
biome_text.text("Biome: ").scale(0.8f).position(0.0f, 500.0f);
speed_text.text("Speed: 0 m/s").scale(0.8f).position(0.0f, 550.0f); // biome
m_texts.insert({version_text.uuid(), std::move(version_text)}); auto& biome_text = m_widget.add_child<Label>("biome");
m_texts.insert({fps_text.uuid(), std::move(fps_text)}); biome_text.set_text("Biome: ").set_scale(SCALE);
m_texts.insert({player_pos_text.uuid(), std::move(player_pos_text)}); m_component.try_emplace(biome_text.id(), &biome_text);
m_texts.insert(
{rendered_chunk_text.uuid(), std::move(rendered_chunk_text)}); // speed
m_texts.insert({os_text.uuid(), std::move(os_text)}); auto& speed_text = m_widget.add_child<Label>("speed");
m_texts.insert({rss_text.uuid(), std::move(rss_text)}); speed_text.set_text("Speed: 0 m/s").set_scale(SCALE);
m_texts.insert({cpu_text.uuid(), std::move(cpu_text)}); m_component.try_emplace(speed_text.id(), &speed_text);
m_texts.insert({gpu_text.uuid(), std::move(gpu_text)});
m_texts.insert(
{opengl_version_text.uuid(), std::move(opengl_version_text)});
m_texts.insert({biome_text.uuid(), std::move(biome_text)});
m_texts.insert({speed_text.uuid(), std::move(speed_text)});
} }
std::unordered_map<std::size_t, Text>& DebugCollector::all_texts() { Widget& DebugCollector::get_widget() { return m_widget; }
return m_texts;
bool DebugCollector::handle_event(const Event& e) {
return std::visit(
Overloaded{[this](const MouseMoveEvent& e) {
if (m_widget.handle_mouse_move_event(e)) {
return true;
}
return false;
},
[this](const MouseButtonEvent& e) {
if (m_widget.handle_mouse_button_event(e)) {
return true;
}
return false;
},
[this](const MouseWheelEvent& e) {
if (m_widget.handle_mouse_wheel_event(e)) {
return true;
}
return false;
},
[this](const KeyEvent& e) {
if (m_widget.handle_key_event(e)) {
return true;
}
return false;
},
[](const TextInputEvent&) { return false; },
[this](const WindowResizeEvent& e) {
m_widget.handle_window_resize_event(e);
return false;
},
[](const FrameBufferResizeEvent&) { return false; }
},
e);
} }
Text& DebugCollector::text(std::string_view name) { void DebugCollector::report(const std::string& name, std::string_view content) {
std::size_t id = HASH::str(name); auto t = m_component.find(name);
auto it = m_texts.find(id); if (t == m_component.end()) {
ASSERT_MSG(it != m_texts.end(), "Can't Find Text"); return;
return it->second; }
} if (!t->second) {
return;
void DebugCollector::report(std::string_view name, std::string_view content) { }
auto& t = text(name); t->second->set_text(content);
t.text(content);
} }
} // namespace Cubed } // namespace Cubed

View File

@@ -5,6 +5,7 @@
#include "Cubed/gameplay/cave_path.hpp" #include "Cubed/gameplay/cave_path.hpp"
#include "Cubed/gameplay/client_player.hpp" #include "Cubed/gameplay/client_player.hpp"
#include "Cubed/gameplay/river.path.hpp" #include "Cubed/gameplay/river.path.hpp"
#include "Cubed/scene/world_scene.hpp"
#include "Cubed/tools/log.hpp" #include "Cubed/tools/log.hpp"
#include <imgui.h> #include <imgui.h>
@@ -46,10 +47,12 @@ constexpr float DELTA_ANGLE_MAX = 30.0f;
constexpr int PATH_STEP_MIN = 1; constexpr int PATH_STEP_MIN = 1;
constexpr int PATH_STEP_MAX = 1000; constexpr int PATH_STEP_MAX = 1000;
DevPanel::DevPanel(App& app) : m_app(app), m_config(app.config()) {} DevPanel::DevPanel(WorldScene& world_scene)
: m_app(world_scene.scene_manager().app()), m_world_scene(world_scene),
m_config(m_app.config()) {}
void DevPanel::init() { void DevPanel::init() {
m_player = &m_app.client_world().get_player(); m_player = &m_world_scene.client_world().get_player();
update_config_view(); update_config_view();
update_player_profile(); update_player_profile();
} }
@@ -383,7 +386,7 @@ void DevPanel::show_settings_tab_item() {
128)) { 128)) {
m_config.set("world.rendering_distance", m_config.set("world.rendering_distance",
m_config_view.rendering_distance); m_config_view.rendering_distance);
m_app.client_world().hot_reload(); m_world_scene.client_world().hot_reload();
} }
if (ImGui::Checkbox("Fullscreen", &m_config_view.fullscreen)) { if (ImGui::Checkbox("Fullscreen", &m_config_view.fullscreen)) {
m_config.set("window.fullscreen", m_config_view.fullscreen); m_config.set("window.fullscreen", m_config_view.fullscreen);
@@ -551,20 +554,23 @@ void DevPanel::show_server_world_table_bar() {
} }
void DevPanel::show_client_world_table_bar() { void DevPanel::show_client_world_table_bar() {
static int rendering_distance = m_app.client_world().rendering_distance(); static int rendering_distance =
m_world_scene.client_world().rendering_distance();
if (ImGui::SliderInt("Render Distance", &rendering_distance, 2, 128)) { if (ImGui::SliderInt("Render Distance", &rendering_distance, 2, 128)) {
m_app.client_world().rendering_distance(rendering_distance); m_world_scene.client_world().rendering_distance(rendering_distance);
// Config::get().set("world.rendering_distance", rendering_distance); // Config::get().set("world.rendering_distance", rendering_distance);
} }
if (ImGui::Button("Rebuild World")) { if (ImGui::Button("Rebuild World")) {
m_app.client_world().rebuild_world(); m_world_scene.client_world().rebuild_world();
} }
ImGui::SameLine(); ImGui::SameLine();
if (ImGui::Button("Spawn Point")) { if (ImGui::Button("Spawn Point")) {
m_player->set_player_pos({0.0f, 255.0f, 0.0f}); m_player->set_player_pos({0.0f, 255.0f, 0.0f});
} }
ImGui::Text("Chunk Task Id %d", m_app.client_world().get_chunk_task_id()); ImGui::Text("Chunk Task Id %d",
ImGui::Text("Client World Chunk %d", m_app.client_world().chunk_size()); m_world_scene.client_world().get_chunk_task_id());
ImGui::Text("Client World Chunk %d",
m_world_scene.client_world().chunk_size());
} }
void DevPanel::show_player_tab_item() { void DevPanel::show_player_tab_item() {
@@ -649,7 +655,7 @@ void DevPanel::show_items_tab_item() {
if (ImGui::BeginTabItem("item")) { if (ImGui::BeginTabItem("item")) {
ImGui::Text("Place Block "); ImGui::Text("Place Block ");
ImGui::SameLine(); ImGui::SameLine();
auto& place_texture = textures[m_player->place_block()]; auto& place_texture = textures[m_player->get_current_block()];
if (place_texture) { if (place_texture) {
ImGui::Image(static_cast<ImTextureID>( ImGui::Image(static_cast<ImTextureID>(
static_cast<intptr_t>(place_texture->id())), static_cast<intptr_t>(place_texture->id())),

View File

@@ -132,7 +132,7 @@ void ClientPlayer::update(float delta_time) {
m_gait = compute_gait(); m_gait = compute_gait();
update_move(delta_time); update_move(delta_time);
update_lookup_block(); update_lookup_block();
place_block(delta_time);
DebugCollector::get().report("player_pos", DebugCollector::get().report("player_pos",
std::format("x: {:.2f} y: {:.2f} z: {:.2f}", std::format("x: {:.2f} y: {:.2f} z: {:.2f}",
m_player_pos.x, m_player_pos.y, m_player_pos.x, m_player_pos.y,
@@ -141,48 +141,42 @@ void ClientPlayer::update(float delta_time) {
DebugCollector::get().report("speed", DebugCollector::get().report("speed",
std::format("Speed: {:.2} m/s", m_xz_speed)); std::format("Speed: {:.2} m/s", m_xz_speed));
} }
void ClientPlayer::update_player_move_state(int key, int action) { bool ClientPlayer::update_player_move_state(Key key, KeyAction action) {
switch (key) { if (key == Key::W) {
case GLFW_KEY_W: if (action == KeyAction::PRESS) {
if (action == GLFW_PRESS) {
m_move_state.forward = true; m_move_state.forward = true;
} }
if (action == GLFW_RELEASE) { if (action == KeyAction::RELEASE) {
m_move_state.forward = false; m_move_state.forward = false;
m_sprinting = false; m_sprinting = false;
} }
break; } else if (key == Key::S) {
case GLFW_KEY_S: if (action == KeyAction::PRESS) {
if (action == GLFW_PRESS) {
m_move_state.back = true; m_move_state.back = true;
} }
if (action == GLFW_RELEASE) { if (action == KeyAction::RELEASE) {
m_move_state.back = false; m_move_state.back = false;
} }
break; } else if (key == Key::A) {
case GLFW_KEY_A: if (action == KeyAction::PRESS) {
if (action == GLFW_PRESS) {
m_move_state.left = true; m_move_state.left = true;
} }
if (action == GLFW_RELEASE) { if (action == KeyAction::RELEASE) {
m_move_state.left = false; m_move_state.left = false;
} }
break; } else if (key == Key::D) {
case GLFW_KEY_D: if (action == KeyAction::PRESS) {
if (action == GLFW_PRESS) {
m_move_state.right = true; m_move_state.right = true;
} }
if (action == GLFW_RELEASE) { if (action == KeyAction::RELEASE) {
m_move_state.right = false; m_move_state.right = false;
} }
break; } else if (key == Key::SPACE) {
case GLFW_KEY_SPACE: if (action == KeyAction::PRESS) {
if (action == GLFW_PRESS) {
m_move_state.up = true; m_move_state.up = true;
if (space_on) { if (space_on) {
if (m_game_mode == CREATIVE) { if (m_game_mode == CREATIVE) {
is_fly = !is_fly ? true : false; is_fly = !is_fly;
m_y_speed = 0.0f; m_y_speed = 0.0f;
} }
space_on = false; space_on = false;
@@ -191,35 +185,39 @@ void ClientPlayer::update_player_move_state(int key, int action) {
space_on = true; space_on = true;
} }
} }
if (action == GLFW_RELEASE) { if (action == KeyAction::RELEASE) {
m_move_state.up = false; m_move_state.up = false;
} }
break; } else if (key == Key::LEFT_SHIFT) {
case GLFW_KEY_LEFT_SHIFT: if (action == KeyAction::PRESS) {
if (action == GLFW_PRESS) {
m_move_state.down = true; m_move_state.down = true;
} }
if (action == GLFW_RELEASE) { if (action == KeyAction::RELEASE) {
m_move_state.down = false; m_move_state.down = false;
} }
break; } else if (key == Key::LEFT_CTRL) {
case GLFW_KEY_LEFT_CONTROL: if (action == KeyAction::PRESS) {
if (action == GLFW_PRESS) {
m_sprinting = true; m_sprinting = true;
} }
break; /*
case GLFW_KEY_F4: if (action == KeyAction::RELEASE) {
if (action == GLFW_PRESS) { m_sprinting = false;
}*/
} else if (key == Key::F4) {
if (action == KeyAction::PRESS) {
if (m_game_mode == CREATIVE) { if (m_game_mode == CREATIVE) {
change_mode(SPECTATOR); change_mode(SPECTATOR);
} else { } else {
change_mode(CREATIVE); change_mode(CREATIVE);
} }
} }
break; } else {
return false;
} }
m_moving = m_move_state.forward || m_move_state.back || m_move_state.left || m_moving = m_move_state.forward || m_move_state.back || m_move_state.left ||
m_move_state.right; m_move_state.right;
return true;
} }
void ClientPlayer::update_front_vec(float offset_x, float offset_y) { void ClientPlayer::update_front_vec(float offset_x, float offset_y) {
@@ -275,28 +273,34 @@ void ClientPlayer::update_lookup_block() {
} else { } else {
m_look_block = std::nullopt; m_look_block = std::nullopt;
} }
}
void ClientPlayer::place_block(float dt) {
if (m_look_block != std::nullopt) { if (m_look_block == std::nullopt) {
if (Input::get_input_state().mouse_state.left) { return;
if (m_world.is_solid(m_look_block->pos)) { }
m_world.report_block_change(m_look_block->pos, 0); m_place_time += dt;
} if (m_place_time < PLACE_BLOCK_INTERVAL) {
Input::get_input_state().mouse_state.left = false;
return;
}
m_place_time = 0.0f;
if (m_mouse_state.left) {
if (m_world.is_solid(m_look_block->pos)) {
m_world.report_block_change(m_look_block->pos, 0);
} }
if (Input::get_input_state().mouse_state.right) { }
glm::ivec3 near_pos = m_look_block->pos + m_look_block->normal; if (m_mouse_state.right) {
if (!m_world.is_solid(near_pos)) { glm::ivec3 near_pos = m_look_block->pos + m_look_block->normal;
AABB block_box = ClientWorld::get_block_aabb(near_pos); if (!m_world.is_solid(near_pos)) {
AABB player_box = get_aabb(get_player_pos()); AABB block_box = ClientWorld::get_block_aabb(near_pos);
if (!player_box.intersects(block_box)) { AABB player_box = get_aabb(get_player_pos());
m_world.report_block_change(near_pos, m_place_block); if (!player_box.intersects(block_box)) {
} m_world.report_block_change(near_pos, m_place_block);
} }
Input::get_input_state().mouse_state.right = false;
} }
} }
} }
void ClientPlayer::update_move(float delta_time) { void ClientPlayer::update_move(float delta_time) {
// if frame rate less than 1 frame per second, don't update // if frame rate less than 1 frame per second, don't update
if (delta_time > 1.0f) { if (delta_time > 1.0f) {
@@ -523,7 +527,7 @@ Gait ClientPlayer::compute_gait() const {
return Gait::WALK; return Gait::WALK;
} }
void ClientPlayer::update_scroll(double yoffset) { bool ClientPlayer::update_scroll(float yoffset) {
if (m_game_mode == SPECTATOR) { if (m_game_mode == SPECTATOR) {
if (yoffset > 0) { if (yoffset > 0) {
if (m_max_speed < 500.0f) { if (m_max_speed < 500.0f) {
@@ -548,6 +552,47 @@ void ClientPlayer::update_scroll(double yoffset) {
} }
} }
} }
return true;
}
bool ClientPlayer::handle_mouse_button_event(const MouseButtonEvent& e) {
if (e.action == KeyAction::PRESS) {
if (e.key == MouseKey::LEFT_BUTTON) {
m_mouse_state.left = true;
m_place_time = PLACE_BLOCK_INTERVAL;
return true;
}
if (e.key == MouseKey::RIGHT_BUTTON) {
m_mouse_state.right = true;
m_place_time = PLACE_BLOCK_INTERVAL;
return true;
}
}
if (e.action == KeyAction::RELEASE) {
if (e.key == MouseKey::LEFT_BUTTON) {
m_mouse_state.left = false;
return true;
}
if (e.key == MouseKey::RIGHT_BUTTON) {
m_mouse_state.right = false;
return true;
}
}
return false;
}
bool ClientPlayer::handle_key_event(const KeyEvent& e) {
if (update_player_move_state(e.key, e.action)) {
return true;
}
return false;
}
bool ClientPlayer::handle_mouse_wheel_event(const MouseWheelEvent& e) {
if (update_scroll(e.offset)) {
return true;
}
return false;
} }
void ClientPlayer::update_chunk_set(const ChunkPosSet& set) { void ClientPlayer::update_chunk_set(const ChunkPosSet& set) {
@@ -573,7 +618,7 @@ float& ClientPlayer::acceleration() { return m_acceleration; }
float& ClientPlayer::deceleration() { return m_deceleration; } float& ClientPlayer::deceleration() { return m_deceleration; }
float& ClientPlayer::g() { return m_g; } float& ClientPlayer::g() { return m_g; }
float& ClientPlayer::fly_y_speed() { return m_fly_y_speed; } float& ClientPlayer::fly_y_speed() { return m_fly_y_speed; }
unsigned ClientPlayer::place_block() const { return m_place_block; }; unsigned ClientPlayer::get_current_block() const { return m_place_block; };
void ClientPlayer::set_gait(Gait gait) { m_gait = gait; } void ClientPlayer::set_gait(Gait gait) { m_gait = gait; }
GameMode& ClientPlayer::game_mode() { return m_game_mode; } GameMode& ClientPlayer::game_mode() { return m_game_mode; }
ClientWorld& ClientPlayer::get_world() { return m_world; } ClientWorld& ClientPlayer::get_world() { return m_world; }

View File

@@ -21,8 +21,8 @@ struct ChunkRenderData {
}; };
} // namespace } // namespace
ClientWorld::ClientWorld(AudioEngine& auido, Config& config) ClientWorld::ClientWorld(AudioEngine& auido, Config& config, WorldScene& scene)
: m_player(*this), m_audio(auido), m_config(config) {} : m_player(*this), m_audio(auido), m_config(config), m_world_scene(scene) {}
ClientWorld::~ClientWorld() { ClientWorld::~ClientWorld() {
m_client->close(); m_client->close();
@@ -718,6 +718,7 @@ AABB ClientWorld::get_block_aabb(const glm::ivec3& pos) {
AudioEngine& ClientWorld::get_audio() { return m_audio; } AudioEngine& ClientWorld::get_audio() { return m_audio; }
Config& ClientWorld::get_config() { return m_config; } Config& ClientWorld::get_config() { return m_config; }
WorldScene& ClientWorld::world_scene() { return m_world_scene; }
void ClientWorld::request_exit() { void ClientWorld::request_exit() {
if (m_receive_exit) { if (m_receive_exit) {
@@ -905,6 +906,36 @@ void ClientWorld::update(float delta_time) {
} }
} }
bool ClientWorld::handle_event(const Event& e) {
return std::visit(
Overloaded{[this](const MouseButtonEvent& e) {
if (m_player.handle_mouse_button_event(e)) {
return true;
}
return false;
},
[](const MouseMoveEvent&) { return false; },
[this](const MouseWheelEvent& e) {
if (m_player.handle_mouse_wheel_event(e)) {
return true;
}
return false;
},
[this](const KeyEvent& e) {
if (m_player.handle_key_event(e)) {
return true;
}
return false;
},
[](const TextInputEvent&) { return false; },
[](const WindowResizeEvent&) { return false; },
[](const FrameBufferResizeEvent&) { return false; }
},
e);
}
glm::vec3 ClientWorld::sunlight_dir() const { glm::vec3 ClientWorld::sunlight_dir() const {
float altitude = sin((m_day_tick - 6 * PER_HOUR) / float altitude = sin((m_day_tick - 6 * PER_HOUR) /
static_cast<float>(DAY_TIME / 2) * std::numbers::pi) * static_cast<float>(DAY_TIME / 2) * std::numbers::pi) *

View File

@@ -1,13 +0,0 @@
#include "Cubed/input.hpp"
namespace Cubed {
static InputState input_state;
namespace Input {
InputState& get_input_state() { return input_state; }
} // namespace Input
} // namespace Cubed

View File

@@ -4,6 +4,7 @@
#include "Cubed/gameplay/client_world.hpp" #include "Cubed/gameplay/client_world.hpp"
#include "Cubed/primitive_data.hpp" #include "Cubed/primitive_data.hpp"
#include "Cubed/render/renderer.hpp" #include "Cubed/render/renderer.hpp"
#include "Cubed/scene/world_scene.hpp"
#include "Cubed/texture_manager.hpp" #include "Cubed/texture_manager.hpp"
#include <glm/glm.hpp> #include <glm/glm.hpp>
@@ -188,24 +189,24 @@ void PlayerRenderer::init() {
m_inited = true; m_inited = true;
} }
void PlayerRenderer::render(const Shader& shader) { void PlayerRenderer::render(const Shader& shader, ClientWorld& world) {
if (!m_inited) { if (!m_inited) {
Logger::error("Player Renderer isn't init"); Logger::error("Player Renderer isn't init");
return; return;
} }
auto& m_camera = m_renderer.camera();
auto& m_world = m_renderer.world(); auto& camera = world.world_scene().camera();
auto& m_player = m_world.get_player(); auto& m_player = world.get_player();
glm::mat4 m_v_mat = m_camera.get_camera_lookat(); glm::mat4 m_v_mat = camera.get_camera_lookat();
glm::mat4 m_p_mat = m_renderer.world_proj_matrix(); glm::mat4 m_p_mat = m_renderer.world_proj_matrix();
auto& players = m_world.render_player_data(); auto& players = world.render_player_data();
shader.set_loc("proj_matrix", m_p_mat); shader.set_loc("proj_matrix", m_p_mat);
for (auto& player : players) { for (auto& player : players) {
if (player.uuid == m_player.get_uuid()) { if (player.uuid == m_player.get_uuid()) {
if (m_camera.is_first_person()) { if (camera.is_first_person()) {
continue; continue;
} }
} }
@@ -302,15 +303,15 @@ void PlayerRenderer::render(const Shader& shader) {
} }
void PlayerRenderer::shadow_render(const Shader& shader, void PlayerRenderer::shadow_render(const Shader& shader,
glm::mat4& light_matrix) { glm::mat4& light_matrix,
ClientWorld& world) {
if (!m_inited) { if (!m_inited) {
Logger::error("Player Renderer isn't init"); Logger::error("Player Renderer isn't init");
return; return;
} }
shader.use(); shader.use();
shader.set_loc("lightSpaceMatrix", light_matrix); shader.set_loc("lightSpaceMatrix", light_matrix);
auto& m_world = m_renderer.world(); auto& players = world.render_player_data();
auto& players = m_world.render_player_data();
for (auto& player : players) { for (auto& player : players) {
glm::mat4 model(1.0f); glm::mat4 model(1.0f);

View File

@@ -1,11 +1,8 @@
#include "Cubed/render/renderer.hpp" #include "Cubed/render/renderer.hpp"
#include "Cubed/camera.hpp"
#include "Cubed/config.hpp" #include "Cubed/config.hpp"
#include "Cubed/debug_collector.hpp" #include "Cubed/debug_collector.hpp"
#include "Cubed/dev_panel.hpp" #include "Cubed/dev_panel.hpp"
#include "Cubed/gameplay/client_player.hpp"
#include "Cubed/gameplay/client_world.hpp"
#include "Cubed/primitive_data.hpp" #include "Cubed/primitive_data.hpp"
#include "Cubed/render/renderer_constants.hpp" #include "Cubed/render/renderer_constants.hpp"
#include "Cubed/texture_manager.hpp" #include "Cubed/texture_manager.hpp"
@@ -19,12 +16,9 @@
namespace Cubed { namespace Cubed {
Renderer::Renderer(const Camera& camera, ClientWorld& world, Renderer::Renderer(TextureManager& texture_manager, Config& config)
const TextureManager& texture_manager, DevPanel& dev_panel, : m_texture_manager(texture_manager), m_world_renderer(*this),
Config& config) m_config(config) {}
: m_camera(camera), m_dev_panel(dev_panel),
m_texture_manager(texture_manager), m_world(world),
m_world_renderer(*this), m_config(config) {}
Renderer::~Renderer() { Renderer::~Renderer() {
if (m_init) { if (m_init) {
@@ -99,8 +93,9 @@ void Renderer::init(bool debug_on) {
m_vao[3].bind(); m_vao[3].bind();
for (int i = 0; i < 6; i++) { for (int i = 0; i < 6; i++) {
Vertex2D vex{SQUARE_VERTICES[i][0], SQUARE_VERTICES[i][1], Vertex2D vex{SQUARE_VERTICES_TOP_LEFT[i][0],
SQUARE_TEXTURE_POS[i][0], SQUARE_TEXTURE_POS[i][1], 0}; SQUARE_VERTICES_TOP_LEFT[i][1], SQUARE_TEXTURE_POS[i][0],
SQUARE_TEXTURE_POS[i][1], 0};
m_ui.emplace_back(vex); m_ui.emplace_back(vex);
} }
m_ui_vbo->buffer_data(m_ui.data(), m_ui.size() * sizeof(Vertex2D)); m_ui_vbo->buffer_data(m_ui.data(), m_ui.size() * sizeof(Vertex2D));
@@ -119,6 +114,7 @@ void Renderer::init(bool debug_on) {
VertexArray::unbind(); VertexArray::unbind();
VertexBuffer::unbind(); VertexBuffer::unbind();
m_init = true; m_init = true;
} }
@@ -139,63 +135,93 @@ void Renderer::init_quad() {
void Renderer::init_text() { void Renderer::init_text() {
m_vao[4].bind(); m_vao[4].bind();
DebugCollector::get().init_text(); DebugCollector::get().init(m_window_width, m_window_height);
} }
void Renderer::begin_frame() {
void Renderer::render() {
glDisable(GL_FRAMEBUFFER_SRGB); glDisable(GL_FRAMEBUFFER_SRGB);
// clear screen // clear screen
glClearColor(0.0, 0.0, 0.0, 1.0); glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
void Renderer::end_frame() {}
m_world_renderer.render(); void Renderer::begin_render_ui() {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
render_ui(); glDisable(GL_DEPTH_TEST);
}
void Renderer::end_render_ui() { glEnable(GL_DEPTH_TEST); }
render_text(); void Renderer::render_world(ClientWorld& world) {
m_world_renderer.render(world);
render_dev_panel();
} }
void Renderer::render_text() { void Renderer::render_rect(const Rect& rect) {
auto& shader = get_shader("rect");
shader.use();
shader.set_loc("proj_matrix", m_ui_proj_matrix);
auto pos = rect.pos();
glm::mat4 model_matrix =
glm::translate(glm::mat4(1.0f), glm::vec3(pos.x, pos.y, 0.0f)) *
glm::scale(glm::mat4(1.0f),
glm::vec3(rect.width(), rect.height(), 1.0f));
shader.set_loc("model_matrix", model_matrix);
auto color = color_value(rect.color());
shader.set_loc("inColor",
glm::vec4(color.x, color.y, color.z, rect.alpha()));
m_vao[3].bind();
glDrawArrays(GL_TRIANGLES, 0, 6);
}
void Renderer::render_lable(const Label& label) {
const auto& shader = get_shader("text"); const auto& shader = get_shader("text");
shader.use(); shader.use();
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_DEPTH_TEST);
shader.set_loc("projection", m_ui_proj_matrix); shader.set_loc("projection", m_ui_proj_matrix);
auto& texts = DebugCollector::get().all_texts(); Font::text_texture()->bind(0);
for (auto& t : texts) { auto& data = label.data();
t.second.render(shader); auto pos = label.pos();
} auto& text_style = label.text_style();
auto color = color_value(text_style.color);
data.m_vao->bind();
glm::mat4 model_matrix =
glm::translate(glm::mat4(1.0f), glm::vec3(pos.x, pos.y, 0.0f)) *
glm::scale(glm::mat4(1.0f),
glm::vec3(label.scale(), label.scale(), 1.0f));
glEnable(GL_DEPTH_TEST); shader.set_loc("textColor", glm::vec3(color.x, color.y, color.z));
shader.set_loc("mv_matrix", model_matrix);
glDrawArrays(GL_TRIANGLES, 0, data.m_sum);
} }
void Renderer::render_ui() { void Renderer::render_image(const Image& image) {
const auto& shader = get_shader("ui"); if (!image.texture()) {
Logger::error("Image id {} not set image!", image.id());
return;
}
const auto& shader = get_shader("image");
shader.use(); shader.use();
auto pos = image.pos();
glDisable(GL_DEPTH_TEST); glm::mat4 model_matrix =
glEnable(GL_BLEND); glm::translate(glm::mat4(1.0f), glm::vec3(pos.x, pos.y, 0.0f)) *
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glm::scale(glm::mat4(1.0f),
glm::vec3(image.width(), image.height(), 1.0f));
shader.set_loc("m_matrix", m_ui_model_matrix); shader.set_loc("model_matrix", model_matrix);
shader.set_loc("proj_matrix", m_ui_proj_matrix); shader.set_loc("proj_matrix", m_ui_proj_matrix);
m_vao[3].bind(); m_vao[3].bind();
m_texture_manager.get_ui_array()->bind(0);
image.texture()->bind(0);
glDrawArrays(GL_TRIANGLES, 0, 6); glDrawArrays(GL_TRIANGLES, 0, 6);
Tools::check_opengl_error(); Tools::check_opengl_error();
glEnable(GL_DEPTH_TEST);
} }
void Renderer::update(float delta_time) { m_delta_time = delta_time; } void Renderer::update(float delta_time) { m_delta_time = delta_time; }
@@ -207,20 +233,6 @@ void Renderer::update_fov(float fov) {
glm::perspective(glm::radians(fov), m_aspect, NEAR_PLANE, FAR_PLANE); glm::perspective(glm::radians(fov), m_aspect, NEAR_PLANE, FAR_PLANE);
} }
void Renderer::update_proj_matrix(float aspect, float width, float height) {
m_aspect = aspect;
m_world_proj_matrix =
glm::perspective(glm::radians(m_fov), aspect, NEAR_PLANE, FAR_PLANE);
m_ui_proj_matrix = glm::ortho(0.0f, width, height, 0.0f, -1.0f, 1.0f);
// scale and then translate
m_ui_model_matrix =
glm::translate(glm::mat4(1.0f),
glm::vec3(width / 2.0f, height / 2.0f, 0.0)) *
glm::scale(glm::mat4(1.0f), glm::vec3(50.0f, 50.0f, 1.0f));
}
void Renderer::updata_framebuffer(int width, int height) { void Renderer::updata_framebuffer(int width, int height) {
if (width <= 0 || height <= 0) if (width <= 0 || height <= 0)
return; return;
@@ -228,18 +240,55 @@ void Renderer::updata_framebuffer(int width, int height) {
m_world_renderer.updata_framebuffer(width, height); m_world_renderer.updata_framebuffer(width, height);
FrameBuffer::unbind(); FrameBuffer::unbind();
m_width = width;
m_height = height;
} }
void Renderer::render_dev_panel() { void Renderer::render_dev_panel(DevPanel& dev_panel) {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
m_dev_panel.render(); dev_panel.render();
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
} }
bool Renderer::handle_event(const Event& e) {
return std::visit(Overloaded{[](const MouseMoveEvent&) { return false; },
[](const MouseButtonEvent&) { return false; },
[](const MouseWheelEvent&) { return false; },
[](const KeyEvent&) { return false; },
[](const TextInputEvent&) { return false; },
[this](const WindowResizeEvent& e) {
handle_window_resize_event(e);
return false;
},
[this](const FrameBufferResizeEvent& e) {
handle_frame_buffer_resize_event(e);
return false;
}
},
e);
}
bool Renderer::handle_window_resize_event(const WindowResizeEvent& e) {
m_window_width = static_cast<float>(e.width);
m_window_height = static_cast<float>(e.height);
m_ui_proj_matrix =
glm::ortho(0.0f, m_window_width, m_window_height, 0.0f, -1.0f, 1.0f);
return false;
}
bool Renderer::handle_frame_buffer_resize_event(
const FrameBufferResizeEvent& e) {
int frame_height = e.height;
int frame_width = e.width;
m_frame_width = static_cast<float>(e.width);
m_frame_height = static_cast<float>(e.height);
m_aspect = m_frame_width / m_frame_height;
glViewport(0, 0, frame_width, frame_height);
m_world_proj_matrix =
glm::perspective(glm::radians(m_fov), m_aspect, NEAR_PLANE, FAR_PLANE);
updata_framebuffer(frame_width, frame_height);
return false;
}
float& Renderer::ambient_strength() { float& Renderer::ambient_strength() {
return m_world_renderer.ambient_strength(); return m_world_renderer.ambient_strength();
} }
@@ -277,9 +326,6 @@ float& Renderer::underwater_fog_density() {
} }
float& Renderer::water_density() { return m_world_renderer.water_density(); } float& Renderer::water_density() { return m_world_renderer.water_density(); }
const Camera& Renderer::camera() const { return m_camera; }
const ClientWorld& Renderer::world() const { return m_world; }
ClientWorld& Renderer::world() { return m_world; }
const glm::mat4& Renderer::world_proj_matrix() const { const glm::mat4& Renderer::world_proj_matrix() const {
return m_world_proj_matrix; return m_world_proj_matrix;
} }
@@ -289,8 +335,10 @@ const TextureManager& Renderer::texture_mamger() const {
float Renderer::delta_time() const { return m_delta_time; } float Renderer::delta_time() const { return m_delta_time; }
float Renderer::height() const { return m_height; } float Renderer::window_height() const { return m_window_height; }
float Renderer::width() const { return m_width; } float Renderer::window_width() const { return m_window_width; }
float Renderer::frame_height() const { return m_frame_height; }
float Renderer::frame_width() const { return m_frame_width; }
const glm::mat4& Renderer::p_mat() const { return m_world_proj_matrix; } const glm::mat4& Renderer::p_mat() const { return m_world_proj_matrix; }
const std::vector<VertexArray>& Renderer::vao() const { return m_vao; } const std::vector<VertexArray>& Renderer::vao() const { return m_vao; }
} // namespace Cubed } // namespace Cubed

View File

@@ -13,8 +13,8 @@ void ShaderManager::init() {
"shaders/outline_f_shader.glsl"); "shaders/outline_f_shader.glsl");
register_shader("sky", "shaders/sky_v_shader.glsl", register_shader("sky", "shaders/sky_v_shader.glsl",
"shaders/sky_f_shader.glsl"); "shaders/sky_f_shader.glsl");
register_shader("ui", "shaders/ui_v_shader.glsl", register_shader("image", "shaders/image_v_shader.glsl",
"shaders/ui_f_shader.glsl"); "shaders/image_f_shader.glsl");
register_shader("text", "shaders/text_v_shader.glsl", register_shader("text", "shaders/text_v_shader.glsl",
"shaders/text_f_shader.glsl"); "shaders/text_f_shader.glsl");
register_shader("under_water", "shaders/under_water_v_shader.glsl", register_shader("under_water", "shaders/under_water_v_shader.glsl",
@@ -33,6 +33,8 @@ void ShaderManager::init() {
"shaders/player_f_shader.glsl"); "shaders/player_f_shader.glsl");
register_shader("player_depth", "shaders/depth_player_shader.glsl", register_shader("player_depth", "shaders/depth_player_shader.glsl",
"shaders/depth_player_fragment_shader.glsl"); "shaders/depth_player_fragment_shader.glsl");
register_shader("rect", "shaders/rect_v_shader.glsl",
"shaders/rect_f_shader.glsl");
} }
void ShaderManager::register_shader(const std::string& name, void ShaderManager::register_shader(const std::string& name,

View File

@@ -48,8 +48,10 @@ void Texture::parameterfv(TexturePname pname, const float* param) const {
} }
void Texture::tex_image_2d(TextureFormat internalformat, TextureFormat format, void Texture::tex_image_2d(TextureFormat internalformat, TextureFormat format,
GLenum type, const void* data, GLsizei width, GLenum type, const void* data, GLsizei width,
GLsizei height, GLint level, GLint border) const { GLsizei height, GLint level, GLint border) {
bind(); bind();
m_width = static_cast<float>(width);
m_height = static_cast<float>(height);
glTexImage2D(get_gl_texture_type(), level, glTexImage2D(get_gl_texture_type(), level,
std::to_underlying(internalformat), width, height, border, std::to_underlying(internalformat), width, height, border,
std::to_underlying(format), type, data); std::to_underlying(format), type, data);
@@ -58,8 +60,10 @@ void Texture::tex_image_2d(TextureFormat internalformat, TextureFormat format,
void Texture::tex_image_3d(TextureFormat internalformat, TextureFormat format, void Texture::tex_image_3d(TextureFormat internalformat, TextureFormat format,
GLenum type, const void* data, GLsizei width, GLenum type, const void* data, GLsizei width,
GLsizei height, GLsizei depth, GLint level, GLsizei height, GLsizei depth, GLint level,
GLint border) const { GLint border) {
bind(); bind();
m_width = static_cast<float>(width);
m_height = static_cast<float>(height);
glTexImage3D(get_gl_texture_type(), level, glTexImage3D(get_gl_texture_type(), level,
std::to_underlying(internalformat), width, height, depth, std::to_underlying(internalformat), width, height, depth,
border, std::to_underlying(format), type, data); border, std::to_underlying(format), type, data);
@@ -135,7 +139,8 @@ void Texture::set_clamp_to_edge(bool r, bool s, bool t) const {
} }
TextureType Texture::type() const { return M_TYPE; } TextureType Texture::type() const { return M_TYPE; }
float Texture::width() const { return m_width; }
float Texture::height() const { return m_height; }
void Texture::unbind() { void Texture::unbind() {
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
glBindTexture(GL_TEXTURE_2D_ARRAY, 0); glBindTexture(GL_TEXTURE_2D_ARRAY, 0);

View File

@@ -5,12 +5,12 @@
#include "Cubed/gameplay/client_world.hpp" #include "Cubed/gameplay/client_world.hpp"
#include "Cubed/render/renderer.hpp" #include "Cubed/render/renderer.hpp"
#include "Cubed/render/renderer_constants.hpp" #include "Cubed/render/renderer_constants.hpp"
#include "Cubed/scene/world_scene.hpp"
#include "Cubed/texture_manager.hpp" #include "Cubed/texture_manager.hpp"
#include "Cubed/tools/math_tools.hpp" #include "Cubed/tools/math_tools.hpp"
namespace Cubed { namespace Cubed {
WorldRenderer::WorldRenderer(Renderer& renderer) WorldRenderer::WorldRenderer(Renderer& renderer)
: m_renderer(renderer), m_player_renderer(renderer), : m_renderer(renderer), m_player_renderer(renderer),
m_world(renderer.world()), m_camera(renderer.camera()),
m_texture_manager(renderer.texture_mamger()) {} m_texture_manager(renderer.texture_mamger()) {}
WorldRenderer::~WorldRenderer() { WorldRenderer::~WorldRenderer() {
m_accum_texture.reset(); m_accum_texture.reset();
@@ -30,21 +30,21 @@ WorldRenderer::~WorldRenderer() {
void WorldRenderer::init() { m_player_renderer.init(); } void WorldRenderer::init() { m_player_renderer.init(); }
void WorldRenderer::render() { void WorldRenderer::render(ClientWorld& world) {
// update view matrix; // update view matrix;
view_matrix = m_renderer.camera().get_camera_lookat(); view_matrix = world.world_scene().camera().get_camera_lookat();
m_world_fbo->bind(); m_world_fbo->bind();
// clear world framebuffer // clear world framebuffer
glClearColor(0.0, 0.0, 0.0, 1.0); glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
day_night_calculation(); day_night_calculation(world);
render_sky(); render_sky(world);
render_world(); render_world(world);
render_outline(); render_outline(world);
render_player(); render_player(world);
FrameBuffer::unbind(); FrameBuffer::unbind();
@@ -55,13 +55,13 @@ void WorldRenderer::render() {
glClearColor(0.0f, 0.0f, 0.0f, 1.0); glClearColor(0.0f, 0.0f, 0.0f, 1.0);
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
render_underwater(); render_underwater(world);
glDisable(GL_FRAMEBUFFER_SRGB); glDisable(GL_FRAMEBUFFER_SRGB);
} }
void WorldRenderer::day_night_calculation() { void WorldRenderer::day_night_calculation(ClientWorld& world) {
m_parallel_light.sundir = glm::normalize(m_renderer.world().sunlight_dir()); m_parallel_light.sundir = glm::normalize(world.sunlight_dir());
m_parallel_light.sun_height = (-m_parallel_light.sundir).y; m_parallel_light.sun_height = (-m_parallel_light.sundir).y;
m_parallel_light.lightdir = m_parallel_light.sundir; m_parallel_light.lightdir = m_parallel_light.sundir;
@@ -92,7 +92,9 @@ void WorldRenderer::day_night_calculation() {
m_ambient_strength = glm::mix(0.45f, 0.25f, day_factor); m_ambient_strength = glm::mix(0.45f, 0.25f, day_factor);
} }
void WorldRenderer::render_sky() { void WorldRenderer::render_sky(ClientWorld& world) {
auto& camera = world.world_scene().camera();
glm::vec3 zenith = {0.20f, 0.45f, 0.95f}; glm::vec3 zenith = {0.20f, 0.45f, 0.95f};
@@ -142,9 +144,8 @@ void WorldRenderer::render_sky() {
sky_shader.use(); sky_shader.use();
glm::mat4 model_mat = glm::mat4 model_mat = glm::translate(
glm::translate(glm::mat4(1.0f), glm::mat4(1.0f), camera.get_camera_pos() - glm::vec3(0.5f, 0.5f, 0.5f));
m_camera.get_camera_pos() - glm::vec3(0.5f, 0.5f, 0.5f));
glm::mat4 mv_mat = view_matrix * model_mat; glm::mat4 mv_mat = view_matrix * model_mat;
@@ -195,25 +196,27 @@ void WorldRenderer::render_sky() {
glDrawArrays(GL_TRIANGLES, 0, 6); glDrawArrays(GL_TRIANGLES, 0, 6);
}; };
// draw sun // draw sun
glm::vec3 sun_pos = m_camera.get_camera_pos() + glm::vec3 sun_pos =
normalize(-m_world.sunlight_dir()) * (FAR_PLANE * 0.9f); camera.get_camera_pos() +
normalize(-m_parallel_light.sundir) * (FAR_PLANE * 0.9f);
billboard_drawer(sun_pos, SUN_SIZE, SUN_COLOR); billboard_drawer(sun_pos, SUN_SIZE, SUN_COLOR);
// draw moon // draw moon
glm::vec3 moon_pos = m_camera.get_camera_pos() + glm::vec3 moon_pos =
normalize(m_world.sunlight_dir()) * (FAR_PLANE * 0.9f); camera.get_camera_pos() +
normalize(m_parallel_light.sundir) * (FAR_PLANE * 0.9f);
billboard_drawer(moon_pos, MOON_SIZE, MOON_COLOR); billboard_drawer(moon_pos, MOON_SIZE, MOON_COLOR);
glDepthMask(GL_TRUE); glDepthMask(GL_TRUE);
} }
void WorldRenderer::render_world() { void WorldRenderer::render_world(ClientWorld& world) {
// shader map // shader map
auto m_height = m_renderer.height(); auto height = m_renderer.frame_height();
auto m_width = m_renderer.width(); auto width = m_renderer.frame_width();
glm::mat4 model_mat = glm::mat4 model_mat =
glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, 0.0f)); glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, 0.0f));
@@ -223,22 +226,22 @@ void WorldRenderer::render_world() {
glm::mat4 norm_mat = glm::transpose(glm::inverse(mv_mat)); glm::mat4 norm_mat = glm::transpose(glm::inverse(mv_mat));
if (m_shader_on) { if (m_shader_on) {
shadow_map_generate(); shadow_map_generate(world);
} }
m_world_fbo->bind(); m_world_fbo->bind();
glCullFace(GL_BACK); glCullFace(GL_BACK);
glViewport(0, 0, m_width, m_height); glViewport(0, 0, width, height);
render_normal_block(model_mat, mv_mat, norm_mat); render_normal_block(model_mat, mv_mat, norm_mat, world);
// copy depth buffer // copy depth buffer
m_world_fbo->bind(FrameBufferType::READ_FRAMEBUFFER); m_world_fbo->bind(FrameBufferType::READ_FRAMEBUFFER);
m_oit_fbo->bind(FrameBufferType::DRAW_FRAMEBUFFER); m_oit_fbo->bind(FrameBufferType::DRAW_FRAMEBUFFER);
glBlitFramebuffer(0, 0, m_width, m_height, 0, 0, m_width, m_height, glBlitFramebuffer(0, 0, width, height, 0, 0, width, height,
GL_DEPTH_BUFFER_BIT, GL_NEAREST); GL_DEPTH_BUFFER_BIT, GL_NEAREST);
m_oit_fbo->bind(FrameBufferType::DRAW_FRAMEBUFFER); m_oit_fbo->bind(FrameBufferType::DRAW_FRAMEBUFFER);
@@ -256,14 +259,14 @@ void WorldRenderer::render_world() {
glBlendFunci(0, GL_ONE, GL_ONE); glBlendFunci(0, GL_ONE, GL_ONE);
glBlendFunci(1, GL_ZERO, GL_ONE_MINUS_SRC_COLOR); glBlendFunci(1, GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
render_transparent_block(mv_mat, norm_mat); render_transparent_block(mv_mat, norm_mat, world);
} }
void WorldRenderer::render_outline() { void WorldRenderer::render_outline(ClientWorld& world) {
const auto& shader = m_renderer.get_shader("outline"); const auto& shader = m_renderer.get_shader("outline");
shader.use(); shader.use();
const auto& block_pos = m_renderer.world().get_look_block_pos(); const auto& block_pos = world.get_look_block_pos();
if (block_pos != std::nullopt) { if (block_pos != std::nullopt) {
@@ -285,24 +288,24 @@ void WorldRenderer::render_outline() {
} }
} }
void WorldRenderer::shadow_map_generate() { void WorldRenderer::shadow_map_generate(ClientWorld& world) {
float texels_per_unit = 0.0f; float texels_per_unit = 0.0f;
const auto& lightdir = m_parallel_light.lightdir; const auto& lightdir = m_parallel_light.lightdir;
auto m_delta_time = m_renderer.delta_time(); auto m_delta_time = m_renderer.delta_time();
auto& camera = world.world_scene().camera();
// shader map // shader map
glm::mat4& light_space_matrix = m_parallel_light.light_space_matrix; glm::mat4& light_space_matrix = m_parallel_light.light_space_matrix;
auto& m_render_snapshots = m_world.render_snapshots(); auto& m_render_snapshots = world.render_snapshots();
auto& camera_pos = m_camera.get_camera_pos(); auto& camera_pos = camera.get_camera_pos();
const auto& depth_shader = m_renderer.get_shader("depth_shader"); const auto& depth_shader = m_renderer.get_shader("depth_shader");
depth_shader.use(); depth_shader.use();
glm::vec3 cam_pos = m_camera.get_camera_pos(); glm::vec3 cam_pos = camera.get_camera_pos();
glm::vec3 cam_fwd = m_camera.get_camera_front(); glm::vec3 cam_fwd = camera.get_camera_front();
float half_extent = 128.0f; float half_extent = 128.0f;
glm::vec3 center = cam_pos + cam_fwd * (half_extent * 0.5f); glm::vec3 center = cam_pos + cam_fwd * (half_extent * 0.5f);
@@ -389,13 +392,13 @@ void WorldRenderer::shadow_map_generate() {
} }
// player // player
auto& player_shadow = m_renderer.get_shader("player_depth"); auto& player_shadow = m_renderer.get_shader("player_depth");
m_player_renderer.shadow_render(player_shadow, light_space_matrix); m_player_renderer.shadow_render(player_shadow, light_space_matrix, world);
} }
void WorldRenderer::render_underwater() { void WorldRenderer::render_underwater(ClientWorld& world) {
const auto& shader = m_renderer.get_shader("under_water"); const auto& shader = m_renderer.get_shader("under_water");
auto& camera = world.world_scene().camera();
shader.use(); shader.use();
auto& m_vao = m_renderer.vao(); auto& m_vao = m_renderer.vao();
@@ -406,10 +409,10 @@ void WorldRenderer::render_underwater() {
shader.set_loc("u_sceneTexture", 0); shader.set_loc("u_sceneTexture", 0);
shader.set_loc("u_time", static_cast<float>(glfwGetTime())); shader.set_loc("u_time", static_cast<float>(glfwGetTime()));
shader.set_loc("u_underwater", m_camera.is_under_water()); shader.set_loc("u_underwater", camera.is_under_water());
shader.set_loc("u_waterColor", glm::vec3(0.1f, 0.25f, 0.35f)); shader.set_loc("u_waterColor", glm::vec3(0.1f, 0.25f, 0.35f));
shader.set_loc("u_fogDensity", m_underwater_fog_density); shader.set_loc("u_fogDensity", m_underwater_fog_density);
shader.set_loc("cameraPos", m_camera.get_camera_pos()); shader.set_loc("cameraPos", camera.get_camera_pos());
shader.set_loc("sunDir", -m_parallel_light.sundir); shader.set_loc("sunDir", -m_parallel_light.sundir);
shader.set_loc("waterDensity", m_water_density); shader.set_loc("waterDensity", m_water_density);
shader.set_loc("InverseViewProjection", shader.set_loc("InverseViewProjection",
@@ -427,13 +430,14 @@ void WorldRenderer::render_underwater() {
void WorldRenderer::render_normal_block(const glm::mat4& model_mat, void WorldRenderer::render_normal_block(const glm::mat4& model_mat,
const glm::mat4& mv_mat, const glm::mat4& mv_mat,
const glm::mat4& norm_mat) { const glm::mat4& norm_mat,
ClientWorld& world) {
// shader map // shader map
glm::mat4& light_space_matrix = m_parallel_light.light_space_matrix; glm::mat4& light_space_matrix = m_parallel_light.light_space_matrix;
auto& camera = world.world_scene().camera();
auto& m_render_snapshots = m_world.render_snapshots(); auto& m_render_snapshots = world.render_snapshots();
auto& camera_pos = m_camera.get_camera_pos(); auto& camera_pos = camera.get_camera_pos();
const auto& lightdir = m_parallel_light.lightdir; const auto& lightdir = m_parallel_light.lightdir;
@@ -467,14 +471,14 @@ void WorldRenderer::render_normal_block(const glm::mat4& model_mat,
normal_block_shader.set_loc("maxRadius", m_max_radius); normal_block_shader.set_loc("maxRadius", m_max_radius);
normal_block_shader.set_loc("samples", m_samples); normal_block_shader.set_loc("samples", m_samples);
normal_block_shader.set_loc("specularStrength", m_specular_strength); normal_block_shader.set_loc("specularStrength", m_specular_strength);
normal_block_shader.set_loc("cameraPos", m_camera.get_camera_pos()); normal_block_shader.set_loc("cameraPos", camera.get_camera_pos());
normal_block_shader.set_loc("flipY", m_flip_y); normal_block_shader.set_loc("flipY", m_flip_y);
normal_block_shader.set_loc("renderDistance", m_world.rendering_distance()); normal_block_shader.set_loc("renderDistance", world.rendering_distance());
normal_block_shader.set_loc("skyColor", m_sky_uniform.sky_top); normal_block_shader.set_loc("skyColor", m_sky_uniform.sky_top);
glm::mat4 mvp_mat = proj_mat * mv_mat; glm::mat4 mvp_mat = proj_mat * mv_mat;
auto& m_planes = m_world.planes(); auto& m_planes = world.planes();
Math::extract_frustum_planes(mvp_mat, m_planes); Math::extract_frustum_planes(mvp_mat, m_planes);
@@ -545,10 +549,11 @@ void WorldRenderer::render_normal_block(const glm::mat4& model_mat,
} }
void WorldRenderer::render_transparent_block(const glm::mat4& mv_mat, void WorldRenderer::render_transparent_block(const glm::mat4& mv_mat,
const glm::mat4& norm_mat) { const glm::mat4& norm_mat,
ClientWorld& world) {
auto& m_render_snapshots = m_world.render_snapshots();
auto& m_render_snapshots = world.render_snapshots();
auto& camera = world.world_scene().camera();
const auto& lightdir = m_parallel_light.lightdir; const auto& lightdir = m_parallel_light.lightdir;
glm::vec3 light_dir_view = glm::vec3 light_dir_view =
glm::normalize(glm::mat3(view_matrix) * lightdir); glm::normalize(glm::mat3(view_matrix) * lightdir);
@@ -573,11 +578,11 @@ void WorldRenderer::render_transparent_block(const glm::mat4& mv_mat,
accum_shader.use(); accum_shader.use();
set_accum_loc(accum_shader); set_accum_loc(accum_shader);
accum_shader.set_loc("cameraPos", m_camera.get_camera_pos()); accum_shader.set_loc("cameraPos", camera.get_camera_pos());
m_texture_manager.get_texture_array()->bind(0); m_texture_manager.get_texture_array()->bind(0);
auto& m_planes = m_world.planes(); auto& m_planes = world.planes();
for (const auto& snapshot : m_render_snapshots) { for (const auto& snapshot : m_render_snapshots) {
if (!snapshot) { if (!snapshot) {
@@ -619,7 +624,7 @@ void WorldRenderer::render_transparent_block(const glm::mat4& mv_mat,
water_shader.set_loc("cloudWhiteMix", m_sky_uniform.cloud_white_mix); water_shader.set_loc("cloudWhiteMix", m_sky_uniform.cloud_white_mix);
water_shader.set_loc("cloudThresholdLow", m_cloud_threshold_low); water_shader.set_loc("cloudThresholdLow", m_cloud_threshold_low);
water_shader.set_loc("cloudThresholdHigh", m_cloud_threshold_high); water_shader.set_loc("cloudThresholdHigh", m_cloud_threshold_high);
water_shader.set_loc("underwater", m_camera.is_under_water()); water_shader.set_loc("underwater", camera.is_under_water());
water_shader.set_loc("refractStrength", m_refract_strength); water_shader.set_loc("refractStrength", m_refract_strength);
water_shader.set_loc("enablePerturb", m_water_perturb); water_shader.set_loc("enablePerturb", m_water_perturb);
water_shader.set_loc("enableDepthFade", m_water_depth_fade); water_shader.set_loc("enableDepthFade", m_water_depth_fade);
@@ -670,7 +675,7 @@ void WorldRenderer::render_transparent_block(const glm::mat4& mv_mat,
glBindVertexArray(0); glBindVertexArray(0);
} }
void WorldRenderer::render_player() { void WorldRenderer::render_player(ClientWorld& world) {
auto& shader = m_renderer.get_shader("player"); auto& shader = m_renderer.get_shader("player");
shader.use(); shader.use();
glm::vec3 light_dir_view = glm::vec3 light_dir_view =
@@ -692,7 +697,7 @@ void WorldRenderer::render_player() {
// shader.set_loc("skyColor", m_sky_uniform.sky_top); // shader.set_loc("skyColor", m_sky_uniform.sky_top);
m_depth_map_texture->bind(0); m_depth_map_texture->bind(0);
m_player_renderer.render(shader); m_player_renderer.render(shader, world);
} }
glm::vec3 WorldRenderer::quantize_sun_direction(const glm::vec3& lightdir, glm::vec3 WorldRenderer::quantize_sun_direction(const glm::vec3& lightdir,

View File

@@ -0,0 +1,21 @@
#include "Cubed/scene/main_menu_scene.hpp"
namespace Cubed {
MainMenuScene::MainMenuScene(SceneManager& scene_manager)
: m_scene_manager(scene_manager), m_ui_manager(*this) {}
MainMenuScene::~MainMenuScene() {}
void MainMenuScene::update(float dt) { m_ui_manager.update(dt); }
void MainMenuScene::render(Renderer& renderer) {
m_ui_manager.render(renderer);
}
bool MainMenuScene::handle_event(const Event& e) {
if (m_ui_manager.handle_event(e)) {
return true;
}
return false;
}
void MainMenuScene::on_enter() { m_ui_manager.init(); }
void MainMenuScene::on_leave() {}
SceneManager& MainMenuScene::scene_manager() { return m_scene_manager; }
} // namespace Cubed

View File

@@ -0,0 +1,99 @@
#include "Cubed/scene/scene_manager.hpp"
#include "Cubed/scene/main_menu_scene.hpp"
#include "Cubed/scene/world_scene.hpp"
namespace Cubed {
SceneManager::SceneManager(App& app) : m_app(app) {}
SceneManager::~SceneManager() {}
void SceneManager::update(float dt) {
m_pending_delete_scene.clear();
process_operation();
if (!m_scenes.empty()) {
m_scenes.top()->update(dt);
}
}
void SceneManager::render(Renderer& renderer) {
if (m_scenes.empty()) {
return;
}
m_scenes.top()->render(renderer);
}
bool SceneManager::handle_event(const Event& e) {
if (m_scenes.empty()) {
return false;
}
return m_scenes.top()->handle_event(e);
}
void SceneManager::request_change(SceneType type) {
ASSERT(!m_operation.has_value());
m_operation = {OperationType::CHANGE, type};
}
void SceneManager::request_push(SceneType type) {
ASSERT(!m_operation.has_value());
m_operation = {OperationType::PUSH, type};
}
void SceneManager::request_pop() {
ASSERT(!m_operation.has_value());
m_operation = {OperationType::POP, std::nullopt};
}
void SceneManager::process_operation() {
while (m_operation) {
auto op = std::move(*m_operation);
m_operation.reset();
switch (op.type) {
case OperationType::PUSH:
push(*op.scene);
break;
case OperationType::POP:
pop();
break;
case OperationType::CHANGE:
change(*op.scene);
break;
}
}
}
void SceneManager::change(SceneType type) {
if (!m_scenes.empty()) {
pop();
}
push(type);
}
void SceneManager::push(SceneType type) {
auto scene = create_scene(type);
scene->on_enter();
m_scenes.push(std::move(scene));
}
void SceneManager::pop() {
if (m_scenes.empty()) {
return;
}
auto scene = std::move(m_scenes.top());
m_scenes.pop();
scene->on_leave();
m_pending_delete_scene.push_back(std::move(scene));
}
std::unique_ptr<Scene> SceneManager::create_scene(SceneType type) {
switch (type) {
case SceneType::WORLD:
return std::make_unique<WorldScene>(*this);
case SceneType::MAIN_MENU:
return std::make_unique<MainMenuScene>(*this);
}
std::string err = std::format("Unknown Scene");
ASSERT_MSG(false, err);
throw std::runtime_error(err);
}
App& SceneManager::app() { return m_app; }
} // namespace Cubed

88
src/scene/world_scene.cpp Normal file
View File

@@ -0,0 +1,88 @@
#include "Cubed/scene/world_scene.hpp"
#include "Cubed/app.hpp"
#include "Cubed/render/renderer.hpp"
#include "Cubed/scene/scene_manager.hpp"
namespace Cubed {
WorldScene::WorldScene(SceneManager& scene_manager)
: m_scene_manager(scene_manager), m_dev_panel(*this),
m_client_world(scene_manager.app().audio(), scene_manager.app().config(),
*this),
m_ui_manager(*this), m_argument(scene_manager.app().argument()) {}
WorldScene::~WorldScene() {
if (m_client) {
m_client->stop();
}
}
void WorldScene::update(float dt) {
m_client_world.update(dt);
m_camera.update_move_camera();
m_client_world.get_audio().update_listener(m_camera.get_camera_pos(),
m_camera.get_camera_front(),
glm::vec3(0, 1, 0));
/*
const auto& player = m_client_world.get_player();
if (player_gait != player.get_gait()) {
player_gait = player.get_gait();
float fov = m_client_world.get("player.fov", 70.0f);
if (player_gait == Gait::WALK) {
m_renderer.update_fov(fov);
}
if (player_gait == Gait::RUN) {
m_renderer.update_fov(fov + 5.0f);
}
}*/
m_ui_manager.update(dt);
}
void WorldScene::render(Renderer& renderer) {
renderer.render_world(m_client_world);
renderer.render_dev_panel(m_dev_panel);
m_ui_manager.render(renderer);
}
bool WorldScene::handle_event(const Event& e) {
if (m_ui_manager.handle_event(e)) {
return true;
}
if (m_camera.handle_event(e)) {
return true;
}
// world event needs to be processed last
if (m_client_world.handle_event(e)) {
return true;
}
return false;
}
void WorldScene::on_enter() {
m_client = std::make_shared<NetworkClient>(m_client_world);
m_client->start(m_argument.ip, m_argument.port);
// init will send packet
m_client_world.init(m_argument.player, m_client);
Logger::info("World Init Success");
m_camera.camera_init(&m_client_world.get_player());
m_scene_manager.app().window().set_camera(&m_camera);
m_dev_panel.init();
m_ui_manager.init();
m_scene_manager.app().window().set_game_running(true);
}
void WorldScene::on_leave() {
m_client_world.request_exit();
m_scene_manager.app().window().set_camera(nullptr);
m_scene_manager.app().window().set_game_running(false);
}
Camera& WorldScene::camera() { return m_camera; }
SceneManager& WorldScene::scene_manager() { return m_scene_manager; }
ClientWorld& WorldScene::client_world() { return m_client_world; }
} // namespace Cubed

View File

@@ -11,7 +11,6 @@ constexpr int BLOCK_SIZE = 16;
constexpr int BLOCK_NORMAL_SIZE = 128; constexpr int BLOCK_NORMAL_SIZE = 128;
constexpr int CROSS_PLANE_SIZE = 16; constexpr int CROSS_PLANE_SIZE = 16;
constexpr int BLOCK_ITEM_SIZE = 16; constexpr int BLOCK_ITEM_SIZE = 16;
constexpr int UI_SIZE = 16;
constexpr int BLOCK_STATUS_SIZE = 16; constexpr int BLOCK_STATUS_SIZE = 16;
constexpr int SKIN_SIZE = 64; constexpr int SKIN_SIZE = 64;
@@ -58,7 +57,13 @@ const Texture* TextureManager::get_texture_array() const {
const Texture* TextureManager::get_cross_plane_array() const { const Texture* TextureManager::get_cross_plane_array() const {
return m_cross_plane_array.get(); return m_cross_plane_array.get();
} }
const Texture* TextureManager::get_ui_array() const { return m_ui_array.get(); } const Texture* TextureManager::get_image_texture(const std::string& path) {
auto it = m_ui_map.find(path);
if (it != m_ui_map.end()) {
return it->second.get();
}
return load_image_texture(path);
}
const Texture* TextureManager::get_pbr_texture() const { const Texture* TextureManager::get_pbr_texture() const {
return m_normal_texture_array.get(); return m_normal_texture_array.get();
@@ -77,15 +82,11 @@ void TextureManager::load_block_status(unsigned id) {
std::string path = "texture/status/" + std::to_string(id) + ".png"; std::string path = "texture/status/" + std::to_string(id) + ".png";
unsigned char* image_data = nullptr; auto image_data = (Tools::load_image_data(path));
image_data = (Tools::load_image_data(path));
m_block_status_array->tex_sub_image_3d( m_block_status_array->tex_sub_image_3d(
TextureFormat::RGBA, GL_UNSIGNED_BYTE, image_data, 0, 0, id, TextureFormat::RGBA, GL_UNSIGNED_BYTE, image_data.data, 0, 0, id,
BLOCK_STATUS_SIZE, BLOCK_STATUS_SIZE); BLOCK_STATUS_SIZE, BLOCK_STATUS_SIZE);
Tools::delete_image_data(image_data);
} }
void TextureManager::load_block_texture(unsigned id) { void TextureManager::load_block_texture(unsigned id) {
@@ -101,7 +102,7 @@ void TextureManager::load_block_texture(unsigned id) {
return; return;
} }
unsigned char* image_data[6]; std::array<ImageData, 6> image_data;
std::string block_texture_path = "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[0] = (Tools::load_image_data(block_texture_path + "/front.png"));
@@ -114,10 +115,9 @@ void TextureManager::load_block_texture(unsigned id) {
Tools::check_opengl_error(); Tools::check_opengl_error();
for (int i = 0; i < 6; i++) { for (int i = 0; i < 6; i++) {
m_texture_array->tex_sub_image_3d(TextureFormat::RGBA, GL_UNSIGNED_BYTE, m_texture_array->tex_sub_image_3d(TextureFormat::RGBA, GL_UNSIGNED_BYTE,
image_data[i], 0, 0, id * 6 + i, image_data[i].data, 0, 0, id * 6 + i,
BLOCK_SIZE, BLOCK_SIZE); BLOCK_SIZE, BLOCK_SIZE);
Tools::check_opengl_error(); Tools::check_opengl_error();
Tools::delete_image_data(image_data[i]);
} }
} }
@@ -127,41 +127,43 @@ void TextureManager::load_block_item_texture(unsigned id) {
std::string name{BlockManager::name_form_id(id)}; std::string name{BlockManager::name_form_id(id)};
std::string path = "texture/item/block/" + name + ".png"; std::string path = "texture/item/block/" + name + ".png";
unsigned char* data = nullptr;
data = Tools::load_image_data(path); auto data = Tools::load_image_data(path);
std::unique_ptr<Texture> texture = std::unique_ptr<Texture> texture =
std::make_unique<Texture>(TextureType::TEXTURE_2D); std::make_unique<Texture>(TextureType::TEXTURE_2D);
texture->tex_image_2d(TextureFormat::RGBA8, TextureFormat::RGBA, texture->tex_image_2d(TextureFormat::RGBA8, TextureFormat::RGBA,
GL_UNSIGNED_BYTE, data, BLOCK_ITEM_SIZE, GL_UNSIGNED_BYTE, data.data, BLOCK_ITEM_SIZE,
BLOCK_ITEM_SIZE); BLOCK_ITEM_SIZE);
texture->set_nearest(); texture->set_nearest();
texture->set_clamp_to_border(); texture->set_clamp_to_border();
m_item_textures.push_back(std::move(texture)); m_item_textures.push_back(std::move(texture));
Tools::delete_image_data(data);
} }
void TextureManager::load_cross_plane_texture(unsigned id) { void TextureManager::load_cross_plane_texture(unsigned id) {
std::string path = std::string path =
"texture/block/" + BlockManager::name_form_id(id) + "/cross.png"; "texture/block/" + BlockManager::name_form_id(id) + "/cross.png";
unsigned char* image_data = Tools::load_image_data(path); auto image_data = Tools::load_image_data(path);
m_cross_plane_array->tex_sub_image_3d(TextureFormat::RGBA, GL_UNSIGNED_BYTE, m_cross_plane_array->tex_sub_image_3d(TextureFormat::RGBA, GL_UNSIGNED_BYTE,
image_data, 0, 0, image_data.data, 0, 0,
BlockManager::cross_plane_index(id), BlockManager::cross_plane_index(id),
CROSS_PLANE_SIZE, CROSS_PLANE_SIZE); CROSS_PLANE_SIZE, CROSS_PLANE_SIZE);
Tools::delete_image_data(image_data);
} }
void TextureManager::load_ui_texture(unsigned id) { const Texture* TextureManager::load_image_texture(const std::string& path) {
ASSERT_MSG(id < MAX_UI_NUM, "Exceed the max ui sum limit");
std::string path = "texture/ui/" + std::to_string(id) + ".png"; auto image_data = (Tools::load_image_data(path));
unsigned char* image_data = nullptr; std::unique_ptr<Texture> image =
image_data = (Tools::load_image_data(path)); std::make_unique<Texture>(TextureType::TEXTURE_2D);
m_ui_array->tex_sub_image_3d(TextureFormat::RGBA, GL_UNSIGNED_BYTE, image->tex_image_2d(RGBA, RGBA, GL_UNSIGNED_BYTE, image_data.data,
image_data, 0, 0, id, UI_SIZE, UI_SIZE); image_data.width, image_data.height);
Tools::delete_image_data(image_data); image->set_nearest();
auto [it, inserted] = m_ui_map.try_emplace(path, std::move(image));
if (!inserted) {
Logger::error("Path {} already exist!", path);
}
return it->second.get();
} }
void TextureManager::load_pbr_texture(unsigned id) { void TextureManager::load_pbr_texture(unsigned id) {
@@ -177,7 +179,7 @@ void TextureManager::load_pbr_texture(unsigned id) {
std::string path = "normal/block/" + BlockManager::name_form_id(id); std::string path = "normal/block/" + BlockManager::name_form_id(id);
unsigned char* image_data[6]; std::array<ImageData, 6> image_data;
image_data[0] = (Tools::load_image_data(path + "/front_n.png", false)); image_data[0] = (Tools::load_image_data(path + "/front_n.png", false));
image_data[1] = (Tools::load_image_data(path + "/right_n.png", false)); image_data[1] = (Tools::load_image_data(path + "/right_n.png", false));
@@ -187,7 +189,7 @@ void TextureManager::load_pbr_texture(unsigned id) {
image_data[5] = (Tools::load_image_data(path + "/base_n.png", false)); image_data[5] = (Tools::load_image_data(path + "/base_n.png", false));
for (int i = 0; i < 6; i++) { for (int i = 0; i < 6; i++) {
unsigned char* data = image_data[i]; unsigned char* data = image_data[i].data;
bool is_fallback = false; bool is_fallback = false;
if (!data) { if (!data) {
is_fallback = true; is_fallback = true;
@@ -200,7 +202,6 @@ void TextureManager::load_pbr_texture(unsigned id) {
if (is_fallback) { if (is_fallback) {
delete[] data; delete[] data;
} else { } else {
Tools::delete_image_data(image_data[i]);
} }
} }
} }
@@ -242,26 +243,16 @@ void TextureManager::init_block() {
Logger::info("Block Texture Load Success"); Logger::info("Block Texture Load Success");
} }
void TextureManager::init_ui() { void TextureManager::init_ui() {}
m_ui_array = std::make_unique<Texture>(TextureType::TEXTURE_2D_ARRAY);
m_ui_array->tex_image_3d(TextureFormat::RGBA, TextureFormat::RGBA,
GL_UNSIGNED_BYTE, nullptr, UI_SIZE, UI_SIZE,
MAX_UI_NUM);
for (int i = 0; i < MAX_UI_NUM; i++) {
load_ui_texture(i);
}
m_ui_array->set_nearest();
}
void TextureManager::init_skin() { void TextureManager::init_skin() {
m_skin = std::make_unique<Texture>(TextureType::TEXTURE_2D); m_skin = std::make_unique<Texture>(TextureType::TEXTURE_2D);
std::string path = "texture/skin/player001.png"; std::string path = "texture/skin/player001.png";
unsigned char* image_data = nullptr;
image_data = (Tools::load_image_data(path)); auto image_data = (Tools::load_image_data(path));
m_skin->tex_image_2d(TextureFormat::RGBA, TextureFormat::RGBA, m_skin->tex_image_2d(TextureFormat::RGBA, TextureFormat::RGBA,
GL_UNSIGNED_BYTE, image_data, SKIN_SIZE, SKIN_SIZE); GL_UNSIGNED_BYTE, image_data.data, SKIN_SIZE,
Tools::delete_image_data(image_data); SKIN_SIZE);
m_skin->set_nearest_and_minpmap(); m_skin->set_nearest_and_minpmap();
m_skin->set_aniso(m_aniso); m_skin->set_aniso(m_aniso);
} }
@@ -314,4 +305,31 @@ void TextureManager::hot_reload() {
int TextureManager::max_aniso() const { return static_cast<int>(m_max_aniso); } int TextureManager::max_aniso() const { return static_cast<int>(m_max_aniso); }
bool TextureManager::handle_event(const Event& e) {
return std::visit(
Overloaded{[](const MouseMoveEvent&) { return false; },
[](const MouseButtonEvent&) { return false; },
[](const MouseWheelEvent&) { return false; },
[this](const KeyEvent& e) {
if (handle_key_event(e)) {
return true;
}
return false;
},
[](const TextInputEvent&) { return false; },
[](const WindowResizeEvent&) { return false; },
[](const FrameBufferResizeEvent&) { return false; }
},
e);
}
bool TextureManager::handle_key_event(const KeyEvent& e) {
if (e.key == Key::R && e.action == KeyAction::PRESS) {
need_reload();
return true;
}
return false;
}
} // namespace Cubed } // namespace Cubed

View File

@@ -38,9 +38,9 @@ void Font::load_character(char8_t c) {
static_cast<int>(c), width, height); static_cast<int>(c), width, height);
Character character = { Character character = {
glm::vec2{0.0f, 0.0f}, glm::vec2{0.5f / m_texture_width, 0.5f / m_texture_height},
glm::vec2{static_cast<float>(width) / m_texture_width, glm::vec2{(width - 0.5f) / m_texture_width,
static_cast<float>(height) / m_texture_height}, (height - 0.5f) / m_texture_height},
glm::ivec2(m_face->glyph->bitmap.width, m_face->glyph->bitmap.rows), glm::ivec2(m_face->glyph->bitmap.width, m_face->glyph->bitmap.rows),
glm::ivec2(m_face->glyph->bitmap_left, m_face->glyph->bitmap_top), glm::ivec2(m_face->glyph->bitmap_left, m_face->glyph->bitmap_top),
static_cast<GLuint>(m_face->glyph->advance.x)}; static_cast<GLuint>(m_face->glyph->advance.x)};
@@ -51,7 +51,7 @@ void Font::load_character(char8_t c) {
void Font::setup_font_character() { void Font::setup_font_character() {
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
m_text_texture = std::make_unique<Texture>(TextureType::TEXTURE_2D_ARRAY); m_text_texture = std::make_unique<Texture>(TextureType::TEXTURE_2D_ARRAY);
m_text_texture->tex_image_3d(TextureFormat::RED, TextureFormat::RED, m_text_texture->tex_image_3d(TextureFormat::R8, TextureFormat::RED,
GL_UNSIGNED_BYTE, nullptr, m_texture_width, GL_UNSIGNED_BYTE, nullptr, m_texture_width,
m_texture_height, MAX_CHARACTER); m_texture_height, MAX_CHARACTER);
@@ -62,24 +62,39 @@ void Font::setup_font_character() {
m_text_texture->set_clamp_to_edge(false, true, true); m_text_texture->set_clamp_to_edge(false, true, true);
} }
std::vector<Vertex2D> Font::vertices(const std::string& text, float x, float y, TextMesh Font::vertices(const std::string& text) {
float scale) {
static Font font; static Font font;
std::vector<Vertex2D> vertices; std::vector<Vertex2D> vertices;
float min_x = std::numeric_limits<float>::max();
float min_y = std::numeric_limits<float>::max();
float max_x = std::numeric_limits<float>::lowest();
float max_y = std::numeric_limits<float>::lowest();
float pen_x = 0.0f;
float pen_y = 0.0f;
for (char8_t c : text) { for (char8_t c : text) {
auto it = font.m_characters.find(c); auto it = font.m_characters.find(c);
if (it == font.m_characters.end()) { if (it == font.m_characters.end()) {
Logger::error("Can't find character {}", static_cast<char>(c)); Logger::error("Can't find character {}", static_cast<char>(c));
continue; continue;
} }
Character& ch = it->second;
float xpos = x + ch.bearing.x * scale;
float ypos = y - ch.bearing.y * scale;
float w = ch.size.x * scale; Character& ch = it->second;
float h = ch.size.y * scale;
float xpos = pen_x + ch.bearing.x;
float ypos = pen_y - ch.bearing.y;
float w = ch.size.x;
float h = ch.size.y;
min_x = std::min(min_x, xpos);
min_y = std::min(min_y, ypos);
max_x = std::max(max_x, xpos + w);
max_y = std::max(max_y, ypos + h);
vertices.emplace_back(xpos, ypos + h, ch.uv_min.x, ch.uv_max.y, vertices.emplace_back(xpos, ypos + h, ch.uv_min.x, ch.uv_max.y,
static_cast<float>(c)); static_cast<float>(c));
@@ -87,6 +102,7 @@ std::vector<Vertex2D> Font::vertices(const std::string& text, float x, float y,
static_cast<float>(c)); static_cast<float>(c));
vertices.emplace_back(xpos + w, ypos, ch.uv_max.x, ch.uv_min.y, vertices.emplace_back(xpos + w, ypos, ch.uv_max.x, ch.uv_min.y,
static_cast<float>(c)); static_cast<float>(c));
vertices.emplace_back(xpos, ypos + h, ch.uv_min.x, ch.uv_max.y, vertices.emplace_back(xpos, ypos + h, ch.uv_min.x, ch.uv_max.y,
static_cast<float>(c)); static_cast<float>(c));
vertices.emplace_back(xpos + w, ypos, ch.uv_max.x, ch.uv_min.y, vertices.emplace_back(xpos + w, ypos, ch.uv_max.x, ch.uv_min.y,
@@ -94,10 +110,15 @@ std::vector<Vertex2D> Font::vertices(const std::string& text, float x, float y,
vertices.emplace_back(xpos + w, ypos + h, ch.uv_max.x, ch.uv_max.y, vertices.emplace_back(xpos + w, ypos + h, ch.uv_max.x, ch.uv_max.y,
static_cast<float>(c)); static_cast<float>(c));
x += (ch.advance >> 6) * scale; pen_x += (ch.advance >> 6);
}
// Top-left anchor point
for (auto& v : vertices) {
v.x -= min_x;
v.y -= min_y;
} }
return vertices; return {std::move(vertices), max_x - min_x, max_y - min_y, 0, 0};
} }
const Texture* Font::text_texture() { return m_text_texture.get(); } const Texture* Font::text_texture() { return m_text_texture.get(); }

View File

@@ -174,8 +174,7 @@ void delete_image_data(unsigned char* data) {
SOIL_free_image_data(data); SOIL_free_image_data(data);
} }
unsigned char* load_image_data(const std::string& tex_image_path, ImageData load_image_data(const std::string& tex_image_path, bool check_exist) {
bool check_exist) {
fs::path path = ASSETS_PATH + tex_image_path; fs::path path = ASSETS_PATH + tex_image_path;
if (check_exist) { if (check_exist) {
ASSERT_MSG(fs::is_regular_file(path), path.c_str()); ASSERT_MSG(fs::is_regular_file(path), path.c_str());
@@ -193,7 +192,7 @@ unsigned char* load_image_data(const std::string& tex_image_path,
} }
} }
return data; return {data, width, height, channels};
} }
} // namespace Tools } // namespace Tools

72
src/ui/button.cpp Normal file
View File

@@ -0,0 +1,72 @@
#include "Cubed/ui/button.hpp"
namespace Cubed {
Button::Button(Widget* parent) : Widget(parent) {}
void Button::update(float dt) {
if (m_background) {
m_background->update(dt);
}
if (m_foreground) {
m_foreground->update(dt);
}
}
void Button::render(Renderer& renderer) {
if (m_background) {
m_background->render(renderer);
}
if (m_foreground) {
m_foreground->render(renderer);
}
}
bool Button::handle_mouse_move_event(const MouseMoveEvent& e) {
auto pos = m_background->pos();
if (e.xpos >= pos.x && e.xpos <= pos.x + width() && e.ypos >= pos.y &&
e.ypos <= pos.y + height()) {
m_hovered = true;
return true;
}
m_hovered = false;
return false;
}
bool Button::handle_mouse_button_event(const MouseButtonEvent& e) {
if (e.action == KeyAction::PRESS && e.key == MouseKey::LEFT_BUTTON) {
if (m_hovered && m_clicked) {
m_clicked();
return true;
}
}
return false;
}
Button& Button::set_scale(float scale) {
m_background->set_scale(scale);
return *this;
}
void Button::set_window_size(int width, int height) {
m_background->set_window_size(width, height);
}
Widget& Button::set_anchor(Anchor anchor) {
m_background->set_anchor(anchor);
return *this;
}
Widget& Button::set_offset(glm::ivec2 offset) {
m_background->set_offset(offset);
return *this;
}
glm::vec2 Button::pos() const { return m_background->pos(); }
float Button::scale() const { return m_background->scale(); }
float Button::width() const { return m_background->width(); }
float Button::height() const { return m_background->height(); }
} // namespace Cubed

37
src/ui/column_layout.cpp Normal file
View File

@@ -0,0 +1,37 @@
#include "Cubed/ui/column_layout.hpp"
namespace Cubed {
ColumnLayout::ColumnLayout(Widget* parent) : Widget(parent) {}
ColumnLayout::~ColumnLayout() {}
void ColumnLayout::update(float dt) {
Widget::update(dt);
layout();
}
float ColumnLayout::width() const {
if (m_parent) {
return m_parent->width();
}
return m_window_width;
}
float ColumnLayout::height() const {
if (m_parent) {
return m_parent->height();
}
return m_window_height;
}
void ColumnLayout::set_spacing(int spacing) { m_spacing = spacing; }
void ColumnLayout::layout() {
auto& children = Widget::children();
int y = 0;
for (auto& child : children) {
child->set_offset({0, y});
child->set_anchor(m_anchor);
y += child->height() + m_spacing;
}
}
} // namespace Cubed

39
src/ui/image.cpp Normal file
View File

@@ -0,0 +1,39 @@
#include "Cubed/ui/image.hpp"
#include "Cubed/render/renderer.hpp"
#include "Cubed/texture_manager.hpp"
namespace Cubed {
Image::Image(Widget* parent) : Widget(parent) {}
void Image::update(float) {}
void Image::render(Renderer& renderer) { renderer.render_image(*this); }
Image& Image::set_image(const std::string& path,
TextureManager& texture_manager) {
m_texture = texture_manager.get_image_texture(path);
return *this;
}
Image& Image::set_scale(float scale) {
m_scale = scale;
return *this;
}
float Image::scale() const { return m_scale; }
float Image::height() const {
if (!m_texture) {
Logger::error("Image id {} not set image!", m_id);
return 0.0f;
}
return m_texture->height() * m_scale;
}
float Image::width() const {
if (!m_texture) {
Logger::error("Image id {} not set image!", m_id);
return 0.0f;
}
return m_texture->width() * m_scale;
}
const Texture* Image::texture() const { return m_texture; }
} // namespace Cubed

50
src/ui/label.cpp Normal file
View File

@@ -0,0 +1,50 @@
#include "Cubed/ui/label.hpp"
#include "Cubed/render/renderer.hpp"
#include "Cubed/tools/font.hpp"
namespace Cubed {
Label::Label(const std::string& id, Widget* parent) : Widget(id, parent) {}
Label::Label(Widget* parent) : Widget(parent) {}
Label& Label::set_text(std::string_view text) {
m_text.text = text;
update_vertices();
return *this;
}
Label& Label::set_color(Color color) {
m_text.color = color;
return *this;
}
Label& Label::set_scale(float scale) {
m_scale = scale;
return *this;
}
void Label::update(float dt) { on_update(dt); }
void Label::on_update(float dt) { (void)dt; }
void Label::render(Renderer& renderer) { on_render(renderer); }
void Label::on_render(Renderer& renderer) { renderer.render_lable(*this); }
void Label::update_vertices() {
auto textmesh = Font::vertices(m_text.text);
m_data.m_vertices = std::move(textmesh.vertices);
m_offset_x = textmesh.min_x;
m_offset_y = textmesh.min_y;
m_real_width = textmesh.width;
m_real_height = textmesh.height;
m_data.update_sum();
m_data.upload();
}
const UIVertexData& Label::data() const { return m_data; }
const TextStyle& Label::text_style() const { return m_text; }
float Label::width() const { return m_real_width * m_scale; }
float Label::height() const { return m_real_height * m_scale; }
float Label::offset_x() const { return m_offset_x; }
float Label::offset_y() const { return m_offset_y; }
float Label::scale() const { return m_scale; }
} // namespace Cubed

View File

@@ -0,0 +1,145 @@
#include "Cubed/ui/main_menu_ui_manager.hpp"
#include "Cubed/app.hpp"
#include "Cubed/render/renderer.hpp"
#include "Cubed/scene/main_menu_scene.hpp"
#include "Cubed/scene/scene_manager.hpp"
#include "Cubed/ui/button.hpp"
#include "Cubed/ui/column_layout.hpp"
namespace Cubed {
MainMenuUIManager::MainMenuUIManager(MainMenuScene& scene) : m_scene(scene) {}
MainMenuUIManager::~MainMenuUIManager() {}
void MainMenuUIManager::init() {
auto rect = std::make_unique<Rect>(nullptr);
rect->set_fill(true);
rect->set_anchor(Anchor::TOP_LEFT);
rect->set_color(Color::WHITE);
auto& renderer = m_scene.scene_manager().app().renderer();
rect->set_window_size(renderer.window_width(), renderer.window_height());
auto& layout = rect->add_child<ColumnLayout>();
layout.set_spacing(20);
layout.set_anchor(Anchor::CENTER);
layout.set_window_size(renderer.window_width(), renderer.window_height());
{
auto& start_game_button = layout.add_child<Button>();
auto& back = start_game_button.set_background<Image>();
back.set_image("texture/ui/button001.png",
m_scene.scene_manager().app().texture_manager());
auto& fore = start_game_button.set_foreground<Label>();
fore.set_text("Start Game");
fore.set_scale(0.6f);
start_game_button.set_clicked([this]() {
m_scene.scene_manager().request_push(SceneType::WORLD);
});
start_game_button.set_scale(4.0f);
}
auto& exit_game = layout.add_child<Button>();
{
auto& back = exit_game.set_background<Image>();
back.set_image("texture/ui/button001.png",
m_scene.scene_manager().app().texture_manager());
auto& fore = exit_game.set_foreground<Label>();
fore.set_scale(0.6f).set_text("Exit");
exit_game.set_scale(4.0f);
exit_game.set_clicked([this]() {
m_scene.scene_manager().app().window().should_close_window();
});
}
m_widgets.try_emplace("background", rect.get());
m_widgets.try_emplace("main menu layout", &layout);
m_root_widget = std::move(rect);
}
void MainMenuUIManager::update(float dt) { m_root_widget->update(dt); }
void MainMenuUIManager::render(Renderer& renderer) {
renderer.begin_render_ui();
m_root_widget->render(renderer);
renderer.end_render_ui();
}
bool MainMenuUIManager::handle_event(const Event& e) {
return std::visit(
Overloaded{[this](const MouseMoveEvent& e) {
if (handle_mouse_move_event(e)) {
return true;
}
return false;
},
[this](const MouseButtonEvent& e) {
if (handle_mouse_button_event(e)) {
return true;
}
return false;
},
[this](const MouseWheelEvent& e) {
if (handle_mouse_wheel_event(e)) {
return true;
}
return false;
},
[this](const KeyEvent& e) {
if (handle_key_event(e)) {
return true;
}
return false;
},
[](const TextInputEvent&) { return false; },
[this](const WindowResizeEvent& e) {
handle_window_resize_event(e);
return false;
},
[](const FrameBufferResizeEvent&) { return false; }
},
e);
}
bool MainMenuUIManager::handle_mouse_move_event(const MouseMoveEvent& e) {
if (m_root_widget->handle_mouse_move_event(e)) {
return true;
}
return false;
}
bool MainMenuUIManager::handle_mouse_button_event(const MouseButtonEvent& e) {
if (m_root_widget->handle_mouse_button_event(e)) {
return true;
}
return false;
}
bool MainMenuUIManager::handle_window_resize_event(const WindowResizeEvent& e) {
if (m_root_widget->handle_window_resize_event(e)) {
return true;
}
return false;
}
bool MainMenuUIManager::handle_mouse_wheel_event(const MouseWheelEvent& e) {
if (m_root_widget->handle_mouse_wheel_event(e)) {
return true;
}
return false;
}
bool MainMenuUIManager::handle_key_event(const KeyEvent& e) {
if (m_root_widget->handle_key_event(e)) {
return true;
}
return false;
}
} // namespace Cubed

58
src/ui/rect.cpp Normal file
View File

@@ -0,0 +1,58 @@
#include "Cubed/ui/rect.hpp"
#include "Cubed/render/renderer.hpp"
namespace Cubed {
Rect::Rect(Widget* parent)
: Widget(parent) {
};
Rect::~Rect() {}
void Rect::update(float dt) {
if (m_fill) {
if (!m_parent) {
m_width = m_window_width;
m_height = m_window_height;
} else {
m_width = m_parent->width();
m_height = m_parent->height();
}
}
Widget::update(dt);
}
void Rect::render(Renderer& renderer) {
renderer.render_rect(*this);
Widget::render(renderer);
}
float Rect::width() const { return m_width * m_scale; }
float Rect::height() const { return m_height * m_scale; }
float Rect::alpha() const { return m_alpha; }
Rect& Rect::set_width(float width) {
m_width = width;
return *this;
}
Rect& Rect::set_height(float height) {
m_height = height;
return *this;
}
Rect& Rect::set_fill(bool fill) {
m_fill = fill;
return *this;
}
Rect& Rect::set_scale(float scale) {
m_scale = scale;
return *this;
}
Rect& Rect::set_color(Color color) {
m_color = color;
return *this;
}
Rect& Rect::set_alpha(float alpha) {
m_alpha = std::clamp(alpha, 0.0f, 1.0f);
return *this;
}
Color Rect::color() const { return m_color; }
} // namespace Cubed

View File

@@ -1,93 +0,0 @@
#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>
namespace Cubed {
Text::Text(std::string_view name)
: NAME(name), UUID(HASH::str(name)),
m_vbo(std::make_unique<VertexBuffer>()),
m_vao(std::make_unique<VertexArray>()) {}
Text::Text(std::string_view name, std::string_view str, glm::vec2 pos,
Color color)
: NAME(name), UUID(HASH::str(name)),
m_vbo(std::make_unique<VertexBuffer>()),
m_vao(std::make_unique<VertexArray>()) {
m_text.assign(str);
m_pos = pos;
m_color = color_value(color);
update_vertices();
}
Text::~Text() { m_vbo.reset(); }
Text::Text(Text&& other) noexcept
: m_scale(other.m_scale), m_pos(other.m_pos), NAME(other.NAME),
UUID(other.UUID), m_text(std::move(other.m_text)), m_color(other.m_color),
m_model_matrix(other.m_model_matrix),
m_vertices(std::move(other.m_vertices)), m_vbo(std::move(other.m_vbo)),
m_vao(std::move(other.m_vao)) {}
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; }
Text& Text::text(std::string_view str) {
m_text.assign(str);
update_vertices();
return *this;
}
void Text::render(const Shader& shader) {
ASSERT_MSG(m_vbo != 0, "VBO not initialized!");
ASSERT_MSG(!m_vertices.empty(), "Text String Not Set");
Font::text_texture()->bind(0);
m_vao->bind();
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));
shader.set_loc("textColor", glm::vec3(m_color.x, m_color.y, m_color.z));
shader.set_loc("mv_matrix", m_model_matrix);
glDrawArrays(GL_TRIANGLES, 0, m_vertices.size());
}
void Text::update_vertices() {
m_vertices = Font::vertices(m_text);
upload_to_gpu();
}
void Text::upload_to_gpu() {
ASSERT_MSG(m_vbo, "Vbo Is Not Gen");
m_vao->bind();
m_vbo->buffer_data(m_vertices.data(), m_vertices.size() * sizeof(Vertex2D),
BufferUsage::DYNAMIC_DRAW);
m_vao->attribute(0, 2, GL_FLOAT, sizeof(Vertex2D), (void*)0);
m_vao->attribute(1, 2, GL_FLOAT, sizeof(Vertex2D),
(void*)offsetof(Vertex2D, s));
m_vao->attribute(2, 1, GL_FLOAT, sizeof(Vertex2D),
(void*)offsetof(Vertex2D, layer));
}
bool Text::operator==(const Text& other) const { return UUID == other.uuid(); }
} // namespace Cubed

46
src/ui/ui_vertex_data.cpp Normal file
View File

@@ -0,0 +1,46 @@
#include "Cubed/ui/ui_vertex_data.hpp"
#include "Cubed/tools/cubed_assert.hpp"
#include "Cubed/tools/log.hpp"
namespace Cubed {
UIVertexData::UIVertexData() {}
UIVertexData::~UIVertexData() {
m_vao.reset();
m_vbo.reset();
}
void UIVertexData::upload() {
if (m_sum == 0) {
Logger::error("You need update_sum first");
ASSERT(false);
}
if (m_vertices.size() == 0) {
return;
}
if (!m_vao) {
m_vao = std::make_unique<VertexArray>();
}
if (!m_vbo) {
m_vbo = std::make_unique<VertexBuffer>();
}
m_vao->bind();
m_vbo->buffer_data(m_vertices.data(), m_vertices.size() * sizeof(Vertex2D),
BufferUsage::DYNAMIC_DRAW);
m_vao->attribute(0, 2, GL_FLOAT, sizeof(Vertex2D), (void*)0);
m_vao->attribute(1, 2, GL_FLOAT, sizeof(Vertex2D),
(void*)offsetof(Vertex2D, s));
m_vao->attribute(2, 1, GL_FLOAT, sizeof(Vertex2D),
(void*)offsetof(Vertex2D, layer));
VertexArray::unbind();
VertexBuffer::unbind();
// Release memory
m_vertices.clear();
}
void UIVertexData::update_sum() { m_sum = m_vertices.size(); }
} // namespace Cubed

166
src/ui/widget.cpp Normal file
View File

@@ -0,0 +1,166 @@
#include "Cubed/ui/widget.hpp"
#include "Cubed/tools/log.hpp"
namespace Cubed {
Widget::Widget(const std::string& id, Widget* parent)
: m_parent(parent), m_id(id) {}
Widget::Widget(Widget* parent) : m_parent(parent) {}
void Widget::update(float dt) {
on_update(dt);
for (auto& child : m_children) {
child->update(dt);
}
}
void Widget::render(Renderer& renderer) {
on_render(renderer);
for (auto& child : m_children) {
child->render(renderer);
}
}
void Widget::on_update(float) {}
void Widget::on_render(Renderer&) {}
std::vector<std::unique_ptr<Widget>>& Widget::children() { return m_children; }
const std::vector<std::unique_ptr<Widget>>& Widget::children() const {
return m_children;
}
glm::vec2 Widget::compute_position() const {
glm::vec2 pos{0, 0};
float parent_w;
float parent_h;
if (!m_parent) {
if (m_window_height == 0 || m_window_width == 0) {
Logger::error("Window Size is 0 !");
}
parent_h = m_window_height;
parent_w = m_window_width;
} else {
parent_h = m_parent->height();
parent_w = m_parent->width();
}
const float W = width();
const float H = height();
switch (m_anchor) {
case Anchor::TOP_LEFT:
pos = {0, 0};
break;
case Anchor::TOP_CENTER:
pos = {(parent_w - W) / 2, 0};
break;
case Anchor::TOP_RIGHT:
pos = {parent_w - W, 0};
break;
case Anchor::CENTER_LEFT:
pos = {0, (parent_h - H) / 2};
break;
case Anchor::CENTER:
pos = {(parent_w - W) / 2, (parent_h - H) / 2};
break;
case Anchor::CENTER_RIGHT:
pos = {parent_w - W, (parent_h - H) / 2};
break;
case Anchor::BOTTOM_LEFT:
pos = {0, parent_h - H};
break;
case Anchor::BOTTOM_CENTER:
pos = {(parent_w - W) / 2, parent_h - H};
break;
case Anchor::BOTTOM_RIGHT:
pos = {parent_w - W, parent_h - H};
break;
}
if (m_parent) {
pos += m_parent->pos();
}
pos += m_offset;
return pos;
}
Widget& Widget::set_anchor(Anchor anchor) {
m_anchor = anchor;
return *this;
}
Widget& Widget::set_offset(glm::ivec2 offset) {
m_offset = offset;
return *this;
}
void Widget::set_window_size(int width, int height) {
m_window_height = height;
m_window_width = width;
}
float Widget::width() const {
if (m_parent) {
return m_parent->width();
}
return m_window_width;
}
float Widget::height() const {
if (m_parent) {
return m_parent->height();
}
return m_window_height;
}
glm::vec2 Widget::pos() const { return compute_position(); }
const std::string& Widget::id() const { return m_id; }
bool Widget::handle_key_event(const KeyEvent& e) {
for (auto it = m_children.rbegin(); it != m_children.rend(); ++it) {
if ((*it)->handle_key_event(e)) {
return true;
}
}
return false;
}
bool Widget::handle_mouse_button_event(const MouseButtonEvent& e) {
for (auto it = m_children.rbegin(); it != m_children.rend(); ++it) {
if ((*it)->handle_mouse_button_event(e)) {
return true;
}
}
return false;
}
bool Widget::handle_mouse_wheel_event(const MouseWheelEvent& e) {
for (auto it = m_children.rbegin(); it != m_children.rend(); ++it) {
if ((*it)->handle_mouse_wheel_event(e)) {
return true;
}
}
return false;
}
bool Widget::handle_window_resize_event(const WindowResizeEvent& e) {
set_window_size(e.width, e.height);
for (auto it = m_children.rbegin(); it != m_children.rend(); ++it) {
if ((*it)->handle_window_resize_event(e)) {
return true;
}
}
return false;
}
bool Widget::handle_mouse_move_event(const MouseMoveEvent& e) {
for (auto it = m_children.rbegin(); it != m_children.rend(); ++it) {
if ((*it)->handle_mouse_move_event(e)) {
return true;
}
}
return false;
}
} // namespace Cubed

120
src/ui/world_ui_manager.cpp Normal file
View File

@@ -0,0 +1,120 @@
#include "Cubed/ui/world_ui_manager.hpp"
#include "Cubed/app.hpp"
#include "Cubed/debug_collector.hpp"
#include "Cubed/render/renderer.hpp"
#include "Cubed/scene/scene_manager.hpp"
#include "Cubed/scene/world_scene.hpp"
namespace Cubed {
WorldUIManager::WorldUIManager(WorldScene& scene) : m_scene(scene) {}
WorldUIManager::~WorldUIManager() {}
void WorldUIManager::init() {
auto crosshair = std::make_unique<Image>(nullptr);
crosshair->set_image("texture/ui/0.png",
m_scene.scene_manager().app().texture_manager());
auto& renderer = m_scene.scene_manager().app().renderer();
crosshair->set_window_size(renderer.window_width(),
renderer.window_height());
crosshair->set_anchor(Anchor::CENTER);
crosshair->set_scale(3.0f);
m_widgets.try_emplace("crosshair", std::move(crosshair));
}
void WorldUIManager::update(float dt) {
for (auto& w : m_widgets) {
w.second->update(dt);
}
}
void WorldUIManager::render(Renderer& renderer) {
renderer.begin_render_ui();
auto& widget = DebugCollector::get().get_widget();
widget.render(renderer);
for (auto& widget : m_widgets) {
widget.second->render(renderer);
}
renderer.end_render_ui();
}
bool WorldUIManager::handle_event(const Event& e) {
return std::visit(
Overloaded{[this](const MouseMoveEvent& e) {
if (handle_mouse_move_event(e)) {
return true;
}
return false;
},
[this](const MouseButtonEvent& e) {
if (handle_mouse_button_event(e)) {
return true;
}
return false;
},
[this](const MouseWheelEvent& e) {
if (handle_mouse_wheel_event(e)) {
return true;
}
return false;
},
[this](const KeyEvent& e) {
if (handle_key_event(e)) {
return true;
}
return false;
},
[](const TextInputEvent&) { return false; },
[this](const WindowResizeEvent& e) {
handle_window_resize_event(e);
return false;
},
[](const FrameBufferResizeEvent&) { return false; }
},
e);
}
bool WorldUIManager::handle_mouse_move_event(const MouseMoveEvent& e) {
for (auto& w : m_widgets) {
if (w.second->handle_mouse_move_event(e)) {
return true;
}
}
return false;
}
bool WorldUIManager::handle_mouse_button_event(const MouseButtonEvent& e) {
for (auto& w : m_widgets) {
if (w.second->handle_mouse_button_event(e)) {
return true;
}
}
return false;
}
bool WorldUIManager::handle_window_resize_event(const WindowResizeEvent& e) {
for (auto& w : m_widgets) {
if (w.second->handle_window_resize_event(e)) {
return true;
}
}
return false;
}
bool WorldUIManager::handle_mouse_wheel_event(const MouseWheelEvent& e) {
for (auto& w : m_widgets) {
if (w.second->handle_mouse_wheel_event(e)) {
return true;
}
}
return false;
}
bool WorldUIManager::handle_key_event(const KeyEvent& e) {
for (auto& w : m_widgets) {
if (w.second->handle_key_event(e)) {
return true;
}
}
return false;
}
} // namespace Cubed

View File

@@ -1,6 +1,6 @@
#include "Cubed/window.hpp" #include "Cubed/window.hpp"
#include "Cubed/render/renderer.hpp" #include "Cubed/camera.hpp"
#include "Cubed/tools/cubed_assert.hpp" #include "Cubed/tools/cubed_assert.hpp"
#include "Cubed/tools/font.hpp" #include "Cubed/tools/font.hpp"
#include "Cubed/tools/log.hpp" #include "Cubed/tools/log.hpp"
@@ -14,8 +14,7 @@ namespace Cubed {
static int windowed_xpos = 0, windowed_ypos = 0; static int windowed_xpos = 0, windowed_ypos = 0;
static int windowed_width = 800, windowed_height = 600; static int windowed_width = 800, windowed_height = 600;
Window::Window(Renderer& renderer, Config& config) Window::Window(Config& config) : m_config(config) {}
: m_renderer(renderer), m_config(config) {}
Window::~Window() { Window::~Window() {
if (m_imgui_init) { if (m_imgui_init) {
@@ -41,14 +40,66 @@ const GLFWwindow* Window::get_glfw_window() const { return m_window; }
GLFWwindow* Window::get_glfw_window() { return m_window; } GLFWwindow* Window::get_glfw_window() { return m_window; }
void Window::update_viewport() { bool Window::handle_event(const Event& e) {
glfwGetFramebufferSize(m_window, &m_width, &m_height); return std::visit(
m_aspect = (float)m_width / (float)m_height; Overloaded{[](const MouseMoveEvent&) { return false; },
glViewport(0, 0, m_width, m_height); [this](const MouseButtonEvent& e) {
m_renderer.update_proj_matrix(m_aspect, m_width, m_height); if (handle_mouse_button_event(e)) {
m_renderer.updata_framebuffer(m_width, m_height); return true;
m_config.set("window.width", windowed_width); }
m_config.set("window.height", windowed_height); return false;
},
[](const MouseWheelEvent&) { return false; },
[this](const KeyEvent& e) {
if (handle_key_event(e)) {
return true;
}
return false;
},
[](const TextInputEvent&) { return false; },
[this](const WindowResizeEvent& e) {
handle_window_resize_event(e);
return false;
},
[](const FrameBufferResizeEvent&) { return false; }
},
e);
}
bool Window::handle_key_event(const KeyEvent& e) {
if (e.key == Key::F11 && e.action == KeyAction::PRESS) {
toggle_fullscreen();
return true;
}
if (e.key == Key::ESCAPE && e.action == KeyAction::PRESS) {
if (!m_game_running) {
glfwSetWindowShouldClose(m_window, GLFW_TRUE);
return true;
}
}
if (e.key == Key::LEFT_ALT && e.action == KeyAction::PRESS) {
toggle_mouse_able();
return true;
}
return false;
}
bool Window::handle_window_resize_event(const WindowResizeEvent& e) {
m_window_height = e.height;
m_window_width = e.width;
return false;
}
bool Window::handle_mouse_button_event(const MouseButtonEvent& e) {
if (e.key == MouseKey::LEFT_BUTTON && e.action == KeyAction::PRESS) {
if (is_mouse_enable()) {
toggle_mouse_able();
return true;
}
}
return false;
} }
void Window::init() { void Window::init() {
@@ -60,15 +111,18 @@ void Window::init() {
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
m_width = m_config.get("window.width", 800);
m_height = m_config.get("window.height", 600); m_window_width = m_config.get("window.width", 800);
m_window_height = m_config.get("window.height", 600);
if (m_config.get("window.fullscreen", false)) { if (m_config.get("window.fullscreen", false)) {
GLFWmonitor* primary_monitor = glfwGetPrimaryMonitor(); GLFWmonitor* primary_monitor = glfwGetPrimaryMonitor();
const GLFWvidmode* mode = glfwGetVideoMode(primary_monitor); const GLFWvidmode* mode = glfwGetVideoMode(primary_monitor);
m_window = glfwCreateWindow(mode->width, mode->height, "Cubed", m_window = glfwCreateWindow(mode->width, mode->height, "Cubed",
primary_monitor, NULL); primary_monitor, NULL);
} else { } else {
m_window = glfwCreateWindow(m_width, m_height, "Cubed", NULL, NULL); m_window = glfwCreateWindow(m_window_width, m_window_height, "Cubed",
NULL, NULL);
} }
glfwMakeContextCurrent(m_window); glfwMakeContextCurrent(m_window);
@@ -77,8 +131,10 @@ void Window::init() {
} else { } else {
glfwSwapInterval(0); glfwSwapInterval(0);
} }
if (m_game_running) {
glfwSetInputMode(m_window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
}
glfwSetInputMode(m_window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
if (glfwRawMouseMotionSupported()) { if (glfwRawMouseMotionSupported()) {
glfwSetInputMode(m_window, GLFW_RAW_MOUSE_MOTION, GLFW_TRUE); glfwSetInputMode(m_window, GLFW_RAW_MOUSE_MOTION, GLFW_TRUE);
} else { } else {
@@ -121,12 +177,13 @@ void Window::hot_reload() {
Logger::error("Can't Find Monitor"); Logger::error("Can't Find Monitor");
} }
} }
update_viewport();
if (!m_mouse_enable) { if (!m_mouse_enable) {
glfwSetInputMode(m_window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); glfwSetInputMode(m_window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
} else { } else {
glfwSetInputMode(m_window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); glfwSetInputMode(m_window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
} }
m_config.set("window.width", windowed_width);
m_config.set("window.height", windowed_height);
} }
void Window::toggle_fullscreen() { void Window::toggle_fullscreen() {
@@ -148,10 +205,14 @@ void Window::toggle_fullscreen() {
GL_DONT_CARE); GL_DONT_CARE);
m_config.set("window.fullscreen", true); m_config.set("window.fullscreen", true);
} }
update_viewport(); m_config.set("window.width", windowed_width);
m_config.set("window.height", windowed_height);
} }
void Window::toggle_mouse_able() { void Window::toggle_mouse_able() {
if (!m_game_running) {
m_mouse_enable = true;
}
// auto& io = ImGui::GetIO(); // auto& io = ImGui::GetIO();
if (m_mouse_enable) { if (m_mouse_enable) {
// io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange; // io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange;
@@ -166,7 +227,20 @@ void Window::toggle_mouse_able() {
glfwSetInputMode(m_window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); glfwSetInputMode(m_window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
m_mouse_enable = true; m_mouse_enable = true;
} }
if (m_camera) {
m_camera->reset_camera();
}
} }
void Window::set_camera(Camera* camera) { m_camera = camera; }
Camera* Window::camera() { return m_camera; }
void Window::set_game_running(bool running) {
m_game_running = running;
m_mouse_enable = running;
toggle_mouse_able();
}
void Window::should_close_window() { glfwSetWindowShouldClose(m_window, true); }
void Window::imgui_init() { void Window::imgui_init() {
float dpi_scale_x, dpi_scale_y; float dpi_scale_x, dpi_scale_y;