3D 第一个控件成功显示

This commit is contained in:
2026-08-14 11:07:38 +08:00
parent 02c60679e4
commit 38231dbc1c
28 changed files with 2758 additions and 28 deletions
+210
View File
@@ -0,0 +1,210 @@
#include "Point_Scene.h"
#include "detail/Datoviz_Point_Backend.h"
#include "detail/Point_Core.h"
#include "detail/Render_Domain.h"
#include <atomic>
#include <algorithm>
#include <cmath>
#include <mutex>
#include <stdexcept>
#include <utility>
namespace renderive::render_3d {
namespace {
void validate(Extent extent) {
if (extent.empty())
throw std::invalid_argument("Point_Scene viewport must be nonempty");
}
void validate(Clear_Color color) {
const auto component = [](float value) {
return std::isfinite(value) && value >= 0.0F && value <= 1.0F;
};
if (!component(color.red) || !component(color.green) ||
!component(color.blue) || !component(color.alpha))
throw std::invalid_argument("Point_Scene clear color must be in [0, 1]");
}
detail::Input_Command_Type pointer_type(::renderive::Event_Type type) {
switch (type) {
case ::renderive::Event_Type::Pointer_Move:
return detail::Input_Command_Type::Pointer_Move;
case ::renderive::Event_Type::Pointer_Press:
return detail::Input_Command_Type::Pointer_Press;
case ::renderive::Event_Type::Pointer_Release:
return detail::Input_Command_Type::Pointer_Release;
default:
throw std::invalid_argument("Point_Scene expected a pointer event");
}
}
float datoviz_wheel_step(float pixel_delta, float angle_delta) {
if (angle_delta != 0.0F)
return angle_delta / 120.0F;
return pixel_delta / 100.0F;
}
} // namespace
struct Point_Scene::Impl {
Impl(const Scene_Options& options, std::shared_ptr<Point_Visual> point_visual)
: visual(std::move(point_visual)),
states(detail::Scene_State{options.viewport, options.clear_color}),
scheduler(options.frame_mode, options.maximum_frames_per_second) {
if (!visual)
throw std::invalid_argument("Point_Scene requires a Point_Visual");
render_domain.invoke([&] {
backend = std::make_unique<detail::Datoviz_Point_Backend>(
options.gpu_index, options.validation_enabled,
detail::Scene_State{options.viewport, options.clear_color});
});
}
~Impl() {
accepting.store(false, std::memory_order_release);
render_domain.invoke([&] { backend.reset(); });
}
[[nodiscard]] bool render() {
if (!accepting.load(std::memory_order_acquire))
return false;
return render_domain.invoke([&] {
return scheduler.render([&](const detail::Point_Frame_Data& frame) {
auto rendered = backend->render(frame);
if (!rendered)
return false;
std::lock_guard lock(frame_mutex);
latest = std::move(rendered);
return true;
});
});
}
std::shared_ptr<Point_Visual> visual;
detail::Scene_State_Buffer states;
detail::Input_Collector input;
detail::Frame_Scheduler scheduler;
detail::Render_Domain render_domain;
std::unique_ptr<detail::Datoviz_Point_Backend> backend;
mutable std::mutex frame_mutex;
std::shared_ptr<const Pixel_Frame> latest;
std::atomic<bool> accepting{true};
};
Point_Scene::Point_Scene(Scene_Options options,
std::shared_ptr<Point_Visual> visual) {
validate(options.viewport);
validate(options.clear_color);
if (!std::isfinite(options.maximum_frames_per_second) ||
options.maximum_frames_per_second <= 0.0)
throw std::invalid_argument("Point_Scene frame frequency must be positive");
impl_ = std::make_unique<Impl>(options, std::move(visual));
}
Point_Scene::~Point_Scene() = default;
void Point_Scene::resize(Extent extent) {
validate(extent);
impl_->states.update([extent](detail::Scene_State& state) {
state.viewport = extent;
});
}
void Point_Scene::set_clear_color(Clear_Color color) {
validate(color);
impl_->states.update([color](detail::Scene_State& state) {
state.clear_color = color;
});
}
void Point_Scene::dispatch(const ::renderive::Event&) {
// Non-positional Show/Hide/Leave events carry no Datoviz controller payload.
}
void Point_Scene::dispatch_pointer(
::renderive::Event_Type type, float x, float y,
::renderive::Mouse_Button button, ::renderive::Mouse_Button_Mask buttons,
::renderive::Keyboard_Modifier modifiers) {
if (!std::isfinite(x) || !std::isfinite(y))
return;
detail::Input_Command command;
command.type = pointer_type(type);
command.x = x;
command.y = y;
command.button = button;
command.buttons = buttons;
command.modifiers = modifiers;
impl_->input.push(command);
}
void Point_Scene::dispatch_wheel(
float x, float y, float pixel_delta_x, float pixel_delta_y,
float angle_delta_x, float angle_delta_y,
::renderive::Keyboard_Modifier modifiers) {
if (!std::isfinite(x) || !std::isfinite(y) ||
!std::isfinite(pixel_delta_x) || !std::isfinite(pixel_delta_y) ||
!std::isfinite(angle_delta_x) || !std::isfinite(angle_delta_y))
return;
detail::Input_Command command;
command.type = detail::Input_Command_Type::Wheel;
command.x = x;
command.y = y;
command.delta_x = datoviz_wheel_step(pixel_delta_x, angle_delta_x);
command.delta_y = datoviz_wheel_step(pixel_delta_y, angle_delta_y);
command.modifiers = modifiers;
impl_->input.push(command);
}
void Point_Scene::dispatch(const ::renderive::Key_Event& event) {
detail::Input_Command command;
command.type = event.type == ::renderive::Event_Type::Key_Release
? detail::Input_Command_Type::Key_Release
: event.auto_repeat
? detail::Input_Command_Type::Key_Repeat
: detail::Input_Command_Type::Key_Press;
command.key = event.key;
command.native_key = event.native_key;
command.modifiers = event.modifiers;
impl_->input.push(command);
}
bool Point_Scene::prepare_frame() {
return impl_->accepting.load(std::memory_order_acquire) &&
impl_->scheduler.prepare(impl_->states, *impl_->visual, impl_->input);
}
bool Point_Scene::refresh_manual_frame() {
return impl_->accepting.load(std::memory_order_acquire) &&
impl_->scheduler.refresh();
}
bool Point_Scene::discard_pending_frame() {
return impl_->accepting.load(std::memory_order_acquire) &&
impl_->scheduler.discard_pending();
}
bool Point_Scene::render_prepared_frame() { return impl_->render(); }
bool Point_Scene::request_frame() {
return prepare_frame() && impl_->scheduler.activate_for_request() &&
render_prepared_frame();
}
std::shared_ptr<const Pixel_Frame> Point_Scene::latest_frame() const {
std::lock_guard lock(impl_->frame_mutex);
return impl_->latest;
}
Frame_Status Point_Scene::frame_status() const {
auto result = impl_->scheduler.status();
std::lock_guard lock(impl_->frame_mutex);
if (impl_->latest)
result.latest_sequence = std::max(result.latest_sequence,
impl_->latest->sequence);
return result;
}
} // namespace renderive::render_3d