Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
2772553e2c
66 changed files with 1452 additions and 3761 deletions
|
@ -22,7 +22,9 @@ endif()
|
||||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" AND NOT IOS)
|
if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" AND NOT IOS)
|
||||||
message("macOS build detected!")
|
message("macOS build detected!")
|
||||||
|
|
||||||
set(ENABLE_METAL TRUE)
|
find_package(SDL2 REQUIRED)
|
||||||
|
|
||||||
|
set(ENABLE_VULKAN TRUE)
|
||||||
set(ENABLE_DARWIN TRUE)
|
set(ENABLE_DARWIN TRUE)
|
||||||
set(ENABLE_MACOS TRUE)
|
set(ENABLE_MACOS TRUE)
|
||||||
|
|
||||||
|
@ -71,7 +73,9 @@ set(CROSS_LIBS
|
||||||
add_subdirectory(extern)
|
add_subdirectory(extern)
|
||||||
|
|
||||||
# enable lto
|
# enable lto
|
||||||
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
|
if (CMAKE_BUILD_TYPE EQUAL "Release")
|
||||||
|
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
|
||||||
|
endif ()
|
||||||
|
|
||||||
add_subdirectory(platforms)
|
add_subdirectory(platforms)
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,6 @@
|
||||||
macro(set_engine_properties target)
|
macro(set_engine_properties target)
|
||||||
target_compile_features(${target} PUBLIC cxx_std_17)
|
target_compile_features(${target} PUBLIC cxx_std_17)
|
||||||
set_target_properties(${target} PROPERTIES CXX_EXTENSIONS OFF)
|
set_target_properties(${target} PROPERTIES CXX_EXTENSIONS OFF)
|
||||||
|
|
||||||
if(ENABLE_MACOS OR ENABLE_LINUX)
|
|
||||||
target_compile_options(${target} PUBLIC
|
|
||||||
-fpermissive) # ew but required for now TODO: remove and test!
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(ENABLE_MACOS)
|
if(ENABLE_MACOS)
|
||||||
target_compile_definitions(${target} PUBLIC PLATFORM_MACOS)
|
target_compile_definitions(${target} PUBLIC PLATFORM_MACOS)
|
||||||
|
|
|
@ -20,7 +20,7 @@ std::unique_ptr<Mesh> load_mesh(const prism::path path) {
|
||||||
|
|
||||||
auto file = prism::open_file(path, true);
|
auto file = prism::open_file(path, true);
|
||||||
if(!file.has_value()) {
|
if(!file.has_value()) {
|
||||||
prism::log::error(System::Renderer, "Failed to load mesh from {}!", path);
|
prism::log("Failed to load mesh from {}!", path.string());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ std::unique_ptr<Mesh> load_mesh(const prism::path path) {
|
||||||
|
|
||||||
if(version == 5 || version == 6) {
|
if(version == 5 || version == 6) {
|
||||||
} else {
|
} else {
|
||||||
prism::log::error(System::Renderer, "{} failed the mesh version check! reported version = {}", path, std::to_string(version));
|
prism::log("{} failed the mesh version check! reported version = {}", path.string(), version);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,7 +190,7 @@ std::unique_ptr<Texture> load_texture(const prism::path path) {
|
||||||
|
|
||||||
auto file = prism::open_file(path, true);
|
auto file = prism::open_file(path, true);
|
||||||
if(!file.has_value()) {
|
if(!file.has_value()) {
|
||||||
prism::log::error(System::Renderer, "Failed to load texture from {}!", path);
|
prism::log("Failed to load texture from {}!", path.string());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,7 +202,7 @@ std::unique_ptr<Texture> load_texture(const prism::path path) {
|
||||||
int width, height, channels;
|
int width, height, channels;
|
||||||
unsigned char* data = stbi_load_from_memory(file->cast_data<unsigned char>(), file->size(), &width, &height, &channels, 4);
|
unsigned char* data = stbi_load_from_memory(file->cast_data<unsigned char>(), file->size(), &width, &height, &channels, 4);
|
||||||
if(!data) {
|
if(!data) {
|
||||||
prism::log::error(System::Renderer, "Failed to load texture from {}!", path);
|
prism::log("Failed to load texture from {}!", path.string());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,7 +247,7 @@ std::unique_ptr<Material> load_material(const prism::path path) {
|
||||||
|
|
||||||
auto file = prism::open_file(path);
|
auto file = prism::open_file(path);
|
||||||
if(!file.has_value()) {
|
if(!file.has_value()) {
|
||||||
prism::log::error(System::Core, "Failed to load material from {}!", path);
|
prism::log("Failed to load material from {}!", path.string());
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,7 +258,7 @@ std::unique_ptr<Material> load_material(const prism::path path) {
|
||||||
mat->path = path.string();
|
mat->path = path.string();
|
||||||
|
|
||||||
if(!j.count("version") || j["version"] != 2) {
|
if(!j.count("version") || j["version"] != 2) {
|
||||||
prism::log::error(System::Core, "Material {} failed the version check!", path);
|
prism::log("Material {} failed the version check!", path.string());
|
||||||
return mat;
|
return mat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,6 @@ set(SRC
|
||||||
include/physics.hpp
|
include/physics.hpp
|
||||||
include/scene.hpp
|
include/scene.hpp
|
||||||
include/imgui_backend.hpp
|
include/imgui_backend.hpp
|
||||||
include/uielement.hpp
|
|
||||||
include/screen.hpp
|
|
||||||
include/object.hpp
|
include/object.hpp
|
||||||
include/debug.hpp
|
include/debug.hpp
|
||||||
include/components.hpp
|
include/components.hpp
|
||||||
|
@ -19,7 +17,6 @@ set(SRC
|
||||||
src/input.cpp
|
src/input.cpp
|
||||||
src/physics.cpp
|
src/physics.cpp
|
||||||
src/imgui_backend.cpp
|
src/imgui_backend.cpp
|
||||||
src/screen.cpp
|
|
||||||
src/scene.cpp
|
src/scene.cpp
|
||||||
src/debug.cpp
|
src/debug.cpp
|
||||||
src/console.cpp)
|
src/console.cpp)
|
||||||
|
|
|
@ -103,17 +103,6 @@ struct Camera {
|
||||||
Matrix4x4 view, perspective;
|
Matrix4x4 view, perspective;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace ui {
|
|
||||||
class Screen;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct UI {
|
|
||||||
int width = 1920, height = 1080;
|
|
||||||
|
|
||||||
std::string ui_path;
|
|
||||||
ui::Screen* screen = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct EnvironmentProbe {
|
struct EnvironmentProbe {
|
||||||
bool is_sized = true;
|
bool is_sized = true;
|
||||||
prism::float3 size = prism::float3(10);
|
prism::float3 size = prism::float3(10);
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
|
||||||
|
void draw_console();
|
||||||
void draw_debug_ui();
|
void draw_debug_ui();
|
||||||
|
|
||||||
void load_debug_options();
|
void load_debug_options();
|
||||||
|
|
|
@ -10,11 +10,6 @@
|
||||||
#include "path.hpp"
|
#include "path.hpp"
|
||||||
|
|
||||||
class GFX;
|
class GFX;
|
||||||
|
|
||||||
namespace ui {
|
|
||||||
class Screen;
|
|
||||||
}
|
|
||||||
|
|
||||||
class Scene;
|
class Scene;
|
||||||
class RenderTarget;
|
class RenderTarget;
|
||||||
class Physics;
|
class Physics;
|
||||||
|
@ -141,22 +136,6 @@ namespace prism {
|
||||||
*/
|
*/
|
||||||
void save_scene(std::string_view path);
|
void save_scene(std::string_view path);
|
||||||
|
|
||||||
/** Load a UI screen from disk. This will not change the current screen.
|
|
||||||
@param path The screen file path.
|
|
||||||
@return Returns a instance of the screen if successful, and nullptr on failure.
|
|
||||||
*/
|
|
||||||
ui::Screen* load_screen(const prism::path& path);
|
|
||||||
|
|
||||||
/** Set the current screen.
|
|
||||||
@param screen The screen object to set as current. Can be null.
|
|
||||||
*/
|
|
||||||
void set_screen(ui::Screen* screen);
|
|
||||||
|
|
||||||
/** Gets the current screen.
|
|
||||||
@return The current screen. Can be null.
|
|
||||||
*/
|
|
||||||
[[nodiscard]] ui::Screen* get_screen() const;
|
|
||||||
|
|
||||||
/** Load a prefab from disk.
|
/** Load a prefab from disk.
|
||||||
@param scene The scene to add the prefab to.
|
@param scene The scene to add the prefab to.
|
||||||
@param path The prefab file path.
|
@param path The prefab file path.
|
||||||
|
@ -231,30 +210,11 @@ namespace prism {
|
||||||
*/
|
*/
|
||||||
void process_mouse_down(int button, prism::Offset offset);
|
void process_mouse_down(int button, prism::Offset offset);
|
||||||
|
|
||||||
/** Pushes a UI event for the current screen. Does nothing if there is no screen set.
|
/**
|
||||||
@param name The name of the event.
|
* Called when text has been inputted. This is only emitted when text input is enabled thru input system
|
||||||
@param data Data for the event. Defaulted to an empty string.
|
* @param string
|
||||||
*/
|
*/
|
||||||
void push_event(std::string_view name, std::string_view data = "");
|
void process_text_input(const std::string_view string);
|
||||||
|
|
||||||
/** Load a localization file from disk. This will change the current localization.
|
|
||||||
@param path The localization file path.
|
|
||||||
*/
|
|
||||||
void load_localization(std::string_view path);
|
|
||||||
|
|
||||||
/** Queries whether or not the current localization loaded has a key.
|
|
||||||
@param id The key to query.
|
|
||||||
@return Whether or not the locale has the key specified.
|
|
||||||
@note Having no localization loaded will always return false.
|
|
||||||
*/
|
|
||||||
[[nodiscard]] bool has_localization(std::string_view id) const;
|
|
||||||
|
|
||||||
/** Localizes a string.
|
|
||||||
@param id The locale key to use.
|
|
||||||
@return A localized string if the key is found, or an empty string if not found.
|
|
||||||
@note Having no localization loaded will always return a empty string.
|
|
||||||
*/
|
|
||||||
std::string localize(const std::string& id);
|
|
||||||
|
|
||||||
/** Adds a timer to the list of timers.
|
/** Adds a timer to the list of timers.
|
||||||
@param timer The timer to add.
|
@param timer The timer to add.
|
||||||
|
@ -288,6 +248,10 @@ namespace prism {
|
||||||
*/
|
*/
|
||||||
void update_scene(Scene& scene);
|
void update_scene(Scene& scene);
|
||||||
|
|
||||||
|
imgui_backend& get_imgui() {
|
||||||
|
return *imgui;
|
||||||
|
}
|
||||||
|
|
||||||
/// The current cutscene.
|
/// The current cutscene.
|
||||||
std::unique_ptr<Cutscene> cutscene;
|
std::unique_ptr<Cutscene> cutscene;
|
||||||
|
|
||||||
|
@ -328,6 +292,8 @@ namespace prism {
|
||||||
bool debug_enabled = false;
|
bool debug_enabled = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
bool console_enabled = true;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setup_scene(Scene& scene);
|
void setup_scene(Scene& scene);
|
||||||
|
|
||||||
|
@ -335,8 +301,6 @@ namespace prism {
|
||||||
|
|
||||||
bool paused = false;
|
bool paused = false;
|
||||||
|
|
||||||
ui::Screen* current_screen = nullptr;
|
|
||||||
|
|
||||||
Scene* current_scene = nullptr;
|
Scene* current_scene = nullptr;
|
||||||
std::vector<std::unique_ptr<Scene>> scenes;
|
std::vector<std::unique_ptr<Scene>> scenes;
|
||||||
std::map<std::string, Scene*> path_to_scene;
|
std::map<std::string, Scene*> path_to_scene;
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <string_view>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
namespace prism {
|
namespace prism {
|
||||||
class imgui_backend {
|
class imgui_backend {
|
||||||
public:
|
public:
|
||||||
|
@ -14,7 +17,33 @@ namespace prism {
|
||||||
void process_key_down(unsigned int key_code);
|
void process_key_down(unsigned int key_code);
|
||||||
void process_key_up(unsigned int key_code);
|
void process_key_up(unsigned int key_code);
|
||||||
|
|
||||||
|
void process_text_input(const std::string_view string);
|
||||||
|
|
||||||
|
/**Opens a file dialog to select a file. This will not block.
|
||||||
|
@param existing Whether or not to limit to existing files.
|
||||||
|
@param returnFunction The callback function when a file is selected or the dialog is cancelled. An empy string is returned when cancelled.
|
||||||
|
@param openDirectory Whether or not to allow selecting directories as well.
|
||||||
|
*/
|
||||||
|
void open_dialog(const bool existing, std::function<void(std::string)> returnFunction, bool openDirectory = false);
|
||||||
|
|
||||||
|
/**Opens a file dialog to select a save location for a file. This will not block.
|
||||||
|
@param returnFunction The callback function when a file is selected or the dialog is cancelled. An empy string is returned when cancelled.
|
||||||
|
*/
|
||||||
|
void save_dialog(std::function<void(std::string)> returnFunction);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool mouse_buttons[3] = {};
|
bool mouse_buttons[3] = {};
|
||||||
|
|
||||||
|
bool open_dialog_next_frame = false;
|
||||||
|
bool save_dialog_next_frame = false;
|
||||||
|
|
||||||
|
struct dialog_data {
|
||||||
|
std::filesystem::path current_path;
|
||||||
|
std::filesystem::path selected_path;
|
||||||
|
std::function<void(std::string)> return_function;
|
||||||
|
};
|
||||||
|
|
||||||
|
dialog_data open_dialog_data;
|
||||||
|
dialog_data save_dialog_data;
|
||||||
};
|
};
|
||||||
}
|
}
|
|
@ -37,7 +37,7 @@ namespace ImGui {
|
||||||
ImGui::ProgressBar(progress_saturated, ImVec2(0.0f, 0.0f), buf);
|
ImGui::ProgressBar(progress_saturated, ImVec2(0.0f, 0.0f), buf);
|
||||||
|
|
||||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||||
ImGui::Text(label);
|
ImGui::Text("%s", label);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool DragQuat(const char* label, Quaternion* quat) {
|
inline bool DragQuat(const char* label, Quaternion* quat) {
|
||||||
|
|
|
@ -81,8 +81,16 @@ namespace prism {
|
||||||
/// Returns all of the bindings registered with this Input system.
|
/// Returns all of the bindings registered with this Input system.
|
||||||
[[nodiscard]] std::vector<input_binding> get_bindings() const;
|
[[nodiscard]] std::vector<input_binding> get_bindings() const;
|
||||||
|
|
||||||
|
void begin_text_input();
|
||||||
|
void end_text_input();
|
||||||
|
bool is_text_input() const;
|
||||||
|
|
||||||
|
bool get_allowable_text_button(unsigned int keycode) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<input_binding> _input_bindings;
|
std::vector<input_binding> _input_bindings;
|
||||||
std::tuple<int, int> _last_cursor_position;
|
std::tuple<int, int> _last_cursor_position;
|
||||||
|
|
||||||
|
bool _in_text_input = false;
|
||||||
};
|
};
|
||||||
}
|
}
|
|
@ -201,7 +201,7 @@ class GFXFramebuffer;
|
||||||
class GFXTexture;
|
class GFXTexture;
|
||||||
|
|
||||||
/// Represents a scene consisting of Objects with varying Components.
|
/// Represents a scene consisting of Objects with varying Components.
|
||||||
class Scene : public ObjectComponents<Data, Transform, Renderable, Light, Camera, Collision, Rigidbody, UI, EnvironmentProbe> {
|
class Scene : public ObjectComponents<Data, Transform, Renderable, Light, Camera, Collision, Rigidbody, EnvironmentProbe> {
|
||||||
public:
|
public:
|
||||||
/// If loaded from disk, the path to the scene file this originated from.
|
/// If loaded from disk, the path to the scene file this originated from.
|
||||||
std::string path;
|
std::string path;
|
||||||
|
|
|
@ -1,43 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include <map>
|
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
#include "uielement.hpp"
|
|
||||||
#include "file.hpp"
|
|
||||||
#include "common.hpp"
|
|
||||||
|
|
||||||
class GFXBuffer;
|
|
||||||
|
|
||||||
namespace ui {
|
|
||||||
class Screen {
|
|
||||||
public:
|
|
||||||
Screen() {}
|
|
||||||
Screen(const prism::path path);
|
|
||||||
|
|
||||||
void process_event(const std::string& type, std::string data = "");
|
|
||||||
|
|
||||||
void process_mouse(const int x, const int y);
|
|
||||||
void calculate_sizes();
|
|
||||||
|
|
||||||
std::vector<UIElement> elements;
|
|
||||||
|
|
||||||
UIElement* find_element(const std::string& id);
|
|
||||||
|
|
||||||
using CallbackFunction = std::function<void()>;
|
|
||||||
std::map<std::string, CallbackFunction> listeners;
|
|
||||||
|
|
||||||
bool blurs_background = false;
|
|
||||||
|
|
||||||
void add_listener(const std::string& id, std::function<void()> callback);
|
|
||||||
|
|
||||||
prism::Extent extent;
|
|
||||||
bool view_changed = false;
|
|
||||||
|
|
||||||
GFXBuffer* glyph_buffer = nullptr;
|
|
||||||
GFXBuffer* instance_buffer = nullptr;
|
|
||||||
GFXBuffer* elements_buffer = nullptr;
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,67 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include "assetptr.hpp"
|
|
||||||
|
|
||||||
enum class MetricType {
|
|
||||||
Absolute,
|
|
||||||
Relative,
|
|
||||||
Offset
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Color {
|
|
||||||
Color() : r(1.0f), g(1.0f), b(1.0f), a(1.0f) {}
|
|
||||||
|
|
||||||
Color(const float v) : r(v), g(v), b(v), a(1.0f) {}
|
|
||||||
|
|
||||||
union {
|
|
||||||
struct {
|
|
||||||
float r, g, b, a;
|
|
||||||
};
|
|
||||||
|
|
||||||
float v[4];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
class GFXTexture;
|
|
||||||
class Texture;
|
|
||||||
|
|
||||||
class UIElement {
|
|
||||||
public:
|
|
||||||
struct Metrics {
|
|
||||||
struct Metric {
|
|
||||||
MetricType type = MetricType::Absolute;
|
|
||||||
int value = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
Metric x, y, width, height;
|
|
||||||
} metrics;
|
|
||||||
|
|
||||||
struct Background {
|
|
||||||
Color color = Color(0.0f);
|
|
||||||
std::string image;
|
|
||||||
|
|
||||||
AssetPtr<Texture> texture;
|
|
||||||
} background;
|
|
||||||
|
|
||||||
enum class TextLocation {
|
|
||||||
TopLeft,
|
|
||||||
Center
|
|
||||||
} text_location = TextLocation::TopLeft;
|
|
||||||
|
|
||||||
std::string id, text, parent;
|
|
||||||
|
|
||||||
bool wrap_text = false;
|
|
||||||
|
|
||||||
float absolute_x = 0.0f, absolute_y = 0.0f, absolute_width = 0.0f, absolute_height = 0.0f;
|
|
||||||
float text_x = 0.0f, text_y = 0.0f;
|
|
||||||
|
|
||||||
bool visible = true;
|
|
||||||
|
|
||||||
std::string on_click_script;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline bool operator==(const UIElement& a, const UIElement& b) {
|
|
||||||
return a.id == b.id;
|
|
||||||
}
|
|
|
@ -39,7 +39,7 @@ void prism::console::invoke_command(const std::string_view name, const prism::co
|
||||||
invalid_format = true;
|
invalid_format = true;
|
||||||
|
|
||||||
if(invalid_format) {
|
if(invalid_format) {
|
||||||
prism::log::info(System::Core, "Invalid command format!");
|
prism::log("Invalid command format!");
|
||||||
} else {
|
} else {
|
||||||
command_data.function(console::arguments());
|
command_data.function(console::arguments());
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ void prism::console::invoke_command(const std::string_view name, const prism::co
|
||||||
invalid_format = true;
|
invalid_format = true;
|
||||||
|
|
||||||
if(invalid_format) {
|
if(invalid_format) {
|
||||||
prism::log::info(System::Core, "Wrong or empty variable type!");
|
prism::log("Wrong or empty variable type!");
|
||||||
} else {
|
} else {
|
||||||
auto argument = arguments[0];
|
auto argument = arguments[0];
|
||||||
switch(argument.query_type()) {
|
switch(argument.query_type()) {
|
||||||
|
@ -73,7 +73,7 @@ void prism::console::invoke_command(const std::string_view name, const prism::co
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
prism::log::info(System::Core, "{} is not the name of a valid command or variable!", name.data());
|
prism::log("{} is not the name of a valid command or variable!", name.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
void prism::console::parse_and_invoke_command(const std::string_view command) {
|
void prism::console::parse_and_invoke_command(const std::string_view command) {
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
#include "scene.hpp"
|
#include "scene.hpp"
|
||||||
#include "renderer.hpp"
|
#include "renderer.hpp"
|
||||||
#include "file.hpp"
|
#include "file.hpp"
|
||||||
|
#include "console.hpp"
|
||||||
|
#include "imgui_backend.hpp"
|
||||||
|
|
||||||
struct Options {
|
struct Options {
|
||||||
std::string shader_source_path;
|
std::string shader_source_path;
|
||||||
|
@ -168,7 +170,7 @@ void draw_shader_editor() {
|
||||||
if(options.shader_source_path.empty()) {
|
if(options.shader_source_path.empty()) {
|
||||||
ImGui::Text("You haven't specified a shader source path yet. Please select one below:");
|
ImGui::Text("You haven't specified a shader source path yet. Please select one below:");
|
||||||
if(ImGui::Button("Select Path")) {
|
if(ImGui::Button("Select Path")) {
|
||||||
platform::open_dialog(false, [](std::string path) {
|
engine->get_imgui().open_dialog(false, [](std::string path) {
|
||||||
// open_dialog() can't select folders yet, so use this as a workaround
|
// open_dialog() can't select folders yet, so use this as a workaround
|
||||||
options.shader_source_path = prism::path(path).parent_path().string();
|
options.shader_source_path = prism::path(path).parent_path().string();
|
||||||
});
|
});
|
||||||
|
@ -244,3 +246,23 @@ void save_debug_options() {
|
||||||
std::string_view get_shader_source_directory() {
|
std::string_view get_shader_source_directory() {
|
||||||
return options.shader_source_path;
|
return options.shader_source_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void draw_console() {
|
||||||
|
ImGui::Text("%s", prism::log_output.c_str());
|
||||||
|
|
||||||
|
static std::string console_input;
|
||||||
|
|
||||||
|
ImGui::SetNextItemWidth(-1.0f);
|
||||||
|
|
||||||
|
const bool input_return = ImGui::InputText("##console_input", &console_input, ImGuiInputTextFlags_EnterReturnsTrue);
|
||||||
|
|
||||||
|
if(input_return)
|
||||||
|
ImGui::SetKeyboardFocusHere(-1);
|
||||||
|
|
||||||
|
const bool button_return = ImGui::Button("Input");
|
||||||
|
|
||||||
|
if(input_return || button_return) {
|
||||||
|
prism::console::parse_and_invoke_command(console_input);
|
||||||
|
console_input.clear();
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,7 +11,6 @@
|
||||||
#include "json_conversions.hpp"
|
#include "json_conversions.hpp"
|
||||||
#include "app.hpp"
|
#include "app.hpp"
|
||||||
#include "assertions.hpp"
|
#include "assertions.hpp"
|
||||||
#include "screen.hpp"
|
|
||||||
#include "renderer.hpp"
|
#include "renderer.hpp"
|
||||||
#include "gfx.hpp"
|
#include "gfx.hpp"
|
||||||
#include "imgui_backend.hpp"
|
#include "imgui_backend.hpp"
|
||||||
|
@ -27,10 +26,10 @@
|
||||||
using prism::engine;
|
using prism::engine;
|
||||||
|
|
||||||
engine::engine(const int argc, char* argv[]) {
|
engine::engine(const int argc, char* argv[]) {
|
||||||
log::info(System::Core, "Prism Engine loading...");
|
log("Prism Engine loading...");
|
||||||
|
|
||||||
console::register_command("test_cmd", console::argument_format(0), [](const console::arguments&) {
|
console::register_command("test_cmd", console::argument_format(0), [](const console::arguments&) {
|
||||||
log::info(System::Core, "Test cmd!");
|
log("Test cmd!");
|
||||||
});
|
});
|
||||||
|
|
||||||
console::register_variable("rs_dynamic_resolution", render_options.dynamic_resolution);
|
console::register_variable("rs_dynamic_resolution", render_options.dynamic_resolution);
|
||||||
|
@ -60,26 +59,12 @@ prism::app* engine::get_app() const {
|
||||||
return app;
|
return app;
|
||||||
}
|
}
|
||||||
|
|
||||||
void engine::load_localization(const std::string_view path) {
|
|
||||||
Expects(!path.empty());
|
|
||||||
|
|
||||||
auto file = prism::open_file(prism::app_domain / path);
|
|
||||||
if(file.has_value()) {
|
|
||||||
nlohmann::json j;
|
|
||||||
file->read_as_stream() >> j;
|
|
||||||
|
|
||||||
strings = j["strings"].get<std::map<std::string, std::string>>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void engine::pause() {
|
void engine::pause() {
|
||||||
paused = true;
|
paused = true;
|
||||||
push_event("engine_pause");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void engine::unpause() {
|
void engine::unpause() {
|
||||||
paused = false;
|
paused = false;
|
||||||
push_event("engine_unpause");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool engine::is_paused() const {
|
bool engine::is_paused() const {
|
||||||
|
@ -94,6 +79,8 @@ void engine::quit() {
|
||||||
bool engine::is_quitting() const {
|
bool engine::is_quitting() const {
|
||||||
if(!windows.empty())
|
if(!windows.empty())
|
||||||
return windows[0]->quit_requested;
|
return windows[0]->quit_requested;
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void engine::prepare_quit() {
|
void engine::prepare_quit() {
|
||||||
|
@ -136,7 +123,7 @@ Scene* engine::load_scene(const prism::path& path) {
|
||||||
|
|
||||||
auto file = prism::open_file(path);
|
auto file = prism::open_file(path);
|
||||||
if(!file.has_value()) {
|
if(!file.has_value()) {
|
||||||
prism::log::error(System::Core, "Failed to load scene from {}!", path);
|
prism::log("Failed to load scene from {}!", path.string());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,25 +178,6 @@ void engine::save_scene(const std::string_view path) {
|
||||||
out << j;
|
out << j;
|
||||||
}
|
}
|
||||||
|
|
||||||
ui::Screen* engine::load_screen(const prism::path& path) {
|
|
||||||
Expects(!path.empty());
|
|
||||||
|
|
||||||
return new ui::Screen(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
void engine::set_screen(ui::Screen* screen) {
|
|
||||||
current_screen = screen;
|
|
||||||
|
|
||||||
screen->extent = windows[0]->extent;
|
|
||||||
screen->calculate_sizes();
|
|
||||||
|
|
||||||
get_renderer()->set_screen(screen);
|
|
||||||
}
|
|
||||||
|
|
||||||
ui::Screen* engine::get_screen() const {
|
|
||||||
return current_screen;
|
|
||||||
}
|
|
||||||
|
|
||||||
AnimationChannel engine::load_animation(nlohmann::json a) {
|
AnimationChannel engine::load_animation(nlohmann::json a) {
|
||||||
AnimationChannel animation;
|
AnimationChannel animation;
|
||||||
|
|
||||||
|
@ -229,7 +197,7 @@ Animation engine::load_animation(const prism::path& path) {
|
||||||
|
|
||||||
auto file = prism::open_file(path, true);
|
auto file = prism::open_file(path, true);
|
||||||
if(!file.has_value()) {
|
if(!file.has_value()) {
|
||||||
prism::log::error(System::Core, "Failed to load animation from {}!", path);
|
prism::log("Failed to load animation from {}!", path.string());
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,7 +257,7 @@ void engine::load_cutscene(const prism::path& path) {
|
||||||
|
|
||||||
auto file = prism::open_file(path);
|
auto file = prism::open_file(path);
|
||||||
if(!file.has_value()) {
|
if(!file.has_value()) {
|
||||||
prism::log::error(System::Core, "Failed to load cutscene from {}!", path);
|
prism::log("Failed to load cutscene from {}!", path.string());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -364,7 +332,7 @@ Object engine::add_prefab(Scene& scene, const prism::path& path, const std::stri
|
||||||
|
|
||||||
auto file = prism::open_file(path);
|
auto file = prism::open_file(path);
|
||||||
if(!file.has_value()) {
|
if(!file.has_value()) {
|
||||||
prism::log::error(System::Core, "Failed to load prefab from {}!", path);
|
prism::log("Failed to load prefab from {}!", path.string());
|
||||||
return NullObject;
|
return NullObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -452,22 +420,21 @@ void engine::resize(const int identifier, const prism::Extent extent) {
|
||||||
|
|
||||||
gfx->recreate_view(identifier, drawable_extent.width, drawable_extent.height);
|
gfx->recreate_view(identifier, drawable_extent.width, drawable_extent.height);
|
||||||
renderer->resize_render_target(*window->render_target, drawable_extent);
|
renderer->resize_render_target(*window->render_target, drawable_extent);
|
||||||
|
|
||||||
if(identifier == 0) {
|
|
||||||
if(current_screen != nullptr) {
|
|
||||||
current_screen->extent = extent;
|
|
||||||
current_screen->calculate_sizes();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void engine::process_key_down(const unsigned int keyCode) {
|
void engine::process_key_down(const unsigned int keyCode) {
|
||||||
Expects(keyCode >= 0);
|
Expects(keyCode >= 0);
|
||||||
|
|
||||||
|
if(input->is_text_input() && !input->get_allowable_text_button(keyCode))
|
||||||
|
return;
|
||||||
|
|
||||||
imgui->process_key_down(keyCode);
|
imgui->process_key_down(keyCode);
|
||||||
|
|
||||||
if(keyCode == platform::get_keycode(debug_button) && !ImGui::GetIO().WantTextInput)
|
if(keyCode == platform::get_keycode(debug_button) && !ImGui::GetIO().WantTextInput)
|
||||||
debug_enabled = !debug_enabled;
|
debug_enabled = !debug_enabled;
|
||||||
|
|
||||||
|
if(keyCode == platform::get_keycode(InputButton::C))
|
||||||
|
console_enabled = !console_enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
void engine::process_key_up(const unsigned int keyCode) {
|
void engine::process_key_up(const unsigned int keyCode) {
|
||||||
|
@ -477,31 +444,9 @@ void engine::process_key_up(const unsigned int keyCode) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void engine::process_mouse_down(const int button, const prism::Offset offset) {
|
void engine::process_mouse_down(const int button, const prism::Offset offset) {
|
||||||
if(current_screen != nullptr && button == 0)
|
|
||||||
current_screen->process_mouse(offset.x, offset.y);
|
|
||||||
|
|
||||||
imgui->process_mouse_down(button);
|
imgui->process_mouse_down(button);
|
||||||
}
|
}
|
||||||
|
|
||||||
void engine::push_event(const std::string_view name, const std::string_view data) {
|
|
||||||
Expects(!name.empty());
|
|
||||||
|
|
||||||
if(current_screen != nullptr)
|
|
||||||
current_screen->process_event(name.data(), data.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool engine::has_localization(const std::string_view id) const {
|
|
||||||
Expects(!id.empty());
|
|
||||||
|
|
||||||
return strings.count(id.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string engine::localize(const std::string& id) {
|
|
||||||
Expects(!id.empty());
|
|
||||||
|
|
||||||
return strings[id];
|
|
||||||
}
|
|
||||||
|
|
||||||
void engine::calculate_bone(Mesh& mesh, const Mesh::Part& part, Bone& bone, const Bone* parent_bone) {
|
void engine::calculate_bone(Mesh& mesh, const Mesh::Part& part, Bone& bone, const Bone* parent_bone) {
|
||||||
if(part.offset_matrices.empty())
|
if(part.offset_matrices.empty())
|
||||||
return;
|
return;
|
||||||
|
@ -665,6 +610,9 @@ void engine::begin_frame(const float delta_time) {
|
||||||
if(debug_enabled)
|
if(debug_enabled)
|
||||||
draw_debug_ui();
|
draw_debug_ui();
|
||||||
|
|
||||||
|
if(console_enabled)
|
||||||
|
draw_console();
|
||||||
|
|
||||||
if(app != nullptr)
|
if(app != nullptr)
|
||||||
app->begin_frame();
|
app->begin_frame();
|
||||||
}
|
}
|
||||||
|
@ -767,11 +715,6 @@ void engine::render(const int index) {
|
||||||
GFXCommandBuffer* commandbuffer = gfx->acquire_command_buffer(true);
|
GFXCommandBuffer* commandbuffer = gfx->acquire_command_buffer(true);
|
||||||
|
|
||||||
if(index == 0) {
|
if(index == 0) {
|
||||||
if(current_screen != nullptr && current_screen->view_changed) {
|
|
||||||
renderer->update_screen();
|
|
||||||
current_screen->view_changed = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
imgui->render(0);
|
imgui->render(0);
|
||||||
|
|
||||||
app->render(commandbuffer);
|
app->render(commandbuffer);
|
||||||
|
@ -864,3 +807,7 @@ void engine::setup_scene(Scene& scene) {
|
||||||
scene.reset_shadows();
|
scene.reset_shadows();
|
||||||
scene.reset_environment();
|
scene.reset_environment();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void prism::engine::process_text_input(const std::string_view string) {
|
||||||
|
imgui->process_text_input(string);
|
||||||
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ std::optional<prism::file> prism::open_file(const prism::path path, const bool b
|
||||||
auto str = get_file_path(path).string();
|
auto str = get_file_path(path).string();
|
||||||
FILE* file = fopen(str.c_str(), binary_mode ? "rb" : "r");
|
FILE* file = fopen(str.c_str(), binary_mode ? "rb" : "r");
|
||||||
if(file == nullptr) {
|
if(file == nullptr) {
|
||||||
prism::log::error(System::File, "Failed to open file handle from {}!", str);
|
prism::log("Failed to open file handle from {}!", str);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "engine.hpp"
|
#include "engine.hpp"
|
||||||
#include "platform.hpp"
|
#include "platform.hpp"
|
||||||
#include "assertions.hpp"
|
#include "assertions.hpp"
|
||||||
|
#include "input.hpp"
|
||||||
|
|
||||||
using prism::imgui_backend;
|
using prism::imgui_backend;
|
||||||
|
|
||||||
|
@ -159,6 +160,17 @@ imgui_backend::imgui_backend() {
|
||||||
|
|
||||||
void imgui_backend::begin_frame(const float delta_time) {
|
void imgui_backend::begin_frame(const float delta_time) {
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
const bool imgui_wants_text = io.WantTextInput;
|
||||||
|
const bool input_is_text = ::engine->get_input()->is_text_input();
|
||||||
|
|
||||||
|
if(imgui_wants_text != input_is_text) {
|
||||||
|
if(imgui_wants_text) {
|
||||||
|
::engine->get_input()->begin_text_input();
|
||||||
|
} else {
|
||||||
|
::engine->get_input()->end_text_input();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const auto [width, height] = platform::get_window_size(0);
|
const auto [width, height] = platform::get_window_size(0);
|
||||||
const auto [dw, dh] = platform::get_window_drawable_size(0);
|
const auto [dw, dh] = platform::get_window_drawable_size(0);
|
||||||
|
@ -192,6 +204,50 @@ void imgui_backend::begin_frame(const float delta_time) {
|
||||||
mouse_buttons[0] = mouse_buttons[1] = mouse_buttons[2] = false;
|
mouse_buttons[0] = mouse_buttons[1] = mouse_buttons[2] = false;
|
||||||
|
|
||||||
ImGui::NewFrame();
|
ImGui::NewFrame();
|
||||||
|
|
||||||
|
if(open_dialog_next_frame) {
|
||||||
|
ImGui::OpenPopup("Open File");
|
||||||
|
open_dialog_next_frame = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(save_dialog_next_frame) {
|
||||||
|
ImGui::OpenPopup("Save File");
|
||||||
|
save_dialog_next_frame = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto dialog_function = [](dialog_data& data) {
|
||||||
|
if(ImGui::Selectable("..", false, ImGuiSelectableFlags_DontClosePopups))
|
||||||
|
data.current_path = data.current_path.parent_path();
|
||||||
|
|
||||||
|
for(auto dir_ent : std::filesystem::directory_iterator(data.current_path)) {
|
||||||
|
if(ImGui::Selectable(dir_ent.path().c_str(), data.selected_path == dir_ent.path(), ImGuiSelectableFlags_DontClosePopups)) {
|
||||||
|
if(dir_ent.is_directory())
|
||||||
|
data.current_path = dir_ent.path();
|
||||||
|
else
|
||||||
|
data.selected_path = dir_ent.path();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::TextDisabled("Selected: %s", data.selected_path.c_str());
|
||||||
|
|
||||||
|
if(ImGui::Button("OK")) {
|
||||||
|
data.return_function(data.selected_path.string());
|
||||||
|
ImGui::CloseCurrentPopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ImGui::Button("Cancel"))
|
||||||
|
ImGui::CloseCurrentPopup();
|
||||||
|
};
|
||||||
|
|
||||||
|
if(ImGui::BeginPopup("Open File")) {
|
||||||
|
dialog_function(open_dialog_data);
|
||||||
|
ImGui::EndPopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ImGui::BeginPopup("Save File")) {
|
||||||
|
dialog_function(save_dialog_data);
|
||||||
|
ImGui::EndPopup();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void imgui_backend::render(int index) {
|
void imgui_backend::render(int index) {
|
||||||
|
@ -205,10 +261,9 @@ void imgui_backend::render(int index) {
|
||||||
|
|
||||||
void imgui_backend::process_key_down(unsigned int key_code) {
|
void imgui_backend::process_key_down(unsigned int key_code) {
|
||||||
Expects(key_code >= 0);
|
Expects(key_code >= 0);
|
||||||
|
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
io.AddInputCharactersUTF8(platform::translate_keycode(key_code));
|
|
||||||
|
|
||||||
io.KeysDown[key_code] = true;
|
io.KeysDown[key_code] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,4 +277,21 @@ void imgui_backend::process_key_up(unsigned int key_code) {
|
||||||
|
|
||||||
void imgui_backend::process_mouse_down(int button) {
|
void imgui_backend::process_mouse_down(int button) {
|
||||||
mouse_buttons[button] = true;
|
mouse_buttons[button] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void prism::imgui_backend::process_text_input(const std::string_view string) {
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.AddInputCharactersUTF8(string.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
void prism::imgui_backend::open_dialog(const bool existing, std::function<void(std::string)> returnFunction, bool openDirectory) {
|
||||||
|
open_dialog_next_frame = true;
|
||||||
|
open_dialog_data.current_path = std::filesystem::current_path();
|
||||||
|
open_dialog_data.return_function = returnFunction;
|
||||||
|
}
|
||||||
|
|
||||||
|
void prism::imgui_backend::save_dialog(std::function<void(std::string)> returnFunction) {
|
||||||
|
save_dialog_next_frame = true;
|
||||||
|
save_dialog_data.current_path = std::filesystem::current_path();
|
||||||
|
save_dialog_data.return_function = returnFunction;
|
||||||
}
|
}
|
|
@ -155,3 +155,27 @@ bool input_system::is_repeating(const std::string& name) {
|
||||||
std::vector<prism::input_binding> input_system::get_bindings() const {
|
std::vector<prism::input_binding> input_system::get_bindings() const {
|
||||||
return _input_bindings;
|
return _input_bindings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void input_system::begin_text_input() {
|
||||||
|
_in_text_input = true;
|
||||||
|
platform::begin_text_input();
|
||||||
|
}
|
||||||
|
|
||||||
|
void input_system::end_text_input() {
|
||||||
|
_in_text_input = false;
|
||||||
|
platform::end_text_input();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool input_system::is_text_input() const {
|
||||||
|
return _in_text_input;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool input_system::get_allowable_text_button(unsigned int keycode) const {
|
||||||
|
if(platform::get_keycode(InputButton::Backspace) == keycode)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if(platform::get_keycode(InputButton::Enter) == keycode)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
|
@ -65,12 +65,6 @@ void load_rigidbody_component(nlohmann::json j, Rigidbody& rigidbody) {
|
||||||
rigidbody.mass = j["mass"];
|
rigidbody.mass = j["mass"];
|
||||||
}
|
}
|
||||||
|
|
||||||
void load_ui_component(nlohmann::json j, UI& ui) {
|
|
||||||
ui.width = j["width"];
|
|
||||||
ui.height = j["height"];
|
|
||||||
ui.ui_path = j["path"];
|
|
||||||
}
|
|
||||||
|
|
||||||
void load_probe_component(nlohmann::json j, EnvironmentProbe& probe) {
|
void load_probe_component(nlohmann::json j, EnvironmentProbe& probe) {
|
||||||
if(j.contains("size"))
|
if(j.contains("size"))
|
||||||
probe.size = j["size"];
|
probe.size = j["size"];
|
||||||
|
@ -104,9 +98,6 @@ Object load_object(Scene& scene, const nlohmann::json obj) {
|
||||||
|
|
||||||
if(obj.contains("rigidbody"))
|
if(obj.contains("rigidbody"))
|
||||||
load_rigidbody_component(obj["rigidbody"], scene.add<Rigidbody>(o));
|
load_rigidbody_component(obj["rigidbody"], scene.add<Rigidbody>(o));
|
||||||
|
|
||||||
if(obj.contains("ui"))
|
|
||||||
load_ui_component(obj["ui"], scene.add<UI>(o));
|
|
||||||
|
|
||||||
if(obj.contains("environment_probe"))
|
if(obj.contains("environment_probe"))
|
||||||
load_probe_component(obj["environment_probe"], scene.add<EnvironmentProbe>(o));
|
load_probe_component(obj["environment_probe"], scene.add<EnvironmentProbe>(o));
|
||||||
|
@ -158,12 +149,6 @@ void save_rigidbody_component(nlohmann::json& j, const Rigidbody& rigidbody) {
|
||||||
j["mass"] = rigidbody.mass;
|
j["mass"] = rigidbody.mass;
|
||||||
}
|
}
|
||||||
|
|
||||||
void save_ui_component(nlohmann::json& j, const UI& ui) {
|
|
||||||
j["width"] = ui.width;
|
|
||||||
j["height"] = ui.height;
|
|
||||||
j["path"] = ui.ui_path;
|
|
||||||
}
|
|
||||||
|
|
||||||
void save_probe_component(nlohmann::json& j, const EnvironmentProbe& probe) {
|
void save_probe_component(nlohmann::json& j, const EnvironmentProbe& probe) {
|
||||||
j["size"] = probe.size;
|
j["size"] = probe.size;
|
||||||
j["is_sized"] = probe.is_sized;
|
j["is_sized"] = probe.is_sized;
|
||||||
|
@ -198,10 +183,7 @@ nlohmann::json save_object(Object obj) {
|
||||||
|
|
||||||
if(scene->has<Rigidbody>(obj))
|
if(scene->has<Rigidbody>(obj))
|
||||||
save_rigidbody_component(j["rigidbody"], scene->get<Rigidbody>(obj));
|
save_rigidbody_component(j["rigidbody"], scene->get<Rigidbody>(obj));
|
||||||
|
|
||||||
if(scene->has<UI>(obj))
|
|
||||||
save_ui_component(j["ui"], scene->get<UI>(obj));
|
|
||||||
|
|
||||||
if(scene->has<EnvironmentProbe>(obj))
|
if(scene->has<EnvironmentProbe>(obj))
|
||||||
save_probe_component(j["environment_probe"], scene->get<EnvironmentProbe>(obj));
|
save_probe_component(j["environment_probe"], scene->get<EnvironmentProbe>(obj));
|
||||||
|
|
||||||
|
|
|
@ -1,191 +0,0 @@
|
||||||
#include "screen.hpp"
|
|
||||||
|
|
||||||
#include <fstream>
|
|
||||||
#include <string_view>
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
|
|
||||||
#include "file.hpp"
|
|
||||||
#include "font.hpp"
|
|
||||||
#include "engine.hpp"
|
|
||||||
#include "string_utils.hpp"
|
|
||||||
#include "log.hpp"
|
|
||||||
#include "assertions.hpp"
|
|
||||||
#include "uielement.hpp"
|
|
||||||
|
|
||||||
void ui::Screen::calculate_sizes() {
|
|
||||||
unsigned int numChildren = 0;
|
|
||||||
|
|
||||||
int actualWidth = extent.width, actualHeight = extent.height;
|
|
||||||
int offsetX = 0, offsetY = 0;
|
|
||||||
|
|
||||||
for(size_t i = 0; i < elements.size(); i++) {
|
|
||||||
auto& element = elements[i];
|
|
||||||
|
|
||||||
auto id = "ui_" + element.id;
|
|
||||||
//if(engine->has_localization(id))
|
|
||||||
// element.text = engine->localize(id);
|
|
||||||
|
|
||||||
UIElement* parent = nullptr;
|
|
||||||
if(!element.parent.empty())
|
|
||||||
parent = find_element(element.parent);
|
|
||||||
|
|
||||||
const auto& fillAbsolute = [parent](const auto& metric, auto& absolute, auto base, auto offset) {
|
|
||||||
switch(metric.type) {
|
|
||||||
case MetricType::Absolute:
|
|
||||||
absolute = offset + metric.value;
|
|
||||||
break;
|
|
||||||
case MetricType::Relative:
|
|
||||||
absolute = offset + ((base - offset) * (metric.value / 100.0f));
|
|
||||||
break;
|
|
||||||
case MetricType::Offset:
|
|
||||||
{
|
|
||||||
if(parent == nullptr)
|
|
||||||
absolute = base - metric.value;
|
|
||||||
else
|
|
||||||
absolute = parent->absolute_height - metric.value;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
fillAbsolute(element.metrics.x, element.absolute_x, offsetX + actualWidth, offsetX);
|
|
||||||
fillAbsolute(element.metrics.y, element.absolute_y, offsetY + actualHeight, offsetY);
|
|
||||||
|
|
||||||
fillAbsolute(element.metrics.width, element.absolute_width, actualWidth, 0);
|
|
||||||
fillAbsolute(element.metrics.height, element.absolute_height, actualHeight, 0);
|
|
||||||
|
|
||||||
if(parent) {
|
|
||||||
const float heightPerRow = actualWidth / (float)elements.size();
|
|
||||||
|
|
||||||
element.absolute_x = (float)numChildren * heightPerRow;
|
|
||||||
element.absolute_y = actualHeight - 50.0f;
|
|
||||||
element.absolute_width = (float)heightPerRow;
|
|
||||||
element.absolute_height = (float)50.0f;
|
|
||||||
|
|
||||||
numChildren++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(element.text_location == UIElement::TextLocation::Center) {
|
|
||||||
if(get_string_width(element.text) < element.absolute_width)
|
|
||||||
element.text_x = (element.absolute_width / 2.0f) - (get_string_width(element.text) / 2.0f);
|
|
||||||
|
|
||||||
if(get_font_height() < element.absolute_height)
|
|
||||||
element.text_y = (element.absolute_height / 2.0f) - (get_font_height() / 2.0f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ui::Screen::process_mouse(const int x, const int y) {
|
|
||||||
Expects(x >= 0);
|
|
||||||
Expects(y >= 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
UIElement* ui::Screen::find_element(const std::string& id) {
|
|
||||||
Expects(!id.empty());
|
|
||||||
|
|
||||||
UIElement* foundElement = nullptr;
|
|
||||||
for(auto& element : elements) {
|
|
||||||
if(element.id == id)
|
|
||||||
foundElement = &element;
|
|
||||||
}
|
|
||||||
|
|
||||||
Expects(foundElement != nullptr);
|
|
||||||
|
|
||||||
return foundElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
ui::Screen::Screen(const prism::path path) {
|
|
||||||
auto file = prism::open_file(path);
|
|
||||||
if(!file.has_value()) {
|
|
||||||
prism::log::error(System::Core, "Failed to load UI from {}!", path);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
nlohmann::json j;
|
|
||||||
file->read_as_stream() >> j;
|
|
||||||
|
|
||||||
for(auto& element : j["elements"]) {
|
|
||||||
UIElement ue;
|
|
||||||
ue.id = element["id"];
|
|
||||||
|
|
||||||
if(element.contains("on_click"))
|
|
||||||
ue.on_click_script = element["on_click"];
|
|
||||||
|
|
||||||
if(element.contains("text"))
|
|
||||||
ue.text = element["text"];
|
|
||||||
|
|
||||||
if(element.contains("parent"))
|
|
||||||
ue.parent = element["parent"];
|
|
||||||
|
|
||||||
if(element.contains("metrics")) {
|
|
||||||
const auto& metrics = element["metrics"];
|
|
||||||
|
|
||||||
const auto parseMetric = [](const std::string& str) {
|
|
||||||
UIElement::Metrics::Metric m;
|
|
||||||
|
|
||||||
if(string_contains(str, "px")) {
|
|
||||||
auto v = remove_substring(str, "px");
|
|
||||||
|
|
||||||
if(string_contains(str, "@")) {
|
|
||||||
m.type = MetricType::Offset;
|
|
||||||
m.value = std::stoi(remove_substring(v, "@"));
|
|
||||||
} else {
|
|
||||||
m.type = MetricType::Absolute;
|
|
||||||
m.value = std::stoi(v);
|
|
||||||
}
|
|
||||||
} else if(string_contains(str, "%")) {
|
|
||||||
m.type = MetricType::Relative;
|
|
||||||
m.value = std::stoi(remove_substring(str, "%"));
|
|
||||||
}
|
|
||||||
|
|
||||||
return m;
|
|
||||||
};
|
|
||||||
|
|
||||||
if(metrics.contains("x"))
|
|
||||||
ue.metrics.x = parseMetric(metrics["x"]);
|
|
||||||
|
|
||||||
if(metrics.contains("y"))
|
|
||||||
ue.metrics.y = parseMetric(metrics["y"]);
|
|
||||||
|
|
||||||
if(metrics.contains("width"))
|
|
||||||
ue.metrics.width = parseMetric(metrics["width"]);
|
|
||||||
|
|
||||||
if(metrics.contains("height"))
|
|
||||||
ue.metrics.height = parseMetric(metrics["height"]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(element.contains("background")) {
|
|
||||||
if(element["background"].contains("color")) {
|
|
||||||
auto tokens = tokenize(element["background"]["color"].get<std::string_view>(), ",");
|
|
||||||
ue.background.color.r = std::stof(tokens[0]);
|
|
||||||
ue.background.color.g = std::stof(tokens[1]);
|
|
||||||
ue.background.color.b = std::stof(tokens[2]);
|
|
||||||
ue.background.color.a = std::stof(tokens[3]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(element["background"].contains("image")) {
|
|
||||||
ue.background.image = element["background"]["image"];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(element.contains("wrap"))
|
|
||||||
ue.wrap_text = element["wrap"];
|
|
||||||
|
|
||||||
if(element.contains("textLocation")) {
|
|
||||||
if(element["textLocation"] == "topLeft")
|
|
||||||
ue.text_location = UIElement::TextLocation::TopLeft;
|
|
||||||
else if(element["textLocation"] == "center")
|
|
||||||
ue.text_location = UIElement::TextLocation::Center;
|
|
||||||
}
|
|
||||||
|
|
||||||
elements.push_back(ue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ui::Screen::add_listener(const std::string& id, std::function<void()> callback) {
|
|
||||||
listeners[id] = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ui::Screen::process_event(const std::string& type, const std::string data) {
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
set(SRC
|
|
||||||
include/gfx_metal.hpp
|
|
||||||
|
|
||||||
src/gfx_metal.mm
|
|
||||||
src/gfx_metal_buffer.hpp
|
|
||||||
src/gfx_metal_pipeline.hpp
|
|
||||||
src/gfx_metal_texture.hpp
|
|
||||||
src/gfx_metal_framebuffer.hpp
|
|
||||||
src/gfx_metal_renderpass.hpp
|
|
||||||
src/gfx_metal_sampler.hpp)
|
|
||||||
|
|
||||||
add_library(GFXMetal STATIC
|
|
||||||
${SRC})
|
|
||||||
|
|
||||||
set_target_properties(GFXMetal PROPERTIES
|
|
||||||
FRAMEWORK TRUE
|
|
||||||
FRAMEWORK_VERSION OBJC
|
|
||||||
PUBLIC_HEADER "${HEADERS}"
|
|
||||||
)
|
|
||||||
target_link_libraries(GFXMetal PUBLIC
|
|
||||||
GFX
|
|
||||||
Core
|
|
||||||
Log
|
|
||||||
"-framework Metal")
|
|
||||||
target_include_directories(GFXMetal PUBLIC
|
|
||||||
include
|
|
||||||
PRIVATE
|
|
||||||
src)
|
|
||||||
set_engine_properties(GFXMetal)
|
|
|
@ -1,70 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <Metal/Metal.h>
|
|
||||||
#include <MetalKit/MetalKit.h>
|
|
||||||
|
|
||||||
#include "gfx.hpp"
|
|
||||||
|
|
||||||
class GFXMetal : public GFX {
|
|
||||||
public:
|
|
||||||
bool is_supported() override;
|
|
||||||
GFXContext required_context() override { return GFXContext::Metal; }
|
|
||||||
ShaderLanguage accepted_shader_language() override { return ShaderLanguage::MSL; }
|
|
||||||
const char* get_name() override;
|
|
||||||
|
|
||||||
bool supports_feature(const GFXFeature feature) override;
|
|
||||||
|
|
||||||
bool initialize(const GFXCreateInfo& createInfo) override;
|
|
||||||
|
|
||||||
void initialize_view(void* native_handle, const int identifier, const uint32_t width, const uint32_t height) override;
|
|
||||||
void remove_view(const int identifier) override;
|
|
||||||
|
|
||||||
// buffer operations
|
|
||||||
GFXBuffer* create_buffer(void* data, const GFXSize size, const bool dynamicData, const GFXBufferUsage usage) override;
|
|
||||||
void copy_buffer(GFXBuffer* buffer, void* data, const GFXSize offset, const GFXSize size) override;
|
|
||||||
|
|
||||||
void* get_buffer_contents(GFXBuffer* buffer) override;
|
|
||||||
|
|
||||||
// texture operations
|
|
||||||
GFXTexture* create_texture(const GFXTextureCreateInfo& info) override;
|
|
||||||
void copy_texture(GFXTexture* texture, void* data, GFXSize size) override;
|
|
||||||
void copy_texture(GFXTexture* from, GFXTexture* to) override;
|
|
||||||
void copy_texture(GFXTexture* from, GFXBuffer* to) override;
|
|
||||||
|
|
||||||
// sampler opeations
|
|
||||||
GFXSampler* create_sampler(const GFXSamplerCreateInfo& info) override;
|
|
||||||
|
|
||||||
// framebuffer operations
|
|
||||||
GFXFramebuffer* create_framebuffer(const GFXFramebufferCreateInfo& info) override;
|
|
||||||
|
|
||||||
// render pass operations
|
|
||||||
GFXRenderPass* create_render_pass(const GFXRenderPassCreateInfo& info) override;
|
|
||||||
|
|
||||||
// pipeline operations
|
|
||||||
GFXPipeline* create_graphics_pipeline(const GFXGraphicsPipelineCreateInfo& info) override;
|
|
||||||
GFXPipeline* create_compute_pipeline(const GFXComputePipelineCreateInfo& info) override;
|
|
||||||
|
|
||||||
GFXCommandBuffer* acquire_command_buffer(bool for_presentation_use = false) override;
|
|
||||||
|
|
||||||
void submit(GFXCommandBuffer* command_buffer, const int window = -1) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct NativeMTLView {
|
|
||||||
int identifier = -1;
|
|
||||||
CAMetalLayer* layer = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<NativeMTLView*> nativeViews;
|
|
||||||
|
|
||||||
NativeMTLView* getNativeView(int identifier) {
|
|
||||||
for(auto& view : nativeViews) {
|
|
||||||
if(view->identifier == identifier)
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
id<MTLDevice> device = nil;
|
|
||||||
id<MTLCommandQueue> command_queue = nil;
|
|
||||||
};
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,19 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <Metal/Metal.h>
|
|
||||||
|
|
||||||
#include "gfx_buffer.hpp"
|
|
||||||
|
|
||||||
class GFXMetalBuffer : public GFXBuffer {
|
|
||||||
public:
|
|
||||||
id<MTLBuffer> handles[3] = {nil, nil, nil};
|
|
||||||
bool dynamicData = false;
|
|
||||||
|
|
||||||
id<MTLBuffer> get(int frameIndex) {
|
|
||||||
if(dynamicData) {
|
|
||||||
return handles[frameIndex];
|
|
||||||
} else {
|
|
||||||
return handles[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -1,13 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <Metal/Metal.h>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "gfx_framebuffer.hpp"
|
|
||||||
|
|
||||||
class GFXMetalTexture;
|
|
||||||
|
|
||||||
class GFXMetalFramebuffer : public GFXFramebuffer {
|
|
||||||
public:
|
|
||||||
std::vector<GFXMetalTexture*> attachments;
|
|
||||||
};
|
|
|
@ -1,32 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <Metal/Metal.h>
|
|
||||||
|
|
||||||
#include "gfx_pipeline.hpp"
|
|
||||||
|
|
||||||
class GFXMetalPipeline : public GFXPipeline {
|
|
||||||
public:
|
|
||||||
std::string label;
|
|
||||||
|
|
||||||
id<MTLRenderPipelineState> handle = nil;
|
|
||||||
id<MTLComputePipelineState> compute_handle = nil;
|
|
||||||
|
|
||||||
MTLSize threadGroupSize;
|
|
||||||
|
|
||||||
id<MTLDepthStencilState> depthStencil = nil;
|
|
||||||
MTLPrimitiveType primitiveType;
|
|
||||||
|
|
||||||
MTLCullMode cullMode;
|
|
||||||
GFXWindingMode winding_mode;
|
|
||||||
|
|
||||||
struct VertexStride {
|
|
||||||
int location, stride;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<VertexStride> vertexStrides;
|
|
||||||
|
|
||||||
int pushConstantSize = 0;
|
|
||||||
int pushConstantIndex = 0;
|
|
||||||
|
|
||||||
bool renderWire = false;
|
|
||||||
};
|
|
|
@ -1,10 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <Metal/Metal.h>
|
|
||||||
|
|
||||||
#include "gfx_renderpass.hpp"
|
|
||||||
|
|
||||||
class GFXMetalRenderPass : public GFXRenderPass {
|
|
||||||
public:
|
|
||||||
std::vector<MTLPixelFormat> attachments;
|
|
||||||
};
|
|
|
@ -1,10 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <Metal/Metal.h>
|
|
||||||
|
|
||||||
#include "gfx_sampler.hpp"
|
|
||||||
|
|
||||||
class GFXMetalSampler : public GFXSampler {
|
|
||||||
public:
|
|
||||||
id<MTLSamplerState> handle = nil;
|
|
||||||
};
|
|
|
@ -1,16 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <Metal/Metal.h>
|
|
||||||
|
|
||||||
#include "gfx_texture.hpp"
|
|
||||||
|
|
||||||
class GFXMetalTexture : public GFXTexture {
|
|
||||||
public:
|
|
||||||
id<MTLTexture> handle = nil;
|
|
||||||
id<MTLSamplerState> sampler = nil;
|
|
||||||
|
|
||||||
int array_length = 1;
|
|
||||||
bool is_cubemap = false;
|
|
||||||
|
|
||||||
MTLPixelFormat format;
|
|
||||||
};
|
|
|
@ -1,12 +1,5 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifdef PLATFORM_WINDOWS
|
|
||||||
#define NOMINMAX // donut define max in windows.h
|
|
||||||
#define VK_USE_PLATFORM_WIN32_KHR
|
|
||||||
#else
|
|
||||||
#define VK_USE_PLATFORM_XCB_KHR
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <vulkan/vulkan.h>
|
#include <vulkan/vulkan.h>
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
@ -18,7 +11,6 @@
|
||||||
struct NativeSurface {
|
struct NativeSurface {
|
||||||
int identifier = -1;
|
int identifier = -1;
|
||||||
|
|
||||||
void* windowNativeHandle;
|
|
||||||
uint32_t surfaceWidth = -1, surfaceHeight = -1;
|
uint32_t surfaceWidth = -1, surfaceHeight = -1;
|
||||||
|
|
||||||
std::vector<VkSemaphore> imageAvailableSemaphores;
|
std::vector<VkSemaphore> imageAvailableSemaphores;
|
||||||
|
@ -43,28 +35,28 @@ class GFXVulkanPipeline;
|
||||||
|
|
||||||
class GFXVulkan : public GFX {
|
class GFXVulkan : public GFX {
|
||||||
public:
|
public:
|
||||||
bool is_supported() { return true; }
|
bool is_supported() override { return true; }
|
||||||
ShaderLanguage accepted_shader_language() override { return ShaderLanguage::SPIRV; }
|
ShaderLanguage accepted_shader_language() override { return ShaderLanguage::SPIRV; }
|
||||||
GFXContext required_context() { return GFXContext::Vulkan; }
|
GFXContext required_context() override { return GFXContext::Vulkan; }
|
||||||
const char* get_name() override;
|
const char* get_name() override;
|
||||||
|
|
||||||
bool supports_feature(const GFXFeature feature) override;
|
bool supports_feature(GFXFeature feature) override;
|
||||||
|
|
||||||
bool initialize(const GFXCreateInfo& info) override;
|
bool initialize(const GFXCreateInfo& info) override;
|
||||||
|
|
||||||
void initialize_view(void* native_handle, const int identifier, const uint32_t width, const uint32_t height) override;
|
void initialize_view(void* native_handle, int identifier, uint32_t width, uint32_t height) override;
|
||||||
void recreate_view(const int identifier, const uint32_t width, const uint32_t height) override;
|
void recreate_view(int identifier, uint32_t width, uint32_t height) override;
|
||||||
|
|
||||||
// buffer operations
|
// buffer operations
|
||||||
GFXBuffer* create_buffer(void* data, const GFXSize size, const bool dynamic_data, const GFXBufferUsage usage) override;
|
GFXBuffer* create_buffer(void* data, GFXSize size, bool dynamic_data, GFXBufferUsage usage) override;
|
||||||
void copy_buffer(GFXBuffer* buffer, void* data, const GFXSize offset, const GFXSize size) override;
|
void copy_buffer(GFXBuffer* buffer, void* data, GFXSize offset, GFXSize size) override;
|
||||||
|
|
||||||
void* get_buffer_contents(GFXBuffer* buffer) override;
|
void* get_buffer_contents(GFXBuffer* buffer) override;
|
||||||
void release_buffer_contents(GFXBuffer* buffer, void* handle) override;
|
void release_buffer_contents(GFXBuffer* buffer, void* handle) override;
|
||||||
|
|
||||||
// texture operations
|
// texture operations
|
||||||
GFXTexture* create_texture(const GFXTextureCreateInfo& info) override;
|
GFXTexture* create_texture(const GFXTextureCreateInfo& info) override;
|
||||||
void copy_texture(GFXTexture* texture, void* data, const GFXSize size) override;
|
void copy_texture(GFXTexture* texture, void* data, GFXSize size) override;
|
||||||
void copy_texture(GFXTexture* from, GFXTexture* to) override;
|
void copy_texture(GFXTexture* from, GFXTexture* to) override;
|
||||||
void copy_texture(GFXTexture* from, GFXBuffer* to) override;
|
void copy_texture(GFXTexture* from, GFXBuffer* to) override;
|
||||||
|
|
||||||
|
@ -82,11 +74,11 @@ public:
|
||||||
GFXPipeline* create_compute_pipeline(const GFXComputePipelineCreateInfo& info) override;
|
GFXPipeline* create_compute_pipeline(const GFXComputePipelineCreateInfo& info) override;
|
||||||
|
|
||||||
// misc operations
|
// misc operations
|
||||||
GFXSize get_alignment(const GFXSize size) override;
|
GFXSize get_alignment(GFXSize size) override;
|
||||||
|
|
||||||
GFXCommandBuffer* acquire_command_buffer(bool for_presentation_use = false) override;
|
GFXCommandBuffer* acquire_command_buffer(bool for_presentation_use) override;
|
||||||
|
|
||||||
void submit(GFXCommandBuffer* command_buffer, const int identifier) override;
|
void submit(GFXCommandBuffer* command_buffer, int identifier) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void createInstance(std::vector<const char*> layers, std::vector<const char*> extensions);
|
void createInstance(std::vector<const char*> layers, std::vector<const char*> extensions);
|
||||||
|
@ -111,7 +103,7 @@ private:
|
||||||
VkImageLayout newLayout,
|
VkImageLayout newLayout,
|
||||||
VkPipelineStageFlags src_stage_mask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
VkPipelineStageFlags src_stage_mask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||||
VkPipelineStageFlags dst_stage_mask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
|
VkPipelineStageFlags dst_stage_mask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
|
||||||
VkShaderModule createShaderModule(const uint32_t* code, const int length);
|
VkShaderModule createShaderModule(const uint32_t* code, int length);
|
||||||
VkCommandBuffer beginSingleTimeCommands();
|
VkCommandBuffer beginSingleTimeCommands();
|
||||||
void endSingleTimeCommands(VkCommandBuffer commandBuffer);
|
void endSingleTimeCommands(VkCommandBuffer commandBuffer);
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
#include "gfx_vulkan_buffer.hpp"
|
#include "gfx_vulkan_buffer.hpp"
|
||||||
#include "gfx_vulkan_pipeline.hpp"
|
#include "gfx_vulkan_pipeline.hpp"
|
||||||
|
@ -20,11 +19,6 @@
|
||||||
|
|
||||||
#include <platform.hpp>
|
#include <platform.hpp>
|
||||||
|
|
||||||
#ifdef PLATFORM_LINUX
|
|
||||||
#include <SDL2/SDL.h>
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
VkFormat toVkFormat(GFXPixelFormat format) {
|
VkFormat toVkFormat(GFXPixelFormat format) {
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case GFXPixelFormat::R_32F:
|
case GFXPixelFormat::R_32F:
|
||||||
|
@ -82,6 +76,8 @@ VkFormat toVkFormat(GFXVertexFormat format) {
|
||||||
|
|
||||||
VkBlendFactor toVkFactor(GFXBlendFactor factor) {
|
VkBlendFactor toVkFactor(GFXBlendFactor factor) {
|
||||||
switch (factor) {
|
switch (factor) {
|
||||||
|
case GFXBlendFactor::Zero:
|
||||||
|
return VK_BLEND_FACTOR_ZERO;
|
||||||
case GFXBlendFactor::One:
|
case GFXBlendFactor::One:
|
||||||
return VK_BLEND_FACTOR_ONE;
|
return VK_BLEND_FACTOR_ONE;
|
||||||
case GFXBlendFactor::OneMinusSrcAlpha:
|
case GFXBlendFactor::OneMinusSrcAlpha:
|
||||||
|
@ -90,6 +86,12 @@ VkBlendFactor toVkFactor(GFXBlendFactor factor) {
|
||||||
return VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR;
|
return VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR;
|
||||||
case GFXBlendFactor::SrcAlpha:
|
case GFXBlendFactor::SrcAlpha:
|
||||||
return VK_BLEND_FACTOR_SRC_ALPHA;
|
return VK_BLEND_FACTOR_SRC_ALPHA;
|
||||||
|
case GFXBlendFactor::DstAlpha:
|
||||||
|
return VK_BLEND_FACTOR_DST_ALPHA;
|
||||||
|
case GFXBlendFactor::SrcColor:
|
||||||
|
return VK_BLEND_FACTOR_SRC_COLOR;
|
||||||
|
case GFXBlendFactor::DstColor:
|
||||||
|
return VK_BLEND_FACTOR_DST_COLOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
return VK_BLEND_FACTOR_ONE;
|
return VK_BLEND_FACTOR_ONE;
|
||||||
|
@ -165,14 +167,14 @@ VKAPI_ATTR VkBool32 VKAPI_CALL DebugCallback(
|
||||||
const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData,
|
const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData,
|
||||||
void *pUserData) {
|
void *pUserData) {
|
||||||
|
|
||||||
prism::log::debug(System::GFX, pCallbackData->pMessage);
|
prism::log("{}", pCallbackData->pMessage);
|
||||||
|
|
||||||
return VK_FALSE;
|
return VK_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkResult name_object(VkDevice device, VkObjectType type, uint64_t object, std::string_view name) {
|
VkResult name_object(VkDevice device, VkObjectType type, uint64_t object, std::string_view name) {
|
||||||
if(object == 0x0) {
|
if(object == 0x0) {
|
||||||
prism::log::error(System::GFX, "Failed to name object {}", name.data());
|
prism::log("Failed to name object {}", name);
|
||||||
return VK_ERROR_DEVICE_LOST;
|
return VK_ERROR_DEVICE_LOST;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -229,11 +231,10 @@ bool GFXVulkan::initialize(const GFXCreateInfo& info) {
|
||||||
void GFXVulkan::initialize_view(void* native_handle, const int identifier, const uint32_t width, const uint32_t height) {
|
void GFXVulkan::initialize_view(void* native_handle, const int identifier, const uint32_t width, const uint32_t height) {
|
||||||
vkDeviceWaitIdle(device);
|
vkDeviceWaitIdle(device);
|
||||||
|
|
||||||
NativeSurface* surface = new NativeSurface();
|
auto surface = new NativeSurface();
|
||||||
surface->identifier = identifier;
|
surface->identifier = identifier;
|
||||||
surface->surfaceWidth = width;
|
surface->surfaceWidth = width;
|
||||||
surface->surfaceHeight = height;
|
surface->surfaceHeight = height;
|
||||||
surface->windowNativeHandle = native_handle;
|
|
||||||
|
|
||||||
createSwapchain(surface);
|
createSwapchain(surface);
|
||||||
createSyncPrimitives(surface);
|
createSyncPrimitives(surface);
|
||||||
|
@ -259,7 +260,7 @@ void GFXVulkan::recreate_view(const int identifier, const uint32_t width, const
|
||||||
}
|
}
|
||||||
|
|
||||||
GFXBuffer* GFXVulkan::create_buffer(void *data, const GFXSize size, const bool dynamic_data, const GFXBufferUsage usage) {
|
GFXBuffer* GFXVulkan::create_buffer(void *data, const GFXSize size, const bool dynamic_data, const GFXBufferUsage usage) {
|
||||||
GFXVulkanBuffer* buffer = new GFXVulkanBuffer();
|
auto buffer = new GFXVulkanBuffer();
|
||||||
|
|
||||||
vkDeviceWaitIdle(device);
|
vkDeviceWaitIdle(device);
|
||||||
|
|
||||||
|
@ -307,7 +308,7 @@ GFXBuffer* GFXVulkan::create_buffer(void *data, const GFXSize size, const bool d
|
||||||
}
|
}
|
||||||
|
|
||||||
void GFXVulkan::copy_buffer(GFXBuffer* buffer, void* data, GFXSize offset, GFXSize size) {
|
void GFXVulkan::copy_buffer(GFXBuffer* buffer, void* data, GFXSize offset, GFXSize size) {
|
||||||
GFXVulkanBuffer* vulkanBuffer = (GFXVulkanBuffer*)buffer;
|
auto vulkanBuffer = (GFXVulkanBuffer*)buffer;
|
||||||
|
|
||||||
void* mapped_data = nullptr;
|
void* mapped_data = nullptr;
|
||||||
vkMapMemory(device, vulkanBuffer->memory, offset, vulkanBuffer->size - offset, 0, &mapped_data);
|
vkMapMemory(device, vulkanBuffer->memory, offset, vulkanBuffer->size - offset, 0, &mapped_data);
|
||||||
|
@ -327,7 +328,7 @@ void GFXVulkan::copy_buffer(GFXBuffer* buffer, void* data, GFXSize offset, GFXSi
|
||||||
}
|
}
|
||||||
|
|
||||||
void* GFXVulkan::get_buffer_contents(GFXBuffer* buffer) {
|
void* GFXVulkan::get_buffer_contents(GFXBuffer* buffer) {
|
||||||
GFXVulkanBuffer* vulkanBuffer = (GFXVulkanBuffer*)buffer;
|
auto vulkanBuffer = (GFXVulkanBuffer*)buffer;
|
||||||
|
|
||||||
void* mapped_data;
|
void* mapped_data;
|
||||||
vkMapMemory(device, vulkanBuffer->memory, 0, VK_WHOLE_SIZE, 0, &mapped_data);
|
vkMapMemory(device, vulkanBuffer->memory, 0, VK_WHOLE_SIZE, 0, &mapped_data);
|
||||||
|
@ -336,7 +337,7 @@ void* GFXVulkan::get_buffer_contents(GFXBuffer* buffer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GFXVulkan::release_buffer_contents(GFXBuffer* buffer, void* handle) {
|
void GFXVulkan::release_buffer_contents(GFXBuffer* buffer, void* handle) {
|
||||||
GFXVulkanBuffer* vulkanBuffer = (GFXVulkanBuffer*)buffer;
|
auto vulkanBuffer = (GFXVulkanBuffer*)buffer;
|
||||||
|
|
||||||
VkMappedMemoryRange range = {};
|
VkMappedMemoryRange range = {};
|
||||||
range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
|
range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
|
||||||
|
@ -349,7 +350,7 @@ void GFXVulkan::release_buffer_contents(GFXBuffer* buffer, void* handle) {
|
||||||
}
|
}
|
||||||
|
|
||||||
GFXTexture* GFXVulkan::create_texture(const GFXTextureCreateInfo& info) {
|
GFXTexture* GFXVulkan::create_texture(const GFXTextureCreateInfo& info) {
|
||||||
GFXVulkanTexture* texture = new GFXVulkanTexture();
|
auto texture = new GFXVulkanTexture();
|
||||||
|
|
||||||
vkDeviceWaitIdle(device);
|
vkDeviceWaitIdle(device);
|
||||||
|
|
||||||
|
@ -514,7 +515,7 @@ GFXTexture* GFXVulkan::create_texture(const GFXTextureCreateInfo& info) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GFXVulkan::copy_texture(GFXTexture* texture, void* data, GFXSize size) {
|
void GFXVulkan::copy_texture(GFXTexture* texture, void* data, GFXSize size) {
|
||||||
GFXVulkanTexture* vulkanTexture = (GFXVulkanTexture*)texture;
|
auto vulkanTexture = (GFXVulkanTexture*)texture;
|
||||||
|
|
||||||
vkDeviceWaitIdle(device);
|
vkDeviceWaitIdle(device);
|
||||||
|
|
||||||
|
@ -579,12 +580,12 @@ void GFXVulkan::copy_texture(GFXTexture* texture, void* data, GFXSize size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GFXVulkan::copy_texture(GFXTexture* from, GFXTexture* to) {
|
void GFXVulkan::copy_texture(GFXTexture* from, GFXTexture* to) {
|
||||||
prism::log::error(System::GFX, "Copy Texture->Texture unimplemented!");
|
prism::log("Copy Texture->Texture unimplemented!");
|
||||||
}
|
}
|
||||||
|
|
||||||
void GFXVulkan::copy_texture(GFXTexture* from, GFXBuffer* to) {
|
void GFXVulkan::copy_texture(GFXTexture* from, GFXBuffer* to) {
|
||||||
GFXVulkanTexture* vulkanTexture = (GFXVulkanTexture*)from;
|
auto vulkanTexture = (GFXVulkanTexture*)from;
|
||||||
GFXVulkanBuffer* vulkanBuffer = (GFXVulkanBuffer*)to;
|
auto vulkanBuffer = (GFXVulkanBuffer*)to;
|
||||||
|
|
||||||
VkCommandBuffer commandBuffer = beginSingleTimeCommands();
|
VkCommandBuffer commandBuffer = beginSingleTimeCommands();
|
||||||
|
|
||||||
|
@ -605,7 +606,7 @@ void GFXVulkan::copy_texture(GFXTexture* from, GFXBuffer* to) {
|
||||||
}
|
}
|
||||||
|
|
||||||
GFXSampler* GFXVulkan::create_sampler(const GFXSamplerCreateInfo& info) {
|
GFXSampler* GFXVulkan::create_sampler(const GFXSamplerCreateInfo& info) {
|
||||||
GFXVulkanSampler* sampler = new GFXVulkanSampler();
|
auto sampler = new GFXVulkanSampler();
|
||||||
|
|
||||||
const VkSamplerAddressMode samplerMode = toSamplerMode(info.samplingMode);
|
const VkSamplerAddressMode samplerMode = toSamplerMode(info.samplingMode);
|
||||||
|
|
||||||
|
@ -629,15 +630,15 @@ GFXSampler* GFXVulkan::create_sampler(const GFXSamplerCreateInfo& info) {
|
||||||
}
|
}
|
||||||
|
|
||||||
GFXFramebuffer* GFXVulkan::create_framebuffer(const GFXFramebufferCreateInfo& info) {
|
GFXFramebuffer* GFXVulkan::create_framebuffer(const GFXFramebufferCreateInfo& info) {
|
||||||
GFXVulkanFramebuffer* framebuffer = new GFXVulkanFramebuffer();
|
auto framebuffer = new GFXVulkanFramebuffer();
|
||||||
|
|
||||||
vkDeviceWaitIdle(device);
|
vkDeviceWaitIdle(device);
|
||||||
|
|
||||||
GFXVulkanRenderPass* renderPass = (GFXVulkanRenderPass*)info.render_pass;
|
auto renderPass = (GFXVulkanRenderPass*)info.render_pass;
|
||||||
|
|
||||||
std::vector<VkImageView> attachments;
|
std::vector<VkImageView> attachments;
|
||||||
for (auto& attachment : info.attachments) {
|
for (auto& attachment : info.attachments) {
|
||||||
GFXVulkanTexture* texture = (GFXVulkanTexture*)attachment;
|
auto texture = (GFXVulkanTexture*)attachment;
|
||||||
attachments.push_back(texture->view);
|
attachments.push_back(texture->view);
|
||||||
|
|
||||||
VkImageLayout expectedLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
VkImageLayout expectedLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||||
|
@ -673,7 +674,7 @@ GFXFramebuffer* GFXVulkan::create_framebuffer(const GFXFramebufferCreateInfo& in
|
||||||
}
|
}
|
||||||
|
|
||||||
GFXRenderPass* GFXVulkan::create_render_pass(const GFXRenderPassCreateInfo& info) {
|
GFXRenderPass* GFXVulkan::create_render_pass(const GFXRenderPassCreateInfo& info) {
|
||||||
GFXVulkanRenderPass* renderPass = new GFXVulkanRenderPass();
|
auto renderPass = new GFXVulkanRenderPass();
|
||||||
|
|
||||||
vkDeviceWaitIdle(device);
|
vkDeviceWaitIdle(device);
|
||||||
|
|
||||||
|
@ -762,7 +763,7 @@ GFXRenderPass* GFXVulkan::create_render_pass(const GFXRenderPassCreateInfo& info
|
||||||
}
|
}
|
||||||
|
|
||||||
GFXPipeline* GFXVulkan::create_graphics_pipeline(const GFXGraphicsPipelineCreateInfo& info) {
|
GFXPipeline* GFXVulkan::create_graphics_pipeline(const GFXGraphicsPipelineCreateInfo& info) {
|
||||||
GFXVulkanPipeline* pipeline = new GFXVulkanPipeline();
|
auto pipeline = new GFXVulkanPipeline();
|
||||||
|
|
||||||
vkDeviceWaitIdle(device);
|
vkDeviceWaitIdle(device);
|
||||||
|
|
||||||
|
@ -935,6 +936,8 @@ GFXPipeline* GFXVulkan::create_graphics_pipeline(const GFXGraphicsPipelineCreate
|
||||||
case GFXDepthMode::Greater:
|
case GFXDepthMode::Greater:
|
||||||
depthStencil.depthCompareOp = VK_COMPARE_OP_GREATER;
|
depthStencil.depthCompareOp = VK_COMPARE_OP_GREATER;
|
||||||
break;
|
break;
|
||||||
|
case GFXDepthMode::None:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -988,6 +991,8 @@ GFXPipeline* GFXVulkan::create_graphics_pipeline(const GFXGraphicsPipelineCreate
|
||||||
case GFXBindingType::Sampler:
|
case GFXBindingType::Sampler:
|
||||||
descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
|
descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
|
||||||
break;
|
break;
|
||||||
|
case GFXBindingType::PushConstant:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkDescriptorSetLayoutBinding layoutBinding = {};
|
VkDescriptorSetLayoutBinding layoutBinding = {};
|
||||||
|
@ -1051,7 +1056,7 @@ GFXPipeline* GFXVulkan::create_graphics_pipeline(const GFXGraphicsPipelineCreate
|
||||||
}
|
}
|
||||||
|
|
||||||
GFXPipeline* GFXVulkan::create_compute_pipeline(const GFXComputePipelineCreateInfo& info) {
|
GFXPipeline* GFXVulkan::create_compute_pipeline(const GFXComputePipelineCreateInfo& info) {
|
||||||
GFXVulkanPipeline* pipeline = new GFXVulkanPipeline();
|
auto pipeline = new GFXVulkanPipeline();
|
||||||
|
|
||||||
vkDeviceWaitIdle(device);
|
vkDeviceWaitIdle(device);
|
||||||
|
|
||||||
|
@ -1123,6 +1128,8 @@ GFXPipeline* GFXVulkan::create_compute_pipeline(const GFXComputePipelineCreateIn
|
||||||
case GFXBindingType::Sampler:
|
case GFXBindingType::Sampler:
|
||||||
descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
|
descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
|
||||||
break;
|
break;
|
||||||
|
case GFXBindingType::PushConstant:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkDescriptorSetLayoutBinding layoutBinding = {};
|
VkDescriptorSetLayoutBinding layoutBinding = {};
|
||||||
|
@ -1176,7 +1183,7 @@ GFXSize GFXVulkan::get_alignment(GFXSize size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
GFXCommandBuffer* GFXVulkan::acquire_command_buffer(bool for_presentation_use) {
|
GFXCommandBuffer* GFXVulkan::acquire_command_buffer(bool for_presentation_use) {
|
||||||
GFXVulkanCommandBuffer* cmdbuf = new GFXVulkanCommandBuffer();
|
auto cmdbuf = new GFXVulkanCommandBuffer();
|
||||||
|
|
||||||
if(!for_presentation_use) {
|
if(!for_presentation_use) {
|
||||||
VkCommandBufferAllocateInfo info = {};
|
VkCommandBufferAllocateInfo info = {};
|
||||||
|
@ -1209,7 +1216,7 @@ void GFXVulkan::submit(GFXCommandBuffer* command_buffer, const int identifier) {
|
||||||
|
|
||||||
VkCommandBuffer cmd = VK_NULL_HANDLE;
|
VkCommandBuffer cmd = VK_NULL_HANDLE;
|
||||||
|
|
||||||
GFXVulkanCommandBuffer* cmdbuf = (GFXVulkanCommandBuffer*)command_buffer;
|
auto cmdbuf = (GFXVulkanCommandBuffer*)command_buffer;
|
||||||
if(cmdbuf->handle != VK_NULL_HANDLE)
|
if(cmdbuf->handle != VK_NULL_HANDLE)
|
||||||
cmd = cmdbuf->handle;
|
cmd = cmdbuf->handle;
|
||||||
else if(current_surface != nullptr)
|
else if(current_surface != nullptr)
|
||||||
|
@ -1258,8 +1265,8 @@ void GFXVulkan::submit(GFXCommandBuffer* command_buffer, const int identifier) {
|
||||||
vkCmdEndRenderPass(cmd);
|
vkCmdEndRenderPass(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
GFXVulkanRenderPass* renderPass = (GFXVulkanRenderPass*)command.data.set_render_pass.render_pass;
|
auto renderPass = (GFXVulkanRenderPass*)command.data.set_render_pass.render_pass;
|
||||||
GFXVulkanFramebuffer* framebuffer = (GFXVulkanFramebuffer*)command.data.set_render_pass.framebuffer;
|
auto framebuffer = (GFXVulkanFramebuffer*)command.data.set_render_pass.framebuffer;
|
||||||
|
|
||||||
if (renderPass != nullptr) {
|
if (renderPass != nullptr) {
|
||||||
currentRenderPass = renderPass->handle;
|
currentRenderPass = renderPass->handle;
|
||||||
|
@ -1429,8 +1436,8 @@ void GFXVulkan::submit(GFXCommandBuffer* command_buffer, const int identifier) {
|
||||||
break;
|
break;
|
||||||
case GFXCommandType::CopyTexture:
|
case GFXCommandType::CopyTexture:
|
||||||
{
|
{
|
||||||
GFXVulkanTexture* src = (GFXVulkanTexture*)command.data.copy_texture.src;
|
auto src = (GFXVulkanTexture*)command.data.copy_texture.src;
|
||||||
GFXVulkanTexture* dst = (GFXVulkanTexture*)command.data.copy_texture.dst;
|
auto dst = (GFXVulkanTexture*)command.data.copy_texture.dst;
|
||||||
|
|
||||||
const int slice_offset = command.data.copy_texture.to_slice + command.data.copy_texture.to_layer * 6;
|
const int slice_offset = command.data.copy_texture.to_slice + command.data.copy_texture.to_layer * 6;
|
||||||
|
|
||||||
|
@ -1534,7 +1541,7 @@ void GFXVulkan::submit(GFXCommandBuffer* command_buffer, const int identifier) {
|
||||||
break;
|
break;
|
||||||
case GFXCommandType::GenerateMipmaps:
|
case GFXCommandType::GenerateMipmaps:
|
||||||
{
|
{
|
||||||
auto texture = static_cast<GFXVulkanTexture*>(command.data.generate_mipmaps.texture);
|
auto texture = dynamic_cast<GFXVulkanTexture*>(command.data.generate_mipmaps.texture);
|
||||||
|
|
||||||
for(int l = 0; l < texture->range.layerCount; l++) {
|
for(int l = 0; l < texture->range.layerCount; l++) {
|
||||||
int mip_width = texture->width;
|
int mip_width = texture->width;
|
||||||
|
@ -1634,7 +1641,7 @@ void GFXVulkan::submit(GFXCommandBuffer* command_buffer, const int identifier) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
prism::log::error(System::GFX, "Unhandled GFX Command Type {}", utility::enum_to_string(command.type));
|
prism::log("Unhandled GFX Command Type {}", utility::enum_to_string(command.type));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1789,7 +1796,33 @@ void GFXVulkan::createLogicalDevice(std::vector<const char*> extensions) {
|
||||||
queueCreateInfo.pQueuePriorities = &queuePriority;
|
queueCreateInfo.pQueuePriorities = &queuePriority;
|
||||||
|
|
||||||
queueCreateInfos.push_back(queueCreateInfo);
|
queueCreateInfos.push_back(queueCreateInfo);
|
||||||
}
|
} else {
|
||||||
|
// graphics
|
||||||
|
{
|
||||||
|
VkDeviceQueueCreateInfo queueCreateInfo = {};
|
||||||
|
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
||||||
|
queueCreateInfo.queueFamilyIndex = graphicsFamilyIndex;
|
||||||
|
queueCreateInfo.queueCount = 1;
|
||||||
|
|
||||||
|
float queuePriority = 1.0f;
|
||||||
|
queueCreateInfo.pQueuePriorities = &queuePriority;
|
||||||
|
|
||||||
|
queueCreateInfos.push_back(queueCreateInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
// present
|
||||||
|
{
|
||||||
|
VkDeviceQueueCreateInfo queueCreateInfo = {};
|
||||||
|
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
||||||
|
queueCreateInfo.queueFamilyIndex = presentFamilyIndex;
|
||||||
|
queueCreateInfo.queueCount = 1;
|
||||||
|
|
||||||
|
float queuePriority = 1.0f;
|
||||||
|
queueCreateInfo.pQueuePriorities = &queuePriority;
|
||||||
|
|
||||||
|
queueCreateInfos.push_back(queueCreateInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
VkDeviceCreateInfo createInfo = {};
|
VkDeviceCreateInfo createInfo = {};
|
||||||
createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
||||||
|
@ -1823,23 +1856,9 @@ void GFXVulkan::createLogicalDevice(std::vector<const char*> extensions) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GFXVulkan::createSwapchain(NativeSurface* native_surface, VkSwapchainKHR oldSwapchain) {
|
void GFXVulkan::createSwapchain(NativeSurface* native_surface, VkSwapchainKHR oldSwapchain) {
|
||||||
|
|
||||||
#ifdef PLATFORM_WINDOWS_OLD
|
|
||||||
// create win32 surface
|
|
||||||
if(native_surface->surface == VK_NULL_HANDLE)
|
|
||||||
{
|
|
||||||
VkWin32SurfaceCreateInfoKHR createInfo = {};
|
|
||||||
createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
|
|
||||||
createInfo.hwnd = (HWND)native_surface->windowNativeHandle;
|
|
||||||
createInfo.hinstance = GetModuleHandle(nullptr);
|
|
||||||
|
|
||||||
vkCreateWin32SurfaceKHR(instance, &createInfo, nullptr, &native_surface->surface);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if(native_surface->surface == VK_NULL_HANDLE) {
|
if(native_surface->surface == VK_NULL_HANDLE) {
|
||||||
native_surface->surface = (VkSurfaceKHR)platform::create_native_surface(native_surface->identifier, (void*)instance);
|
native_surface->surface = (VkSurfaceKHR)platform::create_native_surface(native_surface->identifier, (void*)instance);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
// TODO: fix this pls
|
// TODO: fix this pls
|
||||||
VkBool32 supported;
|
VkBool32 supported;
|
||||||
|
@ -2073,7 +2092,7 @@ void GFXVulkan::cacheDescriptorState(GFXVulkanPipeline* pipeline, VkDescriptorSe
|
||||||
|
|
||||||
VkResult error = vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet);
|
VkResult error = vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet);
|
||||||
if(error != VK_SUCCESS || descriptorSet == VK_NULL_HANDLE) {
|
if(error != VK_SUCCESS || descriptorSet == VK_NULL_HANDLE) {
|
||||||
prism::log::error(System::GFX, "ERROR: COULD NOT CACHE BECAUSE OUT OF DESCRIPTOR SETS.");
|
prism::log("ERROR: COULD NOT CACHE BECAUSE OUT OF DESCRIPTOR SETS.");
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2083,7 +2102,7 @@ void GFXVulkan::cacheDescriptorState(GFXVulkanPipeline* pipeline, VkDescriptorSe
|
||||||
// update set
|
// update set
|
||||||
for (auto [i, buffer] : utility::enumerate(boundShaderBuffers)) {
|
for (auto [i, buffer] : utility::enumerate(boundShaderBuffers)) {
|
||||||
if (buffer.buffer != nullptr) {
|
if (buffer.buffer != nullptr) {
|
||||||
GFXVulkanBuffer* vulkanBuffer = (GFXVulkanBuffer*)buffer.buffer;
|
auto vulkanBuffer = (GFXVulkanBuffer*)buffer.buffer;
|
||||||
|
|
||||||
VkDescriptorBufferInfo bufferInfo = {};
|
VkDescriptorBufferInfo bufferInfo = {};
|
||||||
bufferInfo.buffer = vulkanBuffer->handle; // will this break?
|
bufferInfo.buffer = vulkanBuffer->handle; // will this break?
|
||||||
|
@ -2104,7 +2123,7 @@ void GFXVulkan::cacheDescriptorState(GFXVulkanPipeline* pipeline, VkDescriptorSe
|
||||||
|
|
||||||
for (auto [i, texture] : utility::enumerate(boundTextures)) {
|
for (auto [i, texture] : utility::enumerate(boundTextures)) {
|
||||||
if (texture != nullptr) {
|
if (texture != nullptr) {
|
||||||
GFXVulkanTexture* vulkanTexture = (GFXVulkanTexture*) texture;
|
auto vulkanTexture = (GFXVulkanTexture*) texture;
|
||||||
|
|
||||||
VkDescriptorImageInfo imageInfo = {};
|
VkDescriptorImageInfo imageInfo = {};
|
||||||
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||||
|
@ -2140,7 +2159,7 @@ void GFXVulkan::cacheDescriptorState(GFXVulkanPipeline* pipeline, VkDescriptorSe
|
||||||
|
|
||||||
for (auto [i, sampler] : utility::enumerate(boundSamplers)) {
|
for (auto [i, sampler] : utility::enumerate(boundSamplers)) {
|
||||||
if (sampler != nullptr) {
|
if (sampler != nullptr) {
|
||||||
GFXVulkanSampler* vulkanSampler = (GFXVulkanSampler*) sampler;
|
auto vulkanSampler = (GFXVulkanSampler*) sampler;
|
||||||
|
|
||||||
VkDescriptorImageInfo imageInfo = {};
|
VkDescriptorImageInfo imageInfo = {};
|
||||||
imageInfo.sampler = vulkanSampler->sampler;
|
imageInfo.sampler = vulkanSampler->sampler;
|
||||||
|
|
|
@ -4,5 +4,5 @@ set(SRC
|
||||||
|
|
||||||
add_library(Log STATIC ${SRC})
|
add_library(Log STATIC ${SRC})
|
||||||
target_include_directories(Log PUBLIC include)
|
target_include_directories(Log PUBLIC include)
|
||||||
target_link_libraries(Log PRIVATE Utility)
|
target_link_libraries(Log PUBLIC fmt::fmt)
|
||||||
set_engine_properties(Log)
|
set_engine_properties(Log)
|
||||||
|
|
|
@ -1,66 +1,18 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string_view>
|
#include <fmt/format.h>
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
enum class System {
|
namespace prism {
|
||||||
None,
|
inline std::string log_output;
|
||||||
Core,
|
|
||||||
Renderer,
|
|
||||||
Game,
|
|
||||||
File,
|
|
||||||
GFX
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class Level {
|
inline void vlog(fmt::string_view format, fmt::format_args args) {
|
||||||
Info,
|
auto str = fmt::vformat(format, args);
|
||||||
Warning,
|
fmt::print("{}", str);
|
||||||
Error,
|
log_output += str + "\n";
|
||||||
Debug
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace prism::log {
|
|
||||||
inline void internal_format(std::string &msg, const std::string &arg) {
|
|
||||||
auto pos = msg.find_first_of("{}");
|
|
||||||
msg.replace(pos, 2, arg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void internal_format(std::string &msg, const char *&arg) {
|
template <typename S, typename... Args>
|
||||||
auto pos = msg.find_first_of("{}");
|
inline void log(const S& format, Args&&... args) {
|
||||||
msg.replace(pos, 2, arg);
|
vlog(format, fmt::make_args_checked<Args...>(format, args...));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
void process_message(const Level level, const System system, const std::string_view message);
|
|
||||||
|
|
||||||
template<typename... Args>
|
|
||||||
void internal_print(const Level level, const System system, const std::string_view format, Args &&... args) {
|
|
||||||
auto msg = std::string(format);
|
|
||||||
|
|
||||||
((internal_format(msg, args)), ...);
|
|
||||||
|
|
||||||
process_message(level, system, msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename... Args>
|
|
||||||
void info(const System system, const std::string_view format, Args &&... args) {
|
|
||||||
internal_print(Level::Info, system, format, args...);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename... Args>
|
|
||||||
void warning(const System system, const std::string_view format, Args &&... args) {
|
|
||||||
internal_print(Level::Warning, system, format, args...);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename... Args>
|
|
||||||
void error(const System system, const std::string_view format, Args &&... args) {
|
|
||||||
internal_print(Level::Error, system, format, args...);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename... Args>
|
|
||||||
void debug(const System system, const std::string_view format, Args &&... args) {
|
|
||||||
internal_print(Level::Debug, system, format, args...);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline std::vector<std::string> stored_output;
|
|
||||||
}
|
|
|
@ -1,24 +1 @@
|
||||||
#include "log.hpp"
|
#include "log.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <chrono>
|
|
||||||
#include <iomanip>
|
|
||||||
#include "string_utils.hpp"
|
|
||||||
#include "utility.hpp"
|
|
||||||
|
|
||||||
void prism::log::process_message(const Level level, const System system, const std::string_view message) {
|
|
||||||
auto now = std::chrono::system_clock::now();
|
|
||||||
std::time_t t_c = std::chrono::system_clock::to_time_t(now);
|
|
||||||
|
|
||||||
std::string date;
|
|
||||||
date.resize(30);
|
|
||||||
|
|
||||||
std::strftime(&date[0], date.size(), "%Y-%m-%d %H:%M:%S", std::localtime(&t_c));
|
|
||||||
utility::erase(date, '\0'); // strftime will insert \0 for us, but it's not needed here
|
|
||||||
|
|
||||||
std::string s = utility::format("{} {} {}: {}", date, utility::enum_to_string(system), utility::enum_to_string(level), message);
|
|
||||||
|
|
||||||
std::cout << s << '\n';
|
|
||||||
|
|
||||||
stored_output.push_back(s);
|
|
||||||
}
|
|
|
@ -8,7 +8,6 @@
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
|
||||||
#include "log.hpp"
|
#include "log.hpp"
|
||||||
#include "file_utils.hpp"
|
|
||||||
#include "path.hpp"
|
#include "path.hpp"
|
||||||
|
|
||||||
namespace prism {
|
namespace prism {
|
||||||
|
|
|
@ -159,17 +159,9 @@ namespace platform {
|
||||||
/// On platforms that support moue capture, this will lock the mouse cursor to the window and hide it.
|
/// On platforms that support moue capture, this will lock the mouse cursor to the window and hide it.
|
||||||
void capture_mouse(const bool capture);
|
void capture_mouse(const bool capture);
|
||||||
|
|
||||||
/**Opens a file dialog to select a file. This will not block.
|
// TODO: right now the OS intercepting and saying "We dont want text input anymore" ala software keyboards is NOT supported yet
|
||||||
@param existing Whether or not to limit to existing files.
|
void begin_text_input();
|
||||||
@param returnFunction The callback function when a file is selected or the dialog is cancelled. An empy string is returned when cancelled.
|
void end_text_input();
|
||||||
@param openDirectory Whether or not to allow selecting directories as well.
|
|
||||||
*/
|
|
||||||
void open_dialog(const bool existing, std::function<void(std::string)> returnFunction, bool openDirectory = false);
|
|
||||||
|
|
||||||
/**Opens a file dialog to select a save location for a file. This will not block.
|
|
||||||
@param returnFunction The callback function when a file is selected or the dialog is cancelled. An empy string is returned when cancelled.
|
|
||||||
*/
|
|
||||||
void save_dialog(std::function<void(std::string)> returnFunction);
|
|
||||||
|
|
||||||
/**Translates a virtual keycode to it's character equivalent.
|
/**Translates a virtual keycode to it's character equivalent.
|
||||||
@note Example: translateKey(0x01) = 'a'; 0x01 in this example is a platform and language specific keycode for a key named 'a'.
|
@note Example: translateKey(0x01) = 'a'; 0x01 in this example is a platform and language specific keycode for a key named 'a'.
|
||||||
|
|
|
@ -55,21 +55,12 @@ namespace prism {
|
||||||
|
|
||||||
void recreate_all_render_targets();
|
void recreate_all_render_targets();
|
||||||
|
|
||||||
void set_screen(ui::Screen* screen);
|
|
||||||
|
|
||||||
void init_screen(ui::Screen* screen);
|
|
||||||
|
|
||||||
void update_screen();
|
|
||||||
|
|
||||||
struct controller_continuity {
|
struct controller_continuity {
|
||||||
int elementOffset = 0;
|
int elementOffset = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
void render(GFXCommandBuffer* command_buffer, Scene* scene, RenderTarget& target, int index);
|
void render(GFXCommandBuffer* command_buffer, Scene* scene, RenderTarget& target, int index);
|
||||||
|
|
||||||
void render_screen(GFXCommandBuffer* commandBuffer, ui::Screen* screen, prism::Extent extent,
|
|
||||||
controller_continuity& continuity, render_screen_options options = render_screen_options());
|
|
||||||
|
|
||||||
void render_camera(GFXCommandBuffer* command_buffer, Scene& scene, Object camera_object, Camera& camera,
|
void render_camera(GFXCommandBuffer* command_buffer, Scene& scene, Object camera_object, Camera& camera,
|
||||||
prism::Extent extent, RenderTarget& target, controller_continuity &continuity);
|
prism::Extent extent, RenderTarget& target, controller_continuity &continuity);
|
||||||
|
|
||||||
|
|
|
@ -162,7 +162,7 @@ void ImGuiPass::load_font(const std::string_view filename) {
|
||||||
io.Fonts->AddFontFromMemoryTTF(font_file->cast_data<unsigned char>(), font_file->size(), 15.0 * platform::get_window_dpi(0));
|
io.Fonts->AddFontFromMemoryTTF(font_file->cast_data<unsigned char>(), font_file->size(), 15.0 * platform::get_window_dpi(0));
|
||||||
ImGui::GetIO().FontGlobalScale = 1.0 / platform::get_window_dpi(0);
|
ImGui::GetIO().FontGlobalScale = 1.0 / platform::get_window_dpi(0);
|
||||||
} else {
|
} else {
|
||||||
prism::log::error(System::Renderer, "Failed to load font file for imgui!");
|
prism::log("Failed to load font file for imgui!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
ShaderSource get_shader(std::string filename, bool skinned, bool cubemap) {
|
ShaderSource get_shader(std::string filename, bool skinned, bool cubemap) {
|
||||||
auto shader_file = prism::open_file(prism::internal_domain / filename);
|
auto shader_file = prism::open_file(prism::internal_domain / filename);
|
||||||
if(!shader_file.has_value()) {
|
if(!shader_file.has_value()) {
|
||||||
prism::log::error(System::Renderer, "Failed to open shader file {}!", filename);
|
prism::log("Failed to open shader file {}!", filename);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
|
|
||||||
#include "gfx_commandbuffer.hpp"
|
#include "gfx_commandbuffer.hpp"
|
||||||
#include "math.hpp"
|
#include "math.hpp"
|
||||||
#include "screen.hpp"
|
|
||||||
#include "file.hpp"
|
#include "file.hpp"
|
||||||
#include "scene.hpp"
|
#include "scene.hpp"
|
||||||
#include "font.hpp"
|
#include "font.hpp"
|
||||||
|
@ -185,48 +184,6 @@ void renderer::recreate_all_render_targets() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderer::set_screen(ui::Screen* screen) {
|
|
||||||
Expects(screen != nullptr);
|
|
||||||
|
|
||||||
current_screen = screen;
|
|
||||||
|
|
||||||
init_screen(screen);
|
|
||||||
|
|
||||||
update_screen();
|
|
||||||
}
|
|
||||||
|
|
||||||
void renderer::init_screen(ui::Screen* screen) {
|
|
||||||
Expects(screen != nullptr);
|
|
||||||
|
|
||||||
std::array<GylphMetric, numGlyphs> metrics = {};
|
|
||||||
for(int i = 0; i < numGlyphs; i++) {
|
|
||||||
GylphMetric& metric = metrics[i];
|
|
||||||
metric.x0_y0 = utility::pack_u32(font.sizes[fontSize][i].x0, font.sizes[fontSize][i].y0);
|
|
||||||
metric.x1_y1 = utility::pack_u32(font.sizes[fontSize][i].x1, font.sizes[fontSize][i].y1);
|
|
||||||
metric.xoff = font.sizes[fontSize][i].xoff;
|
|
||||||
metric.yoff = font.sizes[fontSize][i].yoff;
|
|
||||||
metric.xoff2 = font.sizes[fontSize][i].xoff2;
|
|
||||||
metric.yoff2 = font.sizes[fontSize][i].yoff2;
|
|
||||||
}
|
|
||||||
|
|
||||||
screen->glyph_buffer = gfx->create_buffer(nullptr, instance_alignment + (sizeof(GylphMetric) * numGlyphs), false, GFXBufferUsage::Storage);
|
|
||||||
|
|
||||||
gfx->copy_buffer(screen->glyph_buffer, metrics.data(), instance_alignment, sizeof(GylphMetric) * numGlyphs);
|
|
||||||
|
|
||||||
screen->elements_buffer = gfx->create_buffer(nullptr, sizeof(ElementInstance) * 50, true, GFXBufferUsage::Storage);
|
|
||||||
|
|
||||||
screen->instance_buffer = gfx->create_buffer(nullptr, sizeof(StringInstance) * 50, true, GFXBufferUsage::Storage);
|
|
||||||
}
|
|
||||||
|
|
||||||
void renderer::update_screen() {
|
|
||||||
if(current_screen != nullptr) {
|
|
||||||
for(auto& element : current_screen->elements) {
|
|
||||||
if(!element.background.image.empty())
|
|
||||||
element.background.texture = assetm->get<Texture>(prism::app_domain / element.background.image);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void renderer::render(GFXCommandBuffer* commandbuffer, Scene* scene, RenderTarget& target, int index) {
|
void renderer::render(GFXCommandBuffer* commandbuffer, Scene* scene, RenderTarget& target, int index) {
|
||||||
const auto extent = target.extent;
|
const auto extent = target.extent;
|
||||||
const auto render_extent = target.get_render_extent();
|
const auto render_extent = target.get_render_extent();
|
||||||
|
@ -403,10 +360,7 @@ void renderer::render(GFXCommandBuffer* commandbuffer, Scene* scene, RenderTarge
|
||||||
commandbuffer->draw(0, 4, 0, 1);
|
commandbuffer->draw(0, 4, 0, 1);
|
||||||
|
|
||||||
commandbuffer->pop_group();
|
commandbuffer->pop_group();
|
||||||
|
|
||||||
if(current_screen != nullptr)
|
|
||||||
render_screen(commandbuffer, current_screen, extent, continuity);
|
|
||||||
|
|
||||||
commandbuffer->push_group("Extra Passes");
|
commandbuffer->push_group("Extra Passes");
|
||||||
|
|
||||||
for(auto& pass : passes)
|
for(auto& pass : passes)
|
||||||
|
@ -533,18 +487,6 @@ void renderer::render_camera(GFXCommandBuffer* command_buffer, Scene& scene, Obj
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& screens = scene.get_all<UI>();
|
|
||||||
for(const auto& [obj, screen] : screens) {
|
|
||||||
if(!screen.screen)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
render_screen_options options = {};
|
|
||||||
options.render_world = true;
|
|
||||||
options.mvp = camera.perspective * camera.view * scene.get<Transform>(obj).model;
|
|
||||||
|
|
||||||
render_screen(command_buffer, screen.screen, extent, continuity, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
SkyPushConstant pc;
|
SkyPushConstant pc;
|
||||||
pc.view = matrix_from_quat(scene.get<Transform>(camera_object).rotation);
|
pc.view = matrix_from_quat(scene.get<Transform>(camera_object).rotation);
|
||||||
pc.aspect = static_cast<float>(extent.width) / static_cast<float>(extent.height);
|
pc.aspect = static_cast<float>(extent.width) / static_cast<float>(extent.height);
|
||||||
|
@ -568,136 +510,6 @@ void renderer::render_camera(GFXCommandBuffer* command_buffer, Scene& scene, Obj
|
||||||
gfx->copy_buffer(target.sceneBuffer, &sceneInfo, 0, sizeof(SceneInformation));
|
gfx->copy_buffer(target.sceneBuffer, &sceneInfo, 0, sizeof(SceneInformation));
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderer::render_screen(GFXCommandBuffer *commandbuffer, ui::Screen* screen, prism::Extent extent, controller_continuity& continuity, render_screen_options options) {
|
|
||||||
std::array<GlyphInstance, maxInstances> instances;
|
|
||||||
std::vector<ElementInstance> elementInstances;
|
|
||||||
std::array<StringInstance, 50> stringInstances = {};
|
|
||||||
|
|
||||||
int stringLen = 0;
|
|
||||||
int numElements = 0;
|
|
||||||
|
|
||||||
for(auto [i, element] : utility::enumerate(screen->elements)) {
|
|
||||||
if(!element.visible)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
ElementInstance instance;
|
|
||||||
|
|
||||||
instance.position = utility::pack_u32(utility::to_fixed(element.absolute_x), utility::to_fixed(element.absolute_y));
|
|
||||||
instance.size = utility::pack_u32(utility::to_fixed(element.absolute_width), utility::to_fixed(element.absolute_height));
|
|
||||||
instance.color[0] = element.background.color.r;
|
|
||||||
instance.color[1] = element.background.color.g;
|
|
||||||
instance.color[2] = element.background.color.b;
|
|
||||||
instance.color[3] = element.background.color.a;
|
|
||||||
|
|
||||||
elementInstances.push_back(instance);
|
|
||||||
|
|
||||||
stringInstances[i].xy = utility::pack_u32(utility::to_fixed(element.absolute_x + element.text_x), utility::to_fixed(element.absolute_y + element.text_y));
|
|
||||||
|
|
||||||
float advance = 0.0f;
|
|
||||||
float yadvance = 0.0f;
|
|
||||||
|
|
||||||
bool do_y_advance = false; // so we can not advance the text by a space if we're wrapping per word
|
|
||||||
|
|
||||||
for(size_t j = 0; j < element.text.length(); j++) {
|
|
||||||
auto index = element.text[j] - 32;
|
|
||||||
|
|
||||||
if(do_y_advance) {
|
|
||||||
advance = 0.0f;
|
|
||||||
yadvance += font.ascentSizes[fontSize];
|
|
||||||
do_y_advance = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(element.wrap_text) {
|
|
||||||
if(element.text[j] == ' ') {
|
|
||||||
std::string t;
|
|
||||||
float temp_advance = 0.0f;
|
|
||||||
for(size_t k = j + 1; k < element.text.length() + j; k++) {
|
|
||||||
t += element.text[k];
|
|
||||||
auto index = element.text[k] - 32;
|
|
||||||
temp_advance += font.sizes[fontSize][index].xadvance;
|
|
||||||
|
|
||||||
if(element.text[k] == ' ')
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if((temp_advance + advance) >= element.absolute_width)
|
|
||||||
do_y_advance = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GlyphInstance& instance = instances[stringLen + j];
|
|
||||||
instance.position = utility::pack_u32(utility::to_fixed(advance), utility::to_fixed(yadvance));
|
|
||||||
instance.index = utility::pack_u32(index, 0);
|
|
||||||
instance.instance = i;
|
|
||||||
|
|
||||||
advance += font.sizes[fontSize][index].xadvance;
|
|
||||||
|
|
||||||
if(element.text[j] == '\n') {
|
|
||||||
advance = 0.0f;
|
|
||||||
yadvance += font.ascentSizes[fontSize];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stringLen += static_cast<int>(element.text.length());
|
|
||||||
numElements++;
|
|
||||||
}
|
|
||||||
|
|
||||||
gfx->copy_buffer(screen->glyph_buffer, instances.data(), 0, instance_alignment);
|
|
||||||
gfx->copy_buffer(screen->instance_buffer, stringInstances.data(), 0, sizeof(StringInstance) * 50);
|
|
||||||
gfx->copy_buffer(screen->elements_buffer, elementInstances.data(), sizeof(ElementInstance) * continuity.elementOffset, sizeof(ElementInstance) * elementInstances.size());
|
|
||||||
|
|
||||||
const prism::float2 windowSize = {static_cast<float>(extent.width), static_cast<float>(extent.height)};
|
|
||||||
|
|
||||||
for(auto [i, element] : utility::enumerate(screen->elements)) {
|
|
||||||
if(!element.visible)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
UIPushConstant pc;
|
|
||||||
pc.screenSize = windowSize;
|
|
||||||
|
|
||||||
if(options.render_world) {
|
|
||||||
commandbuffer->set_graphics_pipeline(world_general_pipeline);
|
|
||||||
pc.mvp = options.mvp;
|
|
||||||
} else {
|
|
||||||
commandbuffer->set_graphics_pipeline(general_pipeline);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (element.background.texture) {
|
|
||||||
commandbuffer->bind_texture(element.background.texture->handle, 2);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
commandbuffer->bind_texture(dummy_texture, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
commandbuffer->set_push_constant(&pc, sizeof(UIPushConstant));
|
|
||||||
|
|
||||||
commandbuffer->bind_shader_buffer(screen->elements_buffer, 0, 0, sizeof(ElementInstance) * 50);
|
|
||||||
commandbuffer->draw(0, 4, i + continuity.elementOffset, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
UIPushConstant pc;
|
|
||||||
pc.screenSize = windowSize;
|
|
||||||
|
|
||||||
if(options.render_world) {
|
|
||||||
commandbuffer->set_graphics_pipeline(world_text_pipeline);
|
|
||||||
pc.mvp = options.mvp;
|
|
||||||
} else {
|
|
||||||
commandbuffer->set_graphics_pipeline(text_pipeline);
|
|
||||||
}
|
|
||||||
|
|
||||||
commandbuffer->set_push_constant(&pc, sizeof(UIPushConstant));
|
|
||||||
|
|
||||||
commandbuffer->bind_shader_buffer(screen->glyph_buffer, 0, 0, instance_alignment);
|
|
||||||
commandbuffer->bind_shader_buffer(screen->glyph_buffer, instance_alignment, 1, sizeof(GylphMetric) * numGlyphs);
|
|
||||||
commandbuffer->bind_shader_buffer(screen->instance_buffer, 0, 2, sizeof(StringInstance) * 50);
|
|
||||||
commandbuffer->bind_texture(font_texture, 3);
|
|
||||||
|
|
||||||
if(stringLen > 0)
|
|
||||||
commandbuffer->draw(0, 4, 0, stringLen);
|
|
||||||
|
|
||||||
continuity.elementOffset += numElements;
|
|
||||||
}
|
|
||||||
|
|
||||||
void renderer::create_mesh_pipeline(Material& material) const {
|
void renderer::create_mesh_pipeline(Material& material) const {
|
||||||
GFXShaderConstant materials_constant = {};
|
GFXShaderConstant materials_constant = {};
|
||||||
materials_constant.type = GFXShaderConstant::Type::Integer;
|
materials_constant.type = GFXShaderConstant::Type::Integer;
|
||||||
|
@ -866,7 +678,7 @@ void renderer::create_post_pipelines() {
|
||||||
void renderer::create_font_texture() {
|
void renderer::create_font_texture() {
|
||||||
auto file = prism::open_file(prism::app_domain / "font.fp", true);
|
auto file = prism::open_file(prism::app_domain / "font.fp", true);
|
||||||
if(file == std::nullopt) {
|
if(file == std::nullopt) {
|
||||||
prism::log::error(System::Renderer, "Failed to load font file!");
|
prism::log("Failed to load font file!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@ std::vector<uint32_t> compile_glsl_to_spv(const std::string_view source_string,
|
||||||
file_includer.pushExternalLocalDirectory(path);
|
file_includer.pushExternalLocalDirectory(path);
|
||||||
|
|
||||||
if (!shader.parse(&DefaultTBuiltInResource, 100, false, EShMsgDefault, file_includer)) {
|
if (!shader.parse(&DefaultTBuiltInResource, 100, false, EShMsgDefault, file_includer)) {
|
||||||
prism::log::error(System::Renderer, "{}", shader.getInfoLog());
|
prism::log("{}", shader.getInfoLog());
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,7 @@ std::vector<uint32_t> compile_glsl_to_spv(const std::string_view source_string,
|
||||||
Program.addShader(&shader);
|
Program.addShader(&shader);
|
||||||
|
|
||||||
if(!Program.link(EShMsgDefault)) {
|
if(!Program.link(EShMsgDefault)) {
|
||||||
prism::log::error(System::None, "Failed to link shader: {} {} {}", source_string.data(), shader.getInfoLog(), shader.getInfoDebugLog());
|
prism::log("Failed to link shader: {} {} {}", source_string.data(), shader.getInfoLog(), shader.getInfoDebugLog());
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -77,7 +77,7 @@ std::vector<uint32_t> compile_glsl_to_spv(const std::string_view source_string,
|
||||||
|
|
||||||
std::optional<ShaderSource> ShaderCompiler::compile(const ShaderLanguage from_language, const ShaderStage shader_stage, const ShaderSource& shader_source, const ShaderLanguage to_language, const CompileOptions& options) {
|
std::optional<ShaderSource> ShaderCompiler::compile(const ShaderLanguage from_language, const ShaderStage shader_stage, const ShaderSource& shader_source, const ShaderLanguage to_language, const CompileOptions& options) {
|
||||||
if(from_language != ShaderLanguage::GLSL) {
|
if(from_language != ShaderLanguage::GLSL) {
|
||||||
prism::log::error(System::Renderer, "Non-supported input language!");
|
prism::log("Non-supported input language!");
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,7 +96,7 @@ std::optional<ShaderSource> ShaderCompiler::compile(const ShaderLanguage from_la
|
||||||
|
|
||||||
auto spirv = compile_glsl_to_spv(shader_source.as_string(), lang, options);
|
auto spirv = compile_glsl_to_spv(shader_source.as_string(), lang, options);
|
||||||
if(spirv.empty()) {
|
if(spirv.empty()) {
|
||||||
prism::log::error(System::Renderer, "SPIRV generation failed!");
|
prism::log("SPIRV generation failed!");
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@ set(SRC
|
||||||
include/string_utils.hpp
|
include/string_utils.hpp
|
||||||
include/timer.hpp
|
include/timer.hpp
|
||||||
include/common.hpp
|
include/common.hpp
|
||||||
include/file_utils.hpp
|
|
||||||
include/assertions.hpp
|
include/assertions.hpp
|
||||||
include/path.hpp
|
include/path.hpp
|
||||||
|
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <filesystem>
|
|
||||||
|
|
||||||
#include "path.hpp"
|
|
||||||
|
|
||||||
namespace prism::log {
|
|
||||||
inline void internal_format(std::string& msg, const prism::path& arg) {
|
|
||||||
auto pos = msg.find_first_of("{}");
|
|
||||||
msg.replace(pos, 2, arg.string());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -12,20 +12,3 @@ bool string_starts_with(const std::string_view haystack, const std::string_view
|
||||||
bool is_numeric(const std::string_view string);
|
bool is_numeric(const std::string_view string);
|
||||||
|
|
||||||
std::vector<std::string> tokenize(const std::string_view string, const std::string_view& delimiters = ",");
|
std::vector<std::string> tokenize(const std::string_view string, const std::string_view& delimiters = ",");
|
||||||
|
|
||||||
namespace utility {
|
|
||||||
template<class Arg>
|
|
||||||
inline void format_internal_format(std::string& msg, const Arg& arg) {
|
|
||||||
auto pos = msg.find_first_of("{}");
|
|
||||||
msg.replace(pos, 2, arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class... Args>
|
|
||||||
std::string format(const std::string_view format, Args&&... args) {
|
|
||||||
auto msg = std::string(format);
|
|
||||||
|
|
||||||
((format_internal_format<Args>(msg, args)), ...);
|
|
||||||
|
|
||||||
return msg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
#include "path.hpp"
|
#include "path.hpp"
|
||||||
|
|
||||||
void app_main(prism::engine* engine) {
|
void app_main(prism::engine* engine) {
|
||||||
prism::set_domain_path(prism::domain::app, "data");
|
prism::set_domain_path(prism::domain::app, "{resource_dir}/data");
|
||||||
prism::set_domain_path(prism::domain::internal, "{resource_dir}/shaders");
|
prism::set_domain_path(prism::domain::internal, "{resource_dir}/shaders");
|
||||||
|
|
||||||
platform::open_window("Example", {-1, -1, 1280, 720}, WindowFlags::Resizable);
|
platform::open_window("Example", {-1, -1, 1280, 720}, WindowFlags::Resizable);
|
||||||
|
@ -30,8 +30,8 @@ void ExampleApp::initialize_render() {
|
||||||
|
|
||||||
auto sphere_obj = scene->add_object();
|
auto sphere_obj = scene->add_object();
|
||||||
auto& sphere_render = scene->add<Renderable>(sphere_obj);
|
auto& sphere_render = scene->add<Renderable>(sphere_obj);
|
||||||
sphere_render.mesh = assetm->get<Mesh>(prism::path("data/models/sphere.model"));
|
sphere_render.mesh = assetm->get<Mesh>(prism::path(prism::app_domain / "models/sphere.model"));
|
||||||
sphere_render.materials = { assetm->get<Material>(prism::path("data/materials/Material.material")) };
|
sphere_render.materials = { assetm->get<Material>(prism::path(prism::app_domain / "materials/Material.material")) };
|
||||||
|
|
||||||
auto probe_obj = scene->add_object();
|
auto probe_obj = scene->add_object();
|
||||||
scene->add<EnvironmentProbe>(probe_obj);
|
scene->add<EnvironmentProbe>(probe_obj);
|
||||||
|
|
10
extern/CMakeLists.txt
vendored
10
extern/CMakeLists.txt
vendored
|
@ -106,4 +106,12 @@ if(BUILD_TOOLS)
|
||||||
)
|
)
|
||||||
|
|
||||||
FetchContent_MakeAvailable(assimp)
|
FetchContent_MakeAvailable(assimp)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
FetchContent_Declare(
|
||||||
|
fmt
|
||||||
|
GIT_REPOSITORY https://github.com/fmtlib/fmt
|
||||||
|
GIT_TAG 8.0.1
|
||||||
|
)
|
||||||
|
|
||||||
|
FetchContent_MakeAvailable(fmt)
|
1565
extern/magic_enum/include/magic_enum.hpp
vendored
Executable file → Normal file
1565
extern/magic_enum/include/magic_enum.hpp
vendored
Executable file → Normal file
File diff suppressed because it is too large
Load diff
|
@ -7,7 +7,7 @@ if(ENABLE_LINUX)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(ENABLE_MACOS)
|
if(ENABLE_MACOS)
|
||||||
add_subdirectory(mac)
|
add_subdirectory(sdl)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(ENABLE_IOS)
|
if(ENABLE_IOS)
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
include(../../cmake/AddPlatformExecutable.cmake)
|
|
||||||
|
|
||||||
add_platform(
|
|
||||||
MAIN_FILE
|
|
||||||
main.mm.in
|
|
||||||
SRC
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/file.mm
|
|
||||||
EXECUTABLE_PROPERTIES
|
|
||||||
MACOSX_BUNDLE ON
|
|
||||||
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in"
|
|
||||||
LINK_LIBRARIES
|
|
||||||
Core
|
|
||||||
GFXMetal
|
|
||||||
"-framework Cocoa"
|
|
||||||
"-framework QuartzCore"
|
|
||||||
"-framework GameController"
|
|
||||||
COMPILE_OPTIONS
|
|
||||||
-std=c++17
|
|
||||||
)
|
|
||||||
|
|
||||||
function(add_platform_commands target)
|
|
||||||
target_link_options(${target} BEFORE PRIVATE -pagezero_size 10000 -image_base 100000000
|
|
||||||
)
|
|
||||||
if(NOT SKIP_DATA)
|
|
||||||
add_custom_command(TARGET ${target} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/data $<TARGET_FILE_DIR:${target}>/../Resources/data)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
add_custom_command(TARGET ${target} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_BINARY_DIR}/shaders $<TARGET_FILE_DIR:${target}>/../Resources/shaders)
|
|
||||||
endfunction()
|
|
|
@ -1,42 +0,0 @@
|
||||||
#include "file.hpp"
|
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
#include <array>
|
|
||||||
|
|
||||||
#import <AppKit/AppKit.h>
|
|
||||||
|
|
||||||
#include "string_utils.hpp"
|
|
||||||
|
|
||||||
#include "log.hpp"
|
|
||||||
|
|
||||||
inline std::string clean_path(const std::string_view path) {
|
|
||||||
auto p = replace_substring(path, "%20", " ");
|
|
||||||
|
|
||||||
// this is a path returned by an editor, so skip it
|
|
||||||
// TODO: find a better way to do this!! NOO!!
|
|
||||||
if(p.find("file:///") != std::string::npos)
|
|
||||||
return p.substr(7, p.length());
|
|
||||||
else
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
void prism::set_domain_path(const prism::domain domain, const prism::path path) {
|
|
||||||
NSBundle* bundle = [NSBundle mainBundle];
|
|
||||||
NSString* resourceFolderPath = [bundle resourcePath];
|
|
||||||
|
|
||||||
std::string s = std::string(path);
|
|
||||||
s = replace_substring(s, "{resource_dir}", [resourceFolderPath cStringUsingEncoding:NSUTF8StringEncoding]);
|
|
||||||
|
|
||||||
// basically, if we pass a relative path this will convert it to an absolute one, making get_relative_path functional.
|
|
||||||
NSURL * bundleURL = [[bundle bundleURL] URLByDeletingLastPathComponent];
|
|
||||||
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%s", s.c_str()] relativeToURL:bundleURL];
|
|
||||||
|
|
||||||
domain_data[static_cast<int>(domain)] = clean_path([[[url absoluteURL] absoluteString] cStringUsingEncoding:NSUTF8StringEncoding]);
|
|
||||||
}
|
|
||||||
|
|
||||||
prism::path prism::get_writeable_directory() {
|
|
||||||
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
|
|
||||||
NSString* resourceFolderPath = paths[0];
|
|
||||||
|
|
||||||
return [resourceFolderPath cStringUsingEncoding:NSUTF8StringEncoding];
|
|
||||||
}
|
|
|
@ -1,634 +0,0 @@
|
||||||
#import <Cocoa/Cocoa.h>
|
|
||||||
#import <MetalKit/MetalKit.h>
|
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
#include <GameController/GameController.h>
|
|
||||||
#include <mach/mach_time.h>
|
|
||||||
#include <gfx_metal.hpp>
|
|
||||||
#include <engine.hpp>
|
|
||||||
#include <map>
|
|
||||||
#include <file.hpp>
|
|
||||||
#include <string_utils.hpp>
|
|
||||||
|
|
||||||
#include <@APP_INCLUDE@>
|
|
||||||
|
|
||||||
uint64_t last_time = 0;
|
|
||||||
bool is_qutting = false;
|
|
||||||
|
|
||||||
static std::map<InputButton, int> inputToKeyCode = { {
|
|
||||||
{InputButton::C, 8},
|
|
||||||
{InputButton::V, 9},
|
|
||||||
{InputButton::X, 7},
|
|
||||||
{InputButton::Q, 12},
|
|
||||||
{InputButton::Y, 16},
|
|
||||||
{InputButton::Z, 6},
|
|
||||||
{InputButton::Backspace, 51},
|
|
||||||
{InputButton::Enter, 36},
|
|
||||||
{InputButton::Space, 49},
|
|
||||||
{InputButton::Shift, 10},
|
|
||||||
{InputButton::A, 0},
|
|
||||||
{InputButton::W, 13},
|
|
||||||
{InputButton::S, 1},
|
|
||||||
{InputButton::D, 2},
|
|
||||||
{InputButton::Escape, 53},
|
|
||||||
{InputButton::Tab, 48},
|
|
||||||
{InputButton::LeftArrow, 123},
|
|
||||||
{InputButton::RightArrow, 124}
|
|
||||||
}};
|
|
||||||
|
|
||||||
struct NativeWindow;
|
|
||||||
|
|
||||||
const char* platform::get_name() {
|
|
||||||
return "macOS";
|
|
||||||
}
|
|
||||||
|
|
||||||
int platform::get_keycode(InputButton key) {
|
|
||||||
if(inputToKeyCode.count(key))
|
|
||||||
return inputToKeyCode[key];
|
|
||||||
else
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
GFX* interface = nullptr;
|
|
||||||
|
|
||||||
@APP_CLASS@* app = nullptr;
|
|
||||||
|
|
||||||
float scrollX = 0.0f, scrollY = 0.0f;
|
|
||||||
|
|
||||||
std::array<bool, 8> inputKeys;
|
|
||||||
|
|
||||||
float rightX = 0.0f, rightY = 0.0f;
|
|
||||||
float leftX = 0.0f, leftY = 0.0f;
|
|
||||||
|
|
||||||
@interface GameView : NSObject<NSWindowDelegate>
|
|
||||||
|
|
||||||
@property NativeWindow *native;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
struct NativeWindow {
|
|
||||||
int index = 0;
|
|
||||||
NSWindow* window;
|
|
||||||
GameView* delegate;
|
|
||||||
CAMetalLayer* layer;
|
|
||||||
bool willCaptureMouse = false;
|
|
||||||
|
|
||||||
int currentWidth = 0, currentHeight = 0;
|
|
||||||
int timeout = 0;
|
|
||||||
|
|
||||||
NSPoint currentMousePos;
|
|
||||||
bool showingCursor = true;
|
|
||||||
bool inFocus = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<NativeWindow*> windows;
|
|
||||||
|
|
||||||
NativeWindow* get_window(const int index) {
|
|
||||||
for(auto& window : windows) {
|
|
||||||
if(window->index == index)
|
|
||||||
return window;
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
@implementation GameView
|
|
||||||
|
|
||||||
- (void)gameQuit {
|
|
||||||
engine->prepare_quit();
|
|
||||||
}
|
|
||||||
- (void)gameFocus {
|
|
||||||
if(![self native]->showingCursor)
|
|
||||||
[NSCursor hide];
|
|
||||||
|
|
||||||
[self native]->inFocus = true;
|
|
||||||
}
|
|
||||||
- (void)gameLostFocus {
|
|
||||||
if(![self native]->showingCursor)
|
|
||||||
[NSCursor unhide];
|
|
||||||
|
|
||||||
[self native]->inFocus = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const double NANOSECONDS_TO_MILLISECONDS = 1.0 / 1000000000.0;
|
|
||||||
|
|
||||||
- (void)update {
|
|
||||||
const bool is_main_window = [self native]->index == 0;
|
|
||||||
|
|
||||||
if(is_main_window) {
|
|
||||||
if([self native]->willCaptureMouse && [self native]->timeout > 5 && [self native]->inFocus) {
|
|
||||||
NSPoint point;
|
|
||||||
point.x = [self native]->window.frame.origin.x + ([self native]->currentWidth / 2);
|
|
||||||
point.y = [NSScreen mainScreen].frame.size.height - ([self native]->window.frame.origin.y + ([self native]->currentHeight / 2));
|
|
||||||
|
|
||||||
CGWarpMouseCursorPosition(point);
|
|
||||||
CGAssociateMouseAndMouseCursorPosition(true);
|
|
||||||
|
|
||||||
[self native]->currentMousePos.x = [self native]->currentWidth / 2;
|
|
||||||
[self native]->currentMousePos.y = [self native]->currentHeight / 2;
|
|
||||||
|
|
||||||
[self native]->timeout = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
[self native]->timeout++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)render {
|
|
||||||
engine->render([self native]->index);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)windowDidResize:(NSNotification *)notification {
|
|
||||||
[self native]->currentWidth = [self native]->window.contentView.frame.size.width;
|
|
||||||
[self native]->currentHeight = [self native]->window.contentView.frame.size.height;
|
|
||||||
|
|
||||||
NSRect bounds = [[self native]->layer bounds];
|
|
||||||
bounds = [[self native]->window convertRectToBacking:bounds];
|
|
||||||
|
|
||||||
[self native]->layer.drawableSize = NSSizeToCGSize(bounds.size);;
|
|
||||||
|
|
||||||
engine->resize([self native]->index, {static_cast<uint32_t>([self native]->currentWidth), static_cast<uint32_t>([self native]->currentHeight)});
|
|
||||||
}
|
|
||||||
|
|
||||||
-(void)windowWillClose:(NSNotification *)notification {
|
|
||||||
if([self native]->index == 0)
|
|
||||||
is_qutting = app->should_quit();
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) controllerConnected {
|
|
||||||
GCController* controller = [GCController controllers][0];
|
|
||||||
[[controller extendedGamepad] setValueChangedHandler:^(GCExtendedGamepad * _Nonnull gamepad, GCControllerElement * _Nonnull element) {
|
|
||||||
const auto& handle_element = [element](int index, GCControllerElement* e) {
|
|
||||||
if(element == e)
|
|
||||||
inputKeys[index] = [(GCControllerButtonInput*)e value] == 1.0f;
|
|
||||||
};
|
|
||||||
|
|
||||||
handle_element(0, [[controller extendedGamepad] buttonA]);
|
|
||||||
handle_element(1, [[controller extendedGamepad] buttonB]);
|
|
||||||
handle_element(2, [[controller extendedGamepad] buttonX]);
|
|
||||||
handle_element(3, [[controller extendedGamepad] buttonY]);
|
|
||||||
|
|
||||||
if(element == [[controller extendedGamepad] dpad]) {
|
|
||||||
inputKeys[4] = [[[[controller extendedGamepad] dpad] up] value] == 1.0f;
|
|
||||||
inputKeys[5] = [[[[controller extendedGamepad] dpad] down] value] == 1.0f;
|
|
||||||
inputKeys[6] = [[[[controller extendedGamepad] dpad] left] value] == 1.0f;
|
|
||||||
inputKeys[7] = [[[[controller extendedGamepad] dpad] right] value] == 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(element == [[controller extendedGamepad] leftThumbstick]) {
|
|
||||||
leftX = [[[[controller extendedGamepad] leftThumbstick] xAxis] value];
|
|
||||||
leftY = [[[[controller extendedGamepad] leftThumbstick] yAxis] value];
|
|
||||||
}
|
|
||||||
|
|
||||||
if(element == [[controller extendedGamepad] rightThumbstick]) {
|
|
||||||
rightX = [[[[controller extendedGamepad] rightThumbstick] xAxis] value];
|
|
||||||
rightY = [[[[controller extendedGamepad] rightThumbstick] yAxis] value];
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
std::map<int, bool> pressed;
|
|
||||||
NSString* currentCharString = nil;
|
|
||||||
|
|
||||||
bool platform::supports_feature(const PlatformFeature feature) {
|
|
||||||
switch(feature) {
|
|
||||||
case PlatformFeature::Windowing:
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool platform::get_key_down(const InputButton key) {
|
|
||||||
if(key == InputButton::ButtonA)
|
|
||||||
return inputKeys[0];
|
|
||||||
|
|
||||||
if(key == InputButton::ButtonB)
|
|
||||||
return inputKeys[1];
|
|
||||||
|
|
||||||
if(key == InputButton::ButtonX)
|
|
||||||
return inputKeys[2];
|
|
||||||
|
|
||||||
if(key == InputButton::ButtonY)
|
|
||||||
return inputKeys[3];
|
|
||||||
|
|
||||||
if(key == InputButton::DPadUp)
|
|
||||||
return inputKeys[4];
|
|
||||||
|
|
||||||
if(key == InputButton::DPadDown)
|
|
||||||
return inputKeys[5];
|
|
||||||
|
|
||||||
if(key == InputButton::DPadLeft)
|
|
||||||
return inputKeys[6];
|
|
||||||
|
|
||||||
if(key == InputButton::DPadRight)
|
|
||||||
return inputKeys[7];
|
|
||||||
|
|
||||||
if(inputToKeyCode.count(key))
|
|
||||||
return pressed[inputToKeyCode[key]];
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* platform::translate_keycode(const unsigned int keycode) {
|
|
||||||
return const_cast<char*>([currentCharString UTF8String]);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline std::string clean_path(const std::string_view path) {
|
|
||||||
auto p = replace_substring(path, "%20", " ");
|
|
||||||
|
|
||||||
// this is a path returned by an editor, so skip it
|
|
||||||
// TODO: find a better way to do this!! NOO!!
|
|
||||||
if(p.find("file:///") != std::string::npos)
|
|
||||||
return p.substr(7, p.length());
|
|
||||||
else
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
void platform::open_dialog(const bool existing, std::function<void(std::string)> returnFunction, bool openDirectory) {
|
|
||||||
NSOpenPanel* openDlg = [NSOpenPanel openPanel];
|
|
||||||
|
|
||||||
[openDlg setCanChooseFiles:YES];
|
|
||||||
|
|
||||||
[openDlg setAllowsMultipleSelection:NO];
|
|
||||||
|
|
||||||
[openDlg setCanChooseDirectories:openDirectory];
|
|
||||||
|
|
||||||
[openDlg setCanChooseFiles:!openDirectory];
|
|
||||||
|
|
||||||
if([openDlg runModal] == NSModalResponseOK)
|
|
||||||
returnFunction(clean_path([openDlg.URLs[0].absoluteString UTF8String]));
|
|
||||||
}
|
|
||||||
|
|
||||||
void platform::save_dialog(std::function<void(std::string)> returnFunction) {
|
|
||||||
NSSavePanel* openDlg = [NSSavePanel savePanel];
|
|
||||||
|
|
||||||
if ([openDlg runModal] == NSModalResponseOK)
|
|
||||||
returnFunction(clean_path([openDlg.URL.absoluteString UTF8String]));
|
|
||||||
}
|
|
||||||
|
|
||||||
void platform::capture_mouse(const bool capture) {
|
|
||||||
windows[0]->willCaptureMouse = capture;
|
|
||||||
|
|
||||||
if(windows[0]->showingCursor && capture) {
|
|
||||||
[NSCursor hide];
|
|
||||||
windows[0]->showingCursor = false;
|
|
||||||
} else if(!windows[0]->showingCursor && !capture) {
|
|
||||||
[NSCursor unhide];
|
|
||||||
windows[0]->showingCursor = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
float platform::get_window_dpi(const int index) {
|
|
||||||
auto window = get_window(index);
|
|
||||||
return [window->window backingScaleFactor];
|
|
||||||
}
|
|
||||||
|
|
||||||
float platform::get_monitor_dpi() {
|
|
||||||
return [[NSScreen mainScreen] backingScaleFactor];
|
|
||||||
}
|
|
||||||
|
|
||||||
CGRect toTopLeftSpace(NSRect frame) {
|
|
||||||
frame.origin.y = NSMaxY([[NSScreen mainScreen] frame]) - NSMaxY(frame);
|
|
||||||
return NSRectToCGRect(frame);
|
|
||||||
}
|
|
||||||
|
|
||||||
prism::Rectangle platform::get_monitor_resolution() {
|
|
||||||
auto frame = toTopLeftSpace([[NSScreen mainScreen] frame]);
|
|
||||||
|
|
||||||
return {static_cast<int32_t>(frame.origin.x), static_cast<int32_t>(frame.origin.y), static_cast<uint32_t>(frame.size.width), static_cast<uint32_t>(frame.size.height)};
|
|
||||||
}
|
|
||||||
|
|
||||||
prism::Rectangle platform::get_monitor_work_area() {
|
|
||||||
auto frame = toTopLeftSpace([[NSScreen mainScreen] visibleFrame]);
|
|
||||||
|
|
||||||
return {static_cast<int32_t>(frame.origin.x), static_cast<int32_t>(frame.origin.y), static_cast<uint32_t>(frame.size.width), static_cast<uint32_t>(frame.size.height)};
|
|
||||||
}
|
|
||||||
|
|
||||||
NSPoint get_fixed_cursor_point(NSPoint point) {
|
|
||||||
return {point.x, std::max(windows[0]->currentHeight - point.y, 0.0)};
|
|
||||||
}
|
|
||||||
|
|
||||||
prism::Offset platform::get_cursor_position() {
|
|
||||||
return {static_cast<int32_t>(windows[0]->currentMousePos.x), static_cast<int32_t>(windows[0]->currentMousePos.y)};
|
|
||||||
}
|
|
||||||
|
|
||||||
prism::Offset platform::get_screen_cursor_position() {
|
|
||||||
return {static_cast<int32_t>([NSEvent mouseLocation].x), static_cast<int32_t>([[NSScreen mainScreen] frame].size.height - [NSEvent mouseLocation].y)};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::tuple<float, float> platform::get_wheel_delta() {
|
|
||||||
return {scrollX, scrollY};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::tuple<float, float> platform::get_left_stick_position() {
|
|
||||||
return {leftX, leftY};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::tuple<float, float> platform::get_right_stick_position() {
|
|
||||||
return {rightX, rightY};
|
|
||||||
}
|
|
||||||
|
|
||||||
prism::Extent platform::get_window_size(const int index) {
|
|
||||||
auto window = get_window(index);
|
|
||||||
return {static_cast<uint32_t>(window->currentWidth), static_cast<uint32_t>(window->currentHeight)};
|
|
||||||
}
|
|
||||||
|
|
||||||
prism::Extent platform::get_window_drawable_size(const int index) {
|
|
||||||
auto window = get_window(index);
|
|
||||||
return {static_cast<uint32_t>(window->currentWidth * window->window.backingScaleFactor), static_cast<uint32_t>(window->currentHeight * window->window.backingScaleFactor)};
|
|
||||||
}
|
|
||||||
|
|
||||||
prism::Offset platform::get_window_position(const int index) {
|
|
||||||
auto window = get_window(index);
|
|
||||||
|
|
||||||
auto frame = toTopLeftSpace([window->window contentRectForFrameRect:[window->window frame]]);
|
|
||||||
|
|
||||||
return {static_cast<int32_t>(frame.origin.x), static_cast<int32_t>(frame.origin.y)};
|
|
||||||
}
|
|
||||||
|
|
||||||
bool platform::is_window_focused(const int index) {
|
|
||||||
auto window = get_window(index);
|
|
||||||
|
|
||||||
return [window->window isKeyWindow];
|
|
||||||
}
|
|
||||||
|
|
||||||
void platform::set_window_focused(const int index) {
|
|
||||||
auto window = get_window(index);
|
|
||||||
[window->window makeKeyWindow];
|
|
||||||
}
|
|
||||||
|
|
||||||
bool platform::get_mouse_button_down(const int button) {
|
|
||||||
return (button + 1) & [NSEvent pressedMouseButtons];
|
|
||||||
}
|
|
||||||
|
|
||||||
void platform::set_window_position(const int index, const prism::Offset offset) {
|
|
||||||
auto window = get_window(index);
|
|
||||||
|
|
||||||
NSPoint p;
|
|
||||||
p.x = offset.x;
|
|
||||||
p.y = [[NSScreen mainScreen] frame].size.height - offset.y;
|
|
||||||
|
|
||||||
[window->window setFrameTopLeftPoint:p];
|
|
||||||
}
|
|
||||||
|
|
||||||
void platform::set_window_size(const int index, const prism::Extent extent) {
|
|
||||||
auto window = get_window(index);
|
|
||||||
|
|
||||||
NSSize size;
|
|
||||||
size.width = extent.width;
|
|
||||||
size.height = extent.height;
|
|
||||||
|
|
||||||
[window->window setContentSize:size];
|
|
||||||
}
|
|
||||||
|
|
||||||
void platform::set_window_title(const int index, const std::string_view title) {
|
|
||||||
auto window = get_window(index);
|
|
||||||
[window->window setTitle:[NSString stringWithUTF8String:title.data()]];
|
|
||||||
}
|
|
||||||
|
|
||||||
void platform::mute_output() {}
|
|
||||||
void platform::unmute_output() {}
|
|
||||||
|
|
||||||
PlatformTheme platform::get_theme() {
|
|
||||||
auto str = [[[NSApplication sharedApplication] effectiveAppearance] name];
|
|
||||||
|
|
||||||
if(str == NSAppearanceNameAqua)
|
|
||||||
return PlatformTheme::Light;
|
|
||||||
else if(str == NSAppearanceNameDarkAqua)
|
|
||||||
return PlatformTheme::Dark;
|
|
||||||
|
|
||||||
return PlatformTheme::Light;
|
|
||||||
}
|
|
||||||
|
|
||||||
int platform::open_window(const std::string_view title, const prism::Rectangle rect, const WindowFlags flags) {
|
|
||||||
NativeWindow* native = new NativeWindow();
|
|
||||||
native->index = windows.size();
|
|
||||||
GameView* del = [[GameView alloc] init];
|
|
||||||
native->delegate = del;
|
|
||||||
windows.push_back(native);
|
|
||||||
|
|
||||||
NSRect nrect = NSMakeRect(rect.offset.x, rect.offset.y, rect.extent.width, rect.extent.height);
|
|
||||||
|
|
||||||
NSWindowStyleMask windowStyle = NSWindowStyleMaskTitled
|
|
||||||
| NSWindowStyleMaskClosable
|
|
||||||
| NSWindowStyleMaskMiniaturizable;
|
|
||||||
|
|
||||||
if(flags == WindowFlags::Resizable)
|
|
||||||
windowStyle |= NSWindowStyleMaskResizable;
|
|
||||||
else if(flags == WindowFlags::Borderless)
|
|
||||||
windowStyle = NSWindowStyleMaskBorderless;
|
|
||||||
|
|
||||||
native->window = [[NSWindow alloc]
|
|
||||||
initWithContentRect: nrect
|
|
||||||
styleMask:windowStyle
|
|
||||||
backing: NSBackingStoreBuffered
|
|
||||||
defer: NO];
|
|
||||||
|
|
||||||
native->currentWidth = rect.extent.width;
|
|
||||||
native->currentHeight = rect.extent.height;
|
|
||||||
|
|
||||||
native->layer = [CAMetalLayer layer];
|
|
||||||
|
|
||||||
NSView* view = [[NSView alloc] init];
|
|
||||||
view.wantsLayer = YES;
|
|
||||||
view.layer = native->layer;
|
|
||||||
|
|
||||||
native->layer.contentsScale = [native->window backingScaleFactor];
|
|
||||||
|
|
||||||
engine->add_window(view.layer, native->index, rect.extent);
|
|
||||||
|
|
||||||
[native->window setContentView:view];
|
|
||||||
|
|
||||||
if(native->index == 0)
|
|
||||||
app->initialize_render();
|
|
||||||
|
|
||||||
[native->window setTitle:[NSString stringWithUTF8String:title.data()]];
|
|
||||||
|
|
||||||
[del setNative:native];
|
|
||||||
|
|
||||||
[native->window setDelegate:del];
|
|
||||||
[native->window orderFrontRegardless];
|
|
||||||
|
|
||||||
if(native->index == 0) {
|
|
||||||
NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
|
|
||||||
[nc addObserver:del
|
|
||||||
selector:@selector(gameQuit)
|
|
||||||
name:NSApplicationWillTerminateNotification
|
|
||||||
object:nil];
|
|
||||||
|
|
||||||
[nc addObserver:del
|
|
||||||
selector:@selector(gameFocus)
|
|
||||||
name:NSApplicationDidBecomeActiveNotification
|
|
||||||
object:nil];
|
|
||||||
|
|
||||||
[nc addObserver:del
|
|
||||||
selector:@selector(gameLostFocus)
|
|
||||||
name:NSApplicationDidResignActiveNotification
|
|
||||||
object:nil];
|
|
||||||
|
|
||||||
[nc addObserver:del
|
|
||||||
selector:@selector(controllerConnected)
|
|
||||||
name:GCControllerDidConnectNotification
|
|
||||||
object:nil];
|
|
||||||
}
|
|
||||||
|
|
||||||
return native->index;
|
|
||||||
}
|
|
||||||
|
|
||||||
void platform::close_window(const int index) {
|
|
||||||
auto window = get_window(index);
|
|
||||||
|
|
||||||
engine->remove_window(window->index);
|
|
||||||
|
|
||||||
[window->window close];
|
|
||||||
|
|
||||||
utility::erase(windows, window);
|
|
||||||
}
|
|
||||||
|
|
||||||
void platform::force_quit() {
|
|
||||||
[NSApp terminate:nil];
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
|
||||||
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
|
|
||||||
|
|
||||||
NSApp = [NSApplication sharedApplication];
|
|
||||||
|
|
||||||
engine = new prism::engine(argc, argv);
|
|
||||||
|
|
||||||
app = new @APP_CLASS@();
|
|
||||||
engine->set_app(app);
|
|
||||||
|
|
||||||
GFXCreateInfo createInfo = {};
|
|
||||||
createInfo.api_validation_enabled = true;
|
|
||||||
|
|
||||||
interface = new GFXMetal();
|
|
||||||
if(interface->initialize(createInfo)) {
|
|
||||||
engine->set_gfx(interface);
|
|
||||||
} else {
|
|
||||||
NSLog(@"Failed to create Metal context!");
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
app_main(engine);
|
|
||||||
|
|
||||||
[NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskKeyDown handler:^(NSEvent *event) {
|
|
||||||
pressed[event.keyCode] = true;
|
|
||||||
currentCharString = event.characters;
|
|
||||||
|
|
||||||
engine->process_key_down(event.keyCode);
|
|
||||||
|
|
||||||
return (NSEvent*)nil;
|
|
||||||
}];
|
|
||||||
|
|
||||||
[NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskKeyUp handler:^(NSEvent *event) {
|
|
||||||
pressed[event.keyCode] = false;
|
|
||||||
|
|
||||||
engine->process_key_up(event.keyCode);
|
|
||||||
|
|
||||||
return (NSEvent*)nil;
|
|
||||||
}];
|
|
||||||
|
|
||||||
[NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskMouseMoved handler:^(NSEvent *event) {
|
|
||||||
windows[0]->currentMousePos = get_fixed_cursor_point(event.locationInWindow);
|
|
||||||
|
|
||||||
return event;
|
|
||||||
}];
|
|
||||||
|
|
||||||
[NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskLeftMouseDown handler:^(NSEvent *event) {
|
|
||||||
auto point = get_fixed_cursor_point(event.locationInWindow);
|
|
||||||
engine->process_mouse_down(0, {static_cast<int32_t>(point.x), static_cast<int32_t>(point.y)});
|
|
||||||
|
|
||||||
return event;
|
|
||||||
}];
|
|
||||||
|
|
||||||
[NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskRightMouseDown handler:^(NSEvent *event) {
|
|
||||||
auto point = get_fixed_cursor_point(event.locationInWindow);
|
|
||||||
engine->process_mouse_down(1, {static_cast<int32_t>(point.x), static_cast<int32_t>(point.y)});
|
|
||||||
|
|
||||||
return event;
|
|
||||||
}];
|
|
||||||
|
|
||||||
[NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskRightMouseDragged handler:^(NSEvent *event) {
|
|
||||||
windows[0]->currentMousePos = get_fixed_cursor_point(event.locationInWindow);
|
|
||||||
|
|
||||||
return event;
|
|
||||||
}];
|
|
||||||
|
|
||||||
[NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskLeftMouseDragged handler:^(NSEvent *event) {
|
|
||||||
windows[0]->currentMousePos = get_fixed_cursor_point(event.locationInWindow);
|
|
||||||
|
|
||||||
return event;
|
|
||||||
}];
|
|
||||||
|
|
||||||
[NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskScrollWheel handler:^(NSEvent *event) {
|
|
||||||
double wheel_dx = 0.0;
|
|
||||||
double wheel_dy = 0.0;
|
|
||||||
|
|
||||||
wheel_dx = [event scrollingDeltaX];
|
|
||||||
wheel_dy = [event scrollingDeltaY];
|
|
||||||
if ([event hasPreciseScrollingDeltas])
|
|
||||||
{
|
|
||||||
wheel_dx *= 0.1;
|
|
||||||
wheel_dy *= 0.1;
|
|
||||||
}
|
|
||||||
|
|
||||||
scrollX += wheel_dx * 0.1f;
|
|
||||||
scrollY += wheel_dy * 0.1f;
|
|
||||||
|
|
||||||
return event;
|
|
||||||
}];
|
|
||||||
|
|
||||||
last_time = clock_gettime_nsec_np(CLOCK_UPTIME_RAW);
|
|
||||||
|
|
||||||
while (!is_qutting) {
|
|
||||||
@autoreleasepool {
|
|
||||||
NSEvent* event = nullptr;
|
|
||||||
do {
|
|
||||||
event = [NSApp nextEventMatchingMask: NSEventMaskAny
|
|
||||||
untilDate: nil
|
|
||||||
inMode: NSDefaultRunLoopMode
|
|
||||||
dequeue: YES];
|
|
||||||
if(event)
|
|
||||||
[NSApp sendEvent: event];
|
|
||||||
} while(event);
|
|
||||||
|
|
||||||
const uint64_t current = clock_gettime_nsec_np(CLOCK_UPTIME_RAW);
|
|
||||||
const uint64_t elapsed = current - last_time;
|
|
||||||
|
|
||||||
if(engine->is_quitting())
|
|
||||||
is_qutting = true;
|
|
||||||
|
|
||||||
for(auto& window : windows) {
|
|
||||||
if(window != nullptr)
|
|
||||||
[window->delegate update];
|
|
||||||
}
|
|
||||||
|
|
||||||
engine->update(elapsed * NANOSECONDS_TO_MILLISECONDS);
|
|
||||||
|
|
||||||
engine->begin_frame(elapsed * NANOSECONDS_TO_MILLISECONDS);
|
|
||||||
|
|
||||||
for(auto& window : windows) {
|
|
||||||
if(window != nullptr)
|
|
||||||
[window->delegate render];
|
|
||||||
}
|
|
||||||
|
|
||||||
engine->end_frame();
|
|
||||||
|
|
||||||
scrollX = 0.0f;
|
|
||||||
scrollY = 0.0f;
|
|
||||||
|
|
||||||
last_time = current;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
app->prepare_quit();
|
|
||||||
|
|
||||||
[NSApp release];
|
|
||||||
[pool release];
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -4,6 +4,9 @@ add_platform(
|
||||||
SRC ${CMAKE_CURRENT_SOURCE_DIR}/file.cpp
|
SRC ${CMAKE_CURRENT_SOURCE_DIR}/file.cpp
|
||||||
MAIN_FILE
|
MAIN_FILE
|
||||||
main.cpp.in
|
main.cpp.in
|
||||||
|
EXECUTABLE_PROPERTIES
|
||||||
|
MACOSX_BUNDLE ON
|
||||||
|
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in"
|
||||||
LINK_LIBRARIES
|
LINK_LIBRARIES
|
||||||
SDL2::Main
|
SDL2::Main
|
||||||
Core
|
Core
|
||||||
|
@ -12,7 +15,11 @@ add_platform(
|
||||||
|
|
||||||
function(add_platform_commands target)
|
function(add_platform_commands target)
|
||||||
if(NOT SKIP_DATA)
|
if(NOT SKIP_DATA)
|
||||||
add_custom_command(TARGET ${target} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/data $<TARGET_FILE_DIR:${target}>/data)
|
if(ENABLE_MACOS)
|
||||||
|
add_custom_command(TARGET ${target} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/data $<TARGET_FILE_DIR:${target}>/../Resources/data)
|
||||||
|
else()
|
||||||
|
add_custom_command(TARGET ${target} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/data $<TARGET_FILE_DIR:${target}>/data)
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# we HAVE to create this dummy target to convince CMake to properly copy over shader files.
|
# we HAVE to create this dummy target to convince CMake to properly copy over shader files.
|
||||||
|
@ -24,10 +31,18 @@ function(add_platform_commands target)
|
||||||
|
|
||||||
add_custom_target(${DUMMY_NAME} ALL DEPENDS ${CMAKE_BINARY_DIR}/dummy)
|
add_custom_target(${DUMMY_NAME} ALL DEPENDS ${CMAKE_BINARY_DIR}/dummy)
|
||||||
|
|
||||||
add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/dummy
|
if(ENABLE_MACOS)
|
||||||
COMMAND ${CMAKE_COMMAND} -E make_directory $<TARGET_FILE_DIR:${target}>/shaders
|
add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/dummy
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_BINARY_DIR}/shaders $<TARGET_FILE_DIR:${target}>/shaders
|
COMMAND ${CMAKE_COMMAND} -E make_directory $<TARGET_FILE_DIR:${target}>/../Resources/shaders
|
||||||
)
|
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_BINARY_DIR}/shaders $<TARGET_FILE_DIR:${target}>/../Resources/shaders
|
||||||
|
)
|
||||||
|
else()
|
||||||
|
add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/dummy
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E make_directory $<TARGET_FILE_DIR:${target}>/shaders
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_BINARY_DIR}/shaders $<TARGET_FILE_DIR:${target}>/shaders
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
add_dependencies(${target} ${DUMMY_NAME})
|
add_dependencies(${target} ${DUMMY_NAME})
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
<key>CFBundleDisplayName</key>
|
<key>CFBundleDisplayName</key>
|
||||||
<string>Fantasy\U00A0app</string>
|
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
<string>English</string>
|
<string>English</string>
|
||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
|
@ -19,7 +19,7 @@
|
||||||
<key>CFBundleLongVersionString</key>
|
<key>CFBundleLongVersionString</key>
|
||||||
<string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string>
|
<string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string>
|
||||||
<key>CFBundleName</key>
|
<key>CFBundleName</key>
|
||||||
<string>Project Shopkeep</string>
|
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
|
||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
|
@ -31,7 +31,7 @@
|
||||||
<key>CSResourcesFileMapped</key>
|
<key>CSResourcesFileMapped</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>NSHumanReadableCopyright</key>
|
<key>NSHumanReadableCopyright</key>
|
||||||
<string>(c)2020 Blinding Light Games</string>
|
<string>(c) 2021</string>
|
||||||
<key>NSHighResolutionCapable</key>
|
<key>NSHighResolutionCapable</key>
|
||||||
<true/>
|
<true/>
|
||||||
</dict>
|
</dict>
|
|
@ -3,7 +3,11 @@
|
||||||
#include "string_utils.hpp"
|
#include "string_utils.hpp"
|
||||||
|
|
||||||
void prism::set_domain_path(const prism::domain domain, const prism::path path) {
|
void prism::set_domain_path(const prism::domain domain, const prism::path path) {
|
||||||
|
#ifdef PLATFORM_MACOS
|
||||||
|
domain_data[(int)domain] = replace_substring(path.string(), "{resource_dir}/", "../Resources/");
|
||||||
|
#else
|
||||||
domain_data[(int)domain] = replace_substring(path.string(), "{resource_dir}/", "");
|
domain_data[(int)domain] = replace_substring(path.string(), "{resource_dir}/", "");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
prism::path prism::get_writeable_directory() {
|
prism::path prism::get_writeable_directory() {
|
||||||
|
|
|
@ -257,14 +257,16 @@ void platform::capture_mouse(const bool capture) {
|
||||||
SDL_CaptureMouse((SDL_bool)capture);
|
SDL_CaptureMouse((SDL_bool)capture);
|
||||||
}
|
}
|
||||||
|
|
||||||
void platform::open_dialog(const bool existing, std::function<void(std::string)> returnFunction, bool openDirectory) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void platform::save_dialog(std::function<void(std::string)> returnFunction) {
|
|
||||||
}
|
|
||||||
|
|
||||||
char* platform::translate_keycode(const unsigned int keycode) {
|
char* platform::translate_keycode(const unsigned int keycode) {
|
||||||
return const_cast<char*>(SDL_GetKeyName(keycode));
|
return const_cast<char*>(SDL_GetKeyName(SDL_GetKeyFromScancode((SDL_Scancode)keycode)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void platform::begin_text_input() {
|
||||||
|
SDL_StartTextInput();
|
||||||
|
}
|
||||||
|
|
||||||
|
void platform::end_text_input() {
|
||||||
|
SDL_StopTextInput();
|
||||||
}
|
}
|
||||||
|
|
||||||
void platform::mute_output() {}
|
void platform::mute_output() {}
|
||||||
|
@ -320,7 +322,13 @@ int main(int argc, char* argv[]) {
|
||||||
engine->process_key_down(event.key.keysym.scancode);
|
engine->process_key_down(event.key.keysym.scancode);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case SDL_KEYUP:
|
||||||
|
{
|
||||||
|
engine->process_key_up(event.key.keysym.scancode);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case SDL_WINDOWEVENT:
|
case SDL_WINDOWEVENT:
|
||||||
|
{
|
||||||
if (event.window.event == SDL_WINDOWEVENT_RESIZED) {
|
if (event.window.event == SDL_WINDOWEVENT_RESIZED) {
|
||||||
auto window = get_window_by_sdl_id(event.window.windowID);
|
auto window = get_window_by_sdl_id(event.window.windowID);
|
||||||
if(window != nullptr)
|
if(window != nullptr)
|
||||||
|
@ -328,7 +336,13 @@ int main(int argc, char* argv[]) {
|
||||||
} else if(event.window.event == SDL_WINDOWEVENT_CLOSE) {
|
} else if(event.window.event == SDL_WINDOWEVENT_CLOSE) {
|
||||||
engine->quit();
|
engine->quit();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
case SDL_TEXTINPUT:
|
||||||
|
{
|
||||||
|
engine->process_text_input(event.text.text);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "asset.hpp"
|
#include "asset.hpp"
|
||||||
#include "scene.hpp"
|
#include "scene.hpp"
|
||||||
#include "renderer.hpp"
|
#include "renderer.hpp"
|
||||||
|
#include "imgui_backend.hpp"
|
||||||
|
|
||||||
class TransformCommand : public Command {
|
class TransformCommand : public Command {
|
||||||
public:
|
public:
|
||||||
|
@ -369,7 +370,7 @@ inline void editPath(const char* label, std::string& path, bool editable = true,
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
|
||||||
if(ImGui::Button("...")) {
|
if(ImGui::Button("...")) {
|
||||||
platform::open_dialog(false, [&path, &on_selected](std::string p) {
|
engine->get_imgui().open_dialog(false, [&path, &on_selected](std::string p) {
|
||||||
path = prism::get_relative_path(prism::domain::app, p).string();
|
path = prism::get_relative_path(prism::domain::app, p).string();
|
||||||
|
|
||||||
if(on_selected != nullptr)
|
if(on_selected != nullptr)
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
#include "gfx.hpp"
|
#include "gfx.hpp"
|
||||||
#include "gfx_commandbuffer.hpp"
|
#include "gfx_commandbuffer.hpp"
|
||||||
#include "imgui_utility.hpp"
|
#include "imgui_utility.hpp"
|
||||||
#include "screen.hpp"
|
|
||||||
#include "console.hpp"
|
#include "console.hpp"
|
||||||
#include "input.hpp"
|
#include "input.hpp"
|
||||||
#include "scenecapture.hpp"
|
#include "scenecapture.hpp"
|
||||||
|
@ -48,11 +47,7 @@ const std::map<ImGuiKey, InputButton> imToPl = {
|
||||||
};
|
};
|
||||||
|
|
||||||
CommonEditor::CommonEditor(std::string id) : id(id) {
|
CommonEditor::CommonEditor(std::string id) : id(id) {
|
||||||
#ifdef PLATFORM_MACOS
|
prism::set_domain_path(prism::domain::app, "{resource_dir}/data");
|
||||||
prism::set_domain_path(prism::domain::app, "../../../data");
|
|
||||||
#else
|
|
||||||
prism::set_domain_path(prism::domain::app, "data");
|
|
||||||
#endif
|
|
||||||
prism::set_domain_path(prism::domain::internal, "{resource_dir}/shaders");
|
prism::set_domain_path(prism::domain::internal, "{resource_dir}/shaders");
|
||||||
|
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
@ -465,20 +460,6 @@ void editRigidbody(Rigidbody& rigidbody) {
|
||||||
ImGui::DragInt("Mass", &rigidbody.mass);
|
ImGui::DragInt("Mass", &rigidbody.mass);
|
||||||
}
|
}
|
||||||
|
|
||||||
void editUI(UI& ui) {
|
|
||||||
ImGui::DragInt("Width", &ui.width);
|
|
||||||
ImGui::DragInt("Height", &ui.height);
|
|
||||||
ImGui::InputText("Path", &ui.ui_path);
|
|
||||||
|
|
||||||
if(ImGui::Button("Reload")) {
|
|
||||||
ui.screen = engine->load_screen(prism::app_domain / ui.ui_path);
|
|
||||||
engine->get_renderer()->init_screen(ui.screen);
|
|
||||||
ui.screen->extent.width = ui.width;
|
|
||||||
ui.screen->extent.height = ui.height;
|
|
||||||
ui.screen->calculate_sizes();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void editProbe(EnvironmentProbe& probe) {
|
void editProbe(EnvironmentProbe& probe) {
|
||||||
ImGui::Checkbox("Is Sized", &probe.is_sized);
|
ImGui::Checkbox("Is Sized", &probe.is_sized);
|
||||||
if(probe.is_sized)
|
if(probe.is_sized)
|
||||||
|
@ -614,11 +595,6 @@ void CommonEditor::drawPropertyEditor() {
|
||||||
ImGui::CloseCurrentPopup();
|
ImGui::CloseCurrentPopup();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ImGui::Selectable("UI")) {
|
|
||||||
scene->add<UI>(selected_object);
|
|
||||||
ImGui::CloseCurrentPopup();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(ImGui::Selectable("Environment Probe")) {
|
if(ImGui::Selectable("Environment Probe")) {
|
||||||
scene->add<EnvironmentProbe>(selected_object);
|
scene->add<EnvironmentProbe>(selected_object);
|
||||||
ImGui::CloseCurrentPopup();
|
ImGui::CloseCurrentPopup();
|
||||||
|
@ -644,10 +620,7 @@ void CommonEditor::drawPropertyEditor() {
|
||||||
|
|
||||||
if(componentHeader<Rigidbody>(*scene, selected_object, "Rigidbody"))
|
if(componentHeader<Rigidbody>(*scene, selected_object, "Rigidbody"))
|
||||||
editRigidbody(scene->get<Rigidbody>(selected_object));
|
editRigidbody(scene->get<Rigidbody>(selected_object));
|
||||||
|
|
||||||
if(componentHeader<UI>(*scene, selected_object, "UI"))
|
|
||||||
editUI(scene->get<UI>(selected_object));
|
|
||||||
|
|
||||||
if(componentHeader<EnvironmentProbe>(*scene, selected_object, "Environment Probe"))
|
if(componentHeader<EnvironmentProbe>(*scene, selected_object, "Environment Probe"))
|
||||||
editProbe(scene->get<EnvironmentProbe>(selected_object));
|
editProbe(scene->get<EnvironmentProbe>(selected_object));
|
||||||
}
|
}
|
||||||
|
@ -732,7 +705,7 @@ void CommonEditor::set_undo_stack(UndoStack *stack) {
|
||||||
bool mesh_readable(const prism::path path) {
|
bool mesh_readable(const prism::path path) {
|
||||||
auto file = prism::open_file(path);
|
auto file = prism::open_file(path);
|
||||||
if(!file.has_value()) {
|
if(!file.has_value()) {
|
||||||
prism::log::error(System::Renderer, "Failed to load mesh from {}!", path);
|
prism::log("Failed to load mesh from {}!", path.string());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -745,7 +718,7 @@ bool mesh_readable(const prism::path path) {
|
||||||
bool material_readable(const prism::path path) {
|
bool material_readable(const prism::path path) {
|
||||||
auto file = prism::open_file(path);
|
auto file = prism::open_file(path);
|
||||||
if(!file.has_value()) {
|
if(!file.has_value()) {
|
||||||
prism::log::error(System::Core, "Failed to load material from {}!", path);
|
prism::log("Failed to load material from {}!", path.string());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -759,6 +732,9 @@ void cacheAssetFilesystem() {
|
||||||
asset_files.clear();
|
asset_files.clear();
|
||||||
|
|
||||||
auto data_directory = "data";
|
auto data_directory = "data";
|
||||||
|
if(!std::filesystem::exists(data_directory))
|
||||||
|
return;
|
||||||
|
|
||||||
for(auto& p : std::filesystem::recursive_directory_iterator(data_directory)) {
|
for(auto& p : std::filesystem::recursive_directory_iterator(data_directory)) {
|
||||||
if(p.path().extension() == ".model" && mesh_readable(p.path())) {
|
if(p.path().extension() == ".model" && mesh_readable(p.path())) {
|
||||||
asset_files[std::filesystem::relative(p, data_directory)] = AssetType::Mesh;
|
asset_files[std::filesystem::relative(p, data_directory)] = AssetType::Mesh;
|
||||||
|
@ -1045,9 +1021,11 @@ void CommonEditor::drawConsole() {
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::BeginChild("console_output", ImVec2(-1, -1), true);
|
ImGui::BeginChild("console_output", ImVec2(-1, -1), true);
|
||||||
|
|
||||||
for(const auto& message : prism::log::stored_output)
|
// TODO: implement for new log system
|
||||||
ImGui::TextWrapped("%s", message.c_str());
|
//for(const auto& message : prism::log::stored_output)
|
||||||
|
// ImGui::TextWrapped("%s", message.c_str());
|
||||||
|
ImGui::Text("unimplemented :-(");
|
||||||
|
|
||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
}
|
}
|
||||||
|
@ -1123,7 +1101,7 @@ void CommonEditor::save_thumbnail_cache() {
|
||||||
|
|
||||||
FILE* file = fopen("thumbnail-cache", "wb");
|
FILE* file = fopen("thumbnail-cache", "wb");
|
||||||
if(file == nullptr) {
|
if(file == nullptr) {
|
||||||
prism::log::error(System::Core, "Failed to write thumbnail cache!");
|
prism::log("Failed to write thumbnail cache!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,13 +2,11 @@ set(SRC
|
||||||
include/prismeditor.hpp
|
include/prismeditor.hpp
|
||||||
include/materialeditor.hpp
|
include/materialeditor.hpp
|
||||||
include/sceneeditor.hpp
|
include/sceneeditor.hpp
|
||||||
include/uieditor.hpp
|
|
||||||
include/prefabeditor.hpp
|
include/prefabeditor.hpp
|
||||||
|
|
||||||
src/prismeditor.cpp
|
src/prismeditor.cpp
|
||||||
src/materialeditor.cpp
|
src/materialeditor.cpp
|
||||||
src/sceneeditor.cpp
|
src/sceneeditor.cpp
|
||||||
src/uieditor.cpp
|
|
||||||
src/prefabeditor.cpp)
|
src/prefabeditor.cpp)
|
||||||
|
|
||||||
add_platform_executable(
|
add_platform_executable(
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "prismeditor.hpp"
|
|
||||||
|
|
||||||
#include "screen.hpp"
|
|
||||||
|
|
||||||
class UIEditor : public Editor {
|
|
||||||
public:
|
|
||||||
UIEditor();
|
|
||||||
|
|
||||||
ui::Screen* screen = nullptr;
|
|
||||||
UIElement* current_element = nullptr;
|
|
||||||
|
|
||||||
bool has_menubar() const override;
|
|
||||||
std::string get_title() const override;
|
|
||||||
|
|
||||||
Scene* get_scene() const override;
|
|
||||||
|
|
||||||
void setup_windows(ImGuiID dockspace) override;
|
|
||||||
|
|
||||||
void edit_metric(const char* label, UIElement::Metrics::Metric* metric);
|
|
||||||
std::string save_metric(UIElement::Metrics::Metric metric);
|
|
||||||
|
|
||||||
void save(std::string path);
|
|
||||||
|
|
||||||
void draw(CommonEditor* editor) override;
|
|
||||||
};
|
|
|
@ -131,7 +131,7 @@ void MaterialEditor::draw(CommonEditor* editor) {
|
||||||
if (ImGui::BeginMenu("File")) {
|
if (ImGui::BeginMenu("File")) {
|
||||||
if(ImGui::MenuItem("Save", "CTRL+S")) {
|
if(ImGui::MenuItem("Save", "CTRL+S")) {
|
||||||
if (path.empty()) {
|
if (path.empty()) {
|
||||||
platform::save_dialog([this](std::string path) {
|
engine->get_imgui().save_dialog([this](std::string path) {
|
||||||
this->path = path;
|
this->path = path;
|
||||||
|
|
||||||
save_material(*material, path);
|
save_material(*material, path);
|
||||||
|
@ -142,7 +142,7 @@ void MaterialEditor::draw(CommonEditor* editor) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui::MenuItem("Save as...", "CTRL+S")) {
|
if (ImGui::MenuItem("Save as...", "CTRL+S")) {
|
||||||
platform::save_dialog([this](std::string path) {
|
engine->get_imgui().save_dialog([this](std::string path) {
|
||||||
this->path = path;
|
this->path = path;
|
||||||
|
|
||||||
save_material(*material, path);
|
save_material(*material, path);
|
||||||
|
|
|
@ -36,7 +36,7 @@ void PrefabEditor::draw(CommonEditor* editor) {
|
||||||
if (ImGui::BeginMenu("File")) {
|
if (ImGui::BeginMenu("File")) {
|
||||||
if(ImGui::MenuItem("Save", "CTRL+S")) {
|
if(ImGui::MenuItem("Save", "CTRL+S")) {
|
||||||
if (path.empty()) {
|
if (path.empty()) {
|
||||||
platform::save_dialog([this](std::string path) {
|
engine->get_imgui().save_dialog([this](std::string path) {
|
||||||
this->path = path;
|
this->path = path;
|
||||||
|
|
||||||
engine->save_prefab(root_object, path);
|
engine->save_prefab(root_object, path);
|
||||||
|
@ -47,7 +47,7 @@ void PrefabEditor::draw(CommonEditor* editor) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui::MenuItem("Save as...", "CTRL+S")) {
|
if (ImGui::MenuItem("Save as...", "CTRL+S")) {
|
||||||
platform::save_dialog([this](std::string path) {
|
engine->get_imgui().save_dialog([this](std::string path) {
|
||||||
this->path = path;
|
this->path = path;
|
||||||
|
|
||||||
engine->save_prefab(root_object, path);
|
engine->save_prefab(root_object, path);
|
||||||
|
|
|
@ -11,11 +11,9 @@
|
||||||
#include "json_conversions.hpp"
|
#include "json_conversions.hpp"
|
||||||
#include "platform.hpp"
|
#include "platform.hpp"
|
||||||
#include "string_utils.hpp"
|
#include "string_utils.hpp"
|
||||||
#include "screen.hpp"
|
|
||||||
#include "sceneeditor.hpp"
|
#include "sceneeditor.hpp"
|
||||||
#include "materialeditor.hpp"
|
#include "materialeditor.hpp"
|
||||||
#include "prefabeditor.hpp"
|
#include "prefabeditor.hpp"
|
||||||
#include "uieditor.hpp"
|
|
||||||
#include "log.hpp"
|
#include "log.hpp"
|
||||||
|
|
||||||
std::string get_filename(const std::string path) {
|
std::string get_filename(const std::string path) {
|
||||||
|
@ -164,15 +162,6 @@ void PrismEditor::open_asset(const prism::path path) {
|
||||||
|
|
||||||
editor->scene = engine->get_scene();
|
editor->scene = engine->get_scene();
|
||||||
|
|
||||||
editors.push_back(editor);
|
|
||||||
} else if(path.extension() == ".json") {
|
|
||||||
UIEditor* editor = new UIEditor();
|
|
||||||
editor->path = path.string();
|
|
||||||
setup_editor(editor);
|
|
||||||
|
|
||||||
editor->screen = engine->load_screen(path);
|
|
||||||
editor->screen->calculate_sizes();
|
|
||||||
|
|
||||||
editors.push_back(editor);
|
editors.push_back(editor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -233,19 +222,11 @@ void PrismEditor::drawUI() {
|
||||||
editors.push_back(editor);
|
editors.push_back(editor);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ImGui::MenuItem("UI")) {
|
|
||||||
UIEditor* editor = new UIEditor();
|
|
||||||
editor->modified = true;
|
|
||||||
setup_editor(editor);
|
|
||||||
|
|
||||||
editors.push_back(editor);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ImGui::MenuItem("Open", "CTRL+O")) {
|
if(ImGui::MenuItem("Open", "CTRL+O")) {
|
||||||
platform::open_dialog(true, [this](std::string path) {
|
engine->get_imgui().open_dialog(true, [this](std::string path) {
|
||||||
open_requests.emplace_back(path, false);
|
open_requests.emplace_back(path, false);
|
||||||
|
|
||||||
addOpenedFile(path);
|
addOpenedFile(path);
|
||||||
|
|
|
@ -44,7 +44,7 @@ void SceneEditor::draw(CommonEditor* editor) {
|
||||||
if (ImGui::BeginMenu("File")) {
|
if (ImGui::BeginMenu("File")) {
|
||||||
if(ImGui::MenuItem("Save", "CTRL+S")) {
|
if(ImGui::MenuItem("Save", "CTRL+S")) {
|
||||||
if (path.empty()) {
|
if (path.empty()) {
|
||||||
platform::save_dialog([this](std::string path) {
|
engine->get_imgui().save_dialog([this](std::string path) {
|
||||||
this->path = path;
|
this->path = path;
|
||||||
|
|
||||||
engine->save_scene(path);
|
engine->save_scene(path);
|
||||||
|
@ -55,7 +55,7 @@ void SceneEditor::draw(CommonEditor* editor) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ImGui::MenuItem("Save as...", "CTRL+S")) {
|
if(ImGui::MenuItem("Save as...", "CTRL+S")) {
|
||||||
platform::save_dialog([this](std::string path) {
|
engine->get_imgui().save_dialog([this](std::string path) {
|
||||||
this->path = path;
|
this->path = path;
|
||||||
|
|
||||||
engine->save_scene(path);
|
engine->save_scene(path);
|
||||||
|
@ -107,7 +107,7 @@ void SceneEditor::draw(CommonEditor* editor) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ImGui::MenuItem("Prefab")) {
|
if(ImGui::MenuItem("Prefab")) {
|
||||||
platform::open_dialog(false, [](std::string path) {
|
engine->get_imgui().open_dialog(false, [](std::string path) {
|
||||||
engine->add_prefab(*engine->get_scene(), path);
|
engine->add_prefab(*engine->get_scene(), path);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,218 +0,0 @@
|
||||||
#include "uieditor.hpp"
|
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
#include <imgui.h>
|
|
||||||
#include <imgui_stdlib.h>
|
|
||||||
#include <imgui_internal.h>
|
|
||||||
|
|
||||||
#include "engine.hpp"
|
|
||||||
#include "imgui_utility.hpp"
|
|
||||||
|
|
||||||
UIEditor::UIEditor() : Editor() {
|
|
||||||
screen = new ui::Screen();
|
|
||||||
screen->extent.width = 1280;
|
|
||||||
screen->extent.height = 720;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool UIEditor::has_menubar() const {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string UIEditor::get_title() const {
|
|
||||||
return path.empty() ? "New UI" : get_filename(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
Scene* UIEditor::get_scene() const {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UIEditor::setup_windows(ImGuiID dockspace) {
|
|
||||||
ImGuiID dock_main_id = dockspace;
|
|
||||||
|
|
||||||
ImGuiID dock_id_left, dock_id_right;
|
|
||||||
ImGui::DockBuilderSplitNode(dock_main_id, ImGuiDir_Left, 0.60f, &dock_id_left, &dock_id_right);
|
|
||||||
|
|
||||||
ImGui::DockBuilderDockWindow(get_window_name("Properties").c_str(), dock_id_right);
|
|
||||||
|
|
||||||
ImGui::DockBuilderSplitNode(dock_id_left, ImGuiDir_Left, 0.30f, &dock_id_left, &dock_id_right);
|
|
||||||
ImGui::DockBuilderDockWindow(get_window_name("Outliner").c_str(), dock_id_left);
|
|
||||||
ImGui::DockBuilderDockWindow(get_window_name("Preview").c_str(), dock_id_right);
|
|
||||||
}
|
|
||||||
|
|
||||||
void UIEditor::edit_metric(const char* label, UIElement::Metrics::Metric* metric) {
|
|
||||||
if(ImGui::DragInt(label, &metric->value, 1.0f, 0, 0, metric->type == MetricType::Absolute ? "%d" : "%d%%"))
|
|
||||||
screen->calculate_sizes();
|
|
||||||
|
|
||||||
ImGui::SameLine();
|
|
||||||
|
|
||||||
ImGui::PushID(label);
|
|
||||||
|
|
||||||
if(ImGui::ComboEnum("T", &metric->type))
|
|
||||||
screen->calculate_sizes();
|
|
||||||
|
|
||||||
ImGui::PopID();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string UIEditor::save_metric(UIElement::Metrics::Metric metric) {
|
|
||||||
return std::to_string(metric.value) + (metric.type == MetricType::Absolute ? "px" : "%");
|
|
||||||
}
|
|
||||||
|
|
||||||
void UIEditor::save(std::string path) {
|
|
||||||
nlohmann::json j;
|
|
||||||
|
|
||||||
for (auto& element : screen->elements) {
|
|
||||||
nlohmann::json e;
|
|
||||||
e["id"] = element.id;
|
|
||||||
e["text"] = element.text;
|
|
||||||
e["visible"] = element.visible;
|
|
||||||
e["wrapText"] = element.wrap_text;
|
|
||||||
|
|
||||||
nlohmann::json m;
|
|
||||||
m["x"] = save_metric(element.metrics.x);
|
|
||||||
m["y"] = save_metric(element.metrics.y);
|
|
||||||
m["width"] = save_metric(element.metrics.width);
|
|
||||||
m["height"] = save_metric(element.metrics.height);
|
|
||||||
|
|
||||||
e["metrics"] = m;
|
|
||||||
|
|
||||||
if(element.text_location == UIElement::TextLocation::Center) {
|
|
||||||
e["textLocation"] = "center";
|
|
||||||
} else {
|
|
||||||
e["textLocation"] = "topLeft";
|
|
||||||
}
|
|
||||||
|
|
||||||
j["elements"].push_back(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ofstream out(path);
|
|
||||||
out << std::setw(4) << j;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UIEditor::draw(CommonEditor*) {
|
|
||||||
if (ImGui::BeginMenuBar()) {
|
|
||||||
if (ImGui::BeginMenu("File")) {
|
|
||||||
if(ImGui::MenuItem("Save", "CTRL+S")) {
|
|
||||||
if (path.empty()) {
|
|
||||||
platform::save_dialog([this](std::string path) {
|
|
||||||
this->path = path;
|
|
||||||
|
|
||||||
save(path);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
save(path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui::MenuItem("Save as...", "CTRL+S")) {
|
|
||||||
platform::save_dialog([this](std::string path) {
|
|
||||||
this->path = path;
|
|
||||||
|
|
||||||
save(path);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::Separator();
|
|
||||||
|
|
||||||
if(ImGui::MenuItem("Close"))
|
|
||||||
wants_to_close = true;
|
|
||||||
|
|
||||||
ImGui::EndMenu();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::EndMenuBar();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(begin("Outliner")) {
|
|
||||||
if(ImGui::Button("Add Element")) {
|
|
||||||
screen->elements.push_back(UIElement());
|
|
||||||
current_element = &screen->elements.back();
|
|
||||||
}
|
|
||||||
|
|
||||||
for(auto& element : screen->elements) {
|
|
||||||
if(ImGui::Selectable(element.id.c_str()))
|
|
||||||
current_element = &element;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::End();
|
|
||||||
|
|
||||||
if(begin("Properties")) {
|
|
||||||
if(current_element != nullptr) {
|
|
||||||
ImGui::InputText("ID", ¤t_element->id);
|
|
||||||
|
|
||||||
edit_metric("X", ¤t_element->metrics.x);
|
|
||||||
edit_metric("Y", ¤t_element->metrics.y);
|
|
||||||
edit_metric("Width", ¤t_element->metrics.width);
|
|
||||||
edit_metric("Height", ¤t_element->metrics.height);
|
|
||||||
|
|
||||||
ImGui::InputText("Text", ¤t_element->text);
|
|
||||||
|
|
||||||
ImGui::ColorEdit4("Background color", current_element->background.color.v);
|
|
||||||
|
|
||||||
ImGui::Checkbox("Visible", ¤t_element->visible);
|
|
||||||
ImGui::Checkbox("Wrap text", ¤t_element->wrap_text);
|
|
||||||
|
|
||||||
bool setCenter = current_element->text_location == UIElement::TextLocation::Center;
|
|
||||||
ImGui::Checkbox("Center Text", &setCenter);
|
|
||||||
|
|
||||||
current_element->text_location = setCenter ? UIElement::TextLocation::Center : UIElement::TextLocation::TopLeft;
|
|
||||||
|
|
||||||
if(ImGui::Button("Delete")) {
|
|
||||||
utility::erase(screen->elements, *current_element);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(ImGui::Button("Duplicate")) {
|
|
||||||
UIElement element = *current_element;
|
|
||||||
element.id += " (duplicate)";
|
|
||||||
|
|
||||||
screen->elements.push_back(element);
|
|
||||||
current_element = &screen->elements.back();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::End();
|
|
||||||
|
|
||||||
if(begin("Preview")) {
|
|
||||||
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
|
||||||
|
|
||||||
static int width = 1280, height = 720;
|
|
||||||
static int scale = 3;
|
|
||||||
|
|
||||||
bool c = ImGui::InputInt("Width", &width);
|
|
||||||
c |= ImGui::InputInt("Height", &height);
|
|
||||||
c |= ImGui::InputInt("Scale", &scale);
|
|
||||||
|
|
||||||
if(c) {
|
|
||||||
screen->extent.width = width;
|
|
||||||
screen->extent.height = height;
|
|
||||||
screen->calculate_sizes();
|
|
||||||
}
|
|
||||||
|
|
||||||
const ImVec2 p = ImGui::GetCursorScreenPos();
|
|
||||||
|
|
||||||
draw_list->AddRect(ImVec2(p.x, p.y), ImVec2(p.x + (width / scale), p.y + (height / scale)), IM_COL32_WHITE);
|
|
||||||
|
|
||||||
for(auto& element : screen->elements) {
|
|
||||||
if(element.absolute_width > 0 && element.absolute_height > 0) {
|
|
||||||
draw_list->AddRect(
|
|
||||||
ImVec2(p.x + (element.absolute_x / scale), p.y + (element.absolute_y / scale)),
|
|
||||||
ImVec2(p.x + ((element.absolute_x + element.absolute_width) / scale), p.y + ((element.absolute_y + element.absolute_height) / scale)),
|
|
||||||
IM_COL32_WHITE
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!element.text.empty()) {
|
|
||||||
if(element.text_location == UIElement::TextLocation::Center) {
|
|
||||||
auto textSize = ImGui::CalcTextSize(element.text.c_str());
|
|
||||||
|
|
||||||
draw_list->AddText(ImVec2(p.x + (element.absolute_x + (element.absolute_width / 2)) / scale - (textSize.x / 2), p.y + (element.absolute_y + (element.absolute_height / 2)) / scale - (textSize.y / 2)), IM_COL32_WHITE, element.text.c_str());
|
|
||||||
} else {
|
|
||||||
draw_list->AddText(ImVec2(p.x + (element.absolute_x / scale), p.y + (element.absolute_y / scale)), IM_COL32_WHITE, element.text.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::End();
|
|
||||||
}
|
|
|
@ -5,7 +5,6 @@
|
||||||
#include "shadercompiler.hpp"
|
#include "shadercompiler.hpp"
|
||||||
#include "log.hpp"
|
#include "log.hpp"
|
||||||
#include "string_utils.hpp"
|
#include "string_utils.hpp"
|
||||||
#include "file_utils.hpp"
|
|
||||||
|
|
||||||
bool has_extension(const std::filesystem::path path, const std::string_view extension) {
|
bool has_extension(const std::filesystem::path path, const std::string_view extension) {
|
||||||
return string_contains(path.filename().string(), extension);
|
return string_contains(path.filename().string(), extension);
|
||||||
|
@ -13,7 +12,7 @@ bool has_extension(const std::filesystem::path path, const std::string_view exte
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
if(argc < 2) {
|
if(argc < 2) {
|
||||||
prism::log::error(System::Core, "Not enough arguments!");
|
prism::log("Not enough arguments!");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,17 +41,11 @@ int main(int argc, char* argv[]) {
|
||||||
|
|
||||||
ShaderLanguage language;
|
ShaderLanguage language;
|
||||||
CompileOptions options;
|
CompileOptions options;
|
||||||
#ifdef PLATFORM_MACOS
|
|
||||||
options.is_apple_mobile = (bool)argv[3];
|
|
||||||
|
|
||||||
language = ShaderLanguage::MSL;
|
|
||||||
#else
|
|
||||||
language = ShaderLanguage::SPIRV;
|
language = ShaderLanguage::SPIRV;
|
||||||
#endif
|
|
||||||
|
|
||||||
const auto compiled_source = shader_compiler.compile(ShaderLanguage::GLSL, stage, ShaderSource(buffer.str()), language, options);
|
const auto compiled_source = shader_compiler.compile(ShaderLanguage::GLSL, stage, ShaderSource(buffer.str()), language, options);
|
||||||
if(!compiled_source.has_value()) {
|
if(!compiled_source.has_value()) {
|
||||||
prism::log::error(System::Core, "Error when compiling {}!", source_path);
|
prism::log("Error when compiling {}!", source_path.string());
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Reference in a new issue