Skip to content

Commit 12c7947

Browse files
committed
GPU Display GUI: Make animation points configurable in the GUI
1 parent b7b716d commit 12c7947

13 files changed

Lines changed: 453 additions & 93 deletions

‎GPU/GPUTracking/display/GPUDisplay.h‎

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,11 @@ class GPUDisplay : public GPUDisplayInterface
149149
}
150150
};
151151

152+
struct animationVector { // Animation point, its time is in mCfgC.animationPoints.values
153+
float v[8]; // Camera, depending on cfgL.animationMode (setAnimationPoint)
154+
GPUSettingsDisplayLight cfgL; // Settings at the point
155+
};
156+
152157
class opengl_spline
153158
{
154159
public:
@@ -200,7 +205,13 @@ class GPUDisplay : public GPUDisplayInterface
200205
void rotateCamera(const float (&angles)[3]); // Yaw, pitch, roll in degrees relative to the view, as the keyboard
201206
hmm_mat4 cameraRotation(const float (&angles)[3]) const; // Rotation of rotateCamera, applied to the view matrix also for keyboard / mouse
202207
void resetAnimation();
203-
void removeAnimationPoint();
208+
void removeAnimationPoint(int32_t i = -1); // -1: the selected one, the last one if none is selected
209+
void StopAnimation(); // Ends a running animation, camera and settings stay as they are; for changed settings (checkAndApplyConfigChanges), scene reset, changes of the animation points
210+
void setCameraFromAnimationPoint(const animationVector& p); // Camera stored in the point, as the animation shows it there
211+
void selectAnimationPoint(int32_t i); // -1: none, otherwise also loads its light settings and camera
212+
void setAnimationPointsFromGUI(const GPUDisplayMultiSliderValue& points); // New times from the Qt GUI: reorders the points, selection
213+
void updateAnimationPointsGUI(); // Range end of the GUI multi slider: last time + animationDelay, progress 0 without animation
214+
void animationViewMatrix(float (&vals)[8], int32_t mode, hmm_mat4& viewMatrix) const; // Camera of interpolated / stored animation values (v[1..8]), as animateCamera
204215
void startAnimation();
205216
int32_t animateCamera(bool suspended, float& animateTime, float& mixSlaveImage, hmm_mat4& nextViewMatrix);
206217
void showInfo(const char* info);
@@ -324,8 +335,7 @@ class GPUDisplay : public GPUDisplayInterface
324335
int32_t mAnimationLastBase = 0;
325336
int32_t mAnimationMixBase = -1; // Target keyframe of the current config blend (mixing), -1 = none
326337
int32_t mAnimationExport = 0;
327-
vecpod<float> mAnimateVectors[9];
328-
vecpod<GPUSettingsDisplayLight> mAnimateConfig;
338+
vecpod<animationVector> mAnimationVectors;
329339
opengl_spline mAnimationSplines[8];
330340

331341
char mInfoText2[1024];

‎GPU/GPUTracking/display/GPUDisplayControl.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ BeginHiddenConfig(GPUDisplayControl, control)
4141
AddVariable(guiDarkMode, int8_t, -1) // Dark mode of the Qt GUI, -1 = not yet set: the GUI reports the system scheme when it starts
4242
AddVariable(guiScale, float, 1.f) // Scale factor of text and elements of the Qt GUI (on top of the system scaling), Ctrl + mouse wheel / Ctrl + 0 in the GUI
4343
AddVariable(showConsole, bool, false) // Console shown (^ key): all other keys go to the console
44+
AddVariable(animationPoints, GPUDisplayMultiSliderValue, GPUDisplayMultiSliderValue()) // Times of the animation points (GPUDisplay::mAnimationVectors) and the selected one, shown in the Qt GUI
4445
AddVariable(dummy, bool, false) // dummy value to reference for keys that do not change variables
4546
EndConfig()
4647
EndNamespace() // o2::gpu

‎GPU/GPUTracking/display/GPUDisplayTypes.h‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,27 @@
1515
#ifndef GPUDISPLAYTYPES_H
1616
#define GPUDISPLAYTYPES_H
1717

18+
#include "utils/vecpod.h"
19+
#include <cstdint>
20+
#include <ostream>
21+
1822
namespace o2::gpu
1923
{
24+
struct GPUDisplayMultiSliderValue { // Value of a Qt GUI multi slider (GUI_MULTI_SLIDER): positions in the order of the display, selected one (-1: none), end of the range, progress
25+
vecpod<float> values;
26+
int16_t selected = -1;
27+
uint16_t progress = 0; // Fraction (of 65535) of the last position highlighted, e.g. a running animation; small types: GPUDisplayGUIValue must not grow
28+
float max = 0.f;
29+
bool operator==(const GPUDisplayMultiSliderValue&) const = default;
30+
friend std::ostream& operator<<(std::ostream& out, const GPUDisplayMultiSliderValue& v) // For the qconfig printout
31+
{
32+
for (float x : v.values) {
33+
out << x << " ";
34+
}
35+
return out << "(selected " << v.selected << ")";
36+
}
37+
};
38+
2039
template <class T>
2140
struct GPUDisplayCopyableAtomic : std::atomic<T> { // std::atomic deletes the copy, here it copies the value
2241
using std::atomic<T>::atomic;

‎GPU/GPUTracking/display/frontend/GPUDisplayFrontendConfig.cxx‎

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -207,13 +207,17 @@ namespace
207207
void GPUDisplay::checkAndApplyConfigChanges()
208208
{
209209
const auto& [oldCfgH, oldCfgL, oldCfgR] = mOldCfg;
210-
if (memcmp((void*)&oldCfgH, (void*)&mCfgH, sizeof(mCfgH)) != 0) {
210+
const bool changedH = memcmp((void*)&oldCfgH, (void*)&mCfgH, sizeof(mCfgH)) != 0, changedL = memcmp((void*)&oldCfgL, (void*)&mCfgL, sizeof(mCfgL)) != 0, changedR = memcmp((void*)&oldCfgR, (void*)&mCfgR, sizeof(mCfgR)) != 0;
211+
if (mAnimate && (changedH || changedL || changedR || mCfgC.resetScene.load())) {
212+
StopAnimation();
213+
}
214+
if (changedH) {
211215
mUpdateEventData = true;
212216
}
213217
if (mCfgL.propagateTracks != 0 && !mTracksArePropagated) {
214218
mUpdateVertexLists = true;
215219
}
216-
if (memcmp((void*)&oldCfgL, (void*)&mCfgL, sizeof(mCfgL)) != 0 || memcmp((void*)&oldCfgR, (void*)&mCfgR, sizeof(mCfgR)) != 0) {
220+
if (changedL || changedR) {
217221
mUpdateDrawCommands = true;
218222
}
219223
if (oldCfgR.drawQualityMSAA != mCfgR.drawQualityMSAA || oldCfgR.drawQualityDownsampleFSAA != mCfgR.drawQualityDownsampleFSAA || oldCfgL.depthBuffer != mCfgL.depthBuffer || oldCfgR.screenshotScaleFactor != mCfgR.screenshotScaleFactor) {
@@ -250,6 +254,10 @@ void GPUDisplay::checkAndApplyConfigChanges()
250254
std::fill(std::begin(mFrontend->mKeys), std::end(mFrontend->mKeys), false);
251255
}
252256
}
257+
if (mCfgC.animationPoints.selected >= 0 && mCfgC.animationPoints.selected < (int32_t)mAnimationVectors.size()) { // Update animation settings of selected point
258+
mAnimationVectors[mCfgC.animationPoints.selected].cfgL = mCfgL;
259+
}
260+
updateAnimationPointsGUI();
253261
}
254262

255263
void GPUDisplay::HandleExternalGUIKey(int32_t key, bool bypassConsole)
@@ -328,19 +336,22 @@ void GPUDisplayFrontend::add_key_binding(Args&&... args)
328336
}
329337

330338
struct guiType { // Element type and choices, GUI_CHECKBOX, GUI_DROPDOWN(...), etc. in GPUDisplayFrontendConfigQtGUI.inc
331-
guiType(GPUDisplayGUIChannel::ElementType t, std::vector<std::pair<std::string, GPUDisplayGUIValue>> c = {}, std::function<GPUDisplayGUIChannel::Options()> o = {}, uint32_t l = 0, int64_t b = 0) : type(t), choices(std::move(c)), options(std::move(o)), lines(l), bitMask(b) {}
339+
guiType(GPUDisplayGUIChannel::ElementType t, std::vector<std::pair<std::string, GPUDisplayGUIValue>> c = {}, std::function<GPUDisplayGUIChannel::Options()> o = {}, uint32_t l = 0, int64_t b = 0, double s = 0) : type(t), choices(std::move(c)), options(std::move(o)), lines(l), bitMask(b), step(s) {}
332340
GPUDisplayGUIChannel::ElementType type;
333341
std::vector<std::pair<std::string, GPUDisplayGUIValue>> choices;
334342
std::function<GPUDisplayGUIChannel::Options()> options; // GUI_SLIDER_DYNAMIC / GUI_DROPDOWN_DYNAMIC
335343
uint32_t lines = 0; // GUI_TEXTEDIT
336344
int64_t bitMask = 0; // GUI_CHECKBOX_BIT
345+
double step = 0; // GUI_MULTI_SLIDER
337346
};
338347

339348
static std::vector<std::pair<std::string, GPUDisplayGUIValue>> guiSliderValues(std::initializer_list<GPUDisplayGUIValue> values) // Choices of GUI_SLIDER_VALUES, named by their value
340349
{
341350
auto name = [](const auto& x) -> std::string {
342351
if constexpr (std::is_same_v<std::remove_cvref_t<decltype(x)>, std::string>) {
343352
return x;
353+
} else if constexpr (std::is_same_v<std::remove_cvref_t<decltype(x)>, GPUDisplayMultiSliderValue>) {
354+
return "";
344355
} else {
345356
return qConfig::print_type(x);
346357
}
@@ -378,7 +389,11 @@ static void guiAssign(T& dst, const GPUDisplayGUIValue& value) // Default GUI_LA
378389
{
379390
std::visit([&](const auto& v) {
380391
using V = std::remove_cvref_t<decltype(v)>;
381-
if constexpr (std::is_same_v<T, std::string>) {
392+
if constexpr (std::is_same_v<T, V>) {
393+
dst = v;
394+
} else if constexpr (std::is_same_v<T, GPUDisplayMultiSliderValue> || std::is_same_v<V, GPUDisplayMultiSliderValue>) {
395+
throw std::runtime_error("GUI value of a multi slider for another element type, or vice versa");
396+
} else if constexpr (std::is_same_v<T, std::string>) {
382397
if constexpr (std::is_same_v<V, std::string>) {
383398
dst = v;
384399
} else {
@@ -406,6 +421,8 @@ static GPUDisplayGUIValue toGUIValue(const T& v)
406421
}
407422
}
408423

424+
static GPUDisplayGUIValue toGUIValue(const GPUDisplayMultiSliderValue& v) { return v; }
425+
409426
template <class T>
410427
static GPUDisplayGUIValue toGUIValue(const GPUDisplayCopyableAtomic<T>& v)
411428
{
@@ -442,7 +459,7 @@ void GPUDisplayFrontend::add_gui_binding(Args&&... args)
442459
}
443460
static const GPUDisplayGUIChannel::Settings defaults; // Only for the types of the values
444461
const uint32_t id = mConfiguration->guiElements.size();
445-
auto& el = frame.elements.emplace_back(GPUDisplayGUIChannel::Element{.name = element.name, .description = element.rttiIndex < mConfiguration->rttiEntries.size() ? mConfiguration->rttiEntries[element.rttiIndex].description : "", .rttiIndex = element.rttiIndex, .type = element.type.type, .id = id, .isInteger = std::holds_alternative<int64_t>(element.get(defaults)), .isString = std::holds_alternative<std::string>(element.get(defaults)), .lines = element.type.lines, .choices = std::move(element.type.choices), .dynamicOptions = std::move(element.type.options), .get = element.get});
462+
auto& el = frame.elements.emplace_back(GPUDisplayGUIChannel::Element{.name = element.name, .description = element.rttiIndex < mConfiguration->rttiEntries.size() ? mConfiguration->rttiEntries[element.rttiIndex].description : "", .rttiIndex = element.rttiIndex, .type = element.type.type, .id = id, .isInteger = std::holds_alternative<int64_t>(element.get(defaults)), .isString = std::holds_alternative<std::string>(element.get(defaults)), .lines = element.type.lines, .step = element.type.step, .choices = std::move(element.type.choices), .dynamicOptions = std::move(element.type.options), .get = element.get});
446463
if (el.dynamicOptions && !((el.type == Type::SLIDER && el.choices.empty()) || el.type == Type::DROPDOWN)) {
447464
throw std::runtime_error("GUI element " + element.name + ": dynamic options only for sliders with range and dropdown menus");
448465
}
@@ -462,6 +479,12 @@ void GPUDisplayFrontend::add_gui_binding(Args&&... args)
462479
el.max = std::stod(mConfiguration->rttiEntries[element.rttiIndex].max);
463480
el.hasRange = true;
464481
}
482+
if (el.step > 0 && !(el.type == Type::MULTI_SLIDER || (el.type == Type::SLIDER && el.choices.empty()))) {
483+
throw std::runtime_error("GUI element " + element.name + ": a step only for sliders with a range and multi sliders");
484+
}
485+
if (el.type == Type::MULTI_SLIDER && (!std::holds_alternative<GPUDisplayMultiSliderValue>(element.get(defaults)) || el.step <= 0)) {
486+
throw std::runtime_error("GUI multi slider " + element.name + " needs an option of type GPUDisplayMultiSliderValue and a step > 0");
487+
}
465488
if ((el.type == Type::RADIO_BUTTONS || el.type == Type::DROPDOWN) ? (el.choices.empty() && !el.dynamicOptions) : (!el.choices.empty() && el.type != Type::SLIDER)) {
466489
throw std::runtime_error("GUI element " + element.name + ": choices are needed for radio buttons and dropdown menus, and only allowed for them and sliders");
467490
}

‎GPU/GPUTracking/display/frontend/GPUDisplayFrontendConfigConsole.inc‎

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ void GPUDisplayFrontend::buildConsoleCommands()
8585
const float xyz[3] = {floatNumber(a[0]), floatNumber(a[1]), floatNumber(a[2])};
8686
const float angles[3] = {floatNumber(a[4]) * toRad, floatNumber(a[3]) * toRad, floatNumber(a[5]) * toRad}; // As mAngle: pitch, yaw, roll
8787
mDisplay->addAnimationPoint(xyz, angles);
88-
mDisplay->SetInfo("Added Animation point (%d points, %6.2f seconds)", (int32_t)mDisplay->mAnimateVectors[0].size(), mDisplay->mAnimateVectors[0].back());
88+
mDisplay->SetInfo("Added Animation point (%d points, %6.2f seconds)", (int32_t)mDisplay->mAnimationVectors.size(), mDisplay->mCfgC.animationPoints.values.back());
8989
},
9090
"dddddd", "Add an animation point: x y z yaw pitch roll (degrees)"};
9191
commands["startAnimation"] = {[this](args) { mDisplay->runAnimation(); }, "", "Run the animation"};
@@ -147,6 +147,26 @@ void GPUDisplayFrontend::buildConsoleCommands()
147147
mDisplay->SetInfo("Reset Animation points", 1);
148148
},
149149
"", "Remove all animation points"};
150+
auto pointIndex = [this](const char* command, const GPUDisplayConsole::consoleArg& a) -> std::optional<int32_t> { // Index of an animation point or -1, error message otherwise
151+
const int64_t i = std::get<int64_t>(a);
152+
if (i < -1 || i >= (int64_t)mDisplay->mAnimationVectors.size()) {
153+
mConsole->consolePrint("%s: no animation point %lld (%zu points)", command, (long long)i, mDisplay->mAnimationVectors.size());
154+
return std::nullopt;
155+
}
156+
return i;
157+
};
158+
commands["removeAnimationPoint"] = {[this, pointIndex](args a) {
159+
if (const auto i = pointIndex("removeAnimationPoint", a[0])) {
160+
mDisplay->removeAnimationPoint(*i);
161+
}
162+
},
163+
"i", "Remove the animation point with this index, -1: the selected one, or the last one if none is selected"};
164+
commands["selectAnimationPoint"] = {[this, pointIndex](args a) {
165+
if (const auto i = pointIndex("selectAnimationPoint", a[0])) {
166+
mDisplay->selectAnimationPoint(*i);
167+
}
168+
},
169+
"i", "Select an animation point (-1: none): loads its settings and camera, later changes of the light settings are stored in it"};
150170
auto fileCommand = [this](std::string GPUDisplayControl::* file, void (GPUDisplay::*function)()) { // Sets the file name option (as in the GUI) and runs the function
151171
return [this, file, function](args a) {
152172
mDisplay->mCfgC.*file = std::get<std::string>(a[0]);
@@ -190,14 +210,14 @@ void GPUDisplayFrontend::buildConsoleCommands()
190210
};
191211
auto transient = [this](uint32_t i) { // Control values that are actions / state, not settings: not saved, not reset with a group
192212
const auto& e = mConfiguration->rttiEntries[i];
193-
return e.type.starts_with("GPUDisplayCopyableAtomic") || e.name == "requestScreenshot" || e.name == "showConsole" || e.name == "dummy"; // TODO: Settings struct should be split in transient and none-transient, to get rid of these string compares
213+
return e.type.starts_with("GPUDisplayCopyableAtomic") || e.name == "requestScreenshot" || e.name == "showConsole" || e.name == "dummy" || e.name == "animationPoints"; // TODO: Settings struct should be split in transient and none-transient, to get rid of these string compares
194214
};
195215
auto defaultValue = [this](uint32_t i) -> GPUDisplayConsole::consoleArg { // Default from the RTTI, as setValue expects it
196216
const auto& e = mConfiguration->rttiEntries[i];
197217
if (e.type == "std::string" || e.type == "bool") {
198218
return e.defaultValue;
199219
}
200-
int64_t intValue;
220+
int64_t intValue = 0;
201221
const char* end = e.defaultValue.c_str() + e.defaultValue.size();
202222
if (std::from_chars(e.defaultValue.c_str(), end, intValue).ptr == end) { // Integers exactly, not through double
203223
return intValue;

‎GPU/GPUTracking/display/frontend/GPUDisplayFrontendConfigKeys.inc‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -241,9 +241,9 @@ void GPUDisplay::buildConfigKeys()
241241

242242
mFrontend->add_key_binding(
243243
KEY_ACTION('y', "START_ANIMATION", runAnimation();),
244-
KEY_ACTION('Y', "ADD_ANIMATION_POINT", setAnimationPoint(); SetInfo("Added Animation point (%d points, %6.2f seconds)", (int32_t)mAnimateVectors[0].size(), mAnimateVectors[0].back());), //
245-
KEY_ACTION('\'', "REMOVE_ANIMATION_POINT", removeAnimationPoint(); SetInfo("Removed Animation point", 1);), //
246-
KEY_ACTION('X', "RESET_ANIMATION", resetAnimation(); SetInfo("Reset Animation points", 1);), //
244+
KEY_ACTION('Y', "ADD_ANIMATION_POINT", setAnimationPoint(); SetInfo("Added Animation point (%d points, %6.2f seconds)", (int32_t)mAnimationVectors.size(), mCfgC.animationPoints.values.back());), //
245+
KEY_ACTION('\'', "REMOVE_ANIMATION_POINT", removeAnimationPoint(); SetInfo("Removed Animation point", 1);), //
246+
KEY_ACTION('X', "RESET_ANIMATION", resetAnimation(); SetInfo("Reset Animation points", 1);), //
247247
KEY_LAMBDA('M', "ANIMATION_MODE", mCfgL, animationMode, {
248248
val++;
249249
if (val == 7) {

0 commit comments

Comments
 (0)