Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MegaMol Project Concept #978

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions core/include/mmcore/MegaMolGraph.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
#include "FrontendResource.h"
#include "FrontendResourcesLookup.h"
#include "ImagePresentationEntryPoints.h"
#include "MegaMolProject.h"
#include "ModuleGraphSubscription.h"

#include "mmcore/MegaMolGraphTypes.h"
#include "mmcore/MegaMolGraph_Convenience.h"
#include "mmcore/RootModuleNamespace.h"
Expand Down Expand Up @@ -136,6 +138,8 @@ class MegaMolGraph {
std::list<Module::ptr_type> graph_entry_points;
megamol::frontend_resources::ImagePresentationEntryPoints* m_image_presentation = nullptr;

megamol::frontend_resources::MegaMolProject* m_current_project_path = nullptr;

MegaMolGraph_Convenience convenience_functions;

frontend_resources::MegaMolGraph_SubscriptionRegistry graph_subscribers;
Expand Down
53 changes: 48 additions & 5 deletions core/include/mmcore/param/FilePathParam.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ class FilePathParam : public AbstractParam {
* @param flags The flags for the parameter
* @param exts The required file extensions for the parameter
*/
FilePathParam(const std::filesystem::path& initVal, Flags_t flags, const Extensions_t& exts,
const std::filesystem::path& project_directory);
FilePathParam(const std::filesystem::path& initVal, Flags_t flags = Flag_File, const Extensions_t& exts = {});
FilePathParam(const std::string& initVal, Flags_t flags = Flag_File, const Extensions_t& exts = {});
FilePathParam(const char* initVal, Flags_t flags = Flag_File, const Extensions_t& exts = {});
Expand Down Expand Up @@ -83,7 +85,7 @@ class FilePathParam : public AbstractParam {
* @return The value of the parameter
*/
std::filesystem::path Value() const {
return this->value;
return this->GetAbsolutePathValue(this->value);
}

/**
Expand All @@ -92,7 +94,7 @@ class FilePathParam : public AbstractParam {
* @return The value of the parameter as string.
*/
std::string ValueString() const override {
return this->value.generic_u8string();
return this->GetRelativePathValueString();
}

/**
Expand All @@ -113,25 +115,66 @@ class FilePathParam : public AbstractParam {
return this->extensions;
}

inline std::filesystem::path GetProjectDirectory() const {
return this->project_directory;
}

/**
* Function checks if path is valid for given flags
*
* @return Return 0 for success, flags with failed check otherwise.
*/
static Flags_t ValidatePath(const std::filesystem::path& p, const Extensions_t&, Flags_t f);
static Flags_t ValidatePath(
const std::filesystem::path& p, const Extensions_t&, Flags_t f, const std::filesystem::path& project_dir = "");


/**
* Adds absolute path to current project directory to the file path parameter.
* This way file paths relative to the project directory can be resolved.
*/
void SetProjectDirectory(const std::filesystem::path& p);

/**
* Returns either the current path value if it is an absolute path,
* or concatinates project directory path and current path value if it is a relative path.
*/
std::filesystem::path GetAbsolutePathValue(const std::filesystem::path& p) const;

/**
* Returns the current raw path value, which might be an absolute path in the file system
* or a path relative to some project directory
*/
std::filesystem::path GetRelativePathValue() const {
return this->value;
}

/**
* Returns string of the current raw path value, which might be an absolute path in the file system
* or a path relative to some project directory.
* This is used by the serialization function of the MegaMolGraph to preserve relative paths of FilePathParams.
*/
std::string GetRelativePathValueString() const {
return GetRelativePathValue().generic_u8string();
}

private:
/** The flags of the parameter */
const Flags_t flags;
Flags_t flags;

/** The accepted file extension(s).
* Leave empty to allow all extensions.
* Only considered when Flag_RestrictExtension is set.
*/
const Extensions_t extensions;
Extensions_t extensions;

/** The file or directory path */
std::filesystem::path value;

/**
* Absolute path to project directory. If empty, no project path available.
* This path is absolute per guarantee of the frontend
*/
std::filesystem::path project_directory;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might also be just a "prefix_path"

};


Expand Down
22 changes: 22 additions & 0 deletions core/src/MegaMolGraph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "ResourceRequest.h"
#include "mmcore/AbstractSlot.h"
#include "mmcore/param/ButtonParam.h"
#include "mmcore/param/FilePathParam.h"
#include "mmcore/utility/String.h"
#include "mmcore/utility/log/Log.h"
#include "mmcore/view/AbstractView_EventConsumption.h"
Expand Down Expand Up @@ -476,6 +477,7 @@ bool megamol::core::MegaMolGraph::AddFrontendResources(

auto [success, graph_resources] = provided_resources_lookup.get_requested_resources({
"ImagePresentationEntryPoints",
"MegaMolProject",
});

if (!success)
Expand All @@ -484,6 +486,9 @@ bool megamol::core::MegaMolGraph::AddFrontendResources(
m_image_presentation = &const_cast<megamol::frontend_resources::ImagePresentationEntryPoints&>(
graph_resources[0].getResource<megamol::frontend_resources::ImagePresentationEntryPoints>());

m_current_project_path = &const_cast<megamol::frontend_resources::MegaMolProject&>(
graph_resources[1].getResource<megamol::frontend_resources::MegaMolProject>());

return true;
}

Expand Down Expand Up @@ -598,6 +603,23 @@ bool megamol::core::MegaMolGraph::add_module(ModuleInstantiationRequest_t const&

module_ptr->setParent(this->dummy_namespace);

// we want to enable filename parameters to open file paths relative to the current .lua project file
// for this to work we need to manually find FilePathParam parameters in created modules and tell them
// the current project directory path
if (m_current_project_path->attributes.has_value()) {
auto project_directory_path = m_current_project_path->attributes.value().project_directory;

for (auto child = module_ptr->ChildList_Begin(); child != module_ptr->ChildList_End(); ++child) {
auto ps = dynamic_cast<param::ParamSlot*>((*child).get());
if (ps != nullptr) {
auto p = ps->Param<param::FilePathParam>();
if (p != nullptr) {
p->SetProjectDirectory(project_directory_path);
}
}
}
}

const auto create_module = [module_description, module_ptr](auto& module_lifetime_dependencies) {
const bool init_ok =
module_ptr->Create(module_lifetime_dependencies); // seems like Create() internally checks IsAvailable()
Expand Down
10 changes: 8 additions & 2 deletions core/src/MegaMolGraph_Convenience.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,16 +74,22 @@ std::string megamol::core::MegaMolGraph_Convenience::SerializeCalls() const {
std::string megamol::core::MegaMolGraph_Convenience::SerializeModuleParameters(std::string const& module_name) const {
std::string serParams;

auto parameter_serialization = [](std::string const& name, std::string const& value) {
return "mmSetParamValue(\"" + name + "\",[=[" + value + "]=])\n";
};

for (auto& paramSlot : get(m_graph_ptr).EnumerateModuleParameterSlots(module_name)) {
// it seems serialiing button params is illegal
// it seems serializing button params is illegal
if (auto* p_ptr = paramSlot->template Param<core::param::ButtonParam>()) {
continue;
}

auto name = std::string{paramSlot->FullName()};
// as FullName() prepends :: to module names, normalize multiple leading :: in parameter name path
name = "::" + name.substr(name.find_first_not_of(':'));

auto value = paramSlot->Parameter()->ValueString();
serParams.append("mmSetParamValue(\"" + name + "\",[=[" + value + "]=])\n");
serParams.append(parameter_serialization(name, value));
}

return serParams + '\n';
Expand Down
71 changes: 62 additions & 9 deletions core/src/param/FilePathParam.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@

using namespace megamol::core::param;

FilePathParam::FilePathParam(const std::filesystem::path& initVal, Flags_t flags, const Extensions_t& exts,
const std::filesystem::path& project_directory)
: FilePathParam(initVal, flags, exts) {
this->SetProjectDirectory(project_directory);
}

FilePathParam::FilePathParam(const std::filesystem::path& initVal, Flags_t flags, const Extensions_t& exts)
: AbstractParam()
Expand Down Expand Up @@ -42,12 +47,18 @@ bool FilePathParam::ParseValue(std::string const& v) {

void FilePathParam::SetValue(const std::filesystem::path& v, bool setDirty) {

try {
auto tmp_val_str = v.generic_u8string();
const auto normalize_path = [](std::filesystem::path const& path) -> std::filesystem::path {
auto tmp_val_str = path.generic_u8string();
std::replace(tmp_val_str.begin(), tmp_val_str.end(), '\\', '/');
auto new_value = std::filesystem::path(tmp_val_str);
return std::filesystem::path{tmp_val_str};
};

try {
auto new_value = normalize_path(v);

if (this->value != new_value) {
auto error_flags = FilePathParam::ValidatePath(new_value, this->extensions, this->flags);
auto absolute_new_value = GetAbsolutePathValue(new_value);
auto error_flags = FilePathParam::ValidatePath(absolute_new_value, this->extensions, this->flags);

if (error_flags & Flag_File) {
megamol::core::utility::log::Log::DefaultLog.WriteWarn(
Expand All @@ -73,6 +84,29 @@ void FilePathParam::SetValue(const std::filesystem::path& v, bool setDirty) {
new_value.generic_u8string().c_str(), log_exts.c_str());
}
if (error_flags == 0) {
if (new_value.is_absolute() && !this->project_directory.empty()) {
// is new path in project directory?
// then represent as relative path

// walk along directory path where project dir and new file path are the same
auto val_it = new_value.begin();
auto proj_it = project_directory.begin();
while (*val_it == *proj_it) {
val_it++;
proj_it++;
}
// if we walked the project directory till the end, new file is inside that directory
if (*proj_it == *project_directory.end()) {
// collect the tail of new file path and use it as new value
std::filesystem::path project_relative_path;
while (val_it != new_value.end()) {
project_relative_path = project_relative_path / *val_it;
val_it++;
}
new_value = normalize_path(project_relative_path);
}
}

this->value = new_value;
this->indicateParamChange();
if (setDirty)
Expand All @@ -98,25 +132,31 @@ void megamol::core::param::FilePathParam::SetValue(const char* v, bool setDirty)
}


FilePathParam::Flags_t FilePathParam::ValidatePath(const std::filesystem::path& p, const Extensions_t& e, Flags_t f) {
FilePathParam::Flags_t FilePathParam::ValidatePath(
const std::filesystem::path& p, const Extensions_t& e, Flags_t f, const std::filesystem::path& project_dir) {

std::filesystem::path path = p;
if (!project_dir.empty() && project_dir.is_absolute() && p.is_relative()) {
path = project_dir / p;
}

try {
FilePathParam::Flags_t retval = 0;
if ((f & FilePathParam::Flag_Any) != FilePathParam::Flag_Any) {
if ((f & FilePathParam::Flag_File) && std::filesystem::is_directory(p)) {
if ((f & FilePathParam::Flag_File) && std::filesystem::is_directory(path)) {
retval |= FilePathParam::Flag_File;
}
if ((f & FilePathParam::Flag_Directory) && std::filesystem::is_regular_file(p)) {
if ((f & FilePathParam::Flag_Directory) && std::filesystem::is_regular_file(path)) {
retval |= FilePathParam::Flag_Directory;
}
}
if (!(f & Internal_NoExistenceCheck) && !std::filesystem::exists(p)) {
if (!(f & Internal_NoExistenceCheck) && !std::filesystem::exists(path)) {
retval |= FilePathParam::Internal_NoExistenceCheck;
}
if (f & FilePathParam::Internal_RestrictExtension) {
bool valid_ext = false;
for (auto& ext : e) {
if (p.extension().generic_u8string() == std::string("." + ext)) {
if (path.extension().generic_u8string() == std::string("." + ext)) {
valid_ext = true;
}
}
Expand All @@ -131,3 +171,16 @@ FilePathParam::Flags_t FilePathParam::ValidatePath(const std::filesystem::path&
return 0;
}
}

void FilePathParam::SetProjectDirectory(const std::filesystem::path& p) {
assert(p.is_absolute());

this->project_directory = p;
}

std::filesystem::path FilePathParam::GetAbsolutePathValue(const std::filesystem::path& p) const {
if (p.empty() || p.is_absolute())
return p;

return this->project_directory / p;
}
1 change: 1 addition & 0 deletions frontend/main/src/CLIConfigParsing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ std::pair<RuntimeConfig, GlobalValueStore> megamol::frontend::handle_cli_and_con
RuntimeConfig config;

config.megamol_executable_directory = getExecutableDirectory().u8string();
config.megamol_current_working_directory = std::filesystem::current_path().u8string();

// config files are already checked to exist in file system
config.configuration_files = extract_config_file_paths(argc, argv);
Expand Down
41 changes: 41 additions & 0 deletions frontend/resources/include/MegaMolProject.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* MegaMolProject.h
*
* Copyright (C) 2022 by VISUS (Universitaet Stuttgart).
* Alle Rechte vorbehalten.
*/

#pragma once

#include <cassert>
#include <filesystem>
#include <optional>
#include <string>

namespace megamol {
namespace frontend_resources {

struct MegaMolProject {
using path = std::filesystem::path;

struct ProjectAttributes {
// example: C:/megamol/project.lua
std::string project_name = ""; // name of project in some way, either "projcet.lua" or "project" or "something"
path project_file; // C:/megamol/project.lua
path project_directory; // C:/megamol/
};

std::optional<ProjectAttributes> attributes = std::nullopt;

void setProjectFile(path const& file) {
assert(file.is_absolute());
ProjectAttributes a;
a.project_file = file;
a.project_directory = path{file}.remove_filename(); // leaves trailing '/'
a.project_name = file.filename().stem().string();

attributes = a;
}
};
} /* end namespace frontend_resources */
} /* end namespace megamol */
3 changes: 2 additions & 1 deletion frontend/resources/include/RuntimeConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ struct RuntimeConfig {
std::vector<std::string> configuration_file_contents = {};
std::vector<StringPair> cli_options_from_configs = {}; // mmSetCliOption - set config/option values accepted in CLI
std::vector<std::string> configuration_file_contents_as_cli = {};
Path megamol_executable_directory = ""; // mmGetMegaMolExecutableDirectory
Path megamol_executable_directory = ""; // mmGetMegaMolExecutableDirectory
Path megamol_current_working_directory = "";
Path application_directory = ""; // mmSetAppDir
std::vector<Path> resource_directories = {}; // mmAddResourceDir
std::vector<Path> shader_directories = {}; // mmAddShaderDir
Expand Down
Loading