129 lines
4.1 KiB
C++
129 lines
4.1 KiB
C++
#include "Point_Visual.h"
|
|
|
|
#include "detail/Point_Core.h"
|
|
|
|
#include <renderive/real_time_data/Double_Buffer_Strategy.hpp>
|
|
#include <renderive/state/Double_State_Storage.hpp>
|
|
|
|
#include <cmath>
|
|
#include <mutex>
|
|
#include <stdexcept>
|
|
#include <utility>
|
|
|
|
namespace renderive::render_3d {
|
|
namespace {
|
|
|
|
void validate(const Point_State& state) {
|
|
if (!std::isfinite(state.style.stroke_width_px) ||
|
|
state.style.stroke_width_px < 0.0F)
|
|
throw std::invalid_argument("point stroke width must be finite and nonnegative");
|
|
for (float value : state.transform.values) {
|
|
if (!std::isfinite(value))
|
|
throw std::invalid_argument("point transform must contain finite values");
|
|
}
|
|
}
|
|
|
|
void validate(const std::vector<Point>& points) {
|
|
for (const auto& point : points) {
|
|
if (!std::isfinite(point.position.x) || !std::isfinite(point.position.y) ||
|
|
!std::isfinite(point.position.z) || !std::isfinite(point.diameter_px) ||
|
|
point.diameter_px <= 0.0F)
|
|
throw std::invalid_argument("point payload contains invalid coordinates or diameter");
|
|
}
|
|
}
|
|
|
|
} // namespace
|
|
|
|
namespace detail {
|
|
struct Point_Payload_Tag {};
|
|
using Point_Payload = std::shared_ptr<const std::vector<Point>>;
|
|
using Point_Buffer_Layout = ::Double_Buffer_Layout<
|
|
::Buffered_Data<Point_Payload_Tag, Point_Payload>>;
|
|
using Point_Buffer_Strategy =
|
|
::Multi_Double_Buffer_Strategy<Point_Buffer_Layout, std::mutex>;
|
|
using Point_State_Strategy =
|
|
::Double_State_Storage<Point_State, std::mutex>;
|
|
} // namespace detail
|
|
|
|
struct Point_Visual::Impl final : detail::Point_Buffer_Strategy,
|
|
detail::Point_State_Strategy {
|
|
Impl(std::vector<Point> points, const Point_State& initial)
|
|
: detail::Point_State_Strategy(initial) {
|
|
validate(initial);
|
|
update_points(std::move(points));
|
|
}
|
|
|
|
void update_points(std::vector<Point> points) {
|
|
validate(points);
|
|
write<detail::Point_Payload_Tag>(
|
|
std::make_shared<const std::vector<Point>>(std::move(points)));
|
|
}
|
|
|
|
void edit_points(const std::function<void(std::vector<Point>&)>& edit) {
|
|
if (!edit)
|
|
throw std::invalid_argument("Point_Visual point edit is empty");
|
|
const auto& published = points();
|
|
auto next = published ? *published : std::vector<Point>{};
|
|
edit(next);
|
|
update_points(std::move(next));
|
|
}
|
|
|
|
[[nodiscard]] const detail::Point_Payload& points() const noexcept {
|
|
return render_buffer_value<detail::Point_Payload_Tag>();
|
|
}
|
|
|
|
[[nodiscard]] std::size_t point_count() const noexcept {
|
|
return points() ? points()->size() : 0U;
|
|
}
|
|
|
|
void configure(Point_State state) {
|
|
validate(state);
|
|
update([state = std::move(state)](Point_State& target) mutable {
|
|
target = std::move(state);
|
|
});
|
|
}
|
|
|
|
[[nodiscard]] detail::Published_Point publish_frame() {
|
|
detail::Point_State_Strategy::publish();
|
|
detail::Point_Buffer_Strategy::publish();
|
|
return {
|
|
detail::Point_State_Strategy::render_state_value(),
|
|
detail::Point_Buffer_Strategy::render_buffer_value<
|
|
detail::Point_Payload_Tag>(),
|
|
detail::Point_State_Strategy::state_revision(),
|
|
detail::Point_Buffer_Strategy::revision()};
|
|
}
|
|
};
|
|
|
|
Point_Visual::Point_Visual(std::vector<Point> points, Point_State initial)
|
|
: impl_(std::make_unique<Impl>(std::move(points), initial)) {}
|
|
|
|
Point_Visual::~Point_Visual() = default;
|
|
|
|
void Point_Visual::update_points(std::vector<Point> points) {
|
|
impl_->update_points(std::move(points));
|
|
}
|
|
|
|
void Point_Visual::edit_points(
|
|
const std::function<void(std::vector<Point>&)>& edit) {
|
|
impl_->edit_points(edit);
|
|
}
|
|
|
|
std::size_t Point_Visual::point_count() const {
|
|
return impl_->point_count();
|
|
}
|
|
|
|
std::uint64_t Point_Visual::data_revision() const {
|
|
return impl_->revision();
|
|
}
|
|
|
|
void Point_Visual::configure(Point_State state) {
|
|
impl_->configure(std::move(state));
|
|
}
|
|
|
|
detail::Published_Point detail::Point_State_Access::publish(Point_Visual& visual) {
|
|
return visual.impl_->publish_frame();
|
|
}
|
|
|
|
} // namespace renderive::render_3d
|