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

Complete refactor of options API #1471

Merged
merged 83 commits into from
Aug 20, 2024
Merged

Conversation

mwestphal
Copy link
Contributor

@mwestphal mwestphal commented Jun 17, 2024

Complete refactor of options API based on generated struct and methods from a options.json file.

  • Add struct and methods generation code in f3dOptions.cmake
  • Add generation in library/CMakeLists.txt
  • Add options.json containing all options
  • Add new API in options.h and implement it in options.cxx, remove old API
  • Adapt code in library and in app for the new API
  • Add options testing
  • Added a quick doc about the three APIs and in header docs
  • Add a C++11 compatibility
  • Added examples
  • Improve clang-format CI and update files accordingly

Will be done in other PRs:

Copy link

You are modifying libf3d public API! ⚠️Please update bindings accordingly⚠️!
You can find them in their respective directories: python, java, webassembly.

Copy link

codecov bot commented Jul 18, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 96.84%. Comparing base (5d89ea3) to head (a564083).
Report is 1 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1471      +/-   ##
==========================================
+ Coverage   96.83%   96.84%   +0.01%     
==========================================
  Files         106      106              
  Lines        7871     7680     -191     
==========================================
- Hits         7622     7438     -184     
+ Misses        249      242       -7     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

library/public/options.h Outdated Show resolved Hide resolved
library/public/options.h Outdated Show resolved Hide resolved
library/CMakeLists.txt Outdated Show resolved Hide resolved
library/src/options.cxx Outdated Show resolved Hide resolved
@mwestphal mwestphal changed the title Option struct Complete refactor of options API Jul 28, 2024
@mwestphal mwestphal requested a review from Meakk July 28, 2024 15:30
@mwestphal
Copy link
Contributor Author

mwestphal commented Jul 30, 2024

options_struct.h

#ifndef f3d_options_struct_h
#define f3d_options_struct_h

#include "types.h"

#include <vector>
#include <string>

namespace f3d {
struct options_struct {
  struct interactor {
    bool axis = false;
    bool invert_zoom = false;
    bool trackball = false;
  } interactor;

  struct model {
    struct color {
      double opacity = 1.0;
      std::vector<double> rgb = {1.0, 1.0, 1.0};
      std::string texture = "";
    } color;

    struct emissive {
      std::vector<double> factor = {1.0, 1.0, 1.0};
      std::string texture = "";
    } emissive;

    struct matcap {
      std::string texture = "";
    } matcap;

    struct material {
      double metallic = 0.0;
      double roughness = 0.3;
      std::string texture = "";
    } material;

    struct normal {
      double scale = 1.0;
      std::string texture = "";
    } normal;

    struct point_sprites {
      bool enable = false;
      std::string type = "sphere";
    } point_sprites;

    struct scivis {
      std::string array_name = "f3d_reserved";
      bool cells = false;
      std::vector<double> colormap = {0.0, 0.0, 0.0, 0.0, 0.4, 0.9, 0.0, 0.0, 0.8, 0.9, 0.9, 0.0, 1.0, 1.0, 1.0, 1.0};
      int component = -1;
      std::vector<double> range = {0.0};
    } scivis;

    struct volume {
      bool enable = false;
      bool inverse = false;
    } volume;

  } model;

  struct render {
    std::string backface_type = "default";
    struct background {
      bool blur = false;
      double blur_coc = 20.0;
      std::vector<double> color = {0.2, 0.2, 0.2};
      bool skybox = false;
    } background;

    struct effect {
      bool ambient_occlusion = false;
      bool anti_aliasing = false;
      std::string final_shader = "";
      bool tone_mapping = false;
      bool translucency_support = false;
    } effect;

    struct grid {
      bool absolute = false;
      std::vector<double> color = {0.0, 0.0, 0.0};
      bool enable = false;
      int subdivisions = 10;
      double unit = 0.0;
    } grid;

    struct hdri {
      bool ambient = false;
      std::string file = "";
    } hdri;

    struct light {
      double intensity = 1.0;
    } light;

    double line_width = 1.0;
    double point_size = 10.0;
    struct raytracing {
      bool denoise = false;
      bool enable = false;
      int samples = 5;
    } raytracing;

    bool show_edges = false;
  } render;

  struct scene {
    struct animation {
      bool autoplay = false;
      double frame_rate = 60.0;
      int index = 0;
      f3d::ratio_t speed_factor = f3d::ratio_t(1.0);
      double time = 0.0;
    } animation;

    struct camera {
      int index = -1;
      bool orthographic = false;
    } camera;

    std::string up_direction = "+Y";
  } scene;

  struct ui {
    bool animation_progress = false;
    bool cheatsheet = false;
    bool dropzone = false;
    std::string dropzone_info = "";
    bool filename = false;
    std::string filename_info = "";
    std::string font_file = "";
    bool fps = false;
    bool loader_progress = false;
    bool metadata = false;
    bool scalar_bar = false;
  } ui;

};
};
#endif

@mwestphal
Copy link
Contributor Author

mwestphal commented Jul 30, 2024

options_struct_internals.h:

#ifndef f3d_options_struct_internals_h
#define f3d_options_struct_internals_h

#include "options_struct.h"
#include "options.h"

namespace options_struct_internals {
void set(f3d::options_struct& ostruct, const std::string& name, const option_variant_t& value){
  try
  {
    if (name == "interactor.axis") ostruct.interactor.axis = std::get<bool>(value);
    else if (name == "interactor.invert_zoom") ostruct.interactor.invert_zoom = std::get<bool>(value);
    else if (name == "interactor.trackball") ostruct.interactor.trackball = std::get<bool>(value);
    else if (name == "model.color.opacity") ostruct.model.color.opacity = std::get<double>(value);
    else if (name == "model.color.rgb") ostruct.model.color.rgb = std::get<std::vector<double>>(value);
    else if (name == "model.color.texture") ostruct.model.color.texture = std::get<std::string>(value);
    else if (name == "model.emissive.factor") ostruct.model.emissive.factor = std::get<std::vector<double>>(value);
    else if (name == "model.emissive.texture") ostruct.model.emissive.texture = std::get<std::string>(value);
    else if (name == "model.matcap.texture") ostruct.model.matcap.texture = std::get<std::string>(value);
    else if (name == "model.material.metallic") ostruct.model.material.metallic = std::get<double>(value);
    else if (name == "model.material.roughness") ostruct.model.material.roughness = std::get<double>(value);
    else if (name == "model.material.texture") ostruct.model.material.texture = std::get<std::string>(value);
    else if (name == "model.normal.scale") ostruct.model.normal.scale = std::get<double>(value);
    else if (name == "model.normal.texture") ostruct.model.normal.texture = std::get<std::string>(value);
    else if (name == "model.point_sprites.enable") ostruct.model.point_sprites.enable = std::get<bool>(value);
    else if (name == "model.point_sprites.type") ostruct.model.point_sprites.type = std::get<std::string>(value);
    else if (name == "model.scivis.array_name") ostruct.model.scivis.array_name = std::get<std::string>(value);
    else if (name == "model.scivis.cells") ostruct.model.scivis.cells = std::get<bool>(value);
    else if (name == "model.scivis.colormap") ostruct.model.scivis.colormap = std::get<std::vector<double>>(value);
    else if (name == "model.scivis.component") ostruct.model.scivis.component = std::get<int>(value);
    else if (name == "model.scivis.range") ostruct.model.scivis.range = std::get<std::vector<double>>(value);
    else if (name == "model.volume.enable") ostruct.model.volume.enable = std::get<bool>(value);
    else if (name == "model.volume.inverse") ostruct.model.volume.inverse = std::get<bool>(value);
    else if (name == "render.backface_type") ostruct.render.backface_type = std::get<std::string>(value);
    else if (name == "render.background.blur") ostruct.render.background.blur = std::get<bool>(value);
    else if (name == "render.background.blur_coc") ostruct.render.background.blur_coc = std::get<double>(value);
    else if (name == "render.background.color") ostruct.render.background.color = std::get<std::vector<double>>(value);
    else if (name == "render.background.skybox") ostruct.render.background.skybox = std::get<bool>(value);
    else if (name == "render.effect.ambient_occlusion") ostruct.render.effect.ambient_occlusion = std::get<bool>(value);
    else if (name == "render.effect.anti_aliasing") ostruct.render.effect.anti_aliasing = std::get<bool>(value);
    else if (name == "render.effect.final_shader") ostruct.render.effect.final_shader = std::get<std::string>(value);
    else if (name == "render.effect.tone_mapping") ostruct.render.effect.tone_mapping = std::get<bool>(value);
    else if (name == "render.effect.translucency_support") ostruct.render.effect.translucency_support = std::get<bool>(value);
    else if (name == "render.grid.absolute") ostruct.render.grid.absolute = std::get<bool>(value);
    else if (name == "render.grid.color") ostruct.render.grid.color = std::get<std::vector<double>>(value);
    else if (name == "render.grid.enable") ostruct.render.grid.enable = std::get<bool>(value);
    else if (name == "render.grid.subdivisions") ostruct.render.grid.subdivisions = std::get<int>(value);
    else if (name == "render.grid.unit") ostruct.render.grid.unit = std::get<double>(value);
    else if (name == "render.hdri.ambient") ostruct.render.hdri.ambient = std::get<bool>(value);
    else if (name == "render.hdri.file") ostruct.render.hdri.file = std::get<std::string>(value);
    else if (name == "render.light.intensity") ostruct.render.light.intensity = std::get<double>(value);
    else if (name == "render.line_width") ostruct.render.line_width = std::get<double>(value);
    else if (name == "render.point_size") ostruct.render.point_size = std::get<double>(value);
    else if (name == "render.raytracing.denoise") ostruct.render.raytracing.denoise = std::get<bool>(value);
    else if (name == "render.raytracing.enable") ostruct.render.raytracing.enable = std::get<bool>(value);
    else if (name == "render.raytracing.samples") ostruct.render.raytracing.samples = std::get<int>(value);
    else if (name == "render.show_edges") ostruct.render.show_edges = std::get<bool>(value);
    else if (name == "scene.animation.autoplay") ostruct.scene.animation.autoplay = std::get<bool>(value);
    else if (name == "scene.animation.frame_rate") ostruct.scene.animation.frame_rate = std::get<double>(value);
    else if (name == "scene.animation.index") ostruct.scene.animation.index = std::get<int>(value);
    else if (name == "scene.animation.speed_factor") ostruct.scene.animation.speed_factor = std::get<f3d::ratio_t>(value);
    else if (name == "scene.animation.time") ostruct.scene.animation.time = std::get<double>(value);
    else if (name == "scene.camera.index") ostruct.scene.camera.index = std::get<int>(value);
    else if (name == "scene.camera.orthographic") ostruct.scene.camera.orthographic = std::get<bool>(value);
    else if (name == "scene.up_direction") ostruct.scene.up_direction = std::get<std::string>(value);
    else if (name == "ui.animation_progress") ostruct.ui.animation_progress = std::get<bool>(value);
    else if (name == "ui.cheatsheet") ostruct.ui.cheatsheet = std::get<bool>(value);
    else if (name == "ui.dropzone") ostruct.ui.dropzone = std::get<bool>(value);
    else if (name == "ui.dropzone_info") ostruct.ui.dropzone_info = std::get<std::string>(value);
    else if (name == "ui.filename") ostruct.ui.filename = std::get<bool>(value);
    else if (name == "ui.filename_info") ostruct.ui.filename_info = std::get<std::string>(value);
    else if (name == "ui.font_file") ostruct.ui.font_file = std::get<std::string>(value);
    else if (name == "ui.fps") ostruct.ui.fps = std::get<bool>(value);
    else if (name == "ui.loader_progress") ostruct.ui.loader_progress = std::get<bool>(value);
    else if (name == "ui.metadata") ostruct.ui.metadata = std::get<bool>(value);
    else if (name == "ui.scalar_bar") ostruct.ui.scalar_bar = std::get<bool>(value);
    else throw f3d::options::inexistent_exception("Option " + name + " does not exist");
  }
  catch (const std::bad_variant_access&)
  {
    throw f3d::options::incompatible_exception(
      "Trying to set " + name + " with incompatible type");
  }
}

option_variant_t get(const f3d::options_struct& ostruct, const std::string& name){
  option_variant_t var;
  if (name == "interactor.axis") var = ostruct.interactor.axis;
  else if (name == "interactor.invert_zoom") var = ostruct.interactor.invert_zoom;
  else if (name == "interactor.trackball") var = ostruct.interactor.trackball;
  else if (name == "model.color.opacity") var = ostruct.model.color.opacity;
  else if (name == "model.color.rgb") var = ostruct.model.color.rgb;
  else if (name == "model.color.texture") var = ostruct.model.color.texture;
  else if (name == "model.emissive.factor") var = ostruct.model.emissive.factor;
  else if (name == "model.emissive.texture") var = ostruct.model.emissive.texture;
  else if (name == "model.matcap.texture") var = ostruct.model.matcap.texture;
  else if (name == "model.material.metallic") var = ostruct.model.material.metallic;
  else if (name == "model.material.roughness") var = ostruct.model.material.roughness;
  else if (name == "model.material.texture") var = ostruct.model.material.texture;
  else if (name == "model.normal.scale") var = ostruct.model.normal.scale;
  else if (name == "model.normal.texture") var = ostruct.model.normal.texture;
  else if (name == "model.point_sprites.enable") var = ostruct.model.point_sprites.enable;
  else if (name == "model.point_sprites.type") var = ostruct.model.point_sprites.type;
  else if (name == "model.scivis.array_name") var = ostruct.model.scivis.array_name;
  else if (name == "model.scivis.cells") var = ostruct.model.scivis.cells;
  else if (name == "model.scivis.colormap") var = ostruct.model.scivis.colormap;
  else if (name == "model.scivis.component") var = ostruct.model.scivis.component;
  else if (name == "model.scivis.range") var = ostruct.model.scivis.range;
  else if (name == "model.volume.enable") var = ostruct.model.volume.enable;
  else if (name == "model.volume.inverse") var = ostruct.model.volume.inverse;
  else if (name == "render.backface_type") var = ostruct.render.backface_type;
  else if (name == "render.background.blur") var = ostruct.render.background.blur;
  else if (name == "render.background.blur_coc") var = ostruct.render.background.blur_coc;
  else if (name == "render.background.color") var = ostruct.render.background.color;
  else if (name == "render.background.skybox") var = ostruct.render.background.skybox;
  else if (name == "render.effect.ambient_occlusion") var = ostruct.render.effect.ambient_occlusion;
  else if (name == "render.effect.anti_aliasing") var = ostruct.render.effect.anti_aliasing;
  else if (name == "render.effect.final_shader") var = ostruct.render.effect.final_shader;
  else if (name == "render.effect.tone_mapping") var = ostruct.render.effect.tone_mapping;
  else if (name == "render.effect.translucency_support") var = ostruct.render.effect.translucency_support;
  else if (name == "render.grid.absolute") var = ostruct.render.grid.absolute;
  else if (name == "render.grid.color") var = ostruct.render.grid.color;
  else if (name == "render.grid.enable") var = ostruct.render.grid.enable;
  else if (name == "render.grid.subdivisions") var = ostruct.render.grid.subdivisions;
  else if (name == "render.grid.unit") var = ostruct.render.grid.unit;
  else if (name == "render.hdri.ambient") var = ostruct.render.hdri.ambient;
  else if (name == "render.hdri.file") var = ostruct.render.hdri.file;
  else if (name == "render.light.intensity") var = ostruct.render.light.intensity;
  else if (name == "render.line_width") var = ostruct.render.line_width;
  else if (name == "render.point_size") var = ostruct.render.point_size;
  else if (name == "render.raytracing.denoise") var = ostruct.render.raytracing.denoise;
  else if (name == "render.raytracing.enable") var = ostruct.render.raytracing.enable;
  else if (name == "render.raytracing.samples") var = ostruct.render.raytracing.samples;
  else if (name == "render.show_edges") var = ostruct.render.show_edges;
  else if (name == "scene.animation.autoplay") var = ostruct.scene.animation.autoplay;
  else if (name == "scene.animation.frame_rate") var = ostruct.scene.animation.frame_rate;
  else if (name == "scene.animation.index") var = ostruct.scene.animation.index;
  else if (name == "scene.animation.speed_factor") var = ostruct.scene.animation.speed_factor;
  else if (name == "scene.animation.time") var = ostruct.scene.animation.time;
  else if (name == "scene.camera.index") var = ostruct.scene.camera.index;
  else if (name == "scene.camera.orthographic") var = ostruct.scene.camera.orthographic;
  else if (name == "scene.up_direction") var = ostruct.scene.up_direction;
  else if (name == "ui.animation_progress") var = ostruct.ui.animation_progress;
  else if (name == "ui.cheatsheet") var = ostruct.ui.cheatsheet;
  else if (name == "ui.dropzone") var = ostruct.ui.dropzone;
  else if (name == "ui.dropzone_info") var = ostruct.ui.dropzone_info;
  else if (name == "ui.filename") var = ostruct.ui.filename;
  else if (name == "ui.filename_info") var = ostruct.ui.filename_info;
  else if (name == "ui.font_file") var = ostruct.ui.font_file;
  else if (name == "ui.fps") var = ostruct.ui.fps;
  else if (name == "ui.loader_progress") var = ostruct.ui.loader_progress;
  else if (name == "ui.metadata") var = ostruct.ui.metadata;
  else if (name == "ui.scalar_bar") var = ostruct.ui.scalar_bar;
  else throw f3d::options::inexistent_exception("Option " + name + " does not exist");
  return var;
}

std::vector<std::string> getNames() {
  std::vector<std::string> vec{
  "interactor.axis",
  "interactor.invert_zoom",
  "interactor.trackball",
  "model.color.opacity",
  "model.color.rgb",
  "model.color.texture",
  "model.emissive.factor",
  "model.emissive.texture",
  "model.matcap.texture",
  "model.material.metallic",
  "model.material.roughness",
  "model.material.texture",
  "model.normal.scale",
  "model.normal.texture",
  "model.point_sprites.enable",
  "model.point_sprites.type",
  "model.scivis.array_name",
  "model.scivis.cells",
  "model.scivis.colormap",
  "model.scivis.component",
  "model.scivis.range",
  "model.volume.enable",
  "model.volume.inverse",
  "render.backface_type",
  "render.background.blur",
  "render.background.blur_coc",
  "render.background.color",
  "render.background.skybox",
  "render.effect.ambient_occlusion",
  "render.effect.anti_aliasing",
  "render.effect.final_shader",
  "render.effect.tone_mapping",
  "render.effect.translucency_support",
  "render.grid.absolute",
  "render.grid.color",
  "render.grid.enable",
  "render.grid.subdivisions",
  "render.grid.unit",
  "render.hdri.ambient",
  "render.hdri.file",
  "render.light.intensity",
  "render.line_width",
  "render.point_size",
  "render.raytracing.denoise",
  "render.raytracing.enable",
  "render.raytracing.samples",
  "render.show_edges",
  "scene.animation.autoplay",
  "scene.animation.frame_rate",
  "scene.animation.index",
  "scene.animation.speed_factor",
  "scene.animation.time",
  "scene.camera.index",
  "scene.camera.orthographic",
  "scene.up_direction",
  "ui.animation_progress",
  "ui.cheatsheet",
  "ui.dropzone",
  "ui.dropzone_info",
  "ui.filename",
  "ui.filename_info",
  "ui.font_file",
  "ui.fps",
  "ui.loader_progress",
  "ui.metadata",
  "ui.scalar_bar"
  };
  return vec;
}
}
#endif

doc/libf3d/OPTIONS.md Outdated Show resolved Hide resolved
doc/libf3d/OPTIONS.md Outdated Show resolved Hide resolved
doc/libf3d/OPTIONS.md Outdated Show resolved Hide resolved
doc/libf3d/OPTIONS.md Outdated Show resolved Hide resolved
library/private/options_tools.h.in Show resolved Hide resolved
library/public/types.h Show resolved Hide resolved
library/public/types.h Outdated Show resolved Hide resolved
library/public/types.h Show resolved Hide resolved
library/options.json Show resolved Hide resolved
CMakeLists.txt Outdated Show resolved Hide resolved
@mwestphal mwestphal force-pushed the option_struct branch 3 times, most recently from bfa103e to 701121a Compare August 18, 2024 16:39
@mwestphal mwestphal requested a review from Meakk August 18, 2024 16:44
doc/libf3d/OPTIONS.md Outdated Show resolved Hide resolved
application/F3DOptionsParser.cxx Outdated Show resolved Hide resolved
application/F3DOptionsParser.cxx Outdated Show resolved Hide resolved
application/F3DOptionsParser.cxx Outdated Show resolved Hide resolved
application/F3DOptionsParser.cxx Outdated Show resolved Hide resolved
examples/libf3d/cpp/check-engine/main.cxx Outdated Show resolved Hide resolved
library/public/options.h.in Outdated Show resolved Hide resolved
library/public/options.h.in Outdated Show resolved Hide resolved
library/public/types.h Show resolved Hide resolved
library/public/types.h Outdated Show resolved Hide resolved
python/F3DPythonBindings.cxx Show resolved Hide resolved
cmake/f3dOptions.cmake Outdated Show resolved Hide resolved
cmake/f3dOptions.cmake Outdated Show resolved Hide resolved
doc/libf3d/OPTIONS.md Show resolved Hide resolved
library/CMakeLists.txt Outdated Show resolved Hide resolved
library/src/window_impl.cxx Outdated Show resolved Hide resolved
library/src/window_impl.cxx Show resolved Hide resolved
library/src/window_impl.cxx Show resolved Hide resolved
python/F3DPythonBindings.cxx Show resolved Hide resolved
library/private/options_tools.h.in Outdated Show resolved Hide resolved
library/private/options_tools.h.in Outdated Show resolved Hide resolved
library/src/window_impl.cxx Outdated Show resolved Hide resolved
library/src/window_impl.cxx Outdated Show resolved Hide resolved
@mwestphal mwestphal requested review from snoyer and Meakk August 20, 2024 10:42
@mwestphal mwestphal merged commit 92845d5 into f3d-app:master Aug 20, 2024
40 checks passed
Nokse22 pushed a commit to Nokse22/f3d that referenced this pull request Sep 21, 2024
Complete refactor of options API based on generated struct and methods from a `options.json` file.

 - Add struct and methods generation code in f3dOptions.cmake
 - Add generation in library/CMakeLists.txt
 - Add options.json containing all options
 - Add new API in options.h and implement it in options.cxx, remove old API
 - Adapt code in library and in app for the new API
 - Add options testing
 - Added a quick doc about the three APIs and in header docs
 - Add a C++11 compatibility
 - Added examples
 - Improve clang-format CI and update files accordingly
 
Will be done in other PRs:

 - Add deprecation logic in generation code: f3d-app#1568
 - Rework application and simplify option logic: f3d-app#1569
 - Add more options types : f3d-app#1570
 - Add actual parsing for all options types: f3d-app#1571
 - Add complete documentation for options and option parsing: f3d-app#1572
 - Proper java and javascript bindings: f3d-app#1573 f3d-app#1574
 - use exception translator in python bindings: f3d-app#1575
  - Improve compile-time opti in options_tools.h.in:  f3d-app#1576
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants