mirror of
https://github.com/enduro2d/enduro2d.git
synced 2025-12-14 16:09:06 +07:00
Merge remote-tracking branch 'origin/master' into feature/debug_hierarchy
This commit is contained in:
@@ -16,6 +16,7 @@
|
|||||||
#include "input.hpp"
|
#include "input.hpp"
|
||||||
#include "network.hpp"
|
#include "network.hpp"
|
||||||
#include "platform.hpp"
|
#include "platform.hpp"
|
||||||
|
#include "profiler.hpp"
|
||||||
#include "render.hpp"
|
#include "render.hpp"
|
||||||
#include "render.inl"
|
#include "render.inl"
|
||||||
#include "vfs.hpp"
|
#include "vfs.hpp"
|
||||||
|
|||||||
@@ -12,7 +12,6 @@
|
|||||||
|
|
||||||
#include <curly.hpp/curly.hpp>
|
#include <curly.hpp/curly.hpp>
|
||||||
|
|
||||||
#include <promise.hpp/invoke.hpp>
|
|
||||||
#include <promise.hpp/jobber.hpp>
|
#include <promise.hpp/jobber.hpp>
|
||||||
#include <promise.hpp/promise.hpp>
|
#include <promise.hpp/promise.hpp>
|
||||||
#include <promise.hpp/scheduler.hpp>
|
#include <promise.hpp/scheduler.hpp>
|
||||||
@@ -26,7 +25,6 @@ namespace e2d
|
|||||||
|
|
||||||
namespace stdex
|
namespace stdex
|
||||||
{
|
{
|
||||||
using namespace invoke_hpp;
|
|
||||||
using namespace jobber_hpp;
|
using namespace jobber_hpp;
|
||||||
using namespace promise_hpp;
|
using namespace promise_hpp;
|
||||||
using namespace scheduler_hpp;
|
using namespace scheduler_hpp;
|
||||||
@@ -44,6 +42,7 @@ namespace e2d
|
|||||||
class input;
|
class input;
|
||||||
class network;
|
class network;
|
||||||
class platform;
|
class platform;
|
||||||
|
class profiler;
|
||||||
class render;
|
class render;
|
||||||
class shader;
|
class shader;
|
||||||
class texture;
|
class texture;
|
||||||
|
|||||||
@@ -83,12 +83,9 @@ namespace e2d
|
|||||||
audio(debug& d);
|
audio(debug& d);
|
||||||
~audio() noexcept;
|
~audio() noexcept;
|
||||||
|
|
||||||
[[nodiscard]] sound_stream_ptr preload_stream(
|
[[nodiscard]] sound_stream_ptr create_stream(
|
||||||
buffer_view sound_data);
|
buffer_view sound_data);
|
||||||
|
|
||||||
[[nodiscard]] sound_stream_ptr preload_stream(
|
|
||||||
const input_stream_uptr& file_stream);
|
|
||||||
|
|
||||||
[[nodiscard]] sound_stream_ptr create_stream(
|
[[nodiscard]] sound_stream_ptr create_stream(
|
||||||
input_stream_uptr file_stream);
|
input_stream_uptr file_stream);
|
||||||
|
|
||||||
@@ -99,7 +96,7 @@ namespace e2d
|
|||||||
|
|
||||||
void volume(f32 value) noexcept;
|
void volume(f32 value) noexcept;
|
||||||
[[nodiscard]] f32 volume() const noexcept;
|
[[nodiscard]] f32 volume() const noexcept;
|
||||||
|
|
||||||
void resume() noexcept;
|
void resume() noexcept;
|
||||||
void pause() noexcept;
|
void pause() noexcept;
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ namespace e2d
|
|||||||
|
|
||||||
template < typename T >
|
template < typename T >
|
||||||
void active_safe_wait_promise(const stdex::promise<T>& promise) noexcept;
|
void active_safe_wait_promise(const stdex::promise<T>& promise) noexcept;
|
||||||
|
|
||||||
|
void frame_tick() noexcept;
|
||||||
private:
|
private:
|
||||||
stdex::jobber worker_;
|
stdex::jobber worker_;
|
||||||
stdex::scheduler scheduler_;
|
stdex::scheduler scheduler_;
|
||||||
|
|||||||
@@ -8,8 +8,6 @@
|
|||||||
|
|
||||||
#include "_core.hpp"
|
#include "_core.hpp"
|
||||||
|
|
||||||
#include "window.hpp"
|
|
||||||
|
|
||||||
namespace e2d
|
namespace e2d
|
||||||
{
|
{
|
||||||
class mouse final : private noncopyable {
|
class mouse final : private noncopyable {
|
||||||
@@ -120,16 +118,4 @@ namespace e2d
|
|||||||
class internal_state;
|
class internal_state;
|
||||||
std::unique_ptr<internal_state> state_;
|
std::unique_ptr<internal_state> state_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class window_input_source : public window::event_listener {
|
|
||||||
public:
|
|
||||||
window_input_source(input& input) noexcept;
|
|
||||||
void on_input_char(char32_t uchar) noexcept final;
|
|
||||||
void on_move_cursor(const v2f& pos) noexcept final;
|
|
||||||
void on_mouse_scroll(const v2f& delta) noexcept final;
|
|
||||||
void on_mouse_button(mouse_button btn, mouse_button_action act) noexcept final;
|
|
||||||
void on_keyboard_key(keyboard_key key, u32 scancode, keyboard_key_action act) noexcept final;
|
|
||||||
private:
|
|
||||||
input& input_;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|||||||
221
headers/enduro2d/core/profiler.hpp
Normal file
221
headers/enduro2d/core/profiler.hpp
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* This file is part of the "Enduro2D"
|
||||||
|
* For conditions of distribution and use, see copyright notice in LICENSE.md
|
||||||
|
* Copyright (C) 2018-2019, by Matvey Cherevko (blackmatov@gmail.com)
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "_core.hpp"
|
||||||
|
|
||||||
|
#include "deferrer.hpp"
|
||||||
|
|
||||||
|
namespace e2d
|
||||||
|
{
|
||||||
|
class profiler final : public module<profiler> {
|
||||||
|
public:
|
||||||
|
using args_t = flat_map<str, str>;
|
||||||
|
|
||||||
|
struct begin_scope_info {
|
||||||
|
str name;
|
||||||
|
args_t args;
|
||||||
|
std::thread::id tid;
|
||||||
|
std::chrono::microseconds tp;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct end_scope_info {
|
||||||
|
std::thread::id tid;
|
||||||
|
std::chrono::microseconds tp;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct thread_event_info {
|
||||||
|
str name;
|
||||||
|
args_t args;
|
||||||
|
std::thread::id tid;
|
||||||
|
std::chrono::microseconds tp;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct global_event_info {
|
||||||
|
str name;
|
||||||
|
args_t args;
|
||||||
|
std::thread::id tid;
|
||||||
|
std::chrono::microseconds tp;
|
||||||
|
};
|
||||||
|
|
||||||
|
using event_info = std::variant<
|
||||||
|
begin_scope_info,
|
||||||
|
end_scope_info,
|
||||||
|
thread_event_info,
|
||||||
|
global_event_info>;
|
||||||
|
public:
|
||||||
|
class sink : private e2d::noncopyable {
|
||||||
|
public:
|
||||||
|
virtual ~sink() noexcept = default;
|
||||||
|
virtual void on_event(const event_info& event) noexcept = 0;
|
||||||
|
};
|
||||||
|
using sink_uptr = std::unique_ptr<sink>;
|
||||||
|
public:
|
||||||
|
class auto_scope final : private e2d::noncopyable {
|
||||||
|
public:
|
||||||
|
auto_scope(profiler* profiler, str name);
|
||||||
|
auto_scope(profiler* profiler, str name, args_t args);
|
||||||
|
~auto_scope() noexcept;
|
||||||
|
private:
|
||||||
|
profiler* profiler_ = nullptr;
|
||||||
|
};
|
||||||
|
public:
|
||||||
|
profiler(deferrer& d);
|
||||||
|
~profiler() noexcept final;
|
||||||
|
|
||||||
|
void begin_scope(str name) noexcept;
|
||||||
|
void begin_scope(str name, args_t args) noexcept;
|
||||||
|
void end_scope() noexcept;
|
||||||
|
|
||||||
|
void thread_event(str name) noexcept;
|
||||||
|
void thread_event(str name, args_t args) noexcept;
|
||||||
|
|
||||||
|
void global_event(str name) noexcept;
|
||||||
|
void global_event(str name, args_t args) noexcept;
|
||||||
|
public:
|
||||||
|
struct recording_info {
|
||||||
|
vector<event_info> events;
|
||||||
|
};
|
||||||
|
|
||||||
|
template < typename Rep, typename Period >
|
||||||
|
stdex::promise<recording_info> record_for(
|
||||||
|
const std::chrono::duration<Rep, Period>& timeout_duration);
|
||||||
|
|
||||||
|
template < typename Clock, typename Duration >
|
||||||
|
stdex::promise<recording_info> record_until(
|
||||||
|
const std::chrono::time_point<Clock, Duration>& timeout_time);
|
||||||
|
public:
|
||||||
|
template < typename T, typename... Args >
|
||||||
|
T& register_sink(Args&&... args);
|
||||||
|
sink& register_sink(sink_uptr sink);
|
||||||
|
void unregister_sink(const sink& sink) noexcept;
|
||||||
|
private:
|
||||||
|
deferrer& deferrer_;
|
||||||
|
std::size_t depth_{0u};
|
||||||
|
vector<sink_uptr> sinks_;
|
||||||
|
std::recursive_mutex rmutex_;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#define E2D_PROFILER_SCOPE(name)\
|
||||||
|
auto E2D_PP_CAT(e2d_generated_profiler_auto_scope_, __LINE__) =\
|
||||||
|
::e2d::profiler::auto_scope(\
|
||||||
|
modules::is_initialized<profiler>() ? &the<profiler>() : nullptr,\
|
||||||
|
name);
|
||||||
|
|
||||||
|
#define E2D_PROFILER_SCOPE_EX(name, ...)\
|
||||||
|
auto E2D_PP_CAT(e2d_generated_profiler_auto_scope_, __LINE__) =\
|
||||||
|
::e2d::profiler::auto_scope(\
|
||||||
|
modules::is_initialized<profiler>() ? &the<profiler>() : nullptr,\
|
||||||
|
name,\
|
||||||
|
__VA_ARGS__);
|
||||||
|
|
||||||
|
#define E2D_PROFILER_THREAD_EVENT(name)\
|
||||||
|
if ( modules::is_initialized<profiler>() ) {\
|
||||||
|
the<profiler>().thread_event(name);\
|
||||||
|
}
|
||||||
|
|
||||||
|
#define E2D_PROFILER_THREAD_EVENT_EX(name, ...)\
|
||||||
|
if ( modules::is_initialized<profiler>() ) {\
|
||||||
|
the<profiler>().thread_event(name, __VA_ARGS___);\
|
||||||
|
}
|
||||||
|
|
||||||
|
#define E2D_PROFILER_GLOBAL_EVENT(name)\
|
||||||
|
if ( modules::is_initialized<profiler>() ) {\
|
||||||
|
the<profiler>().global_event(name);\
|
||||||
|
}
|
||||||
|
|
||||||
|
#define E2D_PROFILER_GLOBAL_EVENT_EX(name, ...)\
|
||||||
|
if ( modules::is_initialized<profiler>() ) {\
|
||||||
|
the<profiler>().global_event(name, __VA_ARGS__);\
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace e2d
|
||||||
|
{
|
||||||
|
template < typename Rep, typename Period >
|
||||||
|
stdex::promise<profiler::recording_info> profiler::record_for(
|
||||||
|
const std::chrono::duration<Rep, Period>& timeout_duration)
|
||||||
|
{
|
||||||
|
return record_until(std::chrono::steady_clock::now() + timeout_duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename Clock, typename Duration >
|
||||||
|
stdex::promise<profiler::recording_info> profiler::record_until(
|
||||||
|
const std::chrono::time_point<Clock, Duration>& timeout_time)
|
||||||
|
{
|
||||||
|
using promise_t = stdex::promise<recording_info>;
|
||||||
|
using time_point_t = std::chrono::time_point<Clock, Duration>;
|
||||||
|
|
||||||
|
class temp_sink final : public sink {
|
||||||
|
public:
|
||||||
|
temp_sink(std::size_t depth, time_point_t time_point)
|
||||||
|
: depth_(depth)
|
||||||
|
, time_point_(time_point) {}
|
||||||
|
|
||||||
|
void on_event(const event_info& event) noexcept final {
|
||||||
|
const bool skip = info_.events.empty() && depth_;
|
||||||
|
|
||||||
|
if ( std::holds_alternative<begin_scope_info>(event) ) {
|
||||||
|
++depth_;
|
||||||
|
} else if ( std::holds_alternative<end_scope_info>(event) ) {
|
||||||
|
E2D_ASSERT(depth_);
|
||||||
|
--depth_;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if ( !skip ) {
|
||||||
|
info_.events.push_back(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !depth_ && time_point_ <= Clock::now() ) {
|
||||||
|
promise_.resolve(std::move(info_));
|
||||||
|
}
|
||||||
|
} catch (...) {
|
||||||
|
promise_.reject(std::current_exception());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
promise_t& promise() noexcept {
|
||||||
|
return promise_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const promise_t& promise() const noexcept {
|
||||||
|
return promise_;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
promise_t promise_;
|
||||||
|
recording_info info_;
|
||||||
|
std::size_t depth_{0u};
|
||||||
|
time_point_t time_point_;
|
||||||
|
};
|
||||||
|
|
||||||
|
temp_sink& s = register_sink<temp_sink>(depth_, timeout_time);
|
||||||
|
return s.promise().then([&s, this](auto&& info){
|
||||||
|
return deferrer_.do_in_main_thread([&s, this](auto&& info){
|
||||||
|
unregister_sink(s);
|
||||||
|
return std::forward<decltype(info)>(info);
|
||||||
|
}, std::forward<decltype(info)>(info));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename T, typename... Args >
|
||||||
|
T& profiler::register_sink(Args&&... args) {
|
||||||
|
return static_cast<T&>(
|
||||||
|
register_sink(std::make_unique<T>(std::forward<Args>(args)...)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace e2d::profilers
|
||||||
|
{
|
||||||
|
bool try_save_recording_info(
|
||||||
|
const profiler::recording_info& src,
|
||||||
|
buffer& dst) noexcept;
|
||||||
|
|
||||||
|
bool try_save_recording_info(
|
||||||
|
const profiler::recording_info& src,
|
||||||
|
const output_stream_uptr& dst) noexcept;
|
||||||
|
}
|
||||||
@@ -908,15 +908,12 @@ namespace e2d
|
|||||||
str_view fragment_source);
|
str_view fragment_source);
|
||||||
|
|
||||||
shader_ptr create_shader(
|
shader_ptr create_shader(
|
||||||
const input_stream_uptr& vertex_stream,
|
buffer_view vertex_source,
|
||||||
const input_stream_uptr& fragment_stream);
|
buffer_view fragment_source);
|
||||||
|
|
||||||
texture_ptr create_texture(
|
texture_ptr create_texture(
|
||||||
const image& image);
|
const image& image);
|
||||||
|
|
||||||
texture_ptr create_texture(
|
|
||||||
const input_stream_uptr& image_stream);
|
|
||||||
|
|
||||||
texture_ptr create_texture(
|
texture_ptr create_texture(
|
||||||
const v2u& size,
|
const v2u& size,
|
||||||
const pixel_declaration& decl);
|
const pixel_declaration& decl);
|
||||||
|
|||||||
@@ -25,9 +25,6 @@ namespace e2d
|
|||||||
|
|
||||||
class vfs final : public module<vfs> {
|
class vfs final : public module<vfs> {
|
||||||
public:
|
public:
|
||||||
vfs();
|
|
||||||
~vfs() noexcept final;
|
|
||||||
|
|
||||||
class file_source : private e2d::noncopyable {
|
class file_source : private e2d::noncopyable {
|
||||||
public:
|
public:
|
||||||
virtual ~file_source() noexcept = default;
|
virtual ~file_source() noexcept = default;
|
||||||
@@ -38,6 +35,12 @@ namespace e2d
|
|||||||
virtual bool trace(str_view path, filesystem::trace_func func) const = 0;
|
virtual bool trace(str_view path, filesystem::trace_func func) const = 0;
|
||||||
};
|
};
|
||||||
using file_source_uptr = std::unique_ptr<file_source>;
|
using file_source_uptr = std::unique_ptr<file_source>;
|
||||||
|
public:
|
||||||
|
vfs();
|
||||||
|
~vfs() noexcept final;
|
||||||
|
|
||||||
|
stdex::jobber& worker() noexcept;
|
||||||
|
const stdex::jobber& worker() const noexcept;
|
||||||
|
|
||||||
template < typename T, typename... Args >
|
template < typename T, typename... Args >
|
||||||
bool register_scheme(str_view scheme, Args&&... args);
|
bool register_scheme(str_view scheme, Args&&... args);
|
||||||
@@ -52,10 +55,10 @@ namespace e2d
|
|||||||
input_stream_uptr read(const url& url) const;
|
input_stream_uptr read(const url& url) const;
|
||||||
output_stream_uptr write(const url& url, bool append) const;
|
output_stream_uptr write(const url& url, bool append) const;
|
||||||
|
|
||||||
bool load(const url& url, buffer& dst) const;
|
std::optional<buffer> load(const url& url) const;
|
||||||
stdex::promise<buffer> load_async(const url& url) const;
|
stdex::promise<buffer> load_async(const url& url) const;
|
||||||
|
|
||||||
bool load_as_string(const url& url, str& dst) const;
|
std::optional<str> load_as_string(const url& url) const;
|
||||||
stdex::promise<str> load_as_string_async(const url& url) const;
|
stdex::promise<str> load_as_string_async(const url& url) const;
|
||||||
|
|
||||||
template < typename Iter >
|
template < typename Iter >
|
||||||
|
|||||||
@@ -89,9 +89,9 @@ namespace e2d
|
|||||||
std::unique_ptr<state> state_;
|
std::unique_ptr<state> state_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class window_trace_event_listener final : public window::event_listener {
|
class window_event_tracer final : public window::event_listener {
|
||||||
public:
|
public:
|
||||||
window_trace_event_listener(debug& debug) noexcept;
|
window_event_tracer(debug& debug) noexcept;
|
||||||
void on_input_char(char32_t uchar) noexcept final;
|
void on_input_char(char32_t uchar) noexcept final;
|
||||||
void on_move_cursor(const v2f& pos) noexcept final;
|
void on_move_cursor(const v2f& pos) noexcept final;
|
||||||
void on_mouse_scroll(const v2f& delta) noexcept final;
|
void on_mouse_scroll(const v2f& delta) noexcept final;
|
||||||
@@ -105,6 +105,18 @@ namespace e2d
|
|||||||
private:
|
private:
|
||||||
debug& debug_;
|
debug& debug_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class window_input_source final : public window::event_listener {
|
||||||
|
public:
|
||||||
|
window_input_source(input& input) noexcept;
|
||||||
|
void on_input_char(char32_t uchar) noexcept final;
|
||||||
|
void on_move_cursor(const v2f& pos) noexcept final;
|
||||||
|
void on_mouse_scroll(const v2f& delta) noexcept final;
|
||||||
|
void on_mouse_button(mouse_button btn, mouse_button_action act) noexcept final;
|
||||||
|
void on_keyboard_key(keyboard_key key, u32 scancode, keyboard_key_action act) noexcept final;
|
||||||
|
private:
|
||||||
|
input& input_;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
ENUM_HPP_REGISTER_TRAITS(e2d::window::cursor_shapes)
|
ENUM_HPP_REGISTER_TRAITS(e2d::window::cursor_shapes)
|
||||||
|
|||||||
@@ -24,8 +24,8 @@ namespace e2d
|
|||||||
template < typename F >
|
template < typename F >
|
||||||
decltype(auto) with_state(F&& f) const;
|
decltype(auto) with_state(F&& f) const;
|
||||||
|
|
||||||
|
std::optional<script> load_script(str_view src);
|
||||||
std::optional<script> load_script(buffer_view src);
|
std::optional<script> load_script(buffer_view src);
|
||||||
std::optional<script> load_script(const input_stream_uptr& src);
|
|
||||||
private:
|
private:
|
||||||
sol::state state_;
|
sol::state state_;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -27,9 +27,6 @@ namespace e2d
|
|||||||
template < typename T >
|
template < typename T >
|
||||||
buffer_view(const vector<T>& buffer) noexcept;
|
buffer_view(const vector<T>& buffer) noexcept;
|
||||||
|
|
||||||
template < typename Char >
|
|
||||||
buffer_view(const basic_string<Char>& buffer) noexcept;
|
|
||||||
|
|
||||||
template < typename T, std::size_t N >
|
template < typename T, std::size_t N >
|
||||||
buffer_view(const std::array<T,N>& buffer) noexcept;
|
buffer_view(const std::array<T,N>& buffer) noexcept;
|
||||||
|
|
||||||
@@ -60,16 +57,11 @@ namespace e2d
|
|||||||
: data_(buffer.data())
|
: data_(buffer.data())
|
||||||
, size_(buffer.size() * sizeof(T)) {}
|
, size_(buffer.size() * sizeof(T)) {}
|
||||||
|
|
||||||
template < typename Char >
|
|
||||||
buffer_view::buffer_view(const basic_string<Char>& buffer) noexcept
|
|
||||||
: data_(buffer.data())
|
|
||||||
, size_(buffer.size() * sizeof(Char)) {}
|
|
||||||
|
|
||||||
template < typename T, std::size_t N >
|
template < typename T, std::size_t N >
|
||||||
buffer_view::buffer_view(const std::array<T,N>& buffer) noexcept
|
buffer_view::buffer_view(const std::array<T,N>& buffer) noexcept
|
||||||
: data_(buffer.data())
|
: data_(buffer.data())
|
||||||
, size_(buffer.size() * sizeof(T)) {}
|
, size_(buffer.size() * sizeof(T)) {}
|
||||||
|
|
||||||
template < typename T, std::size_t N >
|
template < typename T, std::size_t N >
|
||||||
buffer_view::buffer_view(const T (&buffer)[N]) noexcept
|
buffer_view::buffer_view(const T (&buffer)[N]) noexcept
|
||||||
: data_(&buffer[0])
|
: data_(&buffer[0])
|
||||||
|
|||||||
@@ -13,27 +13,16 @@ namespace e2d
|
|||||||
namespace impl
|
namespace impl
|
||||||
{
|
{
|
||||||
template < typename F >
|
template < typename F >
|
||||||
class defer_impl {
|
class defer_impl final : noncopyable {
|
||||||
public:
|
public:
|
||||||
defer_impl() = delete;
|
|
||||||
defer_impl(const defer_impl&) = delete;
|
|
||||||
defer_impl& operator=(const defer_impl&) = delete;
|
|
||||||
|
|
||||||
explicit defer_impl(F f)
|
explicit defer_impl(F f)
|
||||||
: f_(std::move(f)) {}
|
: f_(std::move(f)) {}
|
||||||
|
|
||||||
~defer_impl() noexcept(std::is_nothrow_invocable_v<F>) {
|
~defer_impl() noexcept(std::is_nothrow_invocable_v<F>) {
|
||||||
if ( !cancelled_ ) {
|
f_();
|
||||||
f_();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void cancel() noexcept {
|
|
||||||
cancelled_ = true;
|
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
F f_;
|
F f_;
|
||||||
bool cancelled_{false};
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,4 +33,4 @@ namespace e2d
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define E2D_DEFER(lambda)\
|
#define E2D_DEFER(lambda)\
|
||||||
auto E2D_PP_CAT(e2d_defer_, __LINE__) = ::e2d::make_defer(lambda)
|
auto E2D_PP_CAT(e2d_generated_defer_, __LINE__) = ::e2d::make_defer(lambda)
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ namespace e2d::filesystem
|
|||||||
|
|
||||||
bool try_read_all(str& dst, str_view path) noexcept;
|
bool try_read_all(str& dst, str_view path) noexcept;
|
||||||
bool try_read_all(buffer& dst, str_view path) noexcept;
|
bool try_read_all(buffer& dst, str_view path) noexcept;
|
||||||
|
bool try_write_all(str_view src, str_view path, bool append) noexcept;
|
||||||
bool try_write_all(buffer_view src, str_view path, bool append) noexcept;
|
bool try_write_all(buffer_view src, str_view path, bool append) noexcept;
|
||||||
|
|
||||||
ENUM_HPP_CLASS_DECL(predef_path, u8,
|
ENUM_HPP_CLASS_DECL(predef_path, u8,
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ namespace e2d
|
|||||||
|
|
||||||
output_sequence& seek(std::ptrdiff_t offset, bool relative) noexcept;
|
output_sequence& seek(std::ptrdiff_t offset, bool relative) noexcept;
|
||||||
output_sequence& write(const void* src, std::size_t size) noexcept;
|
output_sequence& write(const void* src, std::size_t size) noexcept;
|
||||||
|
output_sequence& write_all(str_view src) noexcept;
|
||||||
output_sequence& write_all(buffer_view src) noexcept;
|
output_sequence& write_all(buffer_view src) noexcept;
|
||||||
|
|
||||||
output_sequence& flush() noexcept;
|
output_sequence& flush() noexcept;
|
||||||
@@ -113,6 +114,10 @@ namespace e2d::streams
|
|||||||
buffer& dst,
|
buffer& dst,
|
||||||
const input_stream_uptr& stream) noexcept;
|
const input_stream_uptr& stream) noexcept;
|
||||||
|
|
||||||
|
bool try_write_tail(
|
||||||
|
str_view src,
|
||||||
|
const output_stream_uptr& stream) noexcept;
|
||||||
|
|
||||||
bool try_write_tail(
|
bool try_write_tail(
|
||||||
buffer_view src,
|
buffer_view src,
|
||||||
const output_stream_uptr& stream) noexcept;
|
const output_stream_uptr& stream) noexcept;
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ namespace e2d
|
|||||||
const str& scheme() const noexcept;
|
const str& scheme() const noexcept;
|
||||||
const str& path() const noexcept;
|
const str& path() const noexcept;
|
||||||
|
|
||||||
|
str schemepath() const;
|
||||||
|
|
||||||
url& operator+=(str_view path);
|
url& operator+=(str_view path);
|
||||||
url& operator/=(str_view path);
|
url& operator/=(str_view path);
|
||||||
private:
|
private:
|
||||||
|
|||||||
Submodule modules/promise.hpp updated: 8ed2aad253...22380ff930
@@ -97,12 +97,19 @@ namespace
|
|||||||
"ships",
|
"ships",
|
||||||
url("piratepack://PNG/Retina/Ships"));
|
url("piratepack://PNG/Retina/Ships"));
|
||||||
|
|
||||||
shader_ = the<render>().create_shader(
|
image texture1_image;
|
||||||
vs_source_cstr, fs_source_cstr);
|
if ( !images::try_load_image(texture1_image, the<vfs>().read(url("ships://ship (2).png"))) ) {
|
||||||
texture1_ = the<render>().create_texture(
|
return false;
|
||||||
the<vfs>().read(url("ships://ship (2).png")));
|
}
|
||||||
texture2_ = the<render>().create_texture(
|
|
||||||
the<vfs>().read(url("ships://ship (19).png")));
|
image texture2_image;
|
||||||
|
if ( !images::try_load_image(texture2_image, the<vfs>().read(url("ships://ship (19).png"))) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
shader_ = the<render>().create_shader(vs_source_cstr, fs_source_cstr);
|
||||||
|
texture1_ = the<render>().create_texture(texture1_image);
|
||||||
|
texture2_ = the<render>().create_texture(texture2_image);
|
||||||
|
|
||||||
if ( !shader_ || !texture1_ || !texture2_ ) {
|
if ( !shader_ || !texture1_ || !texture2_ ) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -157,11 +157,13 @@ namespace
|
|||||||
"ships",
|
"ships",
|
||||||
url("piratepack://PNG/Retina/Ships"));
|
url("piratepack://PNG/Retina/Ships"));
|
||||||
|
|
||||||
shader_ = the<render>().create_shader(
|
image texture_image;
|
||||||
vs_source_cstr, fs_source_cstr);
|
if ( !images::try_load_image(texture_image, the<vfs>().read(url("ships://ship (3).png"))) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
texture_ = the<render>().create_texture(
|
shader_ = the<render>().create_shader(vs_source_cstr, fs_source_cstr);
|
||||||
the<vfs>().read(url("ships://ship (3).png")));
|
texture_ = the<render>().create_texture(texture_image);
|
||||||
|
|
||||||
if ( !shader_ || !texture_ ) {
|
if ( !shader_ || !texture_ ) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -112,11 +112,13 @@ namespace
|
|||||||
"ships",
|
"ships",
|
||||||
url("piratepack://PNG/Retina/Ships"));
|
url("piratepack://PNG/Retina/Ships"));
|
||||||
|
|
||||||
shader_ = the<render>().create_shader(
|
image texture_image;
|
||||||
vs_source_cstr, fs_source_cstr);
|
if ( !images::try_load_image(texture_image, the<vfs>().read(url("ships://ship (3).png"))) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
texture_ = the<render>().create_texture(
|
shader_ = the<render>().create_shader(vs_source_cstr, fs_source_cstr);
|
||||||
the<vfs>().read(url("ships://ship (3).png")));
|
texture_ = the<render>().create_texture(texture_image);
|
||||||
|
|
||||||
if ( !shader_ || !texture_ ) {
|
if ( !shader_ || !texture_ ) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -19,9 +19,9 @@ namespace
|
|||||||
the<vfs>().register_scheme_alias(
|
the<vfs>().register_scheme_alias(
|
||||||
"audio",
|
"audio",
|
||||||
url("rpgaudio://Audio"));
|
url("rpgaudio://Audio"));
|
||||||
|
|
||||||
auto sstream1 = the<audio>().preload_stream(the<vfs>().read(url("audio://chop.ogg")));
|
auto sstream1 = the<audio>().create_stream(the<vfs>().read(url("audio://chop.ogg")));
|
||||||
auto sstream2 = the<audio>().create_stream(the<vfs>().read(url("audio://footstep00.ogg")));
|
auto sstream2 = the<audio>().create_stream(*the<vfs>().load(url("audio://footstep00.ogg")));
|
||||||
|
|
||||||
if ( !sstream1 || !sstream2 ) {
|
if ( !sstream1 || !sstream2 ) {
|
||||||
return false;
|
return false;
|
||||||
@@ -29,7 +29,7 @@ namespace
|
|||||||
|
|
||||||
sound_src1_ = the<audio>().create_source(sstream1);
|
sound_src1_ = the<audio>().create_source(sstream1);
|
||||||
sound_src2_ = the<audio>().create_source(sstream2);
|
sound_src2_ = the<audio>().create_source(sstream2);
|
||||||
|
|
||||||
if ( !sound_src1_ || !sound_src2_ ) {
|
if ( !sound_src1_ || !sound_src2_ ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,8 +6,9 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <enduro2d/core/debug.hpp>
|
|
||||||
#include <enduro2d/core/audio.hpp>
|
#include <enduro2d/core/audio.hpp>
|
||||||
|
#include <enduro2d/core/debug.hpp>
|
||||||
|
#include <enduro2d/core/profiler.hpp>
|
||||||
|
|
||||||
#define E2D_AUDIO_MODE_NONE 1
|
#define E2D_AUDIO_MODE_NONE 1
|
||||||
#define E2D_AUDIO_MODE_BASS 2
|
#define E2D_AUDIO_MODE_BASS 2
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ namespace e2d
|
|||||||
audio::~audio() noexcept {
|
audio::~audio() noexcept {
|
||||||
}
|
}
|
||||||
|
|
||||||
sound_stream_ptr audio::preload_stream(
|
sound_stream_ptr audio::create_stream(
|
||||||
buffer_view sound_data)
|
buffer_view sound_data)
|
||||||
{
|
{
|
||||||
if ( !state_->initialized() ) {
|
if ( !state_->initialized() ) {
|
||||||
@@ -156,6 +156,8 @@ namespace e2d
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
E2D_PROFILER_SCOPE("audio.create_stream");
|
||||||
|
|
||||||
HSAMPLE sample = BASS_SampleLoad(
|
HSAMPLE sample = BASS_SampleLoad(
|
||||||
TRUE,
|
TRUE,
|
||||||
sound_data.data(),
|
sound_data.data(),
|
||||||
@@ -176,23 +178,6 @@ namespace e2d
|
|||||||
state_->dbg(), sample, nullptr));
|
state_->dbg(), sample, nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
sound_stream_ptr audio::preload_stream(
|
|
||||||
const input_stream_uptr& file_stream)
|
|
||||||
{
|
|
||||||
if ( !state_->initialized() ) {
|
|
||||||
state_->dbg().error("AUDIO: Not initialized");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer file_data;
|
|
||||||
if ( !streams::try_read_tail(file_data, file_stream) ) {
|
|
||||||
state_->dbg().error("AUDIO: Failed to read file");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return preload_stream(buffer_view(file_data));
|
|
||||||
}
|
|
||||||
|
|
||||||
sound_stream_ptr audio::create_stream(
|
sound_stream_ptr audio::create_stream(
|
||||||
input_stream_uptr file_stream)
|
input_stream_uptr file_stream)
|
||||||
{
|
{
|
||||||
@@ -206,6 +191,8 @@ namespace e2d
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
E2D_PROFILER_SCOPE("audio.create_stream");
|
||||||
|
|
||||||
BASS_FILEPROCS file_procs = {
|
BASS_FILEPROCS file_procs = {
|
||||||
sound_stream_close_proc,
|
sound_stream_close_proc,
|
||||||
sound_stream_length_proc,
|
sound_stream_length_proc,
|
||||||
@@ -243,10 +230,12 @@ namespace e2d
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
E2D_PROFILER_SCOPE("audio.create_source");
|
||||||
|
|
||||||
HCHANNEL channel = stream->state().stream()
|
HCHANNEL channel = stream->state().stream()
|
||||||
? stream->state().sound()
|
? stream->state().sound()
|
||||||
: BASS_SampleGetChannel(stream->state().sound(), FALSE);
|
: BASS_SampleGetChannel(stream->state().sound(), FALSE);
|
||||||
|
|
||||||
if ( !channel ) {
|
if ( !channel ) {
|
||||||
state_->dbg().error("AUDIO: can net retrive sound channel");
|
state_->dbg().error("AUDIO: can net retrive sound channel");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ namespace e2d
|
|||||||
const input_stream_uptr& sound_stream::internal_state::stream() const noexcept {
|
const input_stream_uptr& sound_stream::internal_state::stream() const noexcept {
|
||||||
return stream_;
|
return stream_;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// sound_source::internal_state
|
// sound_source::internal_state
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -119,20 +119,13 @@ namespace e2d
|
|||||||
audio::~audio() noexcept {
|
audio::~audio() noexcept {
|
||||||
}
|
}
|
||||||
|
|
||||||
sound_stream_ptr audio::preload_stream(
|
sound_stream_ptr audio::create_stream(
|
||||||
buffer_view sound_data)
|
buffer_view sound_data)
|
||||||
{
|
{
|
||||||
E2D_UNUSED(sound_data);
|
E2D_UNUSED(sound_data);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
sound_stream_ptr audio::preload_stream(
|
|
||||||
const input_stream_uptr& file_stream)
|
|
||||||
{
|
|
||||||
E2D_UNUSED(file_stream);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
sound_stream_ptr audio::create_stream(
|
sound_stream_ptr audio::create_stream(
|
||||||
input_stream_uptr file_stream)
|
input_stream_uptr file_stream)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -101,9 +101,9 @@ namespace e2d
|
|||||||
io.DisplaySize =
|
io.DisplaySize =
|
||||||
window_.real_size().cast_to<f32>();
|
window_.real_size().cast_to<f32>();
|
||||||
|
|
||||||
io.DisplayFramebufferScale =
|
io.DisplayFramebufferScale = io.DisplaySize.x > 0.f && io.DisplaySize.y > 0.f
|
||||||
window_.framebuffer_size().cast_to<f32>() /
|
? window_.framebuffer_size().cast_to<f32>() / v2f(io.DisplaySize)
|
||||||
window_.real_size().cast_to<f32>();
|
: v2f(1.f, 1.f);
|
||||||
|
|
||||||
window_.set_cursor_shape(
|
window_.set_cursor_shape(
|
||||||
imgui::convert_mouse_cursor(
|
imgui::convert_mouse_cursor(
|
||||||
@@ -436,6 +436,7 @@ namespace e2d
|
|||||||
}
|
}
|
||||||
|
|
||||||
void dbgui::frame_tick() {
|
void dbgui::frame_tick() {
|
||||||
|
E2D_PROFILER_SCOPE("dbgui.frame_tick");
|
||||||
state_->frame_tick();
|
state_->frame_tick();
|
||||||
|
|
||||||
if ( visible() ) {
|
if ( visible() ) {
|
||||||
@@ -444,6 +445,7 @@ namespace e2d
|
|||||||
}
|
}
|
||||||
|
|
||||||
void dbgui::frame_render() {
|
void dbgui::frame_render() {
|
||||||
|
E2D_PROFILER_SCOPE("dbgui.frame_render");
|
||||||
state_->frame_render();
|
state_->frame_render();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include <enduro2d/core/debug.hpp>
|
#include <enduro2d/core/debug.hpp>
|
||||||
#include <enduro2d/core/engine.hpp>
|
#include <enduro2d/core/engine.hpp>
|
||||||
#include <enduro2d/core/input.hpp>
|
#include <enduro2d/core/input.hpp>
|
||||||
|
#include <enduro2d/core/profiler.hpp>
|
||||||
#include <enduro2d/core/render.hpp>
|
#include <enduro2d/core/render.hpp>
|
||||||
#include <enduro2d/core/window.hpp>
|
#include <enduro2d/core/window.hpp>
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
|
|
||||||
#include <enduro2d/core/deferrer.hpp>
|
#include <enduro2d/core/deferrer.hpp>
|
||||||
|
|
||||||
|
#include <enduro2d/core/profiler.hpp>
|
||||||
|
|
||||||
namespace e2d
|
namespace e2d
|
||||||
{
|
{
|
||||||
deferrer::deferrer()
|
deferrer::deferrer()
|
||||||
@@ -26,4 +28,9 @@ namespace e2d
|
|||||||
const stdex::scheduler& deferrer::scheduler() const noexcept {
|
const stdex::scheduler& deferrer::scheduler() const noexcept {
|
||||||
return scheduler_;
|
return scheduler_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void deferrer::frame_tick() noexcept {
|
||||||
|
E2D_PROFILER_SCOPE("deferrer.frame_tick");
|
||||||
|
scheduler_.process_all_tasks();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include <enduro2d/core/input.hpp>
|
#include <enduro2d/core/input.hpp>
|
||||||
#include <enduro2d/core/network.hpp>
|
#include <enduro2d/core/network.hpp>
|
||||||
#include <enduro2d/core/platform.hpp>
|
#include <enduro2d/core/platform.hpp>
|
||||||
|
#include <enduro2d/core/profiler.hpp>
|
||||||
#include <enduro2d/core/render.hpp>
|
#include <enduro2d/core/render.hpp>
|
||||||
#include <enduro2d/core/vfs.hpp>
|
#include <enduro2d/core/vfs.hpp>
|
||||||
#include <enduro2d/core/window.hpp>
|
#include <enduro2d/core/window.hpp>
|
||||||
@@ -319,6 +320,8 @@ namespace e2d
|
|||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
void calculate_end_frame_timers() noexcept {
|
void calculate_end_frame_timers() noexcept {
|
||||||
|
E2D_PROFILER_SCOPE("engine.wait_for_target_fps");
|
||||||
|
|
||||||
const auto second_us = time::second_us<u64>();
|
const auto second_us = time::second_us<u64>();
|
||||||
|
|
||||||
const auto minimal_delta_time_us =
|
const auto minimal_delta_time_us =
|
||||||
@@ -382,6 +385,11 @@ namespace e2d
|
|||||||
|
|
||||||
safe_module_initialize<deferrer>();
|
safe_module_initialize<deferrer>();
|
||||||
|
|
||||||
|
// setup profiler
|
||||||
|
|
||||||
|
safe_module_initialize<profiler>(
|
||||||
|
the<deferrer>());
|
||||||
|
|
||||||
// setup debug
|
// setup debug
|
||||||
|
|
||||||
safe_module_initialize<debug>();
|
safe_module_initialize<debug>();
|
||||||
@@ -477,6 +485,7 @@ namespace e2d
|
|||||||
modules::shutdown<input>();
|
modules::shutdown<input>();
|
||||||
modules::shutdown<vfs>();
|
modules::shutdown<vfs>();
|
||||||
modules::shutdown<debug>();
|
modules::shutdown<debug>();
|
||||||
|
modules::shutdown<profiler>();
|
||||||
modules::shutdown<deferrer>();
|
modules::shutdown<deferrer>();
|
||||||
modules::shutdown<platform>();
|
modules::shutdown<platform>();
|
||||||
}
|
}
|
||||||
@@ -492,7 +501,7 @@ namespace e2d
|
|||||||
while ( true ) {
|
while ( true ) {
|
||||||
try {
|
try {
|
||||||
the<dbgui>().frame_tick();
|
the<dbgui>().frame_tick();
|
||||||
the<deferrer>().scheduler().process_all_tasks();
|
the<deferrer>().frame_tick();
|
||||||
|
|
||||||
if ( !app->frame_tick() ) {
|
if ( !app->frame_tick() ) {
|
||||||
break;
|
break;
|
||||||
@@ -510,8 +519,11 @@ namespace e2d
|
|||||||
app->shutdown();
|
app->shutdown();
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
the<input>().frame_tick();
|
the<input>().frame_tick();
|
||||||
window::poll_events();
|
window::poll_events();
|
||||||
|
|
||||||
|
E2D_PROFILER_GLOBAL_EVENT("engine.end_of_frame");
|
||||||
}
|
}
|
||||||
|
|
||||||
app->shutdown();
|
app->shutdown();
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
|
|
||||||
#include <enduro2d/core/input.hpp>
|
#include <enduro2d/core/input.hpp>
|
||||||
|
|
||||||
|
#include <enduro2d/core/profiler.hpp>
|
||||||
|
|
||||||
namespace e2d
|
namespace e2d
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
@@ -364,35 +366,8 @@ namespace e2d
|
|||||||
}
|
}
|
||||||
|
|
||||||
void input::frame_tick() noexcept {
|
void input::frame_tick() noexcept {
|
||||||
|
E2D_PROFILER_SCOPE("input.frame_tick");
|
||||||
state_->mouse.state_->frame_tick();
|
state_->mouse.state_->frame_tick();
|
||||||
state_->keyboard.state_->frame_tick();
|
state_->keyboard.state_->frame_tick();
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// class window_input_source
|
|
||||||
//
|
|
||||||
|
|
||||||
window_input_source::window_input_source(input& input) noexcept
|
|
||||||
: input_(input) {}
|
|
||||||
|
|
||||||
void window_input_source::on_input_char(char32_t uchar) noexcept {
|
|
||||||
input_.post_event(input::input_char_event{uchar});
|
|
||||||
}
|
|
||||||
|
|
||||||
void window_input_source::on_move_cursor(const v2f& pos) noexcept {
|
|
||||||
input_.post_event(input::move_cursor_event{pos});
|
|
||||||
}
|
|
||||||
|
|
||||||
void window_input_source::on_mouse_scroll(const v2f& delta) noexcept {
|
|
||||||
input_.post_event(input::mouse_scroll_event{delta});
|
|
||||||
}
|
|
||||||
|
|
||||||
void window_input_source::on_mouse_button(mouse_button btn, mouse_button_action act) noexcept {
|
|
||||||
input_.post_event(input::mouse_button_event{btn, act});
|
|
||||||
}
|
|
||||||
|
|
||||||
void window_input_source::on_keyboard_key(keyboard_key key, u32 scancode, keyboard_key_action act) noexcept {
|
|
||||||
E2D_UNUSED(scancode);
|
|
||||||
input_.post_event(input::keyboard_key_event{key, act});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
248
sources/enduro2d/core/profiler.cpp
Normal file
248
sources/enduro2d/core/profiler.cpp
Normal file
@@ -0,0 +1,248 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* This file is part of the "Enduro2D"
|
||||||
|
* For conditions of distribution and use, see copyright notice in LICENSE.md
|
||||||
|
* Copyright (C) 2018-2019, by Matvey Cherevko (blackmatov@gmail.com)
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#include <enduro2d/core/profiler.hpp>
|
||||||
|
|
||||||
|
#include <enduro2d/core/engine.hpp>
|
||||||
|
#include <enduro2d/core/vfs.hpp>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
using namespace e2d;
|
||||||
|
|
||||||
|
str recording_args_to_json(const profiler::args_t& args) {
|
||||||
|
str dst = "{";
|
||||||
|
for ( auto iter = args.begin(); iter != args.end(); ) {
|
||||||
|
dst += strings::rformat("\"%0\":\"%1\"", iter->first, iter->second);
|
||||||
|
if ( ++iter != args.end() ) {
|
||||||
|
dst += ",";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dst += "}";
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
str recording_info_to_json(const profiler::recording_info& src) {
|
||||||
|
str dst("{\"traceEvents\":[\n");
|
||||||
|
|
||||||
|
dst += strings::rformat(
|
||||||
|
" {\"name\":\"thread_name\",\"ph\":\"M\",\"tid\":%0,\"pid\":0,\"args\":{\"name\":\"%1\"}},\n",
|
||||||
|
std::hash<std::thread::id>()(the<engine>().main_thread()),
|
||||||
|
"Main");
|
||||||
|
|
||||||
|
for ( std::thread::id tid : the<vfs>().worker().thread_ids() ) {
|
||||||
|
dst += strings::rformat(
|
||||||
|
" {\"name\":\"thread_name\",\"ph\":\"M\",\"tid\":%0,\"pid\":0,\"args\":{\"name\":\"%1\"}},\n",
|
||||||
|
std::hash<std::thread::id>()(tid),
|
||||||
|
"VFS");
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( std::thread::id tid : the<deferrer>().worker().thread_ids() ) {
|
||||||
|
dst += strings::rformat(
|
||||||
|
" {\"name\":\"thread_name\",\"ph\":\"M\",\"tid\":%0,\"pid\":0,\"args\":{\"name\":\"%1\"}},\n",
|
||||||
|
std::hash<std::thread::id>()(tid),
|
||||||
|
"Worker");
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( auto iter = src.events.begin(); iter != src.events.end(); ) {
|
||||||
|
std::visit(utils::overloaded {
|
||||||
|
[&dst](const profiler::begin_scope_info& e){
|
||||||
|
char buf[512] = {'\0'};
|
||||||
|
strings::format(buf, std::size(buf),
|
||||||
|
" {\"name\":\"%0\",\"ph\":\"B\",\"ts\":%1,\"tid\":%2,\"pid\":0,\"cat\":\"\",\"args\":%3}",
|
||||||
|
e.name,
|
||||||
|
e.tp.count(),
|
||||||
|
std::hash<std::thread::id>()(e.tid),
|
||||||
|
recording_args_to_json(e.args));
|
||||||
|
dst += buf;
|
||||||
|
},
|
||||||
|
[&dst](const profiler::end_scope_info& e){
|
||||||
|
char buf[512] = {'\0'};
|
||||||
|
strings::format(buf, std::size(buf),
|
||||||
|
" {\"ph\":\"E\",\"ts\":%0,\"tid\":%1,\"pid\":0,\"cat\":\"\"}",
|
||||||
|
e.tp.count(),
|
||||||
|
std::hash<std::thread::id>()(e.tid));
|
||||||
|
dst += buf;
|
||||||
|
},
|
||||||
|
[&dst](const profiler::thread_event_info& e){
|
||||||
|
char buf[512] = {'\0'};
|
||||||
|
strings::format(buf, std::size(buf),
|
||||||
|
" {\"name\":\"%0\",\"ph\":\"i\",\"s\":\"t\",\"ts\":%1,\"tid\":%2,\"pid\":0,\"cat\":\"\",\"args\":%3}",
|
||||||
|
e.name,
|
||||||
|
e.tp.count(),
|
||||||
|
std::hash<std::thread::id>()(e.tid),
|
||||||
|
recording_args_to_json(e.args));
|
||||||
|
dst += buf;
|
||||||
|
},
|
||||||
|
[&dst](const profiler::global_event_info& e){
|
||||||
|
char buf[512] = {'\0'};
|
||||||
|
strings::format(buf, std::size(buf),
|
||||||
|
" {\"name\":\"%0\",\"ph\":\"i\",\"s\":\"g\",\"ts\":%1,\"tid\":%2,\"pid\":0,\"cat\":\"\",\"args\":%3}",
|
||||||
|
e.name,
|
||||||
|
e.tp.count(),
|
||||||
|
std::hash<std::thread::id>()(e.tid),
|
||||||
|
recording_args_to_json(e.args));
|
||||||
|
dst += buf;
|
||||||
|
}
|
||||||
|
}, *iter);
|
||||||
|
|
||||||
|
if ( ++iter != src.events.end() ) {
|
||||||
|
dst += ",\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dst += "\n]}";
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace e2d
|
||||||
|
{
|
||||||
|
profiler::auto_scope::auto_scope(profiler* profiler, str name)
|
||||||
|
: profiler_(profiler) {
|
||||||
|
if ( profiler_ ) {
|
||||||
|
profiler_->begin_scope(std::move(name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
profiler::auto_scope::auto_scope(profiler* profiler, str name, args_t args)
|
||||||
|
: profiler_(profiler) {
|
||||||
|
if ( profiler_ ) {
|
||||||
|
profiler_->begin_scope(std::move(name), std::move(args));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
profiler::auto_scope::~auto_scope() noexcept {
|
||||||
|
if ( profiler_ ) {
|
||||||
|
profiler_->end_scope();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace e2d
|
||||||
|
{
|
||||||
|
profiler::profiler(deferrer& d)
|
||||||
|
: deferrer_(d) {}
|
||||||
|
profiler::~profiler() noexcept = default;
|
||||||
|
|
||||||
|
profiler::sink& profiler::register_sink(sink_uptr sink) {
|
||||||
|
E2D_ASSERT(sink);
|
||||||
|
std::lock_guard guard(rmutex_);
|
||||||
|
sinks_.push_back(std::move(sink));
|
||||||
|
return *sinks_.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
void profiler::unregister_sink(const sink& sink) noexcept {
|
||||||
|
std::lock_guard guard(rmutex_);
|
||||||
|
for ( auto iter = sinks_.begin(); iter != sinks_.end(); ) {
|
||||||
|
if ( iter->get() == &sink ) {
|
||||||
|
iter = sinks_.erase(iter);
|
||||||
|
} else {
|
||||||
|
++iter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void profiler::begin_scope(str name) noexcept {
|
||||||
|
return begin_scope(std::move(name), {});
|
||||||
|
}
|
||||||
|
|
||||||
|
void profiler::begin_scope(str name, args_t args) noexcept {
|
||||||
|
++depth_;
|
||||||
|
|
||||||
|
begin_scope_info event{
|
||||||
|
std::move(name),
|
||||||
|
std::move(args),
|
||||||
|
std::this_thread::get_id(),
|
||||||
|
time::to_chrono(time::now_us())};
|
||||||
|
|
||||||
|
std::lock_guard guard(rmutex_);
|
||||||
|
for ( const auto& sink : sinks_ ) {
|
||||||
|
if ( sink ) {
|
||||||
|
sink->on_event(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void profiler::end_scope() noexcept {
|
||||||
|
E2D_ASSERT(depth_);
|
||||||
|
--depth_;
|
||||||
|
|
||||||
|
end_scope_info event{
|
||||||
|
std::this_thread::get_id(),
|
||||||
|
time::to_chrono(time::now_us())};
|
||||||
|
|
||||||
|
std::lock_guard guard(rmutex_);
|
||||||
|
for ( const auto& sink : sinks_ ) {
|
||||||
|
if ( sink ) {
|
||||||
|
sink->on_event(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void profiler::thread_event(str name) noexcept {
|
||||||
|
return thread_event(std::move(name), {});
|
||||||
|
}
|
||||||
|
|
||||||
|
void profiler::thread_event(str name, args_t args) noexcept {
|
||||||
|
thread_event_info event{
|
||||||
|
std::move(name),
|
||||||
|
std::move(args),
|
||||||
|
std::this_thread::get_id(),
|
||||||
|
time::to_chrono(time::now_us())};
|
||||||
|
|
||||||
|
std::lock_guard guard(rmutex_);
|
||||||
|
for ( const auto& sink : sinks_ ) {
|
||||||
|
if ( sink ) {
|
||||||
|
sink->on_event(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void profiler::global_event(str name) noexcept {
|
||||||
|
return global_event(std::move(name), {});
|
||||||
|
}
|
||||||
|
|
||||||
|
void profiler::global_event(str name, args_t args) noexcept {
|
||||||
|
global_event_info event{
|
||||||
|
std::move(name),
|
||||||
|
std::move(args),
|
||||||
|
std::this_thread::get_id(),
|
||||||
|
time::to_chrono(time::now_us())};
|
||||||
|
|
||||||
|
std::lock_guard guard(rmutex_);
|
||||||
|
for ( const auto& sink : sinks_ ) {
|
||||||
|
if ( sink ) {
|
||||||
|
sink->on_event(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace e2d::profilers
|
||||||
|
{
|
||||||
|
bool try_save_recording_info(
|
||||||
|
const profiler::recording_info& src,
|
||||||
|
buffer& dst) noexcept
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
str json = recording_info_to_json(src);
|
||||||
|
dst.assign(json.data(), json.size());
|
||||||
|
return true;
|
||||||
|
} catch (...) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool try_save_recording_info(
|
||||||
|
const profiler::recording_info& src,
|
||||||
|
const output_stream_uptr& dst) noexcept
|
||||||
|
{
|
||||||
|
buffer file_data;
|
||||||
|
return try_save_recording_info(src, file_data)
|
||||||
|
&& streams::try_write_tail(file_data, dst);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <enduro2d/core/debug.hpp>
|
#include <enduro2d/core/debug.hpp>
|
||||||
|
#include <enduro2d/core/profiler.hpp>
|
||||||
#include <enduro2d/core/render.hpp>
|
#include <enduro2d/core/render.hpp>
|
||||||
#include <enduro2d/core/window.hpp>
|
#include <enduro2d/core/window.hpp>
|
||||||
|
|
||||||
|
|||||||
@@ -181,10 +181,10 @@ namespace e2d
|
|||||||
}
|
}
|
||||||
|
|
||||||
shader_ptr render::create_shader(
|
shader_ptr render::create_shader(
|
||||||
const input_stream_uptr& vertex_stream,
|
buffer_view vertex_source,
|
||||||
const input_stream_uptr& fragment_stream)
|
buffer_view fragment_source)
|
||||||
{
|
{
|
||||||
E2D_UNUSED(vertex_stream, fragment_stream);
|
E2D_UNUSED(vertex_source, fragment_source);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,11 +193,6 @@ namespace e2d
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
texture_ptr render::create_texture(const input_stream_uptr& image_stream) {
|
|
||||||
E2D_UNUSED(image_stream);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
texture_ptr render::create_texture(const v2u& size, const pixel_declaration& decl) {
|
texture_ptr render::create_texture(const v2u& size, const pixel_declaration& decl) {
|
||||||
E2D_UNUSED(size, decl);
|
E2D_UNUSED(size, decl);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@@ -250,7 +245,7 @@ namespace e2d
|
|||||||
E2D_UNUSED(command);
|
E2D_UNUSED(command);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
render& render::update_buffer(
|
render& render::update_buffer(
|
||||||
const index_buffer_ptr& ibuffer,
|
const index_buffer_ptr& ibuffer,
|
||||||
buffer_view indices,
|
buffer_view indices,
|
||||||
|
|||||||
@@ -497,33 +497,51 @@ namespace e2d
|
|||||||
{
|
{
|
||||||
E2D_ASSERT(is_in_main_thread());
|
E2D_ASSERT(is_in_main_thread());
|
||||||
|
|
||||||
gl_shader_id vs = gl_compile_shader(
|
gl_shader_id vs(state_->dbg());
|
||||||
state_->dbg(),
|
|
||||||
vertex_shader_header_cstr(device_capabilities().profile),
|
|
||||||
vertex_source,
|
|
||||||
GL_VERTEX_SHADER);
|
|
||||||
|
|
||||||
if ( vs.empty() ) {
|
{
|
||||||
return nullptr;
|
E2D_PROFILER_SCOPE("render.compile_vertex_shader");
|
||||||
|
|
||||||
|
vs = gl_compile_shader(
|
||||||
|
state_->dbg(),
|
||||||
|
vertex_shader_header_cstr(device_capabilities().profile),
|
||||||
|
vertex_source,
|
||||||
|
GL_VERTEX_SHADER);
|
||||||
|
|
||||||
|
if ( vs.empty() ) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gl_shader_id fs = gl_compile_shader(
|
gl_shader_id fs(state_->dbg());
|
||||||
state_->dbg(),
|
|
||||||
fragment_shader_header_cstr(device_capabilities().profile),
|
|
||||||
fragment_source,
|
|
||||||
GL_FRAGMENT_SHADER);
|
|
||||||
|
|
||||||
if ( fs.empty() ) {
|
{
|
||||||
return nullptr;
|
E2D_PROFILER_SCOPE("render.compile_fragment_shader");
|
||||||
|
|
||||||
|
fs = gl_compile_shader(
|
||||||
|
state_->dbg(),
|
||||||
|
fragment_shader_header_cstr(device_capabilities().profile),
|
||||||
|
fragment_source,
|
||||||
|
GL_FRAGMENT_SHADER);
|
||||||
|
|
||||||
|
if ( fs.empty() ) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gl_program_id ps = gl_link_program(
|
gl_program_id ps(state_->dbg());
|
||||||
state_->dbg(),
|
|
||||||
std::move(vs),
|
|
||||||
std::move(fs));
|
|
||||||
|
|
||||||
if ( ps.empty() ) {
|
{
|
||||||
return nullptr;
|
E2D_PROFILER_SCOPE("render.link_shader_program");
|
||||||
|
|
||||||
|
ps = gl_link_program(
|
||||||
|
state_->dbg(),
|
||||||
|
std::move(vs),
|
||||||
|
std::move(fs));
|
||||||
|
|
||||||
|
if ( ps.empty() ) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::make_shared<shader>(
|
return std::make_shared<shader>(
|
||||||
@@ -532,16 +550,14 @@ namespace e2d
|
|||||||
}
|
}
|
||||||
|
|
||||||
shader_ptr render::create_shader(
|
shader_ptr render::create_shader(
|
||||||
const input_stream_uptr& vertex,
|
buffer_view vertex_source,
|
||||||
const input_stream_uptr& fragment)
|
buffer_view fragment_source)
|
||||||
{
|
{
|
||||||
E2D_ASSERT(is_in_main_thread());
|
E2D_ASSERT(is_in_main_thread());
|
||||||
|
|
||||||
str vertex_source, fragment_source;
|
return create_shader(
|
||||||
return streams::try_read_tail(vertex_source, vertex)
|
str_view(reinterpret_cast<const char*>(vertex_source.data()), vertex_source.size()),
|
||||||
&& streams::try_read_tail(fragment_source, fragment)
|
str_view(reinterpret_cast<const char*>(fragment_source.data()), fragment_source.size()));
|
||||||
? create_shader(vertex_source, fragment_source)
|
|
||||||
: nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
texture_ptr render::create_texture(
|
texture_ptr render::create_texture(
|
||||||
@@ -585,6 +601,11 @@ namespace e2d
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
E2D_PROFILER_SCOPE_EX("render.create_texture_from_image", {
|
||||||
|
{"size", strings::rformat("%0", image.size())},
|
||||||
|
{"format", strings::rformat("%0", image.format())}
|
||||||
|
});
|
||||||
|
|
||||||
gl_texture_id id = gl_texture_id::create(state_->dbg(), GL_TEXTURE_2D);
|
gl_texture_id id = gl_texture_id::create(state_->dbg(), GL_TEXTURE_2D);
|
||||||
if ( id.empty() ) {
|
if ( id.empty() ) {
|
||||||
state_->dbg().error("RENDER: Failed to create texture:\n"
|
state_->dbg().error("RENDER: Failed to create texture:\n"
|
||||||
@@ -622,18 +643,6 @@ namespace e2d
|
|||||||
state_->dbg(), std::move(id), image.size(), decl));
|
state_->dbg(), std::move(id), image.size(), decl));
|
||||||
}
|
}
|
||||||
|
|
||||||
texture_ptr render::create_texture(
|
|
||||||
const input_stream_uptr& image_stream)
|
|
||||||
{
|
|
||||||
E2D_ASSERT(is_in_main_thread());
|
|
||||||
|
|
||||||
image image;
|
|
||||||
if ( !images::try_load_image(image, image_stream) ) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return create_texture(image);
|
|
||||||
}
|
|
||||||
|
|
||||||
texture_ptr render::create_texture(
|
texture_ptr render::create_texture(
|
||||||
const v2u& size,
|
const v2u& size,
|
||||||
const pixel_declaration& decl)
|
const pixel_declaration& decl)
|
||||||
@@ -673,6 +682,11 @@ namespace e2d
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
E2D_PROFILER_SCOPE_EX("render.create_empty_texture", {
|
||||||
|
{"size", strings::rformat("%0", size)},
|
||||||
|
{"format", strings::rformat("%0", decl.type())}
|
||||||
|
});
|
||||||
|
|
||||||
gl_texture_id id = gl_texture_id::create(state_->dbg(), GL_TEXTURE_2D);
|
gl_texture_id id = gl_texture_id::create(state_->dbg(), GL_TEXTURE_2D);
|
||||||
if ( id.empty() ) {
|
if ( id.empty() ) {
|
||||||
state_->dbg().error("RENDER: Failed to create texture:\n"
|
state_->dbg().error("RENDER: Failed to create texture:\n"
|
||||||
@@ -737,6 +751,8 @@ namespace e2d
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
E2D_PROFILER_SCOPE("render.create_index_buffer");
|
||||||
|
|
||||||
gl_buffer_id id = gl_buffer_id::create(state_->dbg(), GL_ELEMENT_ARRAY_BUFFER);
|
gl_buffer_id id = gl_buffer_id::create(state_->dbg(), GL_ELEMENT_ARRAY_BUFFER);
|
||||||
if ( id.empty() ) {
|
if ( id.empty() ) {
|
||||||
state_->dbg().error("RENDER: Failed to create index buffer:\n"
|
state_->dbg().error("RENDER: Failed to create index buffer:\n"
|
||||||
@@ -771,6 +787,8 @@ namespace e2d
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
E2D_PROFILER_SCOPE("render.create_vertex_buffer");
|
||||||
|
|
||||||
gl_buffer_id id = gl_buffer_id::create(state_->dbg(), GL_ARRAY_BUFFER);
|
gl_buffer_id id = gl_buffer_id::create(state_->dbg(), GL_ARRAY_BUFFER);
|
||||||
if ( id.empty() ) {
|
if ( id.empty() ) {
|
||||||
state_->dbg().error("RENDER: Failed to create vertex buffer:\n"
|
state_->dbg().error("RENDER: Failed to create vertex buffer:\n"
|
||||||
@@ -827,6 +845,8 @@ namespace e2d
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
E2D_PROFILER_SCOPE("render.create_render_target");
|
||||||
|
|
||||||
gl_framebuffer_id id = gl_framebuffer_id::create(state_->dbg(), GL_FRAMEBUFFER);
|
gl_framebuffer_id id = gl_framebuffer_id::create(state_->dbg(), GL_FRAMEBUFFER);
|
||||||
if ( id.empty() ) {
|
if ( id.empty() ) {
|
||||||
state_->dbg().error("RENDER: Failed to create framebuffer:\n",
|
state_->dbg().error("RENDER: Failed to create framebuffer:\n",
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
|
|
||||||
#include <enduro2d/core/vfs.hpp>
|
#include <enduro2d/core/vfs.hpp>
|
||||||
|
|
||||||
|
#include <enduro2d/core/profiler.hpp>
|
||||||
|
|
||||||
#include <3rdparty/miniz/miniz.h>
|
#include <3rdparty/miniz/miniz.h>
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
@@ -108,9 +110,18 @@ namespace e2d
|
|||||||
|
|
||||||
vfs::vfs()
|
vfs::vfs()
|
||||||
: state_(new state()){}
|
: state_(new state()){}
|
||||||
|
|
||||||
vfs::~vfs() noexcept = default;
|
vfs::~vfs() noexcept = default;
|
||||||
|
|
||||||
|
stdex::jobber& vfs::worker() noexcept {
|
||||||
|
std::lock_guard<std::mutex> guard(state_->mutex);
|
||||||
|
return state_->worker;
|
||||||
|
}
|
||||||
|
|
||||||
|
const stdex::jobber& vfs::worker() const noexcept {
|
||||||
|
std::lock_guard<std::mutex> guard(state_->mutex);
|
||||||
|
return state_->worker;
|
||||||
|
}
|
||||||
|
|
||||||
bool vfs::register_scheme(str_view scheme, file_source_uptr source) {
|
bool vfs::register_scheme(str_view scheme, file_source_uptr source) {
|
||||||
std::lock_guard<std::mutex> guard(state_->mutex);
|
std::lock_guard<std::mutex> guard(state_->mutex);
|
||||||
return (source && source->valid())
|
return (source && source->valid())
|
||||||
@@ -163,16 +174,20 @@ namespace e2d
|
|||||||
}, output_stream_uptr());
|
}, output_stream_uptr());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool vfs::load(const url& url, buffer& dst) const {
|
std::optional<buffer> vfs::load(const url& url) const {
|
||||||
return load_async(url)
|
E2D_PROFILER_SCOPE_EX("vfs.sync_load", {
|
||||||
.then([&dst](auto&& src){
|
{"url", url.schemepath()}
|
||||||
dst = std::forward<decltype(src)>(src);
|
});
|
||||||
return true;
|
return load_async(url).then([](auto&& src){
|
||||||
}).get_or_default(false);
|
return std::optional<buffer>(std::forward<decltype(src)>(src));
|
||||||
|
}).get_or_default(std::nullopt);
|
||||||
}
|
}
|
||||||
|
|
||||||
stdex::promise<buffer> vfs::load_async(const url& url) const {
|
stdex::promise<buffer> vfs::load_async(const url& url) const {
|
||||||
return state_->worker.async([this, url](){
|
return state_->worker.async([this, url](){
|
||||||
|
E2D_PROFILER_SCOPE_EX("vfs.load_async", {
|
||||||
|
{"url", url.schemepath()}
|
||||||
|
});
|
||||||
buffer content;
|
buffer content;
|
||||||
const input_stream_uptr stream = read(url);
|
const input_stream_uptr stream = read(url);
|
||||||
if ( !stream || !streams::try_read_tail(content, stream) ) {
|
if ( !stream || !streams::try_read_tail(content, stream) ) {
|
||||||
@@ -182,16 +197,20 @@ namespace e2d
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool vfs::load_as_string(const url& url, str& dst) const {
|
std::optional<str> vfs::load_as_string(const url& url) const {
|
||||||
return load_as_string_async(url)
|
E2D_PROFILER_SCOPE_EX("vfs.sync_load_as_string", {
|
||||||
.then([&dst](auto&& src){
|
{"url", url.schemepath()}
|
||||||
dst = std::forward<decltype(src)>(src);
|
});
|
||||||
return true;
|
return load_as_string_async(url).then([](auto&& src){
|
||||||
}).get_or_default(false);
|
return std::optional<str>(std::forward<decltype(src)>(src));
|
||||||
|
}).get_or_default(std::nullopt);
|
||||||
}
|
}
|
||||||
|
|
||||||
stdex::promise<str> vfs::load_as_string_async(const url& url) const {
|
stdex::promise<str> vfs::load_as_string_async(const url& url) const {
|
||||||
return state_->worker.async([this, url](){
|
return state_->worker.async([this, url](){
|
||||||
|
E2D_PROFILER_SCOPE_EX("vfs.load_as_string_async", {
|
||||||
|
{"url", url.schemepath()}
|
||||||
|
});
|
||||||
str content;
|
str content;
|
||||||
const input_stream_uptr stream = read(url);
|
const input_stream_uptr stream = read(url);
|
||||||
if ( !stream || !streams::try_read_tail(content, stream) ) {
|
if ( !stream || !streams::try_read_tail(content, stream) ) {
|
||||||
|
|||||||
@@ -7,13 +7,10 @@
|
|||||||
#include <enduro2d/core/window.hpp>
|
#include <enduro2d/core/window.hpp>
|
||||||
|
|
||||||
#include <enduro2d/core/debug.hpp>
|
#include <enduro2d/core/debug.hpp>
|
||||||
|
#include <enduro2d/core/input.hpp>
|
||||||
|
|
||||||
namespace e2d
|
namespace e2d
|
||||||
{
|
{
|
||||||
//
|
|
||||||
// class window::event_listener
|
|
||||||
//
|
|
||||||
|
|
||||||
void window::event_listener::on_input_char(char32_t uchar) noexcept {
|
void window::event_listener::on_input_char(char32_t uchar) noexcept {
|
||||||
E2D_UNUSED(uchar);
|
E2D_UNUSED(uchar);
|
||||||
}
|
}
|
||||||
@@ -52,56 +49,77 @@ namespace e2d
|
|||||||
void window::event_listener::on_window_minimize(bool minimized) noexcept {
|
void window::event_listener::on_window_minimize(bool minimized) noexcept {
|
||||||
E2D_UNUSED(minimized);
|
E2D_UNUSED(minimized);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//
|
namespace e2d
|
||||||
// class trace_window_event_listener
|
{
|
||||||
//
|
window_event_tracer::window_event_tracer(debug& debug) noexcept
|
||||||
|
|
||||||
window_trace_event_listener::window_trace_event_listener(debug& debug) noexcept
|
|
||||||
: debug_(debug) {}
|
: debug_(debug) {}
|
||||||
|
|
||||||
void window_trace_event_listener::on_input_char(char32_t uchar) noexcept {
|
void window_event_tracer::on_input_char(char32_t uchar) noexcept {
|
||||||
debug_.trace("WINDOW: on_input_char(uchar: %0)", str32_view(&uchar, 1));
|
debug_.trace("WINDOW: on_input_char(uchar: %0)", str32_view(&uchar, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
void window_trace_event_listener::on_move_cursor(const v2f& pos) noexcept {
|
void window_event_tracer::on_move_cursor(const v2f& pos) noexcept {
|
||||||
debug_.trace("WINDOW: on_move_cursor(pos: %0)", pos);
|
debug_.trace("WINDOW: on_move_cursor(pos: %0)", pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
void window_trace_event_listener::on_mouse_scroll(const v2f& delta) noexcept {
|
void window_event_tracer::on_mouse_scroll(const v2f& delta) noexcept {
|
||||||
debug_.trace("WINDOW: on_scroll(delta: %0)", delta);
|
debug_.trace("WINDOW: on_scroll(delta: %0)", delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
void window_trace_event_listener::on_mouse_button(mouse_button btn, mouse_button_action act) noexcept {
|
void window_event_tracer::on_mouse_button(mouse_button btn, mouse_button_action act) noexcept {
|
||||||
debug_.trace("WINDOW: on_mouse_button(btn: %0 act: %1)",
|
debug_.trace("WINDOW: on_mouse_button(btn: %0 act: %1)", btn, act);
|
||||||
btn,
|
|
||||||
act);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void window_trace_event_listener::on_keyboard_key(keyboard_key key, u32 scancode, keyboard_key_action act) noexcept {
|
void window_event_tracer::on_keyboard_key(keyboard_key key, u32 scancode, keyboard_key_action act) noexcept {
|
||||||
debug_.trace("WINDOW: on_keyboard_key(key: %0 scancode: %1 act: %2)",
|
debug_.trace("WINDOW: on_keyboard_key(key: %0 scancode: %1 act: %2)", key, scancode, act);
|
||||||
key,
|
|
||||||
scancode,
|
|
||||||
act);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void window_trace_event_listener::on_window_size(const v2u& size) noexcept {
|
void window_event_tracer::on_window_size(const v2u& size) noexcept {
|
||||||
debug_.trace("WINDOW: on_window_size(size: %0)", size);
|
debug_.trace("WINDOW: on_window_size(size: %0)", size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void window_trace_event_listener::on_framebuffer_size(const v2u& size) noexcept {
|
void window_event_tracer::on_framebuffer_size(const v2u& size) noexcept {
|
||||||
debug_.trace("WINDOW: on_framebuffer_size(size: %0)", size);
|
debug_.trace("WINDOW: on_framebuffer_size(size: %0)", size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void window_trace_event_listener::on_window_close() noexcept {
|
void window_event_tracer::on_window_close() noexcept {
|
||||||
debug_.trace("WINDOW: on_window_close()");
|
debug_.trace("WINDOW: on_window_close()");
|
||||||
}
|
}
|
||||||
|
|
||||||
void window_trace_event_listener::on_window_focus(bool focused) noexcept {
|
void window_event_tracer::on_window_focus(bool focused) noexcept {
|
||||||
debug_.trace("WINDOW: on_window_focus(focused: %0)", focused);
|
debug_.trace("WINDOW: on_window_focus(focused: %0)", focused);
|
||||||
}
|
}
|
||||||
|
|
||||||
void window_trace_event_listener::on_window_minimize(bool minimized) noexcept {
|
void window_event_tracer::on_window_minimize(bool minimized) noexcept {
|
||||||
debug_.trace("WINDOW: on_window_minimize(minimized: %0)", minimized);
|
debug_.trace("WINDOW: on_window_minimize(minimized: %0)", minimized);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace e2d
|
||||||
|
{
|
||||||
|
window_input_source::window_input_source(input& input) noexcept
|
||||||
|
: input_(input) {}
|
||||||
|
|
||||||
|
void window_input_source::on_input_char(char32_t uchar) noexcept {
|
||||||
|
input_.post_event(input::input_char_event{uchar});
|
||||||
|
}
|
||||||
|
|
||||||
|
void window_input_source::on_move_cursor(const v2f& pos) noexcept {
|
||||||
|
input_.post_event(input::move_cursor_event{pos});
|
||||||
|
}
|
||||||
|
|
||||||
|
void window_input_source::on_mouse_scroll(const v2f& delta) noexcept {
|
||||||
|
input_.post_event(input::mouse_scroll_event{delta});
|
||||||
|
}
|
||||||
|
|
||||||
|
void window_input_source::on_mouse_button(mouse_button btn, mouse_button_action act) noexcept {
|
||||||
|
input_.post_event(input::mouse_button_event{btn, act});
|
||||||
|
}
|
||||||
|
|
||||||
|
void window_input_source::on_keyboard_key(keyboard_key key, u32 scancode, keyboard_key_action act) noexcept {
|
||||||
|
E2D_UNUSED(scancode);
|
||||||
|
input_.post_event(input::keyboard_key_event{key, act});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <enduro2d/core/debug.hpp>
|
#include <enduro2d/core/debug.hpp>
|
||||||
|
#include <enduro2d/core/profiler.hpp>
|
||||||
#include <enduro2d/core/window.hpp>
|
#include <enduro2d/core/window.hpp>
|
||||||
|
|
||||||
#define E2D_WINDOW_MODE_NONE 1
|
#define E2D_WINDOW_MODE_NONE 1
|
||||||
|
|||||||
@@ -691,6 +691,7 @@ namespace e2d
|
|||||||
}
|
}
|
||||||
|
|
||||||
void window::swap_buffers() noexcept {
|
void window::swap_buffers() noexcept {
|
||||||
|
E2D_PROFILER_SCOPE("window.swap_buffers");
|
||||||
std::lock_guard<std::recursive_mutex> guard(state_->rmutex);
|
std::lock_guard<std::recursive_mutex> guard(state_->rmutex);
|
||||||
E2D_ASSERT(
|
E2D_ASSERT(
|
||||||
state_->window &&
|
state_->window &&
|
||||||
@@ -699,6 +700,7 @@ namespace e2d
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool window::poll_events() noexcept {
|
bool window::poll_events() noexcept {
|
||||||
|
E2D_PROFILER_SCOPE("window.poll_events");
|
||||||
return glfw_state::poll_events();
|
return glfw_state::poll_events();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,8 +26,16 @@ namespace e2d
|
|||||||
const library& library, str_view address)
|
const library& library, str_view address)
|
||||||
{
|
{
|
||||||
return library.load_asset_async<binary_asset>(address)
|
return library.load_asset_async<binary_asset>(address)
|
||||||
.then([](const binary_asset::load_result& font_data){
|
.then([
|
||||||
return the<deferrer>().do_in_worker_thread([font_data](){
|
address = str(address)
|
||||||
|
](const binary_asset::load_result& font_data){
|
||||||
|
return the<deferrer>().do_in_worker_thread([
|
||||||
|
font_data,
|
||||||
|
address = std::move(address)
|
||||||
|
](){
|
||||||
|
E2D_PROFILER_SCOPE_EX("font_asset.parsing", {
|
||||||
|
{"address", address}
|
||||||
|
});
|
||||||
font content;
|
font content;
|
||||||
if ( !fonts::try_load_font(content, font_data->content()) ) {
|
if ( !fonts::try_load_font(content, font_data->content()) ) {
|
||||||
throw font_asset_loading_exception();
|
throw font_asset_loading_exception();
|
||||||
@@ -35,15 +43,14 @@ namespace e2d
|
|||||||
return content;
|
return content;
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.then([
|
.then_tuple([
|
||||||
&library,
|
&library,
|
||||||
parent_address = path::parent_path(address)
|
parent_address = path::parent_path(address)
|
||||||
](const font& content){
|
](const font& content){
|
||||||
return stdex::make_tuple_promise(std::make_tuple(
|
return std::make_tuple(
|
||||||
stdex::make_resolved_promise(content),
|
stdex::make_resolved_promise(content),
|
||||||
library.load_asset_async<texture_asset>(
|
library.load_asset_async<texture_asset>(
|
||||||
path::combine(parent_address, content.info().atlas_file))
|
path::combine(parent_address, content.info().atlas_file)));
|
||||||
));
|
|
||||||
})
|
})
|
||||||
.then([](const std::tuple<
|
.then([](const std::tuple<
|
||||||
font,
|
font,
|
||||||
|
|||||||
@@ -24,8 +24,16 @@ namespace e2d
|
|||||||
const library& library, str_view address)
|
const library& library, str_view address)
|
||||||
{
|
{
|
||||||
return library.load_asset_async<binary_asset>(address)
|
return library.load_asset_async<binary_asset>(address)
|
||||||
.then([](const binary_asset::load_result& image_data){
|
.then([
|
||||||
return the<deferrer>().do_in_worker_thread([image_data](){
|
address = str(address)
|
||||||
|
](const binary_asset::load_result& image_data){
|
||||||
|
return the<deferrer>().do_in_worker_thread([
|
||||||
|
image_data,
|
||||||
|
address = std::move(address)
|
||||||
|
](){
|
||||||
|
E2D_PROFILER_SCOPE_EX("image_asset.load_async", {
|
||||||
|
{"address", address}
|
||||||
|
});
|
||||||
image content;
|
image content;
|
||||||
if ( !images::try_load_image(content, image_data->content()) ) {
|
if ( !images::try_load_image(content, image_data->content()) ) {
|
||||||
throw image_asset_loading_exception();
|
throw image_asset_loading_exception();
|
||||||
|
|||||||
@@ -24,8 +24,16 @@ namespace e2d
|
|||||||
const library& library, str_view address)
|
const library& library, str_view address)
|
||||||
{
|
{
|
||||||
return library.load_asset_async<text_asset>(address)
|
return library.load_asset_async<text_asset>(address)
|
||||||
.then([](const text_asset::load_result& json_data){
|
.then([
|
||||||
return the<deferrer>().do_in_worker_thread([json_data](){
|
address = str(address)
|
||||||
|
](const text_asset::load_result& json_data){
|
||||||
|
return the<deferrer>().do_in_worker_thread([
|
||||||
|
json_data,
|
||||||
|
address = std::move(address)
|
||||||
|
](){
|
||||||
|
E2D_PROFILER_SCOPE_EX("json_asset.parsing", {
|
||||||
|
{"address", address}
|
||||||
|
});
|
||||||
auto json = std::make_shared<rapidjson::Document>();
|
auto json = std::make_shared<rapidjson::Document>();
|
||||||
if ( json->Parse(json_data->content().c_str()).HasParseError() ) {
|
if ( json->Parse(json_data->content().c_str()).HasParseError() ) {
|
||||||
throw json_asset_loading_exception();
|
throw json_asset_loading_exception();
|
||||||
|
|||||||
@@ -24,8 +24,16 @@ namespace e2d
|
|||||||
const library& library, str_view address)
|
const library& library, str_view address)
|
||||||
{
|
{
|
||||||
return library.load_asset_async<binary_asset>(address)
|
return library.load_asset_async<binary_asset>(address)
|
||||||
.then([](const binary_asset::load_result& mesh_data){
|
.then([
|
||||||
return the<deferrer>().do_in_worker_thread([mesh_data](){
|
address = str(address)
|
||||||
|
](const binary_asset::load_result& mesh_data){
|
||||||
|
return the<deferrer>().do_in_worker_thread([
|
||||||
|
mesh_data,
|
||||||
|
address = std::move(address)
|
||||||
|
](){
|
||||||
|
E2D_PROFILER_SCOPE_EX("mesh_asset.parsing", {
|
||||||
|
{"address", address}
|
||||||
|
});
|
||||||
mesh content;
|
mesh content;
|
||||||
if ( !meshes::try_load_mesh(content, mesh_data->content()) ) {
|
if ( !meshes::try_load_mesh(content, mesh_data->content()) ) {
|
||||||
throw mesh_asset_loading_exception();
|
throw mesh_asset_loading_exception();
|
||||||
|
|||||||
@@ -26,8 +26,16 @@ namespace e2d
|
|||||||
const library& library, str_view address)
|
const library& library, str_view address)
|
||||||
{
|
{
|
||||||
return library.load_asset_async<binary_asset>(address)
|
return library.load_asset_async<binary_asset>(address)
|
||||||
.then([](const binary_asset::load_result& script_data){
|
.then([
|
||||||
return the<deferrer>().do_in_main_thread([script_data](){
|
address = str(address)
|
||||||
|
](const binary_asset::load_result& script_data){
|
||||||
|
return the<deferrer>().do_in_main_thread([
|
||||||
|
script_data,
|
||||||
|
address = std::move(address)
|
||||||
|
](){
|
||||||
|
E2D_PROFILER_SCOPE_EX("script_asset.parsing", {
|
||||||
|
{"address", address}
|
||||||
|
});
|
||||||
std::optional<script> script_opt = the<luasol>().load_script(
|
std::optional<script> script_opt = the<luasol>().load_script(
|
||||||
script_data->content());
|
script_data->content());
|
||||||
if ( !script_opt ) {
|
if ( !script_opt ) {
|
||||||
|
|||||||
@@ -54,21 +54,32 @@ namespace
|
|||||||
const rapidjson::Value& root)
|
const rapidjson::Value& root)
|
||||||
{
|
{
|
||||||
E2D_ASSERT(root.HasMember("vertex") && root["vertex"].IsString());
|
E2D_ASSERT(root.HasMember("vertex") && root["vertex"].IsString());
|
||||||
auto vertex_p = library.load_asset_async<text_asset>(
|
auto vertex_a = path::combine(parent_address, root["vertex"].GetString());
|
||||||
path::combine(parent_address, root["vertex"].GetString()));
|
auto vertex_p = library.load_asset_async<text_asset>(vertex_a);
|
||||||
|
|
||||||
E2D_ASSERT(root.HasMember("fragment") && root["fragment"].IsString());
|
E2D_ASSERT(root.HasMember("fragment") && root["fragment"].IsString());
|
||||||
auto fragment_p = library.load_asset_async<text_asset>(
|
auto fragment_a = path::combine(parent_address, root["fragment"].GetString());
|
||||||
path::combine(parent_address, root["fragment"].GetString()));
|
auto fragment_p = library.load_asset_async<text_asset>(fragment_a);
|
||||||
|
|
||||||
return stdex::make_tuple_promise(std::make_tuple(
|
return stdex::make_tuple_promise(std::make_tuple(
|
||||||
std::move(vertex_p),
|
std::move(vertex_p),
|
||||||
std::move(fragment_p)))
|
std::move(fragment_p)))
|
||||||
.then([](const std::tuple<
|
.then([
|
||||||
|
vertex_a = std::move(vertex_a),
|
||||||
|
fragment_a = std::move(fragment_a)
|
||||||
|
](const std::tuple<
|
||||||
text_asset::load_result,
|
text_asset::load_result,
|
||||||
text_asset::load_result
|
text_asset::load_result
|
||||||
>& results){
|
>& results){
|
||||||
return the<deferrer>().do_in_main_thread([results](){
|
return the<deferrer>().do_in_main_thread([
|
||||||
|
results,
|
||||||
|
vertex_a = std::move(vertex_a),
|
||||||
|
fragment_a = std::move(fragment_a)
|
||||||
|
](){
|
||||||
|
E2D_PROFILER_SCOPE_EX("shader_asset.create_shader", {
|
||||||
|
{"vertex_address", vertex_a},
|
||||||
|
{"fragment_address", fragment_a}
|
||||||
|
});
|
||||||
const shader_ptr content = the<render>().create_shader(
|
const shader_ptr content = the<render>().create_shader(
|
||||||
std::get<0>(results)->content(),
|
std::get<0>(results)->content(),
|
||||||
std::get<1>(results)->content());
|
std::get<1>(results)->content());
|
||||||
|
|||||||
@@ -24,8 +24,16 @@ namespace e2d
|
|||||||
const library& library, str_view address)
|
const library& library, str_view address)
|
||||||
{
|
{
|
||||||
return library.load_asset_async<binary_asset>(address)
|
return library.load_asset_async<binary_asset>(address)
|
||||||
.then([](const binary_asset::load_result& shape_data){
|
.then([
|
||||||
return the<deferrer>().do_in_worker_thread([shape_data](){
|
address = str(address)
|
||||||
|
](const binary_asset::load_result& shape_data){
|
||||||
|
return the<deferrer>().do_in_worker_thread([
|
||||||
|
shape_data,
|
||||||
|
address = std::move(address)
|
||||||
|
](){
|
||||||
|
E2D_PROFILER_SCOPE_EX("shape_asset.parsing", {
|
||||||
|
{"address", address}
|
||||||
|
});
|
||||||
shape content;
|
shape content;
|
||||||
if ( !shapes::try_load_shape(content, shape_data->content()) ) {
|
if ( !shapes::try_load_shape(content, shape_data->content()) ) {
|
||||||
throw shape_asset_loading_exception();
|
throw shape_asset_loading_exception();
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ namespace
|
|||||||
return library.load_asset_async<binary_asset>(sound_address)
|
return library.load_asset_async<binary_asset>(sound_address)
|
||||||
.then([](const binary_asset::load_result& sound_data){
|
.then([](const binary_asset::load_result& sound_data){
|
||||||
return the<deferrer>().do_in_worker_thread([sound_data](){
|
return the<deferrer>().do_in_worker_thread([sound_data](){
|
||||||
sound_stream_ptr content = the<audio>().preload_stream(
|
sound_stream_ptr content = the<audio>().create_stream(
|
||||||
sound_data->content());
|
sound_data->content());
|
||||||
if ( !content ) {
|
if ( !content ) {
|
||||||
throw sound_asset_loading_exception();
|
throw sound_asset_loading_exception();
|
||||||
|
|||||||
@@ -116,58 +116,72 @@ namespace
|
|||||||
return library.load_asset_async<binary_asset>(atlas_path)
|
return library.load_asset_async<binary_asset>(atlas_path)
|
||||||
.then([
|
.then([
|
||||||
&library,
|
&library,
|
||||||
|
atlas_path,
|
||||||
atlas_folder
|
atlas_folder
|
||||||
](const binary_asset::load_result& atlas_data){
|
](const binary_asset::load_result& atlas_data){
|
||||||
auto atlas_internal = std::make_unique<atlas_internal_state>();
|
return the<deferrer>().do_in_worker_thread([](){})
|
||||||
|
.then([
|
||||||
|
&library,
|
||||||
|
atlas_data,
|
||||||
|
atlas_path,
|
||||||
|
atlas_folder
|
||||||
|
](){
|
||||||
|
E2D_PROFILER_SCOPE_EX("spine_asset.atlas_parsing", {
|
||||||
|
{"address", atlas_path}
|
||||||
|
});
|
||||||
|
|
||||||
spine::atlas_ptr atlas(
|
auto atlas_internal = std::make_unique<atlas_internal_state>();
|
||||||
spAtlas_create(
|
|
||||||
reinterpret_cast<const char*>(atlas_data->content().data()),
|
|
||||||
math::numeric_cast<int>(atlas_data->content().size()),
|
|
||||||
atlas_folder.c_str(),
|
|
||||||
atlas_internal.get()),
|
|
||||||
spAtlas_dispose);
|
|
||||||
|
|
||||||
if ( !atlas ) {
|
spine::atlas_ptr atlas(
|
||||||
the<debug>().error("SPINE: Failed to create preload atlas");
|
spAtlas_create(
|
||||||
throw spine_asset_loading_exception();
|
reinterpret_cast<const char*>(atlas_data->content().data()),
|
||||||
}
|
math::numeric_cast<int>(atlas_data->content().size()),
|
||||||
|
atlas_folder.c_str(),
|
||||||
|
atlas_internal.get()),
|
||||||
|
spAtlas_dispose);
|
||||||
|
|
||||||
return stdex::make_tuple_promise(std::make_tuple(
|
if ( !atlas ) {
|
||||||
atlas_internal->loading.load_async(library),
|
the<debug>().error("SPINE: Failed to create preload atlas");
|
||||||
stdex::make_resolved_promise(atlas_data)));
|
throw spine_asset_loading_exception();
|
||||||
})
|
}
|
||||||
.then([
|
|
||||||
atlas_folder
|
|
||||||
](const std::tuple<
|
|
||||||
asset_group,
|
|
||||||
binary_asset::load_result
|
|
||||||
>& results){
|
|
||||||
auto atlas_internal = std::make_unique<atlas_internal_state>();
|
|
||||||
atlas_internal->loaded = std::get<0>(results);
|
|
||||||
|
|
||||||
spine::atlas_ptr atlas(
|
return atlas_internal->loading.load_async(library);
|
||||||
spAtlas_create(
|
})
|
||||||
reinterpret_cast<const char*>(std::get<1>(results)->content().data()),
|
.then([
|
||||||
math::numeric_cast<int>(std::get<1>(results)->content().size()),
|
atlas_data,
|
||||||
atlas_folder.c_str(),
|
atlas_path,
|
||||||
atlas_internal.get()),
|
atlas_folder
|
||||||
spAtlas_dispose);
|
](auto&& dependencies){
|
||||||
|
E2D_PROFILER_SCOPE_EX("spine_asset.atlas_parsing", {
|
||||||
|
{"address", atlas_path}
|
||||||
|
});
|
||||||
|
|
||||||
if ( !atlas ) {
|
auto atlas_internal = std::make_unique<atlas_internal_state>();
|
||||||
the<debug>().error("SPINE: Failed to create preloaded atlas");
|
atlas_internal->loaded = std::forward<decltype(dependencies)>(dependencies);
|
||||||
throw spine_asset_loading_exception();
|
|
||||||
}
|
|
||||||
|
|
||||||
for ( const spAtlasPage* page = atlas->pages; page; page = page->next ) {
|
spine::atlas_ptr atlas(
|
||||||
if ( !page->rendererObject ) {
|
spAtlas_create(
|
||||||
|
reinterpret_cast<const char*>(atlas_data->content().data()),
|
||||||
|
math::numeric_cast<int>(atlas_data->content().size()),
|
||||||
|
atlas_folder.c_str(),
|
||||||
|
atlas_internal.get()),
|
||||||
|
spAtlas_dispose);
|
||||||
|
|
||||||
|
if ( !atlas ) {
|
||||||
the<debug>().error("SPINE: Failed to create preloaded atlas");
|
the<debug>().error("SPINE: Failed to create preloaded atlas");
|
||||||
throw spine_asset_loading_exception();
|
throw spine_asset_loading_exception();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
atlas->rendererObject = nullptr;
|
for ( const spAtlasPage* page = atlas->pages; page; page = page->next ) {
|
||||||
return atlas;
|
if ( !page->rendererObject ) {
|
||||||
|
the<debug>().error("SPINE: Failed to create preloaded atlas");
|
||||||
|
throw spine_asset_loading_exception();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
atlas->rendererObject = nullptr;
|
||||||
|
return atlas;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,75 +192,85 @@ namespace
|
|||||||
f32 skeleton_scale,
|
f32 skeleton_scale,
|
||||||
const spine::atlas_ptr& atlas)
|
const spine::atlas_ptr& atlas)
|
||||||
{
|
{
|
||||||
return library.load_asset_async<binary_asset>(
|
str address = path::combine(parent_address, skeleton_address);
|
||||||
path::combine(parent_address, skeleton_address))
|
return library.load_asset_async<binary_asset>(address)
|
||||||
.then([
|
.then([
|
||||||
atlas,
|
atlas,
|
||||||
skeleton_scale,
|
skeleton_scale,
|
||||||
skeleton_address
|
address = std::move(address)
|
||||||
](const binary_asset::load_result& skeleton_data){
|
](const binary_asset::load_result& skeleton_data){
|
||||||
if ( strings::ends_with(skeleton_address, ".skel") ) {
|
return the<deferrer>().do_in_worker_thread([
|
||||||
using skeleton_bin_ptr = std::unique_ptr<
|
atlas,
|
||||||
spSkeletonBinary,
|
skeleton_scale,
|
||||||
decltype(&::spSkeletonBinary_dispose)>;
|
address = std::move(address),
|
||||||
|
skeleton_data
|
||||||
|
](){
|
||||||
|
E2D_PROFILER_SCOPE_EX("spine_asset.skeleton_parsing", {
|
||||||
|
{"address", address}
|
||||||
|
});
|
||||||
|
if ( strings::ends_with(address, ".skel") ) {
|
||||||
|
using skeleton_bin_ptr = std::unique_ptr<
|
||||||
|
spSkeletonBinary,
|
||||||
|
decltype(&::spSkeletonBinary_dispose)>;
|
||||||
|
|
||||||
skeleton_bin_ptr binary_skeleton(
|
skeleton_bin_ptr binary_skeleton(
|
||||||
spSkeletonBinary_create(atlas.get()),
|
spSkeletonBinary_create(atlas.get()),
|
||||||
spSkeletonBinary_dispose);
|
spSkeletonBinary_dispose);
|
||||||
|
|
||||||
if ( !binary_skeleton ) {
|
if ( !binary_skeleton ) {
|
||||||
the<debug>().error("SPINE: Failed to create binary skeleton");
|
the<debug>().error("SPINE: Failed to create binary skeleton");
|
||||||
throw spine_asset_loading_exception();
|
throw spine_asset_loading_exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
binary_skeleton->scale = skeleton_scale;
|
||||||
|
|
||||||
|
spine::skeleton_data_ptr data_skeleton(
|
||||||
|
spSkeletonBinary_readSkeletonData(
|
||||||
|
binary_skeleton.get(),
|
||||||
|
reinterpret_cast<const unsigned char*>(skeleton_data->content().data()),
|
||||||
|
math::numeric_cast<int>(skeleton_data->content().size())),
|
||||||
|
spSkeletonData_dispose);
|
||||||
|
|
||||||
|
if ( !data_skeleton ) {
|
||||||
|
the<debug>().error("SPINE: Failed to read binary skeleton data:\n"
|
||||||
|
"--> Error: %0",
|
||||||
|
binary_skeleton->error);
|
||||||
|
throw spine_asset_loading_exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
return data_skeleton;
|
||||||
|
} else {
|
||||||
|
using skeleton_json_ptr = std::unique_ptr<
|
||||||
|
spSkeletonJson,
|
||||||
|
decltype(&::spSkeletonJson_dispose)>;
|
||||||
|
|
||||||
|
skeleton_json_ptr json_skeleton(
|
||||||
|
spSkeletonJson_create(atlas.get()),
|
||||||
|
spSkeletonJson_dispose);
|
||||||
|
|
||||||
|
if ( !json_skeleton ) {
|
||||||
|
the<debug>().error("SPINE: Failed to create json skeleton");
|
||||||
|
throw spine_asset_loading_exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
json_skeleton->scale = skeleton_scale;
|
||||||
|
|
||||||
|
spine::skeleton_data_ptr data_skeleton(
|
||||||
|
spSkeletonJson_readSkeletonData(
|
||||||
|
json_skeleton.get(),
|
||||||
|
reinterpret_cast<const char*>(skeleton_data->content().data())),
|
||||||
|
spSkeletonData_dispose);
|
||||||
|
|
||||||
|
if ( !data_skeleton ) {
|
||||||
|
the<debug>().error("SPINE: Failed to read json skeleton data:\n"
|
||||||
|
"--> Error: %0",
|
||||||
|
json_skeleton->error);
|
||||||
|
throw spine_asset_loading_exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
return data_skeleton;
|
||||||
}
|
}
|
||||||
|
});
|
||||||
binary_skeleton->scale = skeleton_scale;
|
|
||||||
|
|
||||||
spine::skeleton_data_ptr data_skeleton(
|
|
||||||
spSkeletonBinary_readSkeletonData(
|
|
||||||
binary_skeleton.get(),
|
|
||||||
reinterpret_cast<const unsigned char*>(skeleton_data->content().data()),
|
|
||||||
math::numeric_cast<int>(skeleton_data->content().size())),
|
|
||||||
spSkeletonData_dispose);
|
|
||||||
|
|
||||||
if ( !data_skeleton ) {
|
|
||||||
the<debug>().error("SPINE: Failed to read binary skeleton data:\n"
|
|
||||||
"--> Error: %0",
|
|
||||||
binary_skeleton->error);
|
|
||||||
throw spine_asset_loading_exception();
|
|
||||||
}
|
|
||||||
|
|
||||||
return data_skeleton;
|
|
||||||
} else {
|
|
||||||
using skeleton_json_ptr = std::unique_ptr<
|
|
||||||
spSkeletonJson,
|
|
||||||
decltype(&::spSkeletonJson_dispose)>;
|
|
||||||
|
|
||||||
skeleton_json_ptr json_skeleton(
|
|
||||||
spSkeletonJson_create(atlas.get()),
|
|
||||||
spSkeletonJson_dispose);
|
|
||||||
|
|
||||||
if ( !json_skeleton ) {
|
|
||||||
the<debug>().error("SPINE: Failed to create json skeleton");
|
|
||||||
throw spine_asset_loading_exception();
|
|
||||||
}
|
|
||||||
|
|
||||||
json_skeleton->scale = skeleton_scale;
|
|
||||||
|
|
||||||
spine::skeleton_data_ptr data_skeleton(
|
|
||||||
spSkeletonJson_readSkeletonData(
|
|
||||||
json_skeleton.get(),
|
|
||||||
reinterpret_cast<const char*>(skeleton_data->content().data())),
|
|
||||||
spSkeletonData_dispose);
|
|
||||||
|
|
||||||
if ( !data_skeleton ) {
|
|
||||||
the<debug>().error("SPINE: Failed to read json skeleton data:\n"
|
|
||||||
"--> Error: %0",
|
|
||||||
json_skeleton->error);
|
|
||||||
throw spine_asset_loading_exception();
|
|
||||||
}
|
|
||||||
|
|
||||||
return data_skeleton;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,8 +24,16 @@ namespace e2d
|
|||||||
const library& library, str_view address)
|
const library& library, str_view address)
|
||||||
{
|
{
|
||||||
return library.load_asset_async<image_asset>(address)
|
return library.load_asset_async<image_asset>(address)
|
||||||
.then([](const image_asset::load_result& texture_data){
|
.then([
|
||||||
return the<deferrer>().do_in_main_thread([texture_data](){
|
address = str(address)
|
||||||
|
](const image_asset::load_result& texture_data){
|
||||||
|
return the<deferrer>().do_in_main_thread([
|
||||||
|
texture_data,
|
||||||
|
address = std::move(address)
|
||||||
|
](){
|
||||||
|
E2D_PROFILER_SCOPE_EX("texture_asset.create_texture", {
|
||||||
|
{"address", address}
|
||||||
|
});
|
||||||
const texture_ptr content = the<render>().create_texture(
|
const texture_ptr content = the<render>().create_texture(
|
||||||
texture_data->content());
|
texture_data->content());
|
||||||
if ( !content ) {
|
if ( !content ) {
|
||||||
|
|||||||
@@ -24,8 +24,16 @@ namespace e2d
|
|||||||
const library& library, str_view address)
|
const library& library, str_view address)
|
||||||
{
|
{
|
||||||
return library.load_asset_async<text_asset>(address)
|
return library.load_asset_async<text_asset>(address)
|
||||||
.then([](const text_asset::load_result& xml_data){
|
.then([
|
||||||
return the<deferrer>().do_in_worker_thread([xml_data](){
|
address = str(address)
|
||||||
|
](const text_asset::load_result& xml_data){
|
||||||
|
return the<deferrer>().do_in_worker_thread([
|
||||||
|
xml_data,
|
||||||
|
address = std::move(address)
|
||||||
|
](){
|
||||||
|
E2D_PROFILER_SCOPE_EX("xml_asset.parsing", {
|
||||||
|
{"address", address}
|
||||||
|
});
|
||||||
auto xml = std::make_shared<pugi::xml_document>();
|
auto xml = std::make_shared<pugi::xml_document>();
|
||||||
if ( !xml->load_string(xml_data->content().c_str()) ) {
|
if ( !xml->load_string(xml_data->content().c_str()) ) {
|
||||||
throw xml_asset_loading_exception();
|
throw xml_asset_loading_exception();
|
||||||
|
|||||||
@@ -38,12 +38,13 @@ namespace e2d
|
|||||||
state_.collect_garbage();
|
state_.collect_garbage();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<script> luasol::load_script(buffer_view src) {
|
std::optional<script> luasol::load_script(str_view src) {
|
||||||
E2D_ASSERT(is_in_main_thread());
|
E2D_ASSERT(is_in_main_thread());
|
||||||
|
|
||||||
|
E2D_PROFILER_SCOPE("luasol.load_script");
|
||||||
|
|
||||||
sol::load_result result = state_.load_buffer(
|
sol::load_result result = state_.load_buffer(
|
||||||
reinterpret_cast<const char*>(src.data()),
|
src.data(), src.size());
|
||||||
src.size());
|
|
||||||
|
|
||||||
if ( !result.valid() ) {
|
if ( !result.valid() ) {
|
||||||
sol::error err = result;
|
sol::error err = result;
|
||||||
@@ -56,15 +57,11 @@ namespace e2d
|
|||||||
return script(sol::protected_function(result));
|
return script(sol::protected_function(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<script> luasol::load_script(const input_stream_uptr& src) {
|
std::optional<script> luasol::load_script(buffer_view src) {
|
||||||
E2D_ASSERT(is_in_main_thread());
|
E2D_ASSERT(is_in_main_thread());
|
||||||
|
|
||||||
buffer file_data;
|
return load_script(str_view(
|
||||||
if ( !streams::try_read_tail(file_data, src) ) {
|
reinterpret_cast<const char*>(src.data()),
|
||||||
the<debug>().error("LUASOL: Failed to read script stream");
|
src.size()));
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
return load_script(file_data);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,31 +72,68 @@ namespace
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool frame_tick() final {
|
bool frame_tick() final {
|
||||||
|
E2D_PROFILER_SCOPE("application.frame_tick");
|
||||||
|
|
||||||
|
world& w = the<world>();
|
||||||
engine& e = the<engine>();
|
engine& e = the<engine>();
|
||||||
|
|
||||||
const f32 dt = e.delta_time();
|
const f32 dt = e.delta_time();
|
||||||
const f32 time = e.time();
|
const f32 time = e.time();
|
||||||
|
|
||||||
ecs::registry& registry = the<world>().registry();
|
{
|
||||||
registry.process_event(systems::pre_update_event{dt,time});
|
E2D_PROFILER_SCOPE("ecs.pre_update");
|
||||||
registry.process_event(systems::update_event{dt,time});
|
w.registry().process_event(systems::pre_update_event{dt,time});
|
||||||
registry.process_event(systems::post_update_event{dt,time});
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
E2D_PROFILER_SCOPE("ecs.update");
|
||||||
|
w.registry().process_event(systems::update_event{dt,time});
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
E2D_PROFILER_SCOPE("ecs.post_update");
|
||||||
|
w.registry().process_event(systems::post_update_event{dt,time});
|
||||||
|
}
|
||||||
|
|
||||||
return !the<window>().should_close()
|
return !the<window>().should_close()
|
||||||
|| (application_ && !application_->on_should_close());
|
|| (application_ && !application_->on_should_close());
|
||||||
}
|
}
|
||||||
|
|
||||||
void frame_render() final {
|
void frame_render() final {
|
||||||
ecs::registry& registry = the<world>().registry();
|
E2D_PROFILER_SCOPE("application.frame_render");
|
||||||
registry.process_event(systems::pre_render_event{});
|
|
||||||
registry.process_event(systems::render_event{});
|
world& w = the<world>();
|
||||||
registry.process_event(systems::post_render_event{});
|
|
||||||
|
{
|
||||||
|
E2D_PROFILER_SCOPE("ecs.pre_render");
|
||||||
|
w.registry().process_event(systems::pre_render_event{});
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
E2D_PROFILER_SCOPE("ecs.render");
|
||||||
|
w.registry().process_event(systems::render_event{});
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
E2D_PROFILER_SCOPE("ecs.post_render");
|
||||||
|
w.registry().process_event(systems::post_render_event{});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void frame_finalize() final {
|
void frame_finalize() final {
|
||||||
|
E2D_PROFILER_SCOPE("application.frame_finalize");
|
||||||
|
|
||||||
world& w = the<world>();
|
world& w = the<world>();
|
||||||
ecs::registry& registry = w.registry();
|
|
||||||
registry.process_event(systems::frame_finalize_event{});
|
{
|
||||||
w.finalize_instances();
|
E2D_PROFILER_SCOPE("ecs.frame_finalize");
|
||||||
|
w.registry().process_event(systems::frame_finalize_event{});
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
E2D_PROFILER_SCOPE("world.finalize_instances");
|
||||||
|
w.finalize_instances();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
starter::application_uptr application_;
|
starter::application_uptr application_;
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ namespace e2d
|
|||||||
ecs::registry& owner,
|
ecs::registry& owner,
|
||||||
const ecs::after<systems::update_event>& trigger)
|
const ecs::after<systems::update_event>& trigger)
|
||||||
{
|
{
|
||||||
|
E2D_PROFILER_SCOPE("flipbook_system.process");
|
||||||
state_->process(trigger.event.dt, owner);
|
state_->process(trigger.event.dt, owner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -396,6 +396,7 @@ namespace e2d
|
|||||||
const ecs::after<systems::update_event>& trigger)
|
const ecs::after<systems::update_event>& trigger)
|
||||||
{
|
{
|
||||||
E2D_UNUSED(trigger);
|
E2D_UNUSED(trigger);
|
||||||
|
E2D_PROFILER_SCOPE("label_system.process");
|
||||||
state_->process(owner);
|
state_->process(owner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,9 +21,12 @@ namespace
|
|||||||
using namespace e2d::render_system_impl;
|
using namespace e2d::render_system_impl;
|
||||||
|
|
||||||
void for_all_scenes(drawer::context& ctx, const ecs::registry& owner) {
|
void for_all_scenes(drawer::context& ctx, const ecs::registry& owner) {
|
||||||
|
E2D_PROFILER_SCOPE("render_system.for_all_scenes");
|
||||||
|
|
||||||
const auto comp = [](const auto& l, const auto& r) noexcept {
|
const auto comp = [](const auto& l, const auto& r) noexcept {
|
||||||
return std::get<scene>(l).depth() < std::get<scene>(r).depth();
|
return std::get<scene>(l).depth() < std::get<scene>(r).depth();
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto func = [&ctx](
|
const auto func = [&ctx](
|
||||||
const ecs::const_entity&,
|
const ecs::const_entity&,
|
||||||
const scene&,
|
const scene&,
|
||||||
@@ -33,6 +36,7 @@ namespace
|
|||||||
ctx.draw(node);
|
ctx.draw(node);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
systems::for_extracted_sorted_components<scene, actor>(
|
systems::for_extracted_sorted_components<scene, actor>(
|
||||||
owner,
|
owner,
|
||||||
comp,
|
comp,
|
||||||
@@ -41,9 +45,12 @@ namespace
|
|||||||
}
|
}
|
||||||
|
|
||||||
void for_all_cameras(drawer& drawer, const ecs::registry& owner) {
|
void for_all_cameras(drawer& drawer, const ecs::registry& owner) {
|
||||||
|
E2D_PROFILER_SCOPE("render_system.for_all_cameras");
|
||||||
|
|
||||||
const auto comp = [](const auto& l, const auto& r) noexcept {
|
const auto comp = [](const auto& l, const auto& r) noexcept {
|
||||||
return std::get<camera>(l).depth() < std::get<camera>(r).depth();
|
return std::get<camera>(l).depth() < std::get<camera>(r).depth();
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto func = [&drawer, &owner](
|
const auto func = [&drawer, &owner](
|
||||||
const ecs::const_entity&,
|
const ecs::const_entity&,
|
||||||
const camera& cam,
|
const camera& cam,
|
||||||
@@ -53,6 +60,7 @@ namespace
|
|||||||
for_all_scenes(ctx, owner);
|
for_all_scenes(ctx, owner);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
systems::for_extracted_sorted_components<camera, actor>(
|
systems::for_extracted_sorted_components<camera, actor>(
|
||||||
owner,
|
owner,
|
||||||
comp,
|
comp,
|
||||||
@@ -93,6 +101,7 @@ namespace e2d
|
|||||||
const ecs::after<systems::render_event>& trigger)
|
const ecs::after<systems::render_event>& trigger)
|
||||||
{
|
{
|
||||||
E2D_UNUSED(trigger);
|
E2D_UNUSED(trigger);
|
||||||
|
E2D_PROFILER_SCOPE("render_system.process");
|
||||||
state_->process(owner);
|
state_->process(owner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -192,8 +192,8 @@ namespace e2d::render_system_impl
|
|||||||
|
|
||||||
float* uvs = nullptr;
|
float* uvs = nullptr;
|
||||||
unsigned short* indices = nullptr;
|
unsigned short* indices = nullptr;
|
||||||
std::size_t index_count = 0;
|
int index_count = 0;
|
||||||
std::size_t vertex_count = 0;
|
int vertex_count = 0;
|
||||||
const spAtlasPage* atlas_page = nullptr;
|
const spAtlasPage* atlas_page = nullptr;
|
||||||
const spColor* attachment_color = nullptr;
|
const spColor* attachment_color = nullptr;
|
||||||
|
|
||||||
@@ -208,8 +208,10 @@ namespace e2d::render_system_impl
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
vertex_count = 8;
|
vertex_count = 8;
|
||||||
if ( temp_vertices.size() < vertex_count ) {
|
if ( temp_vertices.size() < math::numeric_cast<std::size_t>(vertex_count) ) {
|
||||||
temp_vertices.resize(math::max(temp_vertices.size() * 2u, vertex_count));
|
temp_vertices.resize(math::max(
|
||||||
|
temp_vertices.size() * 2u,
|
||||||
|
math::numeric_cast<std::size_t>(vertex_count)));
|
||||||
}
|
}
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
property_cache_.clear();
|
property_cache_.clear();
|
||||||
@@ -239,8 +241,10 @@ namespace e2d::render_system_impl
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
vertex_count = mesh->super.worldVerticesLength;
|
vertex_count = mesh->super.worldVerticesLength;
|
||||||
if ( temp_vertices.size() < vertex_count ) {
|
if ( temp_vertices.size() < math::numeric_cast<std::size_t>(vertex_count) ) {
|
||||||
temp_vertices.resize(math::max(temp_vertices.size() * 2u, vertex_count));
|
temp_vertices.resize(math::max(
|
||||||
|
temp_vertices.size() * 2u,
|
||||||
|
math::numeric_cast<std::size_t>(vertex_count)));
|
||||||
}
|
}
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
property_cache_.clear();
|
property_cache_.clear();
|
||||||
@@ -417,7 +421,7 @@ namespace e2d::render_system_impl
|
|||||||
batcher_.batch(
|
batcher_.batch(
|
||||||
mat_a,
|
mat_a,
|
||||||
property_cache_,
|
property_cache_,
|
||||||
indices, index_count,
|
indices, math::numeric_cast<std::size_t>(index_count),
|
||||||
batch_vertices.data(), batch_vertex_count);
|
batch_vertices.data(), batch_vertex_count);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
property_cache_.clear();
|
property_cache_.clear();
|
||||||
|
|||||||
@@ -125,6 +125,7 @@ namespace e2d
|
|||||||
const systems::update_event& event)
|
const systems::update_event& event)
|
||||||
{
|
{
|
||||||
E2D_UNUSED(event);
|
E2D_UNUSED(event);
|
||||||
|
E2D_PROFILER_SCOPE("script_system.process");
|
||||||
state_->update_process(owner);
|
state_->update_process(owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,6 +134,7 @@ namespace e2d
|
|||||||
const ecs::before<systems::update_event>& trigger)
|
const ecs::before<systems::update_event>& trigger)
|
||||||
{
|
{
|
||||||
E2D_UNUSED(trigger);
|
E2D_UNUSED(trigger);
|
||||||
|
E2D_PROFILER_SCOPE("script_system.process");
|
||||||
state_->process_events(owner);
|
state_->process_events(owner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -258,6 +258,7 @@ namespace e2d
|
|||||||
ecs::registry& owner,
|
ecs::registry& owner,
|
||||||
const ecs::after<systems::update_event>& trigger)
|
const ecs::after<systems::update_event>& trigger)
|
||||||
{
|
{
|
||||||
|
E2D_PROFILER_SCOPE("spine_system.process");
|
||||||
state_->process(trigger.event.dt, owner);
|
state_->process(trigger.event.dt, owner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -195,6 +195,8 @@ namespace e2d
|
|||||||
}
|
}
|
||||||
|
|
||||||
gobject world::instantiate(const prefab& prefab, const node_iptr& parent) {
|
gobject world::instantiate(const prefab& prefab, const node_iptr& parent) {
|
||||||
|
E2D_PROFILER_SCOPE("world.instantiate");
|
||||||
|
|
||||||
gobject inst = new_instance(*this, prefab);
|
gobject inst = new_instance(*this, prefab);
|
||||||
|
|
||||||
if ( parent ) {
|
if ( parent ) {
|
||||||
@@ -216,6 +218,8 @@ namespace e2d
|
|||||||
}
|
}
|
||||||
|
|
||||||
gobject world::instantiate(const prefab& prefab, const node_iptr& parent, const t2f& transform) {
|
gobject world::instantiate(const prefab& prefab, const node_iptr& parent, const t2f& transform) {
|
||||||
|
E2D_PROFILER_SCOPE("world.instantiate");
|
||||||
|
|
||||||
gobject inst = new_instance(*this, prefab);
|
gobject inst = new_instance(*this, prefab);
|
||||||
inst.component<actor>()->node()->transform(transform);
|
inst.component<actor>()->node()->transform(transform);
|
||||||
|
|
||||||
@@ -244,6 +248,7 @@ namespace e2d
|
|||||||
}
|
}
|
||||||
|
|
||||||
void world::finalize_instances() noexcept {
|
void world::finalize_instances() noexcept {
|
||||||
|
E2D_PROFILER_SCOPE("world.finalize_instances");
|
||||||
while ( !destroying_states_.empty() ) {
|
while ( !destroying_states_.empty() ) {
|
||||||
gobject inst{&destroying_states_.front()};
|
gobject inst{&destroying_states_.front()};
|
||||||
destroying_states_.pop_front();
|
destroying_states_.pop_front();
|
||||||
|
|||||||
@@ -105,6 +105,11 @@ namespace e2d::filesystem
|
|||||||
dst, make_read_file(path));
|
dst, make_read_file(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool try_write_all(str_view src, str_view path, bool append) noexcept {
|
||||||
|
return streams::try_write_tail(
|
||||||
|
src, make_write_file(path, append));
|
||||||
|
}
|
||||||
|
|
||||||
bool try_write_all(buffer_view src, str_view path, bool append) noexcept {
|
bool try_write_all(buffer_view src, str_view path, bool append) noexcept {
|
||||||
return streams::try_write_tail(
|
return streams::try_write_tail(
|
||||||
src, make_write_file(path, append));
|
src, make_write_file(path, append));
|
||||||
|
|||||||
@@ -170,6 +170,12 @@ namespace e2d
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
output_sequence& output_sequence::write_all(str_view src) noexcept {
|
||||||
|
return success_
|
||||||
|
? write(src.data(), src.size())
|
||||||
|
: *this;
|
||||||
|
}
|
||||||
|
|
||||||
output_sequence& output_sequence::write_all(buffer_view src) noexcept {
|
output_sequence& output_sequence::write_all(buffer_view src) noexcept {
|
||||||
return success_
|
return success_
|
||||||
? write(src.data(), src.size())
|
? write(src.data(), src.size())
|
||||||
@@ -222,6 +228,14 @@ namespace e2d::streams
|
|||||||
: false;
|
: false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool try_write_tail(str_view src, const output_stream_uptr& stream) noexcept {
|
||||||
|
return stream
|
||||||
|
? output_sequence(*stream)
|
||||||
|
.write_all(src)
|
||||||
|
.success()
|
||||||
|
: false;
|
||||||
|
}
|
||||||
|
|
||||||
bool try_write_tail(buffer_view src, const output_stream_uptr& stream) noexcept {
|
bool try_write_tail(buffer_view src, const output_stream_uptr& stream) noexcept {
|
||||||
return stream
|
return stream
|
||||||
? output_sequence(*stream)
|
? output_sequence(*stream)
|
||||||
|
|||||||
@@ -135,6 +135,15 @@ namespace e2d
|
|||||||
return path_;
|
return path_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
str url::schemepath() const {
|
||||||
|
str result;
|
||||||
|
result.reserve(scheme_.size() + scheme_separator.size() + path_.size());
|
||||||
|
result.append(scheme_);
|
||||||
|
result.append(scheme_separator);
|
||||||
|
result.append(path_);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
url& url::operator+=(str_view path) {
|
url& url::operator+=(str_view path) {
|
||||||
return concat(path);
|
return concat(path);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,15 +33,15 @@ TEST_CASE("vfs"){
|
|||||||
REQUIRE(v.read({"file", nofile_path}) == input_stream_uptr());
|
REQUIRE(v.read({"file", nofile_path}) == input_stream_uptr());
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
buffer b0;
|
auto b0 = v.load({"file", file_path});
|
||||||
REQUIRE(v.load({"file", file_path}, b0));
|
REQUIRE(b0);
|
||||||
REQUIRE(b0 == buffer{"hello", 5});
|
REQUIRE(b0 == buffer{"hello", 5});
|
||||||
|
|
||||||
auto b1 = v.load_async({"file", file_path}).get();
|
auto b1 = v.load_async({"file", file_path}).get();
|
||||||
REQUIRE(b1 == buffer{"hello", 5});
|
REQUIRE(b1 == buffer{"hello", 5});
|
||||||
|
|
||||||
str b2;
|
auto b2 = v.load_as_string({"file", file_path});
|
||||||
REQUIRE(v.load_as_string({"file", file_path}, b2));
|
REQUIRE(b2);
|
||||||
REQUIRE(b2 == "hello");
|
REQUIRE(b2 == "hello");
|
||||||
|
|
||||||
auto b3 = v.load_as_string_async({"file", file_path}).get();
|
auto b3 = v.load_as_string_async({"file", file_path}).get();
|
||||||
@@ -135,15 +135,15 @@ TEST_CASE("vfs"){
|
|||||||
REQUIRE(b == buffer("hello", 5));
|
REQUIRE(b == buffer("hello", 5));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
buffer b0;
|
auto b0 = v.load(url("archive://test.txt"));
|
||||||
REQUIRE(v.load(url("archive://test.txt"), b0));
|
REQUIRE(b0);
|
||||||
REQUIRE(b0 == buffer("hello", 5));
|
REQUIRE(b0 == buffer("hello", 5));
|
||||||
|
|
||||||
auto b1 = v.load_async(url("archive://test.txt")).get();
|
auto b1 = v.load_async(url("archive://test.txt")).get();
|
||||||
REQUIRE(b1 == buffer("hello", 5));
|
REQUIRE(b1 == buffer("hello", 5));
|
||||||
|
|
||||||
str b2;
|
auto b2 = v.load_as_string(url("archive://test.txt"));
|
||||||
REQUIRE(v.load_as_string(url("archive://test.txt"), b2));
|
REQUIRE(b2);
|
||||||
REQUIRE(b2 == "hello");
|
REQUIRE(b2 == "hello");
|
||||||
|
|
||||||
auto b3 = v.load_as_string_async(url("archive://test.txt")).get();
|
auto b3 = v.load_as_string_async(url("archive://test.txt")).get();
|
||||||
@@ -157,15 +157,15 @@ TEST_CASE("vfs"){
|
|||||||
REQUIRE(b == buffer("world", 5));
|
REQUIRE(b == buffer("world", 5));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
buffer b0;
|
auto b0 = v.load(url("archive://folder/file.txt"));
|
||||||
REQUIRE(v.load(url("archive://folder/file.txt"), b0));
|
REQUIRE(b0);
|
||||||
REQUIRE(b0 == buffer("world", 5));
|
REQUIRE(b0 == buffer("world", 5));
|
||||||
|
|
||||||
auto b1 = v.load_async(url("archive://folder/file.txt")).get();
|
auto b1 = v.load_async(url("archive://folder/file.txt")).get();
|
||||||
REQUIRE(b1 == buffer("world", 5));
|
REQUIRE(b1 == buffer("world", 5));
|
||||||
|
|
||||||
str b2;
|
auto b2 = v.load_as_string(url("archive://folder/file.txt"));
|
||||||
REQUIRE(v.load_as_string(url("archive://folder/file.txt"), b2));
|
REQUIRE(b2);
|
||||||
REQUIRE(b2 == "world");
|
REQUIRE(b2 == "world");
|
||||||
|
|
||||||
auto b3 = v.load_as_string_async(url("archive://folder/file.txt")).get();
|
auto b3 = v.load_as_string_async(url("archive://folder/file.txt")).get();
|
||||||
@@ -174,17 +174,15 @@ TEST_CASE("vfs"){
|
|||||||
{
|
{
|
||||||
REQUIRE(v.read(url("archive://TEst.txt")) == input_stream_uptr());
|
REQUIRE(v.read(url("archive://TEst.txt")) == input_stream_uptr());
|
||||||
|
|
||||||
buffer b0;
|
auto b0 = v.load(url("archive://TEst.txt"));
|
||||||
REQUIRE_FALSE(v.load(url("archive://TEst.txt"), b0));
|
REQUIRE_FALSE(b0);
|
||||||
REQUIRE(b0.empty());
|
|
||||||
|
|
||||||
REQUIRE_THROWS_AS(
|
REQUIRE_THROWS_AS(
|
||||||
v.load_async(url("archive://TEst.txt")).get(),
|
v.load_async(url("archive://TEst.txt")).get(),
|
||||||
vfs_load_async_exception);
|
vfs_load_async_exception);
|
||||||
|
|
||||||
str b2;
|
auto b2 = v.load_as_string(url("archive://TEst.txt"));
|
||||||
REQUIRE_FALSE(v.load_as_string(url("archive://TEst.txt"), b2));
|
REQUIRE_FALSE(b2);
|
||||||
REQUIRE(b2.empty());
|
|
||||||
|
|
||||||
REQUIRE_THROWS_AS(
|
REQUIRE_THROWS_AS(
|
||||||
v.load_as_string_async(url("archive://TEst.txt")).get(),
|
v.load_as_string_async(url("archive://TEst.txt")).get(),
|
||||||
|
|||||||
@@ -221,10 +221,10 @@ TEST_CASE("buffer_view") {
|
|||||||
REQUIRE(v5.data() == b2.data());
|
REQUIRE(v5.data() == b2.data());
|
||||||
REQUIRE(v5.size() == 20);
|
REQUIRE(v5.size() == 20);
|
||||||
|
|
||||||
str32 b3 = make_utf32("hello");
|
u32 b3[3] = {10, 20, 30};
|
||||||
buffer_view v6(b3);
|
buffer_view v6(b3);
|
||||||
REQUIRE(v6.data() == b3.data());
|
REQUIRE(v6.data() == &b3[0]);
|
||||||
REQUIRE(v6.size() == 20);
|
REQUIRE(v6.size() == 12);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const char* s0 = "hell";
|
const char* s0 = "hell";
|
||||||
|
|||||||
@@ -19,24 +19,28 @@ TEST_CASE("url") {
|
|||||||
REQUIRE(u.empty());
|
REQUIRE(u.empty());
|
||||||
REQUIRE(u.scheme().empty());
|
REQUIRE(u.scheme().empty());
|
||||||
REQUIRE(u.path().empty());
|
REQUIRE(u.path().empty());
|
||||||
|
REQUIRE(u.schemepath() == "://");
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
url u("://file");
|
url u("://file");
|
||||||
REQUIRE(!u.empty());
|
REQUIRE(!u.empty());
|
||||||
REQUIRE(u.scheme().empty());
|
REQUIRE(u.scheme().empty());
|
||||||
REQUIRE(u.path() == "file");
|
REQUIRE(u.path() == "file");
|
||||||
|
REQUIRE(u.schemepath() == "://file");
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
url u("file://");
|
url u("file://");
|
||||||
REQUIRE(u.empty());
|
REQUIRE(u.empty());
|
||||||
REQUIRE(u.scheme() == "file");
|
REQUIRE(u.scheme() == "file");
|
||||||
REQUIRE(u.path().empty());
|
REQUIRE(u.path().empty());
|
||||||
|
REQUIRE(u.schemepath() == "file://");
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
url u("file://test_file");
|
url u("file://test_file");
|
||||||
REQUIRE(!u.empty());
|
REQUIRE(!u.empty());
|
||||||
REQUIRE(u.scheme() == "file");
|
REQUIRE(u.scheme() == "file");
|
||||||
REQUIRE(u.path() == "test_file");
|
REQUIRE(u.path() == "test_file");
|
||||||
|
REQUIRE(u.schemepath() == "file://test_file");
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
url u("dir/file");
|
url u("dir/file");
|
||||||
|
|||||||
Reference in New Issue
Block a user