all of the changes
This commit is contained in:
37
include/FluidSim/Desktop/DesktopUi.hpp
Normal file
37
include/FluidSim/Desktop/DesktopUi.hpp
Normal file
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
#include "FluidSim/Scenario.hpp"
|
||||
#include "FluidSim/DynoCurve.hpp"
|
||||
#include "FluidSim/Desktop/PedalControl.hpp"
|
||||
#include "FluidSim/Desktop/EngineRenderer3D.hpp"
|
||||
#include <SFML/Graphics.hpp>
|
||||
namespace fluidsim::port::desktop {
|
||||
struct PlaybackInfo {
|
||||
float pedal_target{},load{};
|
||||
double speed{1};
|
||||
std::size_t buffered{},capacity{};
|
||||
std::uint64_t underruns{};
|
||||
bool auto_gain{},time_warp{};
|
||||
};
|
||||
struct WorkspaceLayout {
|
||||
sf::FloatRect sidebar,viewport,chart,inspector,pedal;
|
||||
static WorkspaceLayout calculate(sf::Vector2u size);
|
||||
};
|
||||
class DesktopUi {
|
||||
public:
|
||||
float pedal() const {return pedal_.value();}
|
||||
void nudge_pedal(float amount) {pedal_.set(pedal_.value()+amount);}
|
||||
void update_pedal(float dt,bool raise,bool lower) {if(!pedal_drag_)pedal_.advance(dt,raise,lower);}
|
||||
bool handle_event(const sf::Event&,sf::Vector2u);
|
||||
void draw(sf::RenderWindow&,const sf::Font*,const ScenarioSnapshot&,const PlaybackInfo&);
|
||||
private:
|
||||
DynoCurve dyno_;
|
||||
EngineRenderer3D renderer_;
|
||||
OrbitCamera camera_;
|
||||
bool three_d_{true},camera_fitted_{},pan_drag_{},pedal_drag_{};
|
||||
PedalControl pedal_;
|
||||
sf::Vector2f pan_{};
|
||||
sf::Vector2i previous_mouse_{};
|
||||
bool dragging_{};
|
||||
float zoom_{1};
|
||||
};
|
||||
}
|
||||
6
include/FluidSim/Desktop/DynoRenderer.hpp
Normal file
6
include/FluidSim/Desktop/DynoRenderer.hpp
Normal file
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
#include "FluidSim/DynoCurve.hpp"
|
||||
#include <SFML/Graphics.hpp>
|
||||
namespace fluidsim::port::desktop {
|
||||
void draw_dyno_curve(sf::RenderWindow&,const sf::Font*,const DynoCurve&,float,float,float,float,float,float);
|
||||
}
|
||||
19
include/FluidSim/Desktop/EngineRenderer3D.hpp
Normal file
19
include/FluidSim/Desktop/EngineRenderer3D.hpp
Normal file
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
#include "FluidSim/Scenario.hpp"
|
||||
#include "FluidSim/Desktop/OrbitCamera.hpp"
|
||||
#include <SFML/Graphics.hpp>
|
||||
#include <memory>
|
||||
namespace fluidsim::port::desktop {
|
||||
// Visualization consumes snapshots only; it never accesses mutable solver state.
|
||||
class EngineRenderer3D {
|
||||
public:
|
||||
EngineRenderer3D();
|
||||
~EngineRenderer3D();
|
||||
EngineRenderer3D(const EngineRenderer3D&)=delete;
|
||||
EngineRenderer3D& operator=(const EngineRenderer3D&)=delete;
|
||||
void draw(sf::RenderWindow&,const ScenarioSnapshot&,sf::FloatRect,const OrbitCamera&);
|
||||
private:
|
||||
struct Impl;
|
||||
std::unique_ptr<Impl> impl_;
|
||||
};
|
||||
}
|
||||
6
include/FluidSim/Desktop/EngineSchematic.hpp
Normal file
6
include/FluidSim/Desktop/EngineSchematic.hpp
Normal file
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
#include "FluidSim/Scenario.hpp"
|
||||
#include <SFML/Graphics.hpp>
|
||||
namespace fluidsim::port::desktop {
|
||||
void draw_schematic(sf::RenderWindow&, const sf::Font*, const ScenarioSnapshot&);
|
||||
}
|
||||
20
include/FluidSim/Desktop/OrbitCamera.hpp
Normal file
20
include/FluidSim/Desktop/OrbitCamera.hpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
#include "FluidSim/AudioProcessing.hpp"
|
||||
#include <SFML/System/Vector2.hpp>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
namespace fluidsim::port::desktop {
|
||||
struct OrbitCamera {
|
||||
Vec3 target{.12f,.25f,0};
|
||||
float yaw{-28},pitch{24},distance{2.2f};
|
||||
void reset(float aspect) {target={.12f,.25f,0};yaw=-28;pitch=24;distance=std::max(.65f,1.6f/aspect)/.414214f;}
|
||||
void orbit(sf::Vector2i delta) {yaw+=delta.x*.35f;pitch=std::clamp(pitch+delta.y*.3f,-75.f,80.f);}
|
||||
void pan(sf::Vector2i delta,float height) {
|
||||
const float y=yaw*.017453293f,p=pitch*.017453293f,k=distance*.828427f/std::max(height,1.f);
|
||||
target.x+=k*(-delta.x*std::cos(y)+delta.y*std::sin(p)*std::sin(y));
|
||||
target.y+=k*delta.y*std::cos(p);
|
||||
target.z+=k*(-delta.x*std::sin(y)-delta.y*std::sin(p)*std::cos(y));
|
||||
}
|
||||
void zoom(float delta) {distance=std::clamp(distance*std::exp(-delta*.12f),.35f,12.f);}
|
||||
};
|
||||
}
|
||||
15
include/FluidSim/Desktop/PedalControl.hpp
Normal file
15
include/FluidSim/Desktop/PedalControl.hpp
Normal file
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
#include <algorithm>
|
||||
namespace fluidsim::port::desktop {
|
||||
// Keyboard input travel is separate from the ECU actuator response.
|
||||
class PedalControl {
|
||||
public:
|
||||
float value() const {return value_;}
|
||||
void set(float value) {value_=std::clamp(value,0.f,1.f);}
|
||||
void advance(float dt,bool raise,bool lower) {
|
||||
if(dt>0) set(value_+(raise && !lower?2.f:-2.f)*dt);
|
||||
}
|
||||
private:
|
||||
float value_{};
|
||||
};
|
||||
}
|
||||
46
include/FluidSim/Desktop/PipePath.hpp
Normal file
46
include/FluidSim/Desktop/PipePath.hpp
Normal file
@@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
#include "FluidSim/AudioProcessing.hpp"
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
namespace fluidsim::port::desktop {
|
||||
struct PipeAnchor {float distance;Vec3 position;};
|
||||
// Knots are distances along the simulated pipe, in metres. Display positions
|
||||
// define its schematic route; changing them never changes fluid cell lengths.
|
||||
class PipePath {
|
||||
public:
|
||||
explicit PipePath(std::vector<PipeAnchor> anchors):anchors_(std::move(anchors)) {
|
||||
if(anchors_.size()<2 || anchors_.front().distance!=0)throw std::invalid_argument("pipe path needs origin and endpoint");
|
||||
for(std::size_t i=0;i<anchors_.size();++i) {
|
||||
const auto& p=anchors_[i];
|
||||
if(!std::isfinite(p.distance) || !std::isfinite(p.position.x) || !std::isfinite(p.position.y) || !std::isfinite(p.position.z) ||
|
||||
(i && !(p.distance>anchors_[i-1].distance))) throw std::invalid_argument("invalid distance-referenced pipe path");
|
||||
}
|
||||
}
|
||||
Vec3 position(float distance) const {
|
||||
distance=std::clamp(distance,0.f,anchors_.back().distance);
|
||||
auto it=std::upper_bound(anchors_.begin(),anchors_.end(),distance,[](float s,const PipeAnchor& a){return s<a.distance;});
|
||||
std::size_t i=std::clamp<std::size_t>(it-anchors_.begin(),1,anchors_.size()-1)-1;
|
||||
const auto& a=anchors_[i];const auto& b=anchors_[i+1];
|
||||
const float span=b.distance-a.distance,t=(distance-a.distance)/span,t2=t*t,t3=t2*t;
|
||||
const auto ma=tangent_at(i),mb=tangent_at(i+1);
|
||||
auto coordinate=[&](float pa,float pb,float ta,float tb){return (2*t3-3*t2+1)*pa+(t3-2*t2+t)*span*ta+(-2*t3+3*t2)*pb+(t3-t2)*span*tb;};
|
||||
return {coordinate(a.position.x,b.position.x,ma.x,mb.x),coordinate(a.position.y,b.position.y,ma.y,mb.y),coordinate(a.position.z,b.position.z,ma.z,mb.z)};
|
||||
}
|
||||
Vec3 tangent(float distance) const {
|
||||
const float epsilon=anchors_.back().distance*.0001f;
|
||||
const auto a=position(distance-epsilon),b=position(distance+epsilon);
|
||||
const float x=b.x-a.x,y=b.y-a.y,z=b.z-a.z,n=std::sqrt(x*x+y*y+z*z);
|
||||
return n>1e-8f?Vec3{x/n,y/n,z/n}:Vec3{1,0,0};
|
||||
}
|
||||
private:
|
||||
Vec3 tangent_at(std::size_t i) const {
|
||||
const auto& a=anchors_[i?i-1:0];const auto& b=anchors_[std::min(i+1,anchors_.size()-1)];
|
||||
const float d=b.distance-a.distance;
|
||||
return {(b.position.x-a.position.x)/d,(b.position.y-a.position.y)/d,(b.position.z-a.position.z)/d};
|
||||
}
|
||||
std::vector<PipeAnchor> anchors_;
|
||||
};
|
||||
}
|
||||
12
include/FluidSim/Desktop/PressurePalette.hpp
Normal file
12
include/FluidSim/Desktop/PressurePalette.hpp
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#include "FluidSim/AudioProcessing.hpp"
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
namespace fluidsim::port::desktop {
|
||||
// Fixed absolute scale: vacuum blue, atmosphere green, >=1 MPa red.
|
||||
inline Vec3 pressure_tint(float pressure) {
|
||||
if(pressure<=101325) {float t=std::clamp(pressure/101325,0.f,1.f);return {.05f,.15f+.70f*t,1-.95f*t};}
|
||||
float t=std::sqrt(std::clamp((pressure-101325)/(1000000-101325),0.f,1.f));
|
||||
return {.05f+.95f*t,.85f-.80f*t,.05f-.03f*t};
|
||||
}
|
||||
}
|
||||
7
include/FluidSim/Desktop/ScenarioMenu.hpp
Normal file
7
include/FluidSim/Desktop/ScenarioMenu.hpp
Normal file
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
#include "FluidSim/ScenarioCatalog.hpp"
|
||||
#include <SFML/Graphics.hpp>
|
||||
#include <optional>
|
||||
namespace fluidsim::port::desktop {
|
||||
std::optional<std::size_t> choose_scenario(sf::RenderWindow&,const sf::Font*,const std::vector<ScenarioExample>&);
|
||||
}
|
||||
Reference in New Issue
Block a user