Skip to content

Commit

Permalink
Visualiser: ImGui support for user-defined interfaces to view/update …
Browse files Browse the repository at this point in the history
…environment properties.

User's are provided the ability to add environment properties/environment array property elements to user interface panel(s) in the form of input boxes, sliders, drag things and checkboxes.

Additionally, moved the debug menu to ImGui and added the initial random seed to it's items.
  • Loading branch information
Robadob committed Sep 12, 2022
1 parent 2c565e2 commit 8dabd35
Show file tree
Hide file tree
Showing 9 changed files with 450 additions and 6 deletions.
2 changes: 1 addition & 1 deletion cmake/dependencies/flamegpu2-visualiser.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ cmake_policy(SET CMP0079 NEW)

# Set the visualiser repo and tag to use unless overridden by the user.
# @todo - If the git version has changed in this file, fetch again?
set(DEFAULT_VISUALISATION_GIT_VERSION "ef676da1daf8d8118bc7b2b75ede958c4f08afc9")
set(DEFAULT_VISUALISATION_GIT_VERSION "imgui")
set(DEFAULT_VISUALISATION_REPOSITORY "https://github.com/FLAMEGPU/FLAMEGPU2-visualiser.git")

# If overridden by the user, attempt to use that
Expand Down
3 changes: 3 additions & 0 deletions include/flamegpu/gpu/CUDASimulation.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ class CUDASimulation : public Simulation {
friend class HostAgentAPI;
friend class SimRunner;
friend class CUDAEnsemble;
#ifdef VISUALISATION
friend class visualiser::ModelVis;
#endif
/**
* Map of a number of CUDA agents by name.
* The CUDA agents are responsible for allocating and managing all the device memory
Expand Down
20 changes: 20 additions & 0 deletions include/flamegpu/visualiser/ModelVis.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "flamegpu/visualiser/AgentVis.h"
#include "flamegpu/visualiser/StaticModelVis.h"
#include "flamegpu/visualiser/LineVis.h"
#include "flamegpu/visualiser/PanelVis.h"
#include "flamegpu/visualiser/color/AutoPalette.h"
#include "flamegpu/visualiser/config/ModelConfig.h"

Expand Down Expand Up @@ -177,6 +178,13 @@ class ModelVis {
* @param a Initial color's alpha component
*/
LineVis newPolylineSketch(float r, float g, float b, float a = 1.0f);
/**
* Add a customisable user interface panel to the visualisation
*
* Each panel can be moved around the screen/minimised with custom elements representing environment properties added
* @param panel_title The string that will be visible in the title of the panel
*/
PanelVis newUIPanel(const std::string& panel_title);
/**
* Sets the visualisation running in a background thread
*/
Expand All @@ -201,11 +209,19 @@ class ModelVis {
* Returns whether the background thread is active or not
*/
bool isRunning() const;
/**
* Random seed has changed
*/
void updateRandomSeed();
/**
* Updates all agent renders from corresponding
* @param sc Step count, the step count value shown in visualisation HUD
*/
void updateBuffers(const unsigned int &sc = UINT_MAX);
/**
* Singletons have init, so env props are ready to grab
*/
void registerEnvProperties();

private:
/**
Expand Down Expand Up @@ -238,6 +254,10 @@ class ModelVis {
* Pointer to the visualisation
*/
std::unique_ptr<FLAMEGPU_Visualisation> visualiser;
/**
* Only need to register env properties once
*/
bool env_registered = false;
};

} // namespace visualiser
Expand Down
291 changes: 291 additions & 0 deletions include/flamegpu/visualiser/PanelVis.h

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,7 @@ if (VISUALISATION)
${FLAMEGPU_ROOT}/include/flamegpu/visualiser/AgentStateVis.h
${FLAMEGPU_ROOT}/include/flamegpu/visualiser/StaticModelVis.h
${FLAMEGPU_ROOT}/include/flamegpu/visualiser/LineVis.h
${FLAMEGPU_ROOT}/include/flamegpu/visualiser/PanelVis.h
${FLAMEGPU_ROOT}/include/flamegpu/visualiser/color/Color.h
${FLAMEGPU_ROOT}/include/flamegpu/visualiser/color/ColorFunction.h
${FLAMEGPU_ROOT}/include/flamegpu/visualiser/color/DiscreteColor.h
Expand All @@ -315,6 +316,7 @@ if (VISUALISATION)
${FLAMEGPU_ROOT}/src/flamegpu/visualiser/AgentStateVis.cpp
${FLAMEGPU_ROOT}/src/flamegpu/visualiser/StaticModelVis.cpp
${FLAMEGPU_ROOT}/src/flamegpu/visualiser/LineVis.cpp
${FLAMEGPU_ROOT}/src/flamegpu/visualiser/PanelVis.cpp
${FLAMEGPU_ROOT}/src/flamegpu/visualiser/color/DiscreteColor.cpp
${FLAMEGPU_ROOT}/src/flamegpu/visualiser/color/StaticColor.cpp
${FLAMEGPU_ROOT}/src/flamegpu/visualiser/color/HSVInterpolation.cpp
Expand Down
13 changes: 11 additions & 2 deletions src/flamegpu/gpu/CUDASimulation.cu
Original file line number Diff line number Diff line change
Expand Up @@ -1431,9 +1431,11 @@ void CUDASimulation::applyConfig_derived() {

// Handle console_mode
#ifdef VISUALISATION
if (getSimulationConfig().console_mode) {
if (visualisation) {
if (visualisation) {
if (getSimulationConfig().console_mode) {
visualisation->deactivate();
} else {
visualisation->updateRandomSeed();
}
}
#endif
Expand Down Expand Up @@ -1545,6 +1547,13 @@ void CUDASimulation::initialiseSingletons() {
// Store the WDDM/TCC driver mode status, for timer class decisions. Result is cached in the anon namespace to avoid multiple queries
deviceUsingWDDM = util::detail::wddm::deviceIsWDDM();

#ifdef VISUALISATION
if (visualisation) {
visualisation->updateRandomSeed(); // Incase user hasn't triggered applyConfig()
visualisation->registerEnvProperties();
}
#endif

singletonsInitialised = true;
} else {
int t = -1;
Expand Down
33 changes: 31 additions & 2 deletions src/flamegpu/visualiser/ModelVis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ void ModelVis::_activate() {
if ((!visualiser || !visualiser->isRunning()) && !model.getSimulationConfig().console_mode) {
// Init visualiser
visualiser = std::make_unique<FLAMEGPU_Visualisation>(modelCfg); // Window resolution
visualiser->setRandomSeed(model.getSimulationConfig().random_seed);
for (auto &agent : agents) {
// If x and y aren't set, throw exception
if (agent.second.core_tex_buffers.find(TexBufferConfig::Position_x) == agent.second.core_tex_buffers.end() &&
Expand All @@ -78,10 +79,25 @@ void ModelVis::_activate() {
}
agent.second.initBindings(visualiser);
}
env_registered = false;
registerEnvProperties();
visualiser->start();
}
}

void ModelVis::registerEnvProperties() {
if (model.singletons && !env_registered) {
char* const host_env_origin = const_cast<char*>(static_cast<const char*>(model.singletons->environment->getHostBuffer()));
for (const auto &panel : modelCfg.panels) {
for (const auto &element : panel.second->ui_elements) {
if (auto a = dynamic_cast<EnvPropertyElement*>(element.get())) {
auto & prop = model.singletons->environment->getPropertiesMap().at(a->getName());
visualiser->registerEnvironmentProperty(a->getName(), host_env_origin + prop.offset, prop.type, prop.elements, prop.isConst);
}
}
}
env_registered = true;
}
}
void ModelVis::deactivate() {
if (visualiser && visualiser->isRunning()) {
visualiser->stop();
Expand Down Expand Up @@ -126,7 +142,12 @@ void ModelVis::updateBuffers(const unsigned int &sc) {
visualiser->releaseMutex();
}
}

void ModelVis::updateRandomSeed() {
if (visualiser) {
// Yolo thread safety, shouldn't matter if random seed is printed wrong for a single frame
visualiser->setRandomSeed(model.getSimulationConfig().random_seed);
}
}
void ModelVis::setWindowTitle(const std::string& title) {
ModelConfig::setString(&modelCfg.windowTitle, title);
}
Expand Down Expand Up @@ -209,6 +230,14 @@ LineVis ModelVis::newPolylineSketch(float r, float g, float b, float a) {
modelCfg.lines.push_back(m);
return LineVis(m, r, g, b, a);
}
PanelVis ModelVis::newUIPanel(const std::string& panel_title) {
if (modelCfg.panels.find(panel_title) != modelCfg.panels.end()) {
THROW exception::InvalidOperation("Panel with title '%s' already exists.\n", panel_title.c_str());
}
auto m = std::make_shared<PanelConfig>(panel_title);
modelCfg.panels.emplace(panel_title, m);
return PanelVis(m, model.getModelDescription().environment);
}

} // namespace visualiser
} // namespace flamegpu
36 changes: 36 additions & 0 deletions src/flamegpu/visualiser/PanelVis.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#include <utility>

#include "flamegpu/visualiser/PanelVis.h"

namespace flamegpu {
namespace visualiser {

PanelVis::PanelVis(std::shared_ptr<PanelConfig> _m, std::shared_ptr<EnvironmentDescription> _environment)
: env_properties(_environment->getPropertiesMap()) // For some reason this method returns a copy, not a reference
, m(std::move(_m)) {
// Rebuild added_properties
for (const auto &element : m->ui_elements) {
if (const EnvPropertyElement* p = dynamic_cast<EnvPropertyElement*>(element.get())) {
added_properties.insert({p->name, p->index});
}
}
}
void PanelVis::newSection(const std::string& header_text, bool begin_open) {
std::unique_ptr<PanelElement> ptr = std::make_unique<HeaderElement>(header_text, begin_open);
m->ui_elements.push_back(std::move(ptr));
}
void PanelVis::newEndSection() {
std::unique_ptr<PanelElement> ptr = std::make_unique<EndSectionElement>();
m->ui_elements.push_back(std::move(ptr));
}
void PanelVis::newStaticLabel(const std::string& label_text) {
std::unique_ptr<PanelElement> ptr = std::make_unique<LabelElement>(label_text);
m->ui_elements.push_back(std::move(ptr));
}
void PanelVis::newSeparator() {
std::unique_ptr<PanelElement> ptr = std::make_unique<SeparatorElement>();
m->ui_elements.push_back(std::move(ptr));
}

} // namespace visualiser
} // namespace flamegpu
56 changes: 55 additions & 1 deletion swig/python/flamegpu.i
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,13 @@ using namespace flamegpu; // @todo - is this required? Ideally it shouldn't be,
%template(function ## Double) classfunction<double>;
%enddef

// Array version, passing default 2nd template arg 0
%define TEMPLATE_VARIABLE_ARRAY_INSTANTIATE_FLOATS(function, classfunction)
// float and double
%template(function ## Float) classfunction<float, 0>;
%template(function ## Double) classfunction<double, 0>;
%enddef

/**
* TEMPLATE_VARIABLE_INSTANTIATE macro
* Expands for int types
Expand All @@ -119,6 +126,21 @@ using namespace flamegpu; // @todo - is this required? Ideally it shouldn't be,
%template(function ## UInt) classfunction<unsigned int>;
%enddef

// Array version, passing default 2nd template arg 0
%define TEMPLATE_VARIABLE_ARRAY_INSTANTIATE_INTS(function, classfunction)
// signed ints
%template(function ## Int16) classfunction<int16_t, 0>;
%template(function ## Int32) classfunction<int32_t, 0>;
%template(function ## Int64) classfunction<int64_t, 0>;
// unsigned ints
%template(function ## UInt16) classfunction<uint16_t, 0>;
%template(function ## UInt32) classfunction<uint32_t, 0>;
%template(function ## UInt64) classfunction<uint64_t, 0>;
// default int types
%template(function ## Int) classfunction<int, 0>;
%template(function ## UInt) classfunction<unsigned int, 0>;
%enddef

/**
* TEMPLATE_VARIABLE_INSTANTIATE macro
* Given a function name and a class::function specifier, this macro instanciates a typed version of the function for a set of basic types.
Expand All @@ -139,6 +161,19 @@ TEMPLATE_VARIABLE_INSTANTIATE_INTS(function, classfunction)
//%template(function ## Bool) classfunction<bool>;
%enddef

// Array version, passing default 2nd template arg 0
%define TEMPLATE_VARIABLE_ARRAY_INSTANTIATE(function, classfunction)
TEMPLATE_VARIABLE_ARRAY_INSTANTIATE_FLOATS(function, classfunction)
TEMPLATE_VARIABLE_ARRAY_INSTANTIATE_INTS(function, classfunction)
// char types
%template(function ## Int8) classfunction<int8_t, 0>;
%template(function ## UInt8) classfunction<uint8_t, 0>;
%template(function ## Char) classfunction<char, 0>;
%template(function ## UChar) classfunction<unsigned char, 0>;
// bool type (not supported causes error)
//%template(function ## Bool) classfunction<bool, 0>;
%enddef

/**
* Special case of the macro for message types
* This also maps ID to id_t, this should be synonymous with UInt/unsigned int
Expand All @@ -148,6 +183,12 @@ TEMPLATE_VARIABLE_INSTANTIATE(function, classfunction)
%template(function ## ID) classfunction<flamegpu::id_t>;
%enddef

// Array version, passing default 2nd template arg 0
%define TEMPLATE_VARIABLE_ARRAY_INSTANTIATE_ID(function, classfunction)
TEMPLATE_VARIABLE_ARRAY_INSTANTIATE(function, classfunction)
%template(function ## ID) classfunction<flamegpu::id_t, 0>;
%enddef


/**
* TEMPLATE_SUM_INSTANTIATE macro
Expand Down Expand Up @@ -891,6 +932,8 @@ TEMPLATE_VARIABLE_INSTANTIATE_FLOATS(logNormal, flamegpu::HostRandom::logNormal)
%ignore flamegpu::visualiser::Palette::begin;
%ignore flamegpu::visualiser::Palette::end;
%ignore flamegpu::visualiser::Palette::colors; // This is protected, i've no idea why SWIG is trying to wrap it
// Mark PanelVis as a class where assignment operator is not supported
%feature("valuewrapper") flamegpu::visualiser::PanelVis;
// Rename directives. These go before any %includes
// -----------------
// Director features. These go before the %includes.
Expand All @@ -904,6 +947,7 @@ TEMPLATE_VARIABLE_INSTANTIATE_FLOATS(logNormal, flamegpu::HostRandom::logNormal)
%include "flamegpu/visualiser/AgentStateVis.h"
%include "flamegpu/visualiser/AgentVis.h"
%include "flamegpu/visualiser/LineVis.h"
%include "flamegpu/visualiser/PanelVis.h"
%include "flamegpu/visualiser/ModelVis.h"
%include "flamegpu/visualiser/color/Color.h"
%include "flamegpu/visualiser/color/ColorFunction.h"
Expand Down Expand Up @@ -954,7 +998,17 @@ TEMPLATE_VARIABLE_INSTANTIATE_FLOATS(logNormal, flamegpu::HostRandom::logNormal)
// Manually create the two DiscretColor templates
%template(iDiscreteColor) flamegpu::visualiser::DiscreteColor<int32_t>;
%template(uDiscreteColor) flamegpu::visualiser::DiscreteColor<uint32_t>;

TEMPLATE_VARIABLE_INSTANTIATE_ID(newEnvironmentPropertySlider, flamegpu::visualiser::PanelVis::newEnvironmentPropertySlider)
TEMPLATE_VARIABLE_INSTANTIATE_ID(newEnvironmentPropertyDrag, flamegpu::visualiser::PanelVis::newEnvironmentPropertyDrag)
TEMPLATE_VARIABLE_INSTANTIATE_ID(newEnvironmentPropertyInput, flamegpu::visualiser::PanelVis::newEnvironmentPropertyInput)
TEMPLATE_VARIABLE_INSTANTIATE_INTS(newEnvironmentPropertyToggle, flamegpu::visualiser::PanelVis::newEnvironmentPropertyToggle)

TEMPLATE_VARIABLE_ARRAY_INSTANTIATE_ID(newEnvironmentPropertySlider, flamegpu::visualiser::PanelVis::newEnvironmentPropertySlider)
TEMPLATE_VARIABLE_ARRAY_INSTANTIATE_ID(newEnvironmentPropertyDrag, flamegpu::visualiser::PanelVis::newEnvironmentPropertyDrag)
TEMPLATE_VARIABLE_ARRAY_INSTANTIATE_ID(newEnvironmentPropertyInput, flamegpu::visualiser::PanelVis::newEnvironmentPropertyInput)
TEMPLATE_VARIABLE_ARRAY_INSTANTIATE_INTS(newEnvironmentPropertyToggle, flamegpu::visualiser::PanelVis::newEnvironmentPropertyToggle)


// Redefine the value to ensure it makes it into the python modules
#undef VISUALISATION
#define VISUALISATION true
Expand Down

0 comments on commit 8dabd35

Please sign in to comment.