.. _program_listing_file_src_flamegpu_visualiser_ModelVis.cpp: Program Listing for File ModelVis.cpp ===================================== |exhale_lsh| :ref:`Return to documentation for file ` (``src/flamegpu/visualiser/ModelVis.cpp``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp // @todo - ifdef visualisation #include "flamegpu/visualiser/ModelVis.h" #include #include #include "flamegpu/simulation/CUDASimulation.h" #include "flamegpu/model/AgentData.h" #include "flamegpu/visualiser/FLAMEGPU_Visualisation.h" namespace flamegpu { namespace visualiser { ModelVisData::ModelVisData(const flamegpu::CUDASimulation &_model) : modelCfg(_model.getModelDescription().name.c_str()) , autoPalette(std::make_shared(Stock::Palettes::DARK2)) , model(_model) , modelData(_model.getModelDescription()) { } void ModelVisData::registerEnvProperties() { if (model.singletons && !env_registered) { char* const host_env_origin = const_cast(static_cast(model.singletons->environment->getHostBuffer())); for (const auto &panel : modelCfg.panels) { for (const auto &element : panel.second->ui_elements) { if (auto a = dynamic_cast(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 ModelVisData::updateBuffers(const unsigned int& sc) { if (visualiser) { bool has_agents = false; for (auto& a : agents) { has_agents = a.second->requestBufferResizes(visualiser, sc == 0 || sc == UINT_MAX) || has_agents; } // Block the sim when we first get agents, until vis has resized buffers, incase vis is being slow to init if (has_agents && (sc == 0 || sc == UINT_MAX)) { while (!visualiser->buffersReady()) { // Do nothing, just spin until ready std::this_thread::yield(); } } // wait for lock data->visualiser (its probably executing render loop in separate thread) This might not be 100% safe. RequestResize might need extra thread safety. visualiser->lockMutex(); // Update step count if (sc != UINT_MAX) { visualiser->setStepCount(sc); } for (auto& a : agents) { a.second->updateBuffers(visualiser); } visualiser->releaseMutex(); // Block the sim again, until vis is fully ready if (has_agents && (sc == 0 || sc == UINT_MAX)) { while (!visualiser->isReady()) { // Do nothing, just spin until ready std::this_thread::yield(); } } } } void ModelVisData::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); } } ModelVis::ModelVis(std::shared_ptr _data, bool _isSWIG) : isSWIG(_isSWIG) , data(std::move(_data)) { } void ModelVis::setAutoPalette(const Palette& palette) { data->autoPalette = std::make_shared(palette); } void ModelVis::clearAutoPalette() { data->autoPalette = nullptr; } AgentVis ModelVis::addAgent(const std::string &agent_name) { // If agent exists if (data->modelData.agents.find(agent_name) != data->modelData.agents.end()) { // If agent is not already in vis map auto visAgent = data->agents.find(agent_name); if (visAgent == data->agents.end()) { // Create new vis agent return AgentVis(data->agents.emplace(agent_name, std::make_shared(data->model.getCUDAAgent(agent_name), data->autoPalette)).first->second); } return AgentVis(visAgent->second); } THROW exception::InvalidAgentName("Agent name '%s' was not found within the model description hierarchy, " "in ModelVis::addAgent()\n", agent_name.c_str()); } AgentVis ModelVis::Agent(const std::string &agent_name) { // If agent exists if (data->modelData.agents.find(agent_name) != data->modelData.agents.end()) { // If agent is not already in vis map auto visAgent = data->agents.find(agent_name); if (visAgent != data->agents.end()) { // Create new vis agent return AgentVis(visAgent->second); } THROW exception::InvalidAgentName("Agent name '%s' has not been marked for visualisation, ModelVis::addAgent() must be called first, " "in ModelVis::Agent()\n", agent_name.c_str()); } THROW exception::InvalidAgentName("Agent name '%s' was not found within the model description hierarchy, " "in ModelVis::Agent()\n", agent_name.c_str()); } // Below methods are related to executing the visualiser void ModelVis::activate() { // Only execute if background thread is not active if ((!data->visualiser || !data->visualiser->isRunning()) && !data->model.getSimulationConfig().console_mode) { // Send Python status to the visualiser data->modelCfg.isPython = isSWIG; // Init visualiser data->visualiser = std::make_unique(data->modelCfg); // Window resolution data->visualiser->setRandomSeed(data->model.getSimulationConfig().random_seed); for (auto &agent : data->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() && agent.second->core_tex_buffers.find(TexBufferConfig::Position_y) == agent.second->core_tex_buffers.end() && agent.second->core_tex_buffers.find(TexBufferConfig::Position_z) == agent.second->core_tex_buffers.end() && agent.second->core_tex_buffers.find(TexBufferConfig::Position_xy) == agent.second->core_tex_buffers.end() && agent.second->core_tex_buffers.find(TexBufferConfig::Position_xyz) == agent.second->core_tex_buffers.end()) { THROW exception::VisualisationException("Agent '%s' has not had x, y or z variables set, agent requires location to render, " "in ModelVis::activate()\n", agent.second->agentData->name.c_str()); } agent.second->initBindings(data->visualiser); } data->env_registered = false; data->registerEnvProperties(); data->visualiser->start(); } } void ModelVis::deactivate() { if (data->visualiser && data->visualiser->isRunning()) { data->visualiser->stop(); join(); data->visualiser.reset(); } } void ModelVis::join() { if (data->visualiser) { data->visualiser->join(); data->visualiser.reset(); } } bool ModelVis::isRunning() const { return data->visualiser ? data->visualiser->isRunning() : false; } void ModelVis::setWindowTitle(const std::string& title) { ModelConfig::setString(&data->modelCfg.windowTitle, title); } void ModelVis::setWindowDimensions(const unsigned int& width, const unsigned int& height) { data->modelCfg.windowDimensions[0] = width; data->modelCfg.windowDimensions[1] = height; } void ModelVis::setClearColor(const float& red, const float& green, const float& blue) { data->modelCfg.clearColor[0] = red; data->modelCfg.clearColor[1] = green; data->modelCfg.clearColor[2] = blue; } void ModelVis::setFPSVisible(const bool& showFPS) { data->modelCfg.fpsVisible = showFPS; } void ModelVis::setFPSColor(const float& red, const float& green, const float& blue) { data->modelCfg.fpsColor[0] = red; data->modelCfg.fpsColor[1] = green; data->modelCfg.fpsColor[2] = blue; } void ModelVis::setInitialCameraLocation(const float &x, const float &y, const float &z) { data->modelCfg.cameraLocation[0] = x; data->modelCfg.cameraLocation[1] = y; data->modelCfg.cameraLocation[2] = z; } void ModelVis::setInitialCameraTarget(const float &x, const float &y, const float &z) { data->modelCfg.cameraTarget[0] = x; data->modelCfg.cameraTarget[1] = y; data->modelCfg.cameraTarget[2] = z; } void ModelVis::setCameraSpeed(const float &speed, const float &shiftMultiplier) { data->modelCfg.cameraSpeed[0] = speed; data->modelCfg.cameraSpeed[1] = shiftMultiplier; } void ModelVis::setViewClips(const float &nearClip, const float &farClip) { data->modelCfg.nearFarClip[0] = nearClip; data->modelCfg.nearFarClip[1] = farClip; } void ModelVis::setOrthographic(const bool& isOrtho) { data->modelCfg.isOrtho = isOrtho; } void ModelVis::setOrthographicZoomModifier(const float& zoomMod) { data->modelCfg.orthoZoom = zoomMod; } void ModelVis::setStepVisible(const bool& showStep) { data->modelCfg.stepVisible = showStep; } void ModelVis::setSimulationSpeed(const unsigned int& _stepsPerSecond) { data->modelCfg.stepsPerSecond = _stepsPerSecond; } void ModelVis::setBeginPaused(const bool& beginPaused) { data->modelCfg.beginPaused = beginPaused; } StaticModelVis ModelVis::newStaticModel(const std::string &modelPath, const std::string &texturePath) { // Create ModelConfig::StaticModel auto m = std::make_shared(); // set modelPath, texturePath m->path = modelPath; m->texture = texturePath; // add to ModelConfig.staticModels data->modelCfg.staticModels.push_back(m); // Create return type return StaticModelVis(data->modelCfg.staticModels.back()); } LineVis ModelVis::newLineSketch(float r, float g, float b, float a) { auto m = std::make_shared(LineConfig::Type::Lines); data->modelCfg.lines.push_back(m); return LineVis(m, r, g, b, a); } LineVis ModelVis::newPolylineSketch(float r, float g, float b, float a) { auto m = std::make_shared(LineConfig::Type::Polyline); data->modelCfg.lines.push_back(m); return LineVis(m, r, g, b, a); } PanelVis ModelVis::newUIPanel(const std::string& panel_title) { if (data->modelCfg.panels.find(panel_title) != data->modelCfg.panels.end()) { THROW exception::InvalidOperation("Panel with title '%s' already exists.\n", panel_title.c_str()); } auto m = std::make_shared(panel_title); data->modelCfg.panels.emplace(panel_title, m); return PanelVis(m, data->model.getModelDescription().environment); } } // namespace visualiser } // namespace flamegpu