Skip to content

Commit

Permalink
Environment directed graph visualiser support
Browse files Browse the repository at this point in the history
  • Loading branch information
Robadob committed Oct 19, 2024
1 parent 09f25de commit 564f44e
Show file tree
Hide file tree
Showing 8 changed files with 103 additions and 27 deletions.
14 changes: 14 additions & 0 deletions include/flamegpu/visualiser/FLAMEGPU_Visualisation.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,23 @@ class FLAMEGPU_Visualisation {
void requestBufferResizes(const std::string &agent_name, const std::string &state_name, const unsigned int buffLen, bool force) {
requestBufferResizes(agent_name.c_str(), state_name.c_str(), buffLen, force);
}
/**
* Main render mutex used to prevent race conditions rendering agents
*/
void lockMutex();
void releaseMutex();
/**
* Dynamic line mutex ensures graphs are fully updated before synced to render
*/
void lockDynamicLinesMutex();
void releaseDynamicLinesMutex();
void updateAgentStateBuffer(const std::string &agent_name, const std::string &state_name, const unsigned int buffLen,
const std::map<TexBufferConfig::Function, TexBufferConfig>& core_tex_buffers, const std::multimap<TexBufferConfig::Function, CustomTexBufferConfig>& tex_buffers) {
updateAgentStateBuffer(agent_name.c_str(), state_name.c_str(), buffLen, core_tex_buffers, tex_buffers);
}
void updateDynamicLine(const std::string &graph_name) {
updateDynamicLine(graph_name.c_str());
}
/**
* Provide an environment property, so it can be displayed
*/
Expand Down Expand Up @@ -81,8 +92,11 @@ class FLAMEGPU_Visualisation {
void requestBufferResizes(const char *agent_name, const char *state_name, const unsigned int buffLen, bool force);
void updateAgentStateBuffer(const char *agent_name, const char *state_name, const unsigned int buffLen,
const std::map<TexBufferConfig::Function, TexBufferConfig>& core_tex_buffers, const std::multimap<TexBufferConfig::Function, CustomTexBufferConfig>& tex_buffers);
void updateDynamicLine(const char* graph_name);

Visualiser *vis = nullptr;
LockHolder *lock = nullptr;
LockHolder *dynamic_lines_lock = nullptr;
/**
* If non-0, limits the number of simulation steps per second, by blocking the return of releaseMutex
* Blocking whilst the mutex was held, would block visualisation updates as that also uses the mutex
Expand Down
4 changes: 4 additions & 0 deletions include/flamegpu/visualiser/config/ModelConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,10 @@ struct ModelConfig {
* Store of user defined line renderings
*/
std::list<std::shared_ptr<LineConfig>> lines;
/**
* Store of user defined graph renderings
*/
std::map<std::string, std::shared_ptr<LineConfig>> dynamic_lines;
/**
* Store of user defined UI panels
*/
Expand Down
3 changes: 3 additions & 0 deletions src/flamegpu/visualiser/Draw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ void Draw::save(bool replaceExisting) {
requiredLength += tState.count;
stateDirectory.insert({ tName, std::move(tState) });
}
bool Draw::has(const std::string &name) {
return stateDirectory.find(name) != stateDirectory.end();
}
Draw::State Draw::_save(bool isTemporary) {
if (tType == Type::Lines && tVertices.size() % 2 != 0) {
THROW VisAssert("Draw::_save(): Line drawings require an even number of vertices.\n");
Expand Down
4 changes: 4 additions & 0 deletions src/flamegpu/visualiser/Draw.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ class Draw : Renderable {
* @throw Throws a runtime exception if called whilst the draw state is not open
*/
void save(bool replaceExisting = false);
/**
* Check whether a drawing with the name exists.
**/
bool has(const std::string &name);
/**
* Renders a saved drawstate
* @param name The name of the draw state to render
Expand Down
14 changes: 14 additions & 0 deletions src/flamegpu/visualiser/FLAMEGPU_Visualisation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ FLAMEGPU_Visualisation::~FLAMEGPU_Visualisation() {
delete vis;
if (lock)
delete lock;
if (dynamic_lines_lock)
delete dynamic_lines_lock;
}
void FLAMEGPU_Visualisation::addAgentState(const char *agent_name, const char *state_name, const AgentStateConfig &vc,
const std::map<TexBufferConfig::Function, TexBufferConfig>& core_tex_buffers, const std::multimap<TexBufferConfig::Function, CustomTexBufferConfig>& tex_buffers) {
Expand All @@ -40,6 +42,9 @@ void FLAMEGPU_Visualisation::updateAgentStateBuffer(const char *agent_name, cons
void FLAMEGPU_Visualisation::registerEnvironmentProperty(const std::string& property_name, void* ptr, const std::type_index type, const unsigned int elements, const bool is_const) {
vis->registerEnvironmentProperty(property_name, ptr, type, elements, is_const);
}
void FLAMEGPU_Visualisation::updateDynamicLine(const char *graph_name) {
vis->updateDynamicLine(graph_name);
}
void FLAMEGPU_Visualisation::setStepCount(const unsigned int stepCount) {
vis->setStepCount(stepCount);
}
Expand Down Expand Up @@ -89,6 +94,15 @@ void FLAMEGPU_Visualisation::releaseMutex() {
}
}
}
void FLAMEGPU_Visualisation::lockDynamicLinesMutex() {
dynamic_lines_lock = new LockHolder(vis->getDynamicLineMutex());
}
void FLAMEGPU_Visualisation::releaseDynamicLinesMutex() {
if (dynamic_lines_lock) {
delete dynamic_lines_lock;
dynamic_lines_lock = nullptr;
}
}

} // namespace visualiser
} // namespace flamegpu
73 changes: 48 additions & 25 deletions src/flamegpu/visualiser/Visualiser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,25 @@ Visualiser::RenderInfo::RenderInfo(const AgentStateConfig& vc,
entity->loadKeyFrameModel(vc.model_pathB);
}
}

void addLine(std::shared_ptr<Draw> &lines, const std::shared_ptr<LineConfig> &line, const std::string &name, bool replace) {
// Check it's valid
if (line->lineType == LineConfig::Type::Polyline) {
if (line->vertices.size() < 6 || line->vertices.size() % 3 != 0 || line->colors.size() % 4 != 0 || (line->colors.size() / 4) * 3 != line->vertices.size()) {
THROW SketchError("Polyline sketch contains invalid number of vertices (%d/3) or colours (%d/4).\n", line->vertices.size(), line->colors.size());
}
} else if (line->lineType == LineConfig::Type::Lines) {
if (line->vertices.size() < 6 || line->vertices.size() % 6 != 0 || line->colors.size() % 4 != 0 || (line->colors.size() / 4) * 3 != line->vertices.size()) {
THROW SketchError("Lines sketch contains invalid number of vertices (%d/3) or colours (%d/4).\n", line->vertices.size(), line->colors.size());
}
}
// Convert to Draw
lines->begin(line->lineType == LineConfig::Type::Polyline ? Draw::Type::Polyline : Draw::Type::Lines, name);
for (size_t i = 0; i < line->vertices.size() / 3; ++i) {
lines->color(*reinterpret_cast<const glm::vec4*>(&line->colors[i * 4]));
lines->vertex(*reinterpret_cast<const glm::vec3*>(&line->vertices[i * 3]));
}
lines->save(replace);
}
Visualiser::Visualiser(const ModelConfig& modelcfg)
: hud(std::make_shared<HUD>(modelcfg.windowDimensions[0], modelcfg.windowDimensions[1]))
, camera(std::make_shared<NoClipCamera>(*reinterpret_cast<const glm::vec3*>(&modelcfg.cameraLocation[0]), *reinterpret_cast<const glm::vec3*>(&modelcfg.cameraTarget[0])))
Expand Down Expand Up @@ -149,9 +167,12 @@ Visualiser::Visualiser(const ModelConfig& modelcfg)
imguiPanel = std::make_shared<ImGuiPanel>(modelcfg.panels, *this);
hud->add(imguiPanel, HUD::AnchorV::North, HUD::AnchorH::West, glm::ivec2(0, 0), INT_MAX-2);
}
lines = std::make_shared<Draw>();
lines->setViewMatPtr(camera->getViewMatPtr());
lines->setProjectionMatPtr(&this->projMat);
lines_static = std::make_shared<Draw>();
lines_static->setViewMatPtr(camera->getViewMatPtr());
lines_static->setProjectionMatPtr(&this->projMat);
lines_dynamic = std::make_shared<Draw>();
lines_dynamic->setViewMatPtr(camera->getViewMatPtr());
lines_dynamic->setProjectionMatPtr(&this->projMat);
// Process static models
for (auto &sm : modelcfg.staticModels) {
std::shared_ptr<Entity> entity;
Expand Down Expand Up @@ -186,23 +207,7 @@ Visualiser::Visualiser(const ModelConfig& modelcfg)
}
// Process lines
for (auto &line : modelcfg.lines) {
// Check it's valid
if (line->lineType == LineConfig::Type::Polyline) {
if (line->vertices.size() < 6 || line->vertices.size() % 3 != 0 || line->colors.size() % 4 != 0 || (line->colors.size() / 4) * 3 != line->vertices.size()) {
THROW SketchError("Polyline sketch contains invalid number of vertices (%d/3) or colours (%d/4).\n", line->vertices.size(), line->colors.size());
}
} else if (line->lineType == LineConfig::Type::Lines) {
if (line->vertices.size() < 6 || line->vertices.size() % 6 != 0 || line->colors.size() % 4 != 0 || (line->colors.size() / 4) * 3 != line->vertices.size()) {
THROW SketchError("Lines sketch contains invalid number of vertices (%d/3) or colours (%d/4).\n", line->vertices.size(), line->colors.size());
}
}
// Convert to Draw
lines->begin(line->lineType == LineConfig::Type::Polyline ? Draw::Type::Polyline : Draw::Type::Lines, std::to_string(totalLines++));
for (size_t i = 0; i < line->vertices.size() / 3; ++i) {
lines->color(*reinterpret_cast<const glm::vec4*>(&line->colors[i * 4]));
lines->vertex(*reinterpret_cast<const glm::vec3*>(&line->vertices[i * 3]));
}
lines->save();
addLine(lines_static, line, std::to_string(totalLines++), false);
}
// Default lighting, single point light attached to camera
// Maybe in future let user specify lights instead of this
Expand Down Expand Up @@ -445,12 +450,23 @@ void Visualiser::render() {
hud->remove(splashScreen);
splashScreen.reset();
}
// Update dynamic lines if they have changed
{
auto lock = std::lock_guard<std::mutex>(lines_dynamic_mutex);
for (auto &name : lines_dynamic_updates)
addLine(lines_dynamic, modelConfig.dynamic_lines.at(name), name, true);
lines_dynamic_updates.clear();
}
// Render lines last, as they may contain alpha
if (renderLines) {
GL_CALL(glEnable(GL_BLEND));
GL_CALL(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
for (unsigned int i = 0; i < totalLines; ++i)
lines->render(std::to_string(i));
lines_static->render(std::to_string(i));
for (const auto &[name, _] : modelConfig.dynamic_lines)
// Dynamic lines may begin uninitialised
if (lines_dynamic->has(name))
lines_dynamic->render(name);
GL_CALL(glDisable(GL_BLEND));
}
GL_CALL(glViewport(0, 0, windowDims.x, windowDims.y));
Expand Down Expand Up @@ -804,7 +820,8 @@ void Visualiser::deallocateGLObjects() {
for (auto &as : agentStates) {
as.second.entity.reset();
}
this->lines.reset();
this->lines_static.reset();
this->lines_dynamic.reset();
render_buffer.reset();
screenshot_buffer.reset();

Expand Down Expand Up @@ -896,8 +913,10 @@ void Visualiser::handleKeypress(SDL_Keycode keycode, int /*x*/, int /*y*/) {
break;
case SDLK_F5:
// Reload all shaders
if (this->lines)
this->lines->reload();
if (this->lines_static)
this->lines_static->reload();
if (this->lines_dynamic)
this->lines_dynamic->reload();
for (auto& as : this->agentStates)
as.second.entity->reload();
for (auto& sm : this->staticModels)
Expand Down Expand Up @@ -1241,6 +1260,10 @@ void Visualiser::setWindowIcon() {
if (surface)
SDL_SetWindowIcon(window, surface.get());
}
void Visualiser::updateDynamicLine(const std::string& name) {
// Store a list of dynamic line updates, as they must occur in render thread
lines_dynamic_updates.insert(name);
}

} // namespace visualiser
} // namespace flamegpu
17 changes: 15 additions & 2 deletions src/flamegpu/visualiser/Visualiser.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <unordered_map>
#include <utility>
#include <map>
#include <set>
#include <cstdint>
#define GLM_FORCE_NO_CTOR_INIT
#include <glm/glm.hpp>
Expand Down Expand Up @@ -67,7 +68,7 @@ class Visualiser : public ViewportExt {

public:
explicit Visualiser(const ModelConfig &modelcfg);
~Visualiser();
~Visualiser() override;
/**
* Starts the render loop running
*/
Expand Down Expand Up @@ -128,6 +129,11 @@ class Visualiser : public ViewportExt {
* Provide the env_cache ptr for the specified environment property, for visualisation
*/
void registerEnvironmentProperty(const std::string& property_name, void* ptr, std::type_index type, unsigned int elements, bool is_const);
/**
* Update the dynamic_lines with the corresponding name
* @note getDynamicLineMutex() should be locked before this is called
*/
void updateDynamicLine(const std::string &name);

private:
void run();
Expand Down Expand Up @@ -242,6 +248,11 @@ class Visualiser : public ViewportExt {
* @see updateAgentStateBuffer(const std::string &, const std::string &, const unsigned int, float *, float *, float *, float *)
*/
std::mutex &getRenderBufferMutex() { return render_buffer_mutex; }
/**
* This must be locked when changes to dynamic_lines are performed
* e.g. during graph updates
*/
std::mutex &getDynamicLineMutex() { return lines_dynamic_mutex; }
/**
* Sets the value to be rendered to the HUD step counter (if enabled)
* @param stepCount The step value to be displayed
Expand Down Expand Up @@ -358,7 +369,9 @@ class Visualiser : public ViewportExt {
/**
* User defined lines to be rendered
*/
std::shared_ptr<Draw> lines;
std::shared_ptr<Draw> lines_static, lines_dynamic;
std::set<std::string> lines_dynamic_updates;
std::mutex lines_dynamic_mutex;
/**
* Provides a simple default lighting configuration located at the camera using the old fixed function pipeline methods
*/
Expand Down
1 change: 1 addition & 0 deletions src/flamegpu/visualiser/config/ModelConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ ModelConfig &ModelConfig::operator=(const ModelConfig &other) {
isPython = other.isPython;
isOrtho = other.isOrtho;
orthoZoom = other.orthoZoom;
dynamic_lines = other.dynamic_lines; // Here because they are probably empty at construction, so addLine() can't be used
// staticModels
// lines
// panels
Expand Down

0 comments on commit 564f44e

Please sign in to comment.