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)
|
||||
message("macOS build detected!")
|
||||
|
||||
set(ENABLE_METAL TRUE)
|
||||
find_package(SDL2 REQUIRED)
|
||||
|
||||
set(ENABLE_VULKAN TRUE)
|
||||
set(ENABLE_DARWIN TRUE)
|
||||
set(ENABLE_MACOS TRUE)
|
||||
|
||||
|
@ -71,7 +73,9 @@ set(CROSS_LIBS
|
|||
add_subdirectory(extern)
|
||||
|
||||
# enable lto
|
||||
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
|
||||
if (CMAKE_BUILD_TYPE EQUAL "Release")
|
||||
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
|
||||
endif ()
|
||||
|
||||
add_subdirectory(platforms)
|
||||
|
||||
|
|
|
@ -1,11 +1,6 @@
|
|||
macro(set_engine_properties target)
|
||||
target_compile_features(${target} PUBLIC cxx_std_17)
|
||||
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)
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,7 @@ std::unique_ptr<Mesh> load_mesh(const prism::path path) {
|
|||
|
||||
if(version == 5 || version == 6) {
|
||||
} 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;
|
||||
}
|
||||
|
||||
|
@ -190,7 +190,7 @@ std::unique_ptr<Texture> load_texture(const prism::path path) {
|
|||
|
||||
auto file = prism::open_file(path, true);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -202,7 +202,7 @@ std::unique_ptr<Texture> load_texture(const prism::path path) {
|
|||
int width, height, channels;
|
||||
unsigned char* data = stbi_load_from_memory(file->cast_data<unsigned char>(), file->size(), &width, &height, &channels, 4);
|
||||
if(!data) {
|
||||
prism::log::error(System::Renderer, "Failed to load texture from {}!", path);
|
||||
prism::log("Failed to load texture from {}!", path.string());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -247,7 +247,7 @@ std::unique_ptr<Material> load_material(const prism::path path) {
|
|||
|
||||
auto file = prism::open_file(path);
|
||||
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 {};
|
||||
}
|
||||
|
||||
|
@ -258,7 +258,7 @@ std::unique_ptr<Material> load_material(const prism::path path) {
|
|||
mat->path = path.string();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,8 +6,6 @@ set(SRC
|
|||
include/physics.hpp
|
||||
include/scene.hpp
|
||||
include/imgui_backend.hpp
|
||||
include/uielement.hpp
|
||||
include/screen.hpp
|
||||
include/object.hpp
|
||||
include/debug.hpp
|
||||
include/components.hpp
|
||||
|
@ -19,7 +17,6 @@ set(SRC
|
|||
src/input.cpp
|
||||
src/physics.cpp
|
||||
src/imgui_backend.cpp
|
||||
src/screen.cpp
|
||||
src/scene.cpp
|
||||
src/debug.cpp
|
||||
src/console.cpp)
|
||||
|
|
|
@ -103,17 +103,6 @@ struct Camera {
|
|||
Matrix4x4 view, perspective;
|
||||
};
|
||||
|
||||
namespace ui {
|
||||
class Screen;
|
||||
}
|
||||
|
||||
struct UI {
|
||||
int width = 1920, height = 1080;
|
||||
|
||||
std::string ui_path;
|
||||
ui::Screen* screen = nullptr;
|
||||
};
|
||||
|
||||
struct EnvironmentProbe {
|
||||
bool is_sized = true;
|
||||
prism::float3 size = prism::float3(10);
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <string_view>
|
||||
|
||||
void draw_console();
|
||||
void draw_debug_ui();
|
||||
|
||||
void load_debug_options();
|
||||
|
|
|
@ -10,11 +10,6 @@
|
|||
#include "path.hpp"
|
||||
|
||||
class GFX;
|
||||
|
||||
namespace ui {
|
||||
class Screen;
|
||||
}
|
||||
|
||||
class Scene;
|
||||
class RenderTarget;
|
||||
class Physics;
|
||||
|
@ -141,22 +136,6 @@ namespace prism {
|
|||
*/
|
||||
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.
|
||||
@param scene The scene to add the prefab to.
|
||||
@param path The prefab file path.
|
||||
|
@ -231,30 +210,11 @@ namespace prism {
|
|||
*/
|
||||
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.
|
||||
@param data Data for the event. Defaulted to an empty string.
|
||||
/**
|
||||
* Called when text has been inputted. This is only emitted when text input is enabled thru input system
|
||||
* @param string
|
||||
*/
|
||||
void push_event(std::string_view name, std::string_view data = "");
|
||||
|
||||
/** 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);
|
||||
void process_text_input(const std::string_view string);
|
||||
|
||||
/** Adds a timer to the list of timers.
|
||||
@param timer The timer to add.
|
||||
|
@ -288,6 +248,10 @@ namespace prism {
|
|||
*/
|
||||
void update_scene(Scene& scene);
|
||||
|
||||
imgui_backend& get_imgui() {
|
||||
return *imgui;
|
||||
}
|
||||
|
||||
/// The current cutscene.
|
||||
std::unique_ptr<Cutscene> cutscene;
|
||||
|
||||
|
@ -328,6 +292,8 @@ namespace prism {
|
|||
bool debug_enabled = false;
|
||||
#endif
|
||||
|
||||
bool console_enabled = true;
|
||||
|
||||
private:
|
||||
void setup_scene(Scene& scene);
|
||||
|
||||
|
@ -335,8 +301,6 @@ namespace prism {
|
|||
|
||||
bool paused = false;
|
||||
|
||||
ui::Screen* current_screen = nullptr;
|
||||
|
||||
Scene* current_scene = nullptr;
|
||||
std::vector<std::unique_ptr<Scene>> scenes;
|
||||
std::map<std::string, Scene*> path_to_scene;
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include <string_view>
|
||||
#include <filesystem>
|
||||
|
||||
namespace prism {
|
||||
class imgui_backend {
|
||||
public:
|
||||
|
@ -14,7 +17,33 @@ namespace prism {
|
|||
void process_key_down(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:
|
||||
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::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||
ImGui::Text(label);
|
||||
ImGui::Text("%s", label);
|
||||
}
|
||||
|
||||
inline bool DragQuat(const char* label, Quaternion* quat) {
|
||||
|
|
|
@ -81,8 +81,16 @@ namespace prism {
|
|||
/// Returns all of the bindings registered with this Input system.
|
||||
[[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:
|
||||
std::vector<input_binding> _input_bindings;
|
||||
std::tuple<int, int> _last_cursor_position;
|
||||
|
||||
bool _in_text_input = false;
|
||||
};
|
||||
}
|
|
@ -201,7 +201,7 @@ class GFXFramebuffer;
|
|||
class GFXTexture;
|
||||
|
||||
/// 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:
|
||||
/// If loaded from disk, the path to the scene file this originated from.
|
||||
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;
|
||||
|
||||
if(invalid_format) {
|
||||
prism::log::info(System::Core, "Invalid command format!");
|
||||
prism::log("Invalid command format!");
|
||||
} else {
|
||||
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;
|
||||
|
||||
if(invalid_format) {
|
||||
prism::log::info(System::Core, "Wrong or empty variable type!");
|
||||
prism::log("Wrong or empty variable type!");
|
||||
} else {
|
||||
auto argument = arguments[0];
|
||||
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) {
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
#include "scene.hpp"
|
||||
#include "renderer.hpp"
|
||||
#include "file.hpp"
|
||||
#include "console.hpp"
|
||||
#include "imgui_backend.hpp"
|
||||
|
||||
struct Options {
|
||||
std::string shader_source_path;
|
||||
|
@ -168,7 +170,7 @@ void draw_shader_editor() {
|
|||
if(options.shader_source_path.empty()) {
|
||||
ImGui::Text("You haven't specified a shader source path yet. Please select one below:");
|
||||
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
|
||||
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() {
|
||||
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 "app.hpp"
|
||||
#include "assertions.hpp"
|
||||
#include "screen.hpp"
|
||||
#include "renderer.hpp"
|
||||
#include "gfx.hpp"
|
||||
#include "imgui_backend.hpp"
|
||||
|
@ -27,10 +26,10 @@
|
|||
using prism::engine;
|
||||
|
||||
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&) {
|
||||
log::info(System::Core, "Test cmd!");
|
||||
log("Test cmd!");
|
||||
});
|
||||
|
||||
console::register_variable("rs_dynamic_resolution", render_options.dynamic_resolution);
|
||||
|
@ -60,26 +59,12 @@ prism::app* engine::get_app() const {
|
|||
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() {
|
||||
paused = true;
|
||||
push_event("engine_pause");
|
||||
}
|
||||
|
||||
void engine::unpause() {
|
||||
paused = false;
|
||||
push_event("engine_unpause");
|
||||
}
|
||||
|
||||
bool engine::is_paused() const {
|
||||
|
@ -94,6 +79,8 @@ void engine::quit() {
|
|||
bool engine::is_quitting() const {
|
||||
if(!windows.empty())
|
||||
return windows[0]->quit_requested;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void engine::prepare_quit() {
|
||||
|
@ -136,7 +123,7 @@ Scene* engine::load_scene(const prism::path& path) {
|
|||
|
||||
auto file = prism::open_file(path);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -191,25 +178,6 @@ void engine::save_scene(const std::string_view path) {
|
|||
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 animation;
|
||||
|
||||
|
@ -229,7 +197,7 @@ Animation engine::load_animation(const prism::path& path) {
|
|||
|
||||
auto file = prism::open_file(path, true);
|
||||
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 {};
|
||||
}
|
||||
|
||||
|
@ -289,7 +257,7 @@ void engine::load_cutscene(const prism::path& path) {
|
|||
|
||||
auto file = prism::open_file(path);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -364,7 +332,7 @@ Object engine::add_prefab(Scene& scene, const prism::path& path, const std::stri
|
|||
|
||||
auto file = prism::open_file(path);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -452,22 +420,21 @@ void engine::resize(const int identifier, const prism::Extent extent) {
|
|||
|
||||
gfx->recreate_view(identifier, drawable_extent.width, drawable_extent.height);
|
||||
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) {
|
||||
Expects(keyCode >= 0);
|
||||
|
||||
|
||||
if(input->is_text_input() && !input->get_allowable_text_button(keyCode))
|
||||
return;
|
||||
|
||||
imgui->process_key_down(keyCode);
|
||||
|
||||
if(keyCode == platform::get_keycode(debug_button) && !ImGui::GetIO().WantTextInput)
|
||||
debug_enabled = !debug_enabled;
|
||||
|
||||
if(keyCode == platform::get_keycode(InputButton::C))
|
||||
console_enabled = !console_enabled;
|
||||
}
|
||||
|
||||
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) {
|
||||
if(current_screen != nullptr && button == 0)
|
||||
current_screen->process_mouse(offset.x, offset.y);
|
||||
|
||||
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) {
|
||||
if(part.offset_matrices.empty())
|
||||
return;
|
||||
|
@ -665,6 +610,9 @@ void engine::begin_frame(const float delta_time) {
|
|||
if(debug_enabled)
|
||||
draw_debug_ui();
|
||||
|
||||
if(console_enabled)
|
||||
draw_console();
|
||||
|
||||
if(app != nullptr)
|
||||
app->begin_frame();
|
||||
}
|
||||
|
@ -767,11 +715,6 @@ void engine::render(const int index) {
|
|||
GFXCommandBuffer* commandbuffer = gfx->acquire_command_buffer(true);
|
||||
|
||||
if(index == 0) {
|
||||
if(current_screen != nullptr && current_screen->view_changed) {
|
||||
renderer->update_screen();
|
||||
current_screen->view_changed = false;
|
||||
}
|
||||
|
||||
imgui->render(0);
|
||||
|
||||
app->render(commandbuffer);
|
||||
|
@ -864,3 +807,7 @@ void engine::setup_scene(Scene& scene) {
|
|||
scene.reset_shadows();
|
||||
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();
|
||||
FILE* file = fopen(str.c_str(), binary_mode ? "rb" : "r");
|
||||
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 {};
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "engine.hpp"
|
||||
#include "platform.hpp"
|
||||
#include "assertions.hpp"
|
||||
#include "input.hpp"
|
||||
|
||||
using prism::imgui_backend;
|
||||
|
||||
|
@ -159,6 +160,17 @@ imgui_backend::imgui_backend() {
|
|||
|
||||
void imgui_backend::begin_frame(const float delta_time) {
|
||||
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 [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;
|
||||
|
||||
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) {
|
||||
|
@ -205,10 +261,9 @@ void imgui_backend::render(int index) {
|
|||
|
||||
void imgui_backend::process_key_down(unsigned int key_code) {
|
||||
Expects(key_code >= 0);
|
||||
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.AddInputCharactersUTF8(platform::translate_keycode(key_code));
|
||||
|
||||
|
||||
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) {
|
||||
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 {
|
||||
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"];
|
||||
}
|
||||
|
||||
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) {
|
||||
if(j.contains("size"))
|
||||
probe.size = j["size"];
|
||||
|
@ -104,9 +98,6 @@ Object load_object(Scene& scene, const nlohmann::json obj) {
|
|||
|
||||
if(obj.contains("rigidbody"))
|
||||
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"))
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
j["size"] = probe.size;
|
||||
j["is_sized"] = probe.is_sized;
|
||||
|
@ -198,10 +183,7 @@ nlohmann::json save_object(Object obj) {
|
|||
|
||||
if(scene->has<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))
|
||||
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
|
||||
|
||||
#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 <map>
|
||||
|
@ -18,7 +11,6 @@
|
|||
struct NativeSurface {
|
||||
int identifier = -1;
|
||||
|
||||
void* windowNativeHandle;
|
||||
uint32_t surfaceWidth = -1, surfaceHeight = -1;
|
||||
|
||||
std::vector<VkSemaphore> imageAvailableSemaphores;
|
||||
|
@ -43,28 +35,28 @@ class GFXVulkanPipeline;
|
|||
|
||||
class GFXVulkan : public GFX {
|
||||
public:
|
||||
bool is_supported() { return true; }
|
||||
bool is_supported() override { return true; }
|
||||
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;
|
||||
|
||||
bool supports_feature(const GFXFeature feature) override;
|
||||
bool supports_feature(GFXFeature feature) 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 recreate_view(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(int identifier, uint32_t width, uint32_t height) override;
|
||||
|
||||
// buffer operations
|
||||
GFXBuffer* create_buffer(void* data, const GFXSize size, const bool dynamic_data, const GFXBufferUsage usage) override;
|
||||
void copy_buffer(GFXBuffer* buffer, void* data, const GFXSize offset, const GFXSize size) override;
|
||||
GFXBuffer* create_buffer(void* data, GFXSize size, bool dynamic_data, GFXBufferUsage usage) override;
|
||||
void copy_buffer(GFXBuffer* buffer, void* data, GFXSize offset, GFXSize size) override;
|
||||
|
||||
void* get_buffer_contents(GFXBuffer* buffer) override;
|
||||
void release_buffer_contents(GFXBuffer* buffer, void* handle) override;
|
||||
|
||||
// texture operations
|
||||
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, GFXBuffer* to) override;
|
||||
|
||||
|
@ -82,11 +74,11 @@ public:
|
|||
GFXPipeline* create_compute_pipeline(const GFXComputePipelineCreateInfo& info) override;
|
||||
|
||||
// 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:
|
||||
void createInstance(std::vector<const char*> layers, std::vector<const char*> extensions);
|
||||
|
@ -111,7 +103,7 @@ private:
|
|||
VkImageLayout newLayout,
|
||||
VkPipelineStageFlags src_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();
|
||||
void endSingleTimeCommands(VkCommandBuffer commandBuffer);
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
#include <limits>
|
||||
#include <cstddef>
|
||||
#include <array>
|
||||
#include <sstream>
|
||||
|
||||
#include "gfx_vulkan_buffer.hpp"
|
||||
#include "gfx_vulkan_pipeline.hpp"
|
||||
|
@ -20,11 +19,6 @@
|
|||
|
||||
#include <platform.hpp>
|
||||
|
||||
#ifdef PLATFORM_LINUX
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
#endif
|
||||
|
||||
VkFormat toVkFormat(GFXPixelFormat format) {
|
||||
switch (format) {
|
||||
case GFXPixelFormat::R_32F:
|
||||
|
@ -82,6 +76,8 @@ VkFormat toVkFormat(GFXVertexFormat format) {
|
|||
|
||||
VkBlendFactor toVkFactor(GFXBlendFactor factor) {
|
||||
switch (factor) {
|
||||
case GFXBlendFactor::Zero:
|
||||
return VK_BLEND_FACTOR_ZERO;
|
||||
case GFXBlendFactor::One:
|
||||
return VK_BLEND_FACTOR_ONE;
|
||||
case GFXBlendFactor::OneMinusSrcAlpha:
|
||||
|
@ -90,6 +86,12 @@ VkBlendFactor toVkFactor(GFXBlendFactor factor) {
|
|||
return VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR;
|
||||
case GFXBlendFactor::SrcAlpha:
|
||||
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;
|
||||
|
@ -165,14 +167,14 @@ VKAPI_ATTR VkBool32 VKAPI_CALL DebugCallback(
|
|||
const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData,
|
||||
void *pUserData) {
|
||||
|
||||
prism::log::debug(System::GFX, pCallbackData->pMessage);
|
||||
prism::log("{}", pCallbackData->pMessage);
|
||||
|
||||
return VK_FALSE;
|
||||
}
|
||||
|
||||
VkResult name_object(VkDevice device, VkObjectType type, uint64_t object, std::string_view name) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
vkDeviceWaitIdle(device);
|
||||
|
||||
NativeSurface* surface = new NativeSurface();
|
||||
auto surface = new NativeSurface();
|
||||
surface->identifier = identifier;
|
||||
surface->surfaceWidth = width;
|
||||
surface->surfaceHeight = height;
|
||||
surface->windowNativeHandle = native_handle;
|
||||
|
||||
createSwapchain(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) {
|
||||
GFXVulkanBuffer* buffer = new GFXVulkanBuffer();
|
||||
auto buffer = new GFXVulkanBuffer();
|
||||
|
||||
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) {
|
||||
GFXVulkanBuffer* vulkanBuffer = (GFXVulkanBuffer*)buffer;
|
||||
auto vulkanBuffer = (GFXVulkanBuffer*)buffer;
|
||||
|
||||
void* mapped_data = nullptr;
|
||||
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) {
|
||||
GFXVulkanBuffer* vulkanBuffer = (GFXVulkanBuffer*)buffer;
|
||||
auto vulkanBuffer = (GFXVulkanBuffer*)buffer;
|
||||
|
||||
void* 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) {
|
||||
GFXVulkanBuffer* vulkanBuffer = (GFXVulkanBuffer*)buffer;
|
||||
auto vulkanBuffer = (GFXVulkanBuffer*)buffer;
|
||||
|
||||
VkMappedMemoryRange 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) {
|
||||
GFXVulkanTexture* texture = new GFXVulkanTexture();
|
||||
auto texture = new GFXVulkanTexture();
|
||||
|
||||
vkDeviceWaitIdle(device);
|
||||
|
||||
|
@ -514,7 +515,7 @@ GFXTexture* GFXVulkan::create_texture(const GFXTextureCreateInfo& info) {
|
|||
}
|
||||
|
||||
void GFXVulkan::copy_texture(GFXTexture* texture, void* data, GFXSize size) {
|
||||
GFXVulkanTexture* vulkanTexture = (GFXVulkanTexture*)texture;
|
||||
auto vulkanTexture = (GFXVulkanTexture*)texture;
|
||||
|
||||
vkDeviceWaitIdle(device);
|
||||
|
||||
|
@ -579,12 +580,12 @@ void GFXVulkan::copy_texture(GFXTexture* texture, void* data, GFXSize size) {
|
|||
}
|
||||
|
||||
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) {
|
||||
GFXVulkanTexture* vulkanTexture = (GFXVulkanTexture*)from;
|
||||
GFXVulkanBuffer* vulkanBuffer = (GFXVulkanBuffer*)to;
|
||||
auto vulkanTexture = (GFXVulkanTexture*)from;
|
||||
auto vulkanBuffer = (GFXVulkanBuffer*)to;
|
||||
|
||||
VkCommandBuffer commandBuffer = beginSingleTimeCommands();
|
||||
|
||||
|
@ -605,7 +606,7 @@ void GFXVulkan::copy_texture(GFXTexture* from, GFXBuffer* to) {
|
|||
}
|
||||
|
||||
GFXSampler* GFXVulkan::create_sampler(const GFXSamplerCreateInfo& info) {
|
||||
GFXVulkanSampler* sampler = new GFXVulkanSampler();
|
||||
auto sampler = new GFXVulkanSampler();
|
||||
|
||||
const VkSamplerAddressMode samplerMode = toSamplerMode(info.samplingMode);
|
||||
|
||||
|
@ -629,15 +630,15 @@ GFXSampler* GFXVulkan::create_sampler(const GFXSamplerCreateInfo& info) {
|
|||
}
|
||||
|
||||
GFXFramebuffer* GFXVulkan::create_framebuffer(const GFXFramebufferCreateInfo& info) {
|
||||
GFXVulkanFramebuffer* framebuffer = new GFXVulkanFramebuffer();
|
||||
auto framebuffer = new GFXVulkanFramebuffer();
|
||||
|
||||
vkDeviceWaitIdle(device);
|
||||
|
||||
GFXVulkanRenderPass* renderPass = (GFXVulkanRenderPass*)info.render_pass;
|
||||
auto renderPass = (GFXVulkanRenderPass*)info.render_pass;
|
||||
|
||||
std::vector<VkImageView> attachments;
|
||||
for (auto& attachment : info.attachments) {
|
||||
GFXVulkanTexture* texture = (GFXVulkanTexture*)attachment;
|
||||
auto texture = (GFXVulkanTexture*)attachment;
|
||||
attachments.push_back(texture->view);
|
||||
|
||||
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) {
|
||||
GFXVulkanRenderPass* renderPass = new GFXVulkanRenderPass();
|
||||
auto renderPass = new GFXVulkanRenderPass();
|
||||
|
||||
vkDeviceWaitIdle(device);
|
||||
|
||||
|
@ -762,7 +763,7 @@ GFXRenderPass* GFXVulkan::create_render_pass(const GFXRenderPassCreateInfo& info
|
|||
}
|
||||
|
||||
GFXPipeline* GFXVulkan::create_graphics_pipeline(const GFXGraphicsPipelineCreateInfo& info) {
|
||||
GFXVulkanPipeline* pipeline = new GFXVulkanPipeline();
|
||||
auto pipeline = new GFXVulkanPipeline();
|
||||
|
||||
vkDeviceWaitIdle(device);
|
||||
|
||||
|
@ -935,6 +936,8 @@ GFXPipeline* GFXVulkan::create_graphics_pipeline(const GFXGraphicsPipelineCreate
|
|||
case GFXDepthMode::Greater:
|
||||
depthStencil.depthCompareOp = VK_COMPARE_OP_GREATER;
|
||||
break;
|
||||
case GFXDepthMode::None:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -988,6 +991,8 @@ GFXPipeline* GFXVulkan::create_graphics_pipeline(const GFXGraphicsPipelineCreate
|
|||
case GFXBindingType::Sampler:
|
||||
descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
|
||||
break;
|
||||
case GFXBindingType::PushConstant:
|
||||
break;
|
||||
}
|
||||
|
||||
VkDescriptorSetLayoutBinding layoutBinding = {};
|
||||
|
@ -1051,7 +1056,7 @@ GFXPipeline* GFXVulkan::create_graphics_pipeline(const GFXGraphicsPipelineCreate
|
|||
}
|
||||
|
||||
GFXPipeline* GFXVulkan::create_compute_pipeline(const GFXComputePipelineCreateInfo& info) {
|
||||
GFXVulkanPipeline* pipeline = new GFXVulkanPipeline();
|
||||
auto pipeline = new GFXVulkanPipeline();
|
||||
|
||||
vkDeviceWaitIdle(device);
|
||||
|
||||
|
@ -1123,6 +1128,8 @@ GFXPipeline* GFXVulkan::create_compute_pipeline(const GFXComputePipelineCreateIn
|
|||
case GFXBindingType::Sampler:
|
||||
descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
|
||||
break;
|
||||
case GFXBindingType::PushConstant:
|
||||
break;
|
||||
}
|
||||
|
||||
VkDescriptorSetLayoutBinding layoutBinding = {};
|
||||
|
@ -1176,7 +1183,7 @@ GFXSize GFXVulkan::get_alignment(GFXSize size) {
|
|||
}
|
||||
|
||||
GFXCommandBuffer* GFXVulkan::acquire_command_buffer(bool for_presentation_use) {
|
||||
GFXVulkanCommandBuffer* cmdbuf = new GFXVulkanCommandBuffer();
|
||||
auto cmdbuf = new GFXVulkanCommandBuffer();
|
||||
|
||||
if(!for_presentation_use) {
|
||||
VkCommandBufferAllocateInfo info = {};
|
||||
|
@ -1209,7 +1216,7 @@ void GFXVulkan::submit(GFXCommandBuffer* command_buffer, const int identifier) {
|
|||
|
||||
VkCommandBuffer cmd = VK_NULL_HANDLE;
|
||||
|
||||
GFXVulkanCommandBuffer* cmdbuf = (GFXVulkanCommandBuffer*)command_buffer;
|
||||
auto cmdbuf = (GFXVulkanCommandBuffer*)command_buffer;
|
||||
if(cmdbuf->handle != VK_NULL_HANDLE)
|
||||
cmd = cmdbuf->handle;
|
||||
else if(current_surface != nullptr)
|
||||
|
@ -1258,8 +1265,8 @@ void GFXVulkan::submit(GFXCommandBuffer* command_buffer, const int identifier) {
|
|||
vkCmdEndRenderPass(cmd);
|
||||
}
|
||||
|
||||
GFXVulkanRenderPass* renderPass = (GFXVulkanRenderPass*)command.data.set_render_pass.render_pass;
|
||||
GFXVulkanFramebuffer* framebuffer = (GFXVulkanFramebuffer*)command.data.set_render_pass.framebuffer;
|
||||
auto renderPass = (GFXVulkanRenderPass*)command.data.set_render_pass.render_pass;
|
||||
auto framebuffer = (GFXVulkanFramebuffer*)command.data.set_render_pass.framebuffer;
|
||||
|
||||
if (renderPass != nullptr) {
|
||||
currentRenderPass = renderPass->handle;
|
||||
|
@ -1429,8 +1436,8 @@ void GFXVulkan::submit(GFXCommandBuffer* command_buffer, const int identifier) {
|
|||
break;
|
||||
case GFXCommandType::CopyTexture:
|
||||
{
|
||||
GFXVulkanTexture* src = (GFXVulkanTexture*)command.data.copy_texture.src;
|
||||
GFXVulkanTexture* dst = (GFXVulkanTexture*)command.data.copy_texture.dst;
|
||||
auto src = (GFXVulkanTexture*)command.data.copy_texture.src;
|
||||
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;
|
||||
|
||||
|
@ -1534,7 +1541,7 @@ void GFXVulkan::submit(GFXCommandBuffer* command_buffer, const int identifier) {
|
|||
break;
|
||||
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++) {
|
||||
int mip_width = texture->width;
|
||||
|
@ -1634,7 +1641,7 @@ void GFXVulkan::submit(GFXCommandBuffer* command_buffer, const int identifier) {
|
|||
}
|
||||
break;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -1789,7 +1796,33 @@ void GFXVulkan::createLogicalDevice(std::vector<const char*> extensions) {
|
|||
queueCreateInfo.pQueuePriorities = &queuePriority;
|
||||
|
||||
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 = {};
|
||||
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) {
|
||||
|
||||
#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) {
|
||||
native_surface->surface = (VkSurfaceKHR)platform::create_native_surface(native_surface->identifier, (void*)instance);
|
||||
}
|
||||
#endif
|
||||
|
||||
// TODO: fix this pls
|
||||
VkBool32 supported;
|
||||
|
@ -2073,7 +2092,7 @@ void GFXVulkan::cacheDescriptorState(GFXVulkanPipeline* pipeline, VkDescriptorSe
|
|||
|
||||
VkResult error = vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet);
|
||||
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;
|
||||
}
|
||||
|
@ -2083,7 +2102,7 @@ void GFXVulkan::cacheDescriptorState(GFXVulkanPipeline* pipeline, VkDescriptorSe
|
|||
// update set
|
||||
for (auto [i, buffer] : utility::enumerate(boundShaderBuffers)) {
|
||||
if (buffer.buffer != nullptr) {
|
||||
GFXVulkanBuffer* vulkanBuffer = (GFXVulkanBuffer*)buffer.buffer;
|
||||
auto vulkanBuffer = (GFXVulkanBuffer*)buffer.buffer;
|
||||
|
||||
VkDescriptorBufferInfo bufferInfo = {};
|
||||
bufferInfo.buffer = vulkanBuffer->handle; // will this break?
|
||||
|
@ -2104,7 +2123,7 @@ void GFXVulkan::cacheDescriptorState(GFXVulkanPipeline* pipeline, VkDescriptorSe
|
|||
|
||||
for (auto [i, texture] : utility::enumerate(boundTextures)) {
|
||||
if (texture != nullptr) {
|
||||
GFXVulkanTexture* vulkanTexture = (GFXVulkanTexture*) texture;
|
||||
auto vulkanTexture = (GFXVulkanTexture*) texture;
|
||||
|
||||
VkDescriptorImageInfo imageInfo = {};
|
||||
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)) {
|
||||
if (sampler != nullptr) {
|
||||
GFXVulkanSampler* vulkanSampler = (GFXVulkanSampler*) sampler;
|
||||
auto vulkanSampler = (GFXVulkanSampler*) sampler;
|
||||
|
||||
VkDescriptorImageInfo imageInfo = {};
|
||||
imageInfo.sampler = vulkanSampler->sampler;
|
||||
|
|
|
@ -4,5 +4,5 @@ set(SRC
|
|||
|
||||
add_library(Log STATIC ${SRC})
|
||||
target_include_directories(Log PUBLIC include)
|
||||
target_link_libraries(Log PRIVATE Utility)
|
||||
target_link_libraries(Log PUBLIC fmt::fmt)
|
||||
set_engine_properties(Log)
|
||||
|
|
|
@ -1,66 +1,18 @@
|
|||
#pragma once
|
||||
|
||||
#include <string_view>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <fmt/format.h>
|
||||
|
||||
enum class System {
|
||||
None,
|
||||
Core,
|
||||
Renderer,
|
||||
Game,
|
||||
File,
|
||||
GFX
|
||||
};
|
||||
namespace prism {
|
||||
inline std::string log_output;
|
||||
|
||||
enum class Level {
|
||||
Info,
|
||||
Warning,
|
||||
Error,
|
||||
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 vlog(fmt::string_view format, fmt::format_args args) {
|
||||
auto str = fmt::vformat(format, args);
|
||||
fmt::print("{}", str);
|
||||
log_output += str + "\n";
|
||||
}
|
||||
|
||||
inline void internal_format(std::string &msg, const char *&arg) {
|
||||
auto pos = msg.find_first_of("{}");
|
||||
msg.replace(pos, 2, arg);
|
||||
template <typename S, typename... Args>
|
||||
inline void log(const S& format, Args&&... args) {
|
||||
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 <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);
|
||||
}
|
||||
#include "log.hpp"
|
|
@ -8,7 +8,6 @@
|
|||
#include <filesystem>
|
||||
|
||||
#include "log.hpp"
|
||||
#include "file_utils.hpp"
|
||||
#include "path.hpp"
|
||||
|
||||
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.
|
||||
void capture_mouse(const bool capture);
|
||||
|
||||
/**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);
|
||||
// TODO: right now the OS intercepting and saying "We dont want text input anymore" ala software keyboards is NOT supported yet
|
||||
void begin_text_input();
|
||||
void end_text_input();
|
||||
|
||||
/**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'.
|
||||
|
|
|
@ -55,21 +55,12 @@ namespace prism {
|
|||
|
||||
void recreate_all_render_targets();
|
||||
|
||||
void set_screen(ui::Screen* screen);
|
||||
|
||||
void init_screen(ui::Screen* screen);
|
||||
|
||||
void update_screen();
|
||||
|
||||
struct controller_continuity {
|
||||
int elementOffset = 0;
|
||||
};
|
||||
|
||||
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,
|
||||
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));
|
||||
ImGui::GetIO().FontGlobalScale = 1.0 / platform::get_window_dpi(0);
|
||||
} else {
|
||||
prism::log::error(System::Renderer, "Failed to load font file for imgui!");
|
||||
prism::log("Failed to load font file for imgui!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
ShaderSource get_shader(std::string filename, bool skinned, bool cubemap) {
|
||||
auto shader_file = prism::open_file(prism::internal_domain / filename);
|
||||
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 {};
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
#include "gfx_commandbuffer.hpp"
|
||||
#include "math.hpp"
|
||||
#include "screen.hpp"
|
||||
#include "file.hpp"
|
||||
#include "scene.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) {
|
||||
const auto extent = target.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->pop_group();
|
||||
|
||||
if(current_screen != nullptr)
|
||||
render_screen(commandbuffer, current_screen, extent, continuity);
|
||||
|
||||
|
||||
commandbuffer->push_group("Extra 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;
|
||||
pc.view = matrix_from_quat(scene.get<Transform>(camera_object).rotation);
|
||||
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));
|
||||
}
|
||||
|
||||
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 {
|
||||
GFXShaderConstant materials_constant = {};
|
||||
materials_constant.type = GFXShaderConstant::Type::Integer;
|
||||
|
@ -866,7 +678,7 @@ void renderer::create_post_pipelines() {
|
|||
void renderer::create_font_texture() {
|
||||
auto file = prism::open_file(prism::app_domain / "font.fp", true);
|
||||
if(file == std::nullopt) {
|
||||
prism::log::error(System::Renderer, "Failed to load font file!");
|
||||
prism::log("Failed to load font file!");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ std::vector<uint32_t> compile_glsl_to_spv(const std::string_view source_string,
|
|||
file_includer.pushExternalLocalDirectory(path);
|
||||
|
||||
if (!shader.parse(&DefaultTBuiltInResource, 100, false, EShMsgDefault, file_includer)) {
|
||||
prism::log::error(System::Renderer, "{}", shader.getInfoLog());
|
||||
prism::log("{}", shader.getInfoLog());
|
||||
|
||||
return {};
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ std::vector<uint32_t> compile_glsl_to_spv(const std::string_view source_string,
|
|||
Program.addShader(&shader);
|
||||
|
||||
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 {};
|
||||
}
|
||||
|
@ -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) {
|
||||
if(from_language != ShaderLanguage::GLSL) {
|
||||
prism::log::error(System::Renderer, "Non-supported input language!");
|
||||
prism::log("Non-supported input language!");
|
||||
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);
|
||||
if(spirv.empty()) {
|
||||
prism::log::error(System::Renderer, "SPIRV generation failed!");
|
||||
prism::log("SPIRV generation failed!");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@ set(SRC
|
|||
include/string_utils.hpp
|
||||
include/timer.hpp
|
||||
include/common.hpp
|
||||
include/file_utils.hpp
|
||||
include/assertions.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);
|
||||
|
||||
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"
|
||||
|
||||
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");
|
||||
|
||||
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_render = scene->add<Renderable>(sphere_obj);
|
||||
sphere_render.mesh = assetm->get<Mesh>(prism::path("data/models/sphere.model"));
|
||||
sphere_render.materials = { assetm->get<Material>(prism::path("data/materials/Material.material")) };
|
||||
sphere_render.mesh = assetm->get<Mesh>(prism::path(prism::app_domain / "models/sphere.model"));
|
||||
sphere_render.materials = { assetm->get<Material>(prism::path(prism::app_domain / "materials/Material.material")) };
|
||||
|
||||
auto probe_obj = scene->add_object();
|
||||
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)
|
||||
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()
|
||||
|
||||
if(ENABLE_MACOS)
|
||||
add_subdirectory(mac)
|
||||
add_subdirectory(sdl)
|
||||
endif()
|
||||
|
||||
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
|
||||
MAIN_FILE
|
||||
main.cpp.in
|
||||
EXECUTABLE_PROPERTIES
|
||||
MACOSX_BUNDLE ON
|
||||
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in"
|
||||
LINK_LIBRARIES
|
||||
SDL2::Main
|
||||
Core
|
||||
|
@ -12,7 +15,11 @@ add_platform(
|
|||
|
||||
function(add_platform_commands target)
|
||||
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()
|
||||
|
||||
# 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_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
|
||||
)
|
||||
if(ENABLE_MACOS)
|
||||
add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/dummy
|
||||
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})
|
||||
endfunction()
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>Fantasy\U00A0app</string>
|
||||
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
|
@ -19,7 +19,7 @@
|
|||
<key>CFBundleLongVersionString</key>
|
||||
<string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>Project Shopkeep</string>
|
||||
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
|
@ -31,7 +31,7 @@
|
|||
<key>CSResourcesFileMapped</key>
|
||||
<true/>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>(c)2020 Blinding Light Games</string>
|
||||
<string>(c) 2021</string>
|
||||
<key>NSHighResolutionCapable</key>
|
||||
<true/>
|
||||
</dict>
|
|
@ -3,7 +3,11 @@
|
|||
#include "string_utils.hpp"
|
||||
|
||||
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}/", "");
|
||||
#endif
|
||||
}
|
||||
|
||||
prism::path prism::get_writeable_directory() {
|
||||
|
|
|
@ -257,14 +257,16 @@ void platform::capture_mouse(const 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) {
|
||||
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() {}
|
||||
|
@ -320,7 +322,13 @@ int main(int argc, char* argv[]) {
|
|||
engine->process_key_down(event.key.keysym.scancode);
|
||||
}
|
||||
break;
|
||||
case SDL_KEYUP:
|
||||
{
|
||||
engine->process_key_up(event.key.keysym.scancode);
|
||||
}
|
||||
break;
|
||||
case SDL_WINDOWEVENT:
|
||||
{
|
||||
if (event.window.event == SDL_WINDOWEVENT_RESIZED) {
|
||||
auto window = get_window_by_sdl_id(event.window.windowID);
|
||||
if(window != nullptr)
|
||||
|
@ -328,7 +336,13 @@ int main(int argc, char* argv[]) {
|
|||
} else if(event.window.event == SDL_WINDOWEVENT_CLOSE) {
|
||||
engine->quit();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SDL_TEXTINPUT:
|
||||
{
|
||||
engine->process_text_input(event.text.text);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "asset.hpp"
|
||||
#include "scene.hpp"
|
||||
#include "renderer.hpp"
|
||||
#include "imgui_backend.hpp"
|
||||
|
||||
class TransformCommand : public Command {
|
||||
public:
|
||||
|
@ -369,7 +370,7 @@ inline void editPath(const char* label, std::string& path, bool editable = true,
|
|||
ImGui::SameLine();
|
||||
|
||||
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();
|
||||
|
||||
if(on_selected != nullptr)
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
#include "gfx.hpp"
|
||||
#include "gfx_commandbuffer.hpp"
|
||||
#include "imgui_utility.hpp"
|
||||
#include "screen.hpp"
|
||||
#include "console.hpp"
|
||||
#include "input.hpp"
|
||||
#include "scenecapture.hpp"
|
||||
|
@ -48,11 +47,7 @@ const std::map<ImGuiKey, InputButton> imToPl = {
|
|||
};
|
||||
|
||||
CommonEditor::CommonEditor(std::string id) : id(id) {
|
||||
#ifdef PLATFORM_MACOS
|
||||
prism::set_domain_path(prism::domain::app, "../../../data");
|
||||
#else
|
||||
prism::set_domain_path(prism::domain::app, "data");
|
||||
#endif
|
||||
prism::set_domain_path(prism::domain::app, "{resource_dir}/data");
|
||||
prism::set_domain_path(prism::domain::internal, "{resource_dir}/shaders");
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
@ -465,20 +460,6 @@ void editRigidbody(Rigidbody& rigidbody) {
|
|||
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) {
|
||||
ImGui::Checkbox("Is Sized", &probe.is_sized);
|
||||
if(probe.is_sized)
|
||||
|
@ -614,11 +595,6 @@ void CommonEditor::drawPropertyEditor() {
|
|||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
|
||||
if(ImGui::Selectable("UI")) {
|
||||
scene->add<UI>(selected_object);
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
|
||||
if(ImGui::Selectable("Environment Probe")) {
|
||||
scene->add<EnvironmentProbe>(selected_object);
|
||||
ImGui::CloseCurrentPopup();
|
||||
|
@ -644,10 +620,7 @@ void CommonEditor::drawPropertyEditor() {
|
|||
|
||||
if(componentHeader<Rigidbody>(*scene, selected_object, "Rigidbody"))
|
||||
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"))
|
||||
editProbe(scene->get<EnvironmentProbe>(selected_object));
|
||||
}
|
||||
|
@ -732,7 +705,7 @@ void CommonEditor::set_undo_stack(UndoStack *stack) {
|
|||
bool mesh_readable(const prism::path path) {
|
||||
auto file = prism::open_file(path);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -745,7 +718,7 @@ bool mesh_readable(const prism::path path) {
|
|||
bool material_readable(const prism::path path) {
|
||||
auto file = prism::open_file(path);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -759,6 +732,9 @@ void cacheAssetFilesystem() {
|
|||
asset_files.clear();
|
||||
|
||||
auto data_directory = "data";
|
||||
if(!std::filesystem::exists(data_directory))
|
||||
return;
|
||||
|
||||
for(auto& p : std::filesystem::recursive_directory_iterator(data_directory)) {
|
||||
if(p.path().extension() == ".model" && mesh_readable(p.path())) {
|
||||
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);
|
||||
|
||||
for(const auto& message : prism::log::stored_output)
|
||||
ImGui::TextWrapped("%s", message.c_str());
|
||||
|
||||
// TODO: implement for new log system
|
||||
//for(const auto& message : prism::log::stored_output)
|
||||
// ImGui::TextWrapped("%s", message.c_str());
|
||||
ImGui::Text("unimplemented :-(");
|
||||
|
||||
ImGui::EndChild();
|
||||
}
|
||||
|
@ -1123,7 +1101,7 @@ void CommonEditor::save_thumbnail_cache() {
|
|||
|
||||
FILE* file = fopen("thumbnail-cache", "wb");
|
||||
if(file == nullptr) {
|
||||
prism::log::error(System::Core, "Failed to write thumbnail cache!");
|
||||
prism::log("Failed to write thumbnail cache!");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,13 +2,11 @@ set(SRC
|
|||
include/prismeditor.hpp
|
||||
include/materialeditor.hpp
|
||||
include/sceneeditor.hpp
|
||||
include/uieditor.hpp
|
||||
include/prefabeditor.hpp
|
||||
|
||||
src/prismeditor.cpp
|
||||
src/materialeditor.cpp
|
||||
src/sceneeditor.cpp
|
||||
src/uieditor.cpp
|
||||
src/prefabeditor.cpp)
|
||||
|
||||
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::MenuItem("Save", "CTRL+S")) {
|
||||
if (path.empty()) {
|
||||
platform::save_dialog([this](std::string path) {
|
||||
engine->get_imgui().save_dialog([this](std::string path) {
|
||||
this->path = path;
|
||||
|
||||
save_material(*material, path);
|
||||
|
@ -142,7 +142,7 @@ void MaterialEditor::draw(CommonEditor* editor) {
|
|||
}
|
||||
|
||||
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;
|
||||
|
||||
save_material(*material, path);
|
||||
|
|
|
@ -36,7 +36,7 @@ void PrefabEditor::draw(CommonEditor* editor) {
|
|||
if (ImGui::BeginMenu("File")) {
|
||||
if(ImGui::MenuItem("Save", "CTRL+S")) {
|
||||
if (path.empty()) {
|
||||
platform::save_dialog([this](std::string path) {
|
||||
engine->get_imgui().save_dialog([this](std::string path) {
|
||||
this->path = path;
|
||||
|
||||
engine->save_prefab(root_object, path);
|
||||
|
@ -47,7 +47,7 @@ void PrefabEditor::draw(CommonEditor* editor) {
|
|||
}
|
||||
|
||||
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;
|
||||
|
||||
engine->save_prefab(root_object, path);
|
||||
|
|
|
@ -11,11 +11,9 @@
|
|||
#include "json_conversions.hpp"
|
||||
#include "platform.hpp"
|
||||
#include "string_utils.hpp"
|
||||
#include "screen.hpp"
|
||||
#include "sceneeditor.hpp"
|
||||
#include "materialeditor.hpp"
|
||||
#include "prefabeditor.hpp"
|
||||
#include "uieditor.hpp"
|
||||
#include "log.hpp"
|
||||
|
||||
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();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -233,19 +222,11 @@ void PrismEditor::drawUI() {
|
|||
editors.push_back(editor);
|
||||
}
|
||||
|
||||
if(ImGui::MenuItem("UI")) {
|
||||
UIEditor* editor = new UIEditor();
|
||||
editor->modified = true;
|
||||
setup_editor(editor);
|
||||
|
||||
editors.push_back(editor);
|
||||
}
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
addOpenedFile(path);
|
||||
|
|
|
@ -44,7 +44,7 @@ void SceneEditor::draw(CommonEditor* editor) {
|
|||
if (ImGui::BeginMenu("File")) {
|
||||
if(ImGui::MenuItem("Save", "CTRL+S")) {
|
||||
if (path.empty()) {
|
||||
platform::save_dialog([this](std::string path) {
|
||||
engine->get_imgui().save_dialog([this](std::string path) {
|
||||
this->path = path;
|
||||
|
||||
engine->save_scene(path);
|
||||
|
@ -55,7 +55,7 @@ void SceneEditor::draw(CommonEditor* editor) {
|
|||
}
|
||||
|
||||
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;
|
||||
|
||||
engine->save_scene(path);
|
||||
|
@ -107,7 +107,7 @@ void SceneEditor::draw(CommonEditor* editor) {
|
|||
}
|
||||
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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 "log.hpp"
|
||||
#include "string_utils.hpp"
|
||||
#include "file_utils.hpp"
|
||||
|
||||
bool has_extension(const std::filesystem::path path, const std::string_view 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[]) {
|
||||
if(argc < 2) {
|
||||
prism::log::error(System::Core, "Not enough arguments!");
|
||||
prism::log("Not enough arguments!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -42,17 +41,11 @@ int main(int argc, char* argv[]) {
|
|||
|
||||
ShaderLanguage language;
|
||||
CompileOptions options;
|
||||
#ifdef PLATFORM_MACOS
|
||||
options.is_apple_mobile = (bool)argv[3];
|
||||
|
||||
language = ShaderLanguage::MSL;
|
||||
#else
|
||||
language = ShaderLanguage::SPIRV;
|
||||
#endif
|
||||
|
||||
|
||||
const auto compiled_source = shader_compiler.compile(ShaderLanguage::GLSL, stage, ShaderSource(buffer.str()), language, options);
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
Reference in a new issue