96 lines
7.0 KiB
C++
96 lines
7.0 KiB
C++
#include "FluidSim/Desktop/DesktopUi.hpp"
|
|
#include "FluidSim/Scenario.hpp"
|
|
#include "FluidSim/ScenarioCatalog.hpp"
|
|
#include "FluidSim/DesktopScenario.hpp"
|
|
#include "FluidSim/Desktop/PlaybackControl.hpp"
|
|
#include "FluidSim/Desktop/PipePath.hpp"
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
#include <iostream>
|
|
#include <stdexcept>
|
|
using namespace fluidsim::port::desktop;
|
|
void check(bool condition,const char* reason) {if(!condition)throw std::runtime_error(reason);}
|
|
int main(int argc,char** argv) {
|
|
PlaybackControl playback;
|
|
sf::Event space=sf::Event::KeyPressed{.code=sf::Keyboard::Key::Space};
|
|
sf::Event wheel=sf::Event::MouseWheelScrolled{sf::Mouse::Wheel::Vertical,-1.f,{400,300}};
|
|
check(playback.realtime()&&!playback.handle_event(wheel,true),"realtime mode intercepted camera scrolling");
|
|
check(playback.handle_event(space)&&!playback.realtime(),"Space did not disable realtime");
|
|
check(!playback.handle_event(wheel)&&playback.target_speed()==1,"regular scroll changed manual speed");
|
|
check(playback.handle_event(wheel,true)&&playback.target_speed()<1,"Shift+scroll did not change manual speed");
|
|
const auto manual=playback.target_speed();playback.handle_event(space);check(playback.target_speed()==1,"Space did not restore realtime");
|
|
playback.handle_event(space);check(playback.target_speed()==manual,"manual speed was lost");
|
|
PipePath corner({{0,{0,0,0}},{1,{1,0,0}},{2,{1,1,0}}});
|
|
check(corner.position(.5f)==fluidsim::port::Vec3{.5f,0,0}&&corner.position(1.5f)==fluidsim::port::Vec3{1,.5f,0},"sharp pipe bend was rounded into a spline");
|
|
const auto miter=corner.miter_offset(1,{.70710678f,-.70710678f,0});
|
|
check(std::abs(miter.x-1)<1e-5f&&std::abs(miter.y+1)<1e-5f,"90 degree pipe joint pinches the cross-section");
|
|
for(auto size : {sf::Vector2u{933,1010},sf::Vector2u{1920,1080},sf::Vector2u{1040,800},sf::Vector2u{800,700}}) {
|
|
const auto l=WorkspaceLayout::calculate(size);
|
|
for(auto r : {l.sidebar,l.viewport,l.chart,l.inspector,l.pedal}) {
|
|
check(r.position.x>=0 && r.position.y>=0 && r.size.x>0 && r.size.y>0,"invalid panel bounds");
|
|
check(r.position.x+r.size.x<=size.x && r.position.y+r.size.y<=size.y,"panel escapes window");
|
|
}
|
|
check(l.sidebar.position.x+l.sidebar.size.x<l.viewport.position.x,"sidebar overlaps engine");
|
|
check(l.viewport.position.y+l.viewport.size.y<l.chart.position.y,"engine overlaps dyno");
|
|
check(l.chart.position.x+l.chart.size.x<l.inspector.position.x,"dyno overlaps inspector");
|
|
}
|
|
DesktopUi ui;
|
|
const sf::Vector2u size{1440,900};const auto track=WorkspaceLayout::calculate(size).pedal;
|
|
const sf::Vector2i point{int(track.position.x+track.size.x*.7f),int(track.position.y+12)};
|
|
ui.handle_event(sf::Event::MouseButtonPressed{sf::Mouse::Button::Left,point},size);
|
|
check(std::abs(ui.pedal()-.7f)<.01f,"slider should set direct pedal request");
|
|
ui.update_pedal(.5f,false,true);
|
|
check(std::abs(ui.pedal()-.7f)<.01f,"keyboard ramp must not interfere while dragging slider");
|
|
ui.handle_event(sf::Event::MouseButtonReleased{sf::Mouse::Button::Left,point},size);
|
|
check(ui.pedal()==0,"slider must spring to zero on release");
|
|
ui.update_pedal(.5f,true,false);check(ui.pedal()==1,"W full travel must take 0.5 seconds");
|
|
ui.update_pedal(.25f,false,false);check(std::abs(ui.pedal()-.5f)<1e-6f,"keyboard release travel timing");
|
|
ui.update_pedal(.25f,false,false);check(ui.pedal()==0,"keyboard must return to idle request");
|
|
ui.handle_event(sf::Event::MouseButtonPressed{sf::Mouse::Button::Left,point},size);
|
|
ui.handle_event(sf::Event::FocusLost{},size);check(ui.pedal()==0,"lost focus must release UI pedal");
|
|
OrbitCamera camera;camera.reset(2);auto before=camera.target;
|
|
camera.orbit({40,20});camera.pan({20,15},500);camera.zoom(2);
|
|
check(camera.pitch<=80 && camera.pitch>=-75 && camera.distance>.35f,"camera bounds");
|
|
check(camera.target.x!=before.x || camera.target.y!=before.y,"camera panning must move target");
|
|
for(float yaw:{-90.f,-28.f,0.f,90.f,180.f})for(float pitch:{-60.f,0.f,70.f}) {
|
|
camera.yaw=yaw;camera.pitch=pitch;camera.target={.7f,.4f,-.2f};camera.distance=3;
|
|
const auto listener=camera.listener(1.8f,1.1f);
|
|
const float y=yaw*.017453293f,p=pitch*.017453293f;
|
|
const float dx=listener.position.x-camera.target.x-1.1f;
|
|
const float dy=listener.position.y-camera.target.y,dz=listener.position.z-camera.target.z;
|
|
const float x1=std::cos(y)*dx+std::sin(y)*dz,z1=-std::sin(y)*dx+std::cos(y)*dz;
|
|
check(std::abs(x1)<2e-6f && std::abs(std::cos(p)*dy-std::sin(p)*z1)<2e-6f &&
|
|
std::abs(std::sin(p)*dy+std::cos(p)*z1-5.4f)<2e-6f,
|
|
"audio listener must coincide with the rendered camera including fit offsets");
|
|
check(std::abs(std::cos(y)*listener.right.x+std::sin(y)*listener.right.z-1)<1e-6f,
|
|
"audio ears must rotate with the camera right axis");
|
|
}
|
|
ui.configure_resolution(20);
|
|
const auto buttons=DesktopUi::resolution_buttons(size);
|
|
const auto plus=buttons[1].position+sf::Vector2f{10,8};
|
|
ui.handle_event(sf::Event::MouseButtonPressed{sf::Mouse::Button::Left,{int(plus.x),int(plus.y)}},size);
|
|
check(ui.take_resolution_request()==25,"resolution plus button failed");
|
|
ui.resolution_started();
|
|
ui.handle_event(sf::Event::MouseButtonPressed{sf::Mouse::Button::Left,{int(plus.x),int(plus.y)}},size);
|
|
check(!ui.take_resolution_request(),"resolution changed while rebuilding");
|
|
ui.resolution_finished(25,"Applied");
|
|
if(argc==3 && std::string(argv[1])=="--preview") {
|
|
const std::filesystem::path directory=argv[2];std::filesystem::create_directories(directory);
|
|
sf::ContextSettings context;context.depthBits=24;context.majorVersion=2;context.minorVersion=1;
|
|
sf::RenderWindow window(sf::VideoMode({1440,900}),"Geometry preview",sf::Style::Default,sf::State::Windowed,context);
|
|
window.setVisible(false);sf::Font font("C:/Windows/Fonts/consola.ttf");
|
|
const auto& catalog=fluidsim::port::scenario_examples();
|
|
sf::RenderTexture contact({1280,static_cast<unsigned>((catalog.size()+3)/4)*200});contact.clear(sf::Color::Black);
|
|
unsigned index=0;
|
|
for(const auto& example:catalog) {
|
|
fluidsim::port::DesktopScenario simulation(example);for(int i=0;i<512;++i)simulation.process();
|
|
const auto state=simulation.snapshot();DesktopUi preview;preview.configure_resolution(state.cells_per_meter);preview.draw(window,&font,state,{});
|
|
sf::Texture texture(window.getSize());texture.update(window);
|
|
check(texture.copyToImage().saveToFile(directory/(example.id+".png")),"could not save geometry preview");
|
|
sf::Sprite thumbnail(texture);thumbnail.setScale({320.f/window.getSize().x,200.f/window.getSize().y});thumbnail.setPosition({float(index%4)*320,float(index/4)*200});contact.draw(thumbnail);++index;
|
|
}
|
|
contact.display();check(contact.getTexture().copyToImage().saveToFile(directory/"catalog.png"),"could not save catalog preview");
|
|
}
|
|
std::cout<<"Desktop controls, resolution stepper, and camera checks passed\n";
|
|
}
|