Files
SEQUA-Engine/engines/debug/adapter/src/debug_adapter.cpp
T
Ange-Marie MAURIN - A2M Systèmes 98c778aa28 feat(input): entrees du joueur captees par l'adaptateur (ADR 0011)
L'adaptateur traduit clavier et manette en actions SEQUA (PlayerInput) ;
le Core ne recoit et n'enregistre que ces actions, le rejeu reste exact.

- SEQUA 3D : PlayerInput, poll_input(), capacite player_input
  (interface des adaptateurs en version 2)
- protocole Core - rendu 0.2 : render/input, envoye quand les actions
  changent ; entree remise au neutre si le rendu disparait
- Godot : InputMap du projet (ZQSD, fleches, espace, manette) ou script
  SequaInput.sequa_player_input() pour une correspondance avancee ;
  entree neutre sans focus ; exemple examples/sequa_input.gd
- adaptateur debug : entrees scriptees par numero d'image
- Studio : ligne "Entrees du joueur" du panneau Rendu
2026-11-07 20:48:26 +01:00

125 lines
4.2 KiB
C++

// SPDX-License-Identifier: MPL-2.0
#include "sequa/debug/debug_adapter.hpp"
#include <algorithm>
#include <chrono>
#include <utility>
namespace sequa::debug {
using three_d::BufferSet;
using three_d::Error;
using three_d::FrameBuffer;
DebugEngineAdapter::DebugEngineAdapter(std::unique_ptr<FrameSink> sink, ViewParams view,
std::vector<ScriptedInput> script)
: sink_(std::move(sink)), view_(view), script_(std::move(script))
{
std::stable_sort(script_.begin(), script_.end(),
[](const ScriptedInput& a, const ScriptedInput& b) { return a.frame < b.frame; });
}
three_d::EngineCapabilities DebugEngineAdapter::capabilities() const
{
three_d::EngineCapabilities capabilities;
capabilities.engine_name = "debug";
capabilities.engine_version = "0.1";
// Seul le tampon couleur existe : la vue de côté ne calcule pas la profondeur.
capabilities.buffers = BufferSet{FrameBuffer::color};
capabilities.windowed = false;
capabilities.headless = true;
// max_width/max_height laissés à 0 : aucune limite de taille.
capabilities.player_input = !script_.empty();
return capabilities;
}
std::optional<three_d::PlayerInput> DebugEngineAdapter::poll_input()
{
if (!running_ || script_.empty()) {
return std::nullopt;
}
three_d::PlayerInput current;
if (last_frame_) {
for (const ScriptedInput& entry : script_) {
if (entry.frame > *last_frame_) {
break;
}
current = entry.input;
}
}
return current;
}
std::optional<Error> DebugEngineAdapter::start(const three_d::EngineConfig& config)
{
if (running_) {
return Error{Error::Code::already_started, "adaptateur de débogage déjà démarré"};
}
if (!config.headless) {
return Error{Error::Code::unsupported,
"l'adaptateur de débogage ne sait faire que du rendu hors écran"};
}
if (config.width == 0 || config.height == 0) {
return Error{Error::Code::invalid_argument, "taille d'image nulle"};
}
// Le rendu « fenêtre » n'existe pas : la taille du start() est celle des images.
width_ = config.width;
height_ = config.height;
scene_.clear(); // après start(), la scène du moteur est vide (l'appelant pousse un snapshot)
last_frame_.reset();
running_ = true;
return std::nullopt;
}
void DebugEngineAdapter::stop() noexcept
{
running_ = false;
}
std::optional<Error> DebugEngineAdapter::apply(const three_d::SceneDelta& delta)
{
if (!running_) {
return Error{Error::Code::not_started, "adaptateur de débogage arrêté"};
}
return scene_.apply(delta);
}
three_d::FrameOutcome DebugEngineAdapter::render_frame(const three_d::FrameRequest& request)
{
if (!running_) {
return Error{Error::Code::not_started, "adaptateur de débogage arrêté"};
}
// Taille effective : celle de la requête si elle est non nulle, sinon celle de start().
three_d::FrameRequest effective = request;
if (effective.width == 0) {
effective.width = width_;
}
if (effective.height == 0) {
effective.height = height_;
}
if (std::optional<Error> error = three_d::validate_request(effective, capabilities())) {
return *std::move(error);
}
const auto begin = std::chrono::steady_clock::now();
last_image_ = draw_side_view(scene_, effective.width, effective.height, view_);
if (sink_ != nullptr) {
if (std::optional<Error> error = sink_->write(last_image_)) {
// Le dessin a réussi mais l'écriture a échoué : erreur du sink renvoyée telle
// quelle ; PROVISOIRE, l'image reste consultable via last_image().
return *std::move(error);
}
}
last_frame_ = request.frame_index;
three_d::FrameResult result;
result.frame_index = request.frame_index;
result.world_version = scene_.world_version();
result.produced = BufferSet{FrameBuffer::color};
result.measurements.cpu_ms = std::chrono::duration<double, std::milli>(
std::chrono::steady_clock::now() - begin)
.count();
return result;
}
} // namespace sequa::debug