diff --git a/CMakeLists.txt b/CMakeLists.txt index aff900d..61c88bc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,6 +51,7 @@ set(source_files src/render/VolumeRaycastRenderer.cpp src/render/VolumeRaycastShader.cpp src/UI/UIView.cpp + src/UI/UIDoubleClickedTableCell.cpp libs/glm.cpp src/render/FrameBufferObject.cpp src/render/DepthTexture.cpp @@ -79,6 +80,7 @@ set(header_files include/render/VolumeRaycastRenderer.h include/render/VolumeRaycastShader.h include/UI/UIView.h + include/UI/UIDoubleClickedTableCell.h libs/glm.h include/render/FrameBufferObject.h include/render/DepthTexture.h diff --git a/Resources/Models/plane.obj b/Resources/Models/plane.obj new file mode 100644 index 0000000..3ed0e51 --- /dev/null +++ b/Resources/Models/plane.obj @@ -0,0 +1,14 @@ +# Blender v2.82 (sub 7) OBJ File: '' +# www.blender.org +v -1.000000 0.000000 1.000000 +v 1.000000 0.000000 1.000000 +v -1.000000 0.000000 -1.000000 +v 1.000000 0.000000 -1.000000 +vt 0.000000 0.000000 +vt 1.000000 1.000000 +vt 0.000000 1.000000 +vt 1.000000 0.000000 +vn 0.0000 1.0000 0.0000 +s off +f 2/1/1 3/2/1 1/3/1 +f 2/1/1 4/4/1 3/2/1 diff --git a/Resources/Models/plane2.obj b/Resources/Models/plane2.obj new file mode 100644 index 0000000..3ed0e51 --- /dev/null +++ b/Resources/Models/plane2.obj @@ -0,0 +1,14 @@ +# Blender v2.82 (sub 7) OBJ File: '' +# www.blender.org +v -1.000000 0.000000 1.000000 +v 1.000000 0.000000 1.000000 +v -1.000000 0.000000 -1.000000 +v 1.000000 0.000000 -1.000000 +vt 0.000000 0.000000 +vt 1.000000 1.000000 +vt 0.000000 1.000000 +vt 1.000000 0.000000 +vn 0.0000 1.0000 0.0000 +s off +f 2/1/1 3/2/1 1/3/1 +f 2/1/1 4/4/1 3/2/1 diff --git a/Resources/Models/plane3.obj b/Resources/Models/plane3.obj new file mode 100644 index 0000000..67d154a --- /dev/null +++ b/Resources/Models/plane3.obj @@ -0,0 +1,17 @@ +# Blender v2.82 (sub 7) OBJ File: '' +# www.blender.org +mtllib plane3.mtl +o plane +v 1.000000 1.000000 0.000000 +v -1.000000 -1.000000 0.000000 +v -1.000000 1.000000 0.000000 +v 1.000000 -1.000000 0.000000 +vt 0.000000 0.000000 +vt 1.000000 1.000000 +vt 0.000000 1.000000 +vt 1.000000 0.000000 +vn 0.0000 0.0000 -1.0000 +usemtl Default_OBJ +s 1 +f 1/1/1 2/2/1 3/3/1 +f 1/1/1 4/4/1 2/2/1 diff --git a/Resources/README.md b/Resources/README.md new file mode 100644 index 0000000..861c485 --- /dev/null +++ b/Resources/README.md @@ -0,0 +1,3 @@ +### Resource folder + +All the [Models - obj files ](https://en.wikipedia.org/wiki/Wavefront_.obj_file) used by applications must go on this folder. Make sure the `.objs` have both vertex and texture coordinates (normals are optional). \ No newline at end of file diff --git a/include/UI/UIView.h b/include/UI/UIView.h index 4afb3f7..3051162 100644 --- a/include/UI/UIView.h +++ b/include/UI/UIView.h @@ -17,23 +17,40 @@ class CreateMovieAction; #define INPUT_TEXT_SIZE 200 #define MAX_COLUMS 50 -enum SAVE_MODAL {SAVE_NONE, SAVE_SESSION, SAVE_TRFR_FNC}; -enum LOAD_MODAL {LOAD_NONE, LOAD_SESSION, LOAD_TRFR_FNC }; +enum SAVE_MODAL +{ + SAVE_NONE, + SAVE_SESSION, + SAVE_TRANSFER_FUNCTION +}; +enum LOAD_MODAL +{ + LOAD_NONE, + LOAD_SESSION, + LOAD_TRFR_FNC +}; +enum BUTTON_ACTION +{ + NONE, + ADD, + EDIT, + REMOVE +}; struct Window_Properties { - + int window_w = 0; int window_h = 0; int framebuffer_w = 0; int framebuffer_h = 0; - bool operator==(Window_Properties& other) + bool operator==(Window_Properties &other) { if (other.window_w == window_w && - other.window_h == window_h && - other.framebuffer_w == framebuffer_w && - other.framebuffer_h == framebuffer_h) + other.window_h == window_h && + other.framebuffer_w == framebuffer_w && + other.framebuffer_h == framebuffer_h) { return true; } @@ -44,18 +61,17 @@ struct Window_Properties class UIView { public: - UIView(VRVolumeApp& controllerApp); + UIView(VRVolumeApp &controllerApp); ~UIView(); - void draw_ui_callback(); void init_ui(bool is2D, bool lookingGlass); void update_ui(int numVolumes); - void render_2D(Window_Properties& window_properties); - void render_3D(glm::mat4& space_matrix, Window_Properties& window_properties); + void render_2D(Window_Properties &window_properties); + void render_3D(glm::mat4 &space_matrix, Window_Properties &window_properties); void update_3D_ui_frame(); - void set_cursor_pos(glm::vec2&); + void set_cursor_pos(glm::vec2 &); void set_analog_value(float); int get_num_transfer_functions(); @@ -72,7 +88,7 @@ class UIView void set_enable_render_volume(); - void set_controller_pose(glm::mat4& pose); + void set_controller_pose(glm::mat4 &pose); void set_dynamic_slices(bool); bool is_dynamic_slices(); @@ -87,7 +103,7 @@ class UIView void update_animation(float speed, int numFrames); - void add_data_label(std::string& dataLabel); + void add_data_label(std::string &dataLabel); void clear_data_labels(); @@ -108,39 +124,64 @@ class UIView glm::vec3 get_clip_min(); glm::vec3 get_clip_max(); - void set_chracter(char c); + void set_clip_min(glm::vec3 clip_min); + void set_clip_max(glm::vec3 clip_max); + + void add_character(char c); void remove_character(); void compute_new_histogram_view(); - void addTransferFunction(); + void add_transfer_function(); -private: + void set_animation_length(int num_frames); + + void get_quantiles(int row); + void set_volume_time_info(time_t time); + + void draw_transfer_function_legend(); + + void set_transfer_function_min_max(float min, float max); + + bool get_show_movie_saved_pop_up() const { return m_show_movie_saved_pop_up; } + + void set_show_movie_saved_pop_up(bool val) { m_show_movie_saved_pop_up = val; } + +private: struct MyTransFerFunctions { - int ID; + int ID; std::string Name; std::vector volumes; }; - void open_save_modal_dialog(std::string& id, bool& window_state, - std::function save_function, std::string& extension); + void open_save_modal_dialog(std::string &id, bool &window_state, + std::function save_function, std::string &extension); - void add_trans_function(); + void add_transfer_function(); - void save_trans_functions(std::ofstream& saveFile); + void save_transfer_functions(std::ofstream &saveFile); - void save_user_session(std::ofstream& saveFile); + void save_user_session(std::ofstream &saveFile); - void load_trans_functions(std::ifstream& loadPath); + void load_transfer_functions(std::ifstream &loadPath); void load_user_session(std::string filePath); + void save_simulation_states(std::ofstream &loadPath, int num_poi); + + void load_camera_poi(std::ifstream &loadPath, int num_poi); + + void read_file_line(std::string &line, std::vector &values); + + void load_ocean_color_maps(); - VRVolumeApp& m_controller_app; - VRMenuHandler* m_menu_handler; + void adjust_transfer_function_to_histogram(); + + VRVolumeApp &m_controller_app; + VRMenuHandler *m_menu_handler; imgui_addons::ImGuiFileBrowser fileDialog; bool m_file_dialog_open; bool m_file_dialog_save_dir; @@ -172,6 +213,7 @@ class UIView bool m_animated; float m_ui_frame_controller; + unsigned int m_num_animation_frames; float m_stopped; glm::vec3 m_clip_min; @@ -181,13 +223,15 @@ class UIView glm::vec3 m_clip_ypr; glm::vec3 m_clip_pos; - int m_table_selection; + int m_trnfnc_table_selection; + + int m_camera_poi_table_selection; bool m_initialized; - bool m_trn_fct_opitions_window; + bool m_transfer_function_options_window; - bool m_save_trnfct_open; + bool m_save_transfer_function_open; bool m_save_session_dialog_open; @@ -199,6 +243,12 @@ class UIView std::string m_copy_trnfnct_name; + std::string m_copy_camera_name; + + bool m_camera_name_window_open; + + BUTTON_ACTION m_camera_button_action; + std::string m_save_file_name; unsigned int m_trnfnct_counter; @@ -207,29 +257,47 @@ class UIView bool m_ui_background; - - bool m_column_selected[MAX_COLUMS]; unsigned int m_column_selection_state; + bool m_compute_new_histogram; Histogram m_histogram; - void adjust_transfer_function_to_histogram(); - vec2f m_histogram_point_1; vec2f m_histogram_point_2; - float m_histogram_quantiles[2]; - - - void load_ocean_color_maps(); + float m_histogram_quantiles[2]; std::vector m_ocean_color_maps_names; std::string m_color_map_directory; + float m_animation_step; + std::string m_string_animation_duration; + + bool m_camera_animation_duration_open; + + std::vector m_clip_maxs; + std::vector m_clip_mins; + + bool m_show_clock; + float m_clock_pos_x; + float m_clock_pos_y; + float m_clock_width; + float m_clock_height; + + float m_legend_pos_y; + + std::string m_time_info; + std::string m_day_info; + + std::string m_months[12] = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}; + + int m_simulation_state_selection; + bool m_time_frame_edited; + + bool m_show_movie_saved_pop_up; }; - #endif diff --git a/include/interaction/ArcBall.h b/include/interaction/ArcBallCamera.h similarity index 63% rename from include/interaction/ArcBall.h rename to include/interaction/ArcBallCamera.h index 9c663d2..de151a6 100644 --- a/include/interaction/ArcBall.h +++ b/include/interaction/ArcBallCamera.h @@ -1,25 +1,25 @@ // ---------------------------------- -// Copyright © 2017, Brown University, Providence, RI. -// +// Copyright © 2017, Brown University, Providence, RI. +// // All Rights Reserved -// -// Use of the software is provided under the terms of the GNU General Public License version 3 -// as published by the Free Software Foundation at http://www.gnu.org/licenses/gpl-3.0.html, provided -// that this copyright notice appear in all copies and that the name of Brown University not be used in -// advertising or publicity pertaining to the use or distribution of the software without specific written +// +// Use of the software is provided under the terms of the GNU General Public License version 3 +// as published by the Free Software Foundation at http://www.gnu.org/licenses/gpl-3.0.html, provided +// that this copyright notice appear in all copies and that the name of Brown University not be used in +// advertising or publicity pertaining to the use or distribution of the software without specific written // prior permission from Brown University. -// +// // See license.txt for further information. -// -// BROWN UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE WHICH IS -// PROVIDED “AS IS”, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -// FOR ANY PARTICULAR PURPOSE. IN NO EVENT SHALL BROWN UNIVERSITY BE LIABLE FOR ANY -// SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR FOR ANY DAMAGES WHATSOEVER RESULTING -// FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR -// OTHER TORTIOUS ACTION, OR ANY OTHER LEGAL THEORY, ARISING OUT OF OR IN CONNECTION -// WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +// +// BROWN UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE WHICH IS +// PROVIDED "AS IS", INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR ANY PARTICULAR PURPOSE. IN NO EVENT SHALL BROWN UNIVERSITY BE LIABLE FOR ANY +// SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR FOR ANY DAMAGES WHATSOEVER RESULTING +// FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +// OTHER TORTIOUS ACTION, OR ANY OTHER LEGAL THEORY, ARISING OUT OF OR IN CONNECTION +// WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. // ---------------------------------- -// +// ///\file ArcBall.h ///\author Benjamin Knorlein ///\date 10/17/2019 @@ -29,6 +29,9 @@ #include #include +#include + +#include "PointOfInterests.h" enum WASD_KEYS { @@ -43,38 +46,53 @@ enum WASD_KEYS /** Adds a HeadMatrix to the RenderState that gets updated repeatedly based upon head tracking events. */ -class ArcBall { -public: - ArcBall(); +class ArcBallCamera +{ +public: + ArcBallCamera(); - virtual ~ArcBall(); + virtual ~ArcBallCamera(); void mouse_pressed(int button, bool isDown); void mouse_move(float x, float y); void mouse_scroll(float dist); void setCameraCenterRotation(bool useCameraCenter); - void wasd_pressed(int awsd); + void wasd_pressed(int wasd); - glm::mat4& getViewmatrix() + glm::mat4 &get_view_matrix() { - updateCameraMatrix(); - return viewmatrix; + update_camera_matrix(); + return m_viewmatrix; } + void update_camera_matrix(); + + void update_sim_poi(PointOfInterest &poi); + + PointOfInterest &get_current_poi(); + + void set_current_poi(const PointOfInterest &poi); + + void reset_camera(); + + void set_app_mode(unsigned int mode); + protected: void Rotate(float dTheta, float dPhi); void RotateEyeAxis(float dy); void Zoom(float distance); void Pan(float dx, float dy); - void updateCameraMatrix(); float m_radius; glm::vec3 m_target; glm::vec3 m_up; glm::vec3 m_eye; - glm::mat4 viewmatrix; + PointOfInterest m_current_poi; + PointOfInterest m_simulation_poi; + + glm::mat4 m_viewmatrix; bool m_mouse_left_pressed; bool m_mouse_right_pressed; bool m_mouse_center_pressed; @@ -82,9 +100,9 @@ class ArcBall { float m_PanFactor; float m_RotateFactor; float m_cameraScrollFactor; - bool m_rotate_camera_center; + + unsigned int m_app_mode; }; #endif - diff --git a/include/interaction/LabelManager.h b/include/interaction/LabelManager.h new file mode 100644 index 0000000..52a5cf5 --- /dev/null +++ b/include/interaction/LabelManager.h @@ -0,0 +1,83 @@ +// ---------------------------------- +// Copyright © 2015, Brown University, Providence, RI. +// +// All Rights Reserved +// +// Use of the software is provided under the terms of the GNU General Public License version 3 +// as published by the Free Software Foundation at http://www.gnu.org/licenses/gpl-3.0.html, provided +// that this copyright notice appear in all copies and that the name of Brown University not be used in +// advertising or publicity pertaining to the use or distribution of the software without specific written +// prior permission from Brown University. +// +// See license.txt for further information. +// +// BROWN UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE WHICH IS +// PROVIDED “AS IS”, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR ANY PARTICULAR PURPOSE. IN NO EVENT SHALL BROWN UNIVERSITY BE LIABLE FOR ANY +// SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR FOR ANY DAMAGES WHATSOEVER RESULTING +// FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +// OTHER TORTIOUS ACTION, OR ANY OTHER LEGAL THEORY, ARISING OUT OF OR IN CONNECTION +// WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +// ---------------------------------- +// +///\file Labels.h +///\author Benjamin Knorlein +///\date 6/25/2019 + +#ifndef LABELS_H +#define LABELS_H +#include +#include +#include +#include + +class Model; +class Texture; +class VRVolumeApp; +class ShaderProgram; + +struct BillboardLabel +{ + unsigned int line_vba; + Texture *label_texture; + Model *label_model; + glm::vec3 position; +}; + +class LabelManager +{ +public: + LabelManager(ShaderProgram &lines_shader, ShaderProgram &plane_shader); + ~LabelManager(); + + void add_label(std::string texture, float x, float y, float z, float textPosZ, float size, int volume); + void draw_labels(glm::mat4 MV, glm::mat4 projection_matrix, glm::mat4 &headpose, float z_scale); + void draw_lines(); + + void clear(); + void set_parent_directory(std::string &directory); + +private: + unsigned int create_line_vba(glm::vec3 &start, glm::vec3 &end); + + std::vector m_billboard_labels; + + std::vector m_text; + std::vector m_position; + std::vector m_position2; + std::vector m_size; + std::vector m_volume; + + std::vector m_lines_vba; + std::vector m_lines_vbo; + bool m_init_plane_model; + Model *m_plane_model; + + std::map m_texture_cache; + std::string m_parent_directory; + + ShaderProgram &m_lines_shader_program; + ShaderProgram &m_plane_shader_program; +}; + +#endif // LABELS_H diff --git a/include/interaction/Labels.h b/include/interaction/Labels.h deleted file mode 100644 index 5ec3b9e..0000000 --- a/include/interaction/Labels.h +++ /dev/null @@ -1,53 +0,0 @@ -// ---------------------------------- -// Copyright © 2015, Brown University, Providence, RI. -// -// All Rights Reserved -// -// Use of the software is provided under the terms of the GNU General Public License version 3 -// as published by the Free Software Foundation at http://www.gnu.org/licenses/gpl-3.0.html, provided -// that this copyright notice appear in all copies and that the name of Brown University not be used in -// advertising or publicity pertaining to the use or distribution of the software without specific written -// prior permission from Brown University. -// -// See license.txt for further information. -// -// BROWN UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE WHICH IS -// PROVIDED “AS IS”, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -// FOR ANY PARTICULAR PURPOSE. IN NO EVENT SHALL BROWN UNIVERSITY BE LIABLE FOR ANY -// SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR FOR ANY DAMAGES WHATSOEVER RESULTING -// FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR -// OTHER TORTIOUS ACTION, OR ANY OTHER LEGAL THEORY, ARISING OUT OF OR IN CONNECTION -// WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -// ---------------------------------- -// -///\file Labels.h -///\author Benjamin Knorlein -///\date 6/25/2019 - -#pragma once - -#ifndef LABELS_H -#define LABELS_H -#include -#include -#include - -class Labels -{ -public: - Labels(); - ~Labels(); - - void add(std::string text, float x, float y, float z, float textPosZ, float size, int volume); - void draw(std::vector& MV, glm::mat4& headpose, float z_scale); - void clear(); - -private: - std::vector m_text; - std::vector m_position; - std::vector m_position2; - std::vector m_size; - std::vector m_volume; -}; - -#endif // LABELS_H diff --git a/include/interaction/PointOfInterests.h b/include/interaction/PointOfInterests.h new file mode 100644 index 0000000..21c1ae6 --- /dev/null +++ b/include/interaction/PointOfInterests.h @@ -0,0 +1,48 @@ +#ifndef POINTOFINTEREST_H +#define POINTOFINTEREST_H + +#include +#include + +class PointOfInterest { + +public : + + PointOfInterest():eye(glm::vec3(0.0f, 0.0f, 1.0f)), target(glm::vec3(0.0f, 0.0f, 0.0f)), up(glm::vec3(0.0f, 1.0f, 0.0f)), radius(1.f) + { + } + + PointOfInterest(glm::vec3 p_eye, glm::vec3 p_target, glm::vec3 p_up, float p_radius):eye(p_eye),target(p_target),up(p_up),radius(p_radius) + { + + } + + PointOfInterest(const PointOfInterest& other) + { + eye = other.eye; + radius = other.radius; + target =other.target; + up = other.up; + }; + + //The orbit camera is constrained to move around a centered point ("target"). + //The camera position is calculated as a linear combination between the center object + //and the radius of the virtual sphere that surrounds it. + //This is not equal to the view matrix eye position determined by the homogeneous coordinate (4th column) + + glm::vec3 get_camera_position() + { + eye = (glm::normalize(eye)); + return radius * eye + target; + } + + glm::vec3 eye; + glm::vec3 target; + glm::vec3 up; + float radius; + std::string label; + + +}; + +#endif \ No newline at end of file diff --git a/include/interaction/Simulation.h b/include/interaction/Simulation.h new file mode 100644 index 0000000..62fe9f6 --- /dev/null +++ b/include/interaction/Simulation.h @@ -0,0 +1,98 @@ +#ifndef SIMULATION_H +#define SIMULATION_H + +#include "choreograph/Choreograph.h" + +#include + +#include "PointOfInterests.h" + +enum ANIMATION_STATE +{ + STOP, + PLAYING, + PAUSE +}; + +/* + SimulationState represents a frame in the simulation/animation + where the camera is set on a postion P, pointing on direction of a target T, + and min/max are set on a X-Y value. + the animation change SimulationStates by interpolating between the mentioned values. +*/ + +#define SIMULATION_TIME_STEP 30.0 + +struct SimulationState +{ + SimulationState(){}; + + SimulationState(const SimulationState &other) + { + poi = other.poi; + max_clip = other.max_clip; + min_clip = other.min_clip; + } + + std::string time_label; + PointOfInterest poi; + glm::vec3 max_clip; + glm::vec3 min_clip; +}; + +class VRVolumeApp; + +class Simulation +{ +public: + Simulation(VRVolumeApp &controller_app, float time = 10.0f); + + void add_simulation_state(SimulationState &simulationState); + + void create_simulation_time_frames(); + void update_simulation(); + + void set_animation_state(); + + ANIMATION_STATE get_animation_state(); + std::string get_camera_animation_state(); + float get_simulation_duration(); + void set_simulation_duration(float duration); + + const std::list &get_simulation_states(); + + SimulationState &get_simulation_state_at(unsigned int index); + + SimulationState get_current_simulation_state(); + + void remove_simulation_state(unsigned int index); + + float get_animation_duration(); + +private: + void update_time_step(); + + ch::Timeline m_timeline; + float m_simulation_duration; + + std::list m_simulation_states; + + std::vector> m_vec3_sequences; + std::vector> m_float_sequences; + + ch::Output m_target_animation; + ch::Output m_eye_animation; + ch::Output m_up_animation; + ch::Output m_radius_animation; + ch::Output m_max_clip_animation; + ch::Output m_min_clip_animation; + + bool m_is_animate_path; + + ANIMATION_STATE m_animation_state; + std::string animation_button_label; + + VRVolumeApp &m_controller_app; +}; + +#endif \ No newline at end of file diff --git a/include/loader/VRDataLoader.h b/include/loader/VRDataLoader.h index ae48bf5..e99ea7e 100644 --- a/include/loader/VRDataLoader.h +++ b/include/loader/VRDataLoader.h @@ -7,18 +7,9 @@ class VRVolumeApp; class VRDataLoader { public: - - - static VRDataLoader* get_instance(); - - static void load_txt_file(VRVolumeApp& vrVolumeApp, std::string& filename); - -private: - VRDataLoader(); - static VRDataLoader* m_instance; + static void load_txt_file(VRVolumeApp &vrVolumeApp, std::string &filename); }; #endif - diff --git a/include/render/VolumeRaycastRenderer.h b/include/render/VolumeRaycastRenderer.h index 1024d70..1d5d65a 100644 --- a/include/render/VolumeRaycastRenderer.h +++ b/include/render/VolumeRaycastRenderer.h @@ -67,14 +67,14 @@ class VolumeRaycastRenderer : public VolumeRenderer virtual void set_blending(bool useBlending, float alpha, Volume* volume) override; virtual void useMultichannelColormap(bool useMulti); - virtual void set_numSlices(int slices) override; + virtual void set_num_slices(int slices) override; void setDepthTexture(DepthTexture* depth_texture) { shader.setDepthTexture(depth_texture); } - virtual void setClipMinMax(glm::vec3 min_clip, glm::vec3 max_clip); + virtual void set_clip_min_max(glm::vec3 min_clip, glm::vec3 max_clip); private: void setChannel(Volume* volume); diff --git a/include/render/VolumeRenderer.h b/include/render/VolumeRenderer.h index 75e75c6..60ff3f6 100644 --- a/include/render/VolumeRenderer.h +++ b/include/render/VolumeRenderer.h @@ -1,31 +1,29 @@ // ---------------------------------- // Copyright © 2015, Brown University, Providence, RI. -// +// // All Rights Reserved -// -// Use of the software is provided under the terms of the GNU General Public License version 3 -// as published by the Free Software Foundation at http://www.gnu.org/licenses/gpl-3.0.html, provided -// that this copyright notice appear in all copies and that the name of Brown University not be used in -// advertising or publicity pertaining to the use or distribution of the software without specific written +// +// Use of the software is provided under the terms of the GNU General Public License version 3 +// as published by the Free Software Foundation at http://www.gnu.org/licenses/gpl-3.0.html, provided +// that this copyright notice appear in all copies and that the name of Brown University not be used in +// advertising or publicity pertaining to the use or distribution of the software without specific written // prior permission from Brown University. -// +// // See license.txt for further information. -// -// BROWN UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE WHICH IS -// PROVIDED “AS IS”, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -// FOR ANY PARTICULAR PURPOSE. IN NO EVENT SHALL BROWN UNIVERSITY BE LIABLE FOR ANY -// SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR FOR ANY DAMAGES WHATSOEVER RESULTING -// FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR -// OTHER TORTIOUS ACTION, OR ANY OTHER LEGAL THEORY, ARISING OUT OF OR IN CONNECTION -// WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +// +// BROWN UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE WHICH IS +// PROVIDED “AS IS”, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR ANY PARTICULAR PURPOSE. IN NO EVENT SHALL BROWN UNIVERSITY BE LIABLE FOR ANY +// SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR FOR ANY DAMAGES WHATSOEVER RESULTING +// FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +// OTHER TORTIOUS ACTION, OR ANY OTHER LEGAL THEORY, ARISING OUT OF OR IN CONNECTION +// WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. // ---------------------------------- -// +// ///\file VolumeRenderer.h ///\author Benjamin Knorlein ///\date 5/24/2019 -#pragma once - #ifndef VOLUMERENDER_H #define VOLUMERENDER_H @@ -33,32 +31,35 @@ #include "Volume.h" class VolumeRenderer - { - public: - VolumeRenderer(){}; - virtual ~VolumeRenderer(){}; +{ +public: + VolumeRenderer(){}; + virtual ~VolumeRenderer(){}; - virtual void initGL() = 0; - virtual void render(Volume* volume, const glm::mat4 &MV, glm::mat4 &P, float z_scale, GLint colorma, int renderChannel) = 0; + virtual void initGL() = 0; + virtual void render(Volume *volume, const glm::mat4 &MV, glm::mat4 &P, float z_scale, GLint colorma, int renderChannel) = 0; - virtual void set_threshold(float threshold) = 0; - virtual void set_multiplier(float multiplier) = 0; - virtual void set_numSlices(int slices) = 0; - - virtual void set_blending(bool useBlending, float alpha, Volume* volume) = 0; - virtual void useMultichannelColormap(bool useMulti) = 0; - - virtual void setClipMinMax(glm::vec3 min_clip, glm::vec3 max_clip) = 0; + virtual void set_threshold(float threshold) = 0; + virtual void set_multiplier(float multiplier) = 0; + virtual void set_num_slices(int slices) = 0; - void setClipping(bool isClipping, glm::mat4 * clipPlane) - { - m_clipping = isClipping; - if (m_clipping) - m_clipPlane = *clipPlane; - }; + virtual void set_blending(bool useBlending, float alpha, Volume *volume) = 0; + virtual void useMultichannelColormap(bool useMulti) = 0; + + virtual void set_clip_min_max(glm::vec3 min_clip, glm::vec3 max_clip) = 0; - protected: - bool m_clipping; - glm::mat4 m_clipPlane; + void set_clipping_plane(bool isClipping, glm::mat4 *clipPlane) + { + m_clipping = isClipping; + if (m_clipping) + { + m_clip_plane = *clipPlane; + } }; + +protected: + bool m_clipping; + glm::mat4 m_clip_plane; +}; + #endif // VOLUMERENDER_H diff --git a/include/render/VolumeSliceRenderer.h b/include/render/VolumeSliceRenderer.h index 8c9991f..c8e79f2 100644 --- a/include/render/VolumeSliceRenderer.h +++ b/include/render/VolumeSliceRenderer.h @@ -66,7 +66,7 @@ class VolumeSliceRenderer : public VolumeRenderer virtual void set_threshold(float threshold) override; virtual void set_multiplier(float multiplier) override; - virtual void set_numSlices(int slices) override; + virtual void set_num_slices(int slices) override; virtual void useMultichannelColormap(bool useMulti); virtual void set_blending(bool useBlending, float alpha, Volume* volume) override @@ -74,7 +74,7 @@ class VolumeSliceRenderer : public VolumeRenderer //unsupported for now } - virtual void setClipMinMax(glm::vec3 min_clip, glm::vec3 max_clip); + virtual void set_clip_min_max(glm::vec3 min_clip, glm::vec3 max_clip); private: //function to get the max (abs) dimension of the given vertex v diff --git a/include/vrapp/VRVolumeApp.h b/include/vrapp/VRVolumeApp.h index a2dcca8..0c7b3f2 100644 --- a/include/vrapp/VRVolumeApp.h +++ b/include/vrapp/VRVolumeApp.h @@ -1,15 +1,17 @@ #ifndef VRVOLUMEAPP_H #define VRVOLUMEAPP_H + #include #include #include #include -#include "interaction/Labels.h" -#include "interaction/ArcBall.h" + +#include "interaction/ArcBallCamera.h" #include "render/Volume.h" -#include "Model.h" + +#include "ShaderProgram.h" class UIView; @@ -17,15 +19,30 @@ class CreateMovieAction; class VolumeRenderer; class DepthTexture; class Window_Properties; +class Model; +class Texture; +class Simulation; +class LabelManager; + +enum MOVIESTATE +{ + MOVIE_STOP, + MOVIE_RECORD +}; + +enum APPMODE +{ + MANUAL, + SIMULATION +}; class VRVolumeApp { public: VRVolumeApp(); - ~VRVolumeApp(); - + ~VRVolumeApp(); void render(const MinVR::VRGraphicsState& renderState); @@ -90,10 +107,11 @@ class VRVolumeApp void update_trackBall_state(); - void update_animation(); + void update_animation(float fps); #if (!defined(__APPLE__)) - void run_movie(); + void run_movie(bool is_animation); + void stop_movie(); #endif @@ -152,7 +170,24 @@ class VRVolumeApp std::vector< Volume* >& get_volume(int volume); - + ArcBallCamera& get_trackball_camera(); + + /* + increase/decrease the step size of the volume animation by a `scale` factor. + It is a step unit, not related to any time unit. + */ + void set_volume_animation_scale_factor(float scale); + + Simulation& get_simulation(); + + void set_clip_min(glm::vec3 clip_min); + void set_clip_max(glm::vec3 clip_max); + + std::string get_movie_state_label(); + + MOVIESTATE get_movie_state(); + + void set_app_mode(APPMODE ); protected: @@ -167,7 +202,7 @@ class VRVolumeApp - void render_labels(const MinVR::VRGraphicsState& renderState); + void render_labels(glm::mat4& volume_mv, const MinVR::VRGraphicsState& renderState); void render_mesh(const MinVR::VRGraphicsState& renderState); void render_volume(const MinVR::VRGraphicsState& renderState); void render_ui(const MinVR::VRGraphicsState& renderState); @@ -179,7 +214,7 @@ class VRVolumeApp std::vector < std::vector< Volume* >> m_volumes; std::vector m_description; - Labels m_labels; + LabelManager* m_labels; std::vector m_models_filenames; std::vector m_models_displayLists; std::vector m_models_position; @@ -198,6 +233,8 @@ class VRVolumeApp Model* m_mesh_model; ShaderProgram m_simple_texture_shader; + ShaderProgram m_line_shader; + std::string m_shader_file_path; std::string m_texture_filePath; Texture* m_texture; @@ -206,6 +243,7 @@ class VRVolumeApp bool m_animated; float m_threshold; int m_descriptionHeight; + float m_volume_animation_scale_factor; float m_frame; float m_speed; @@ -230,7 +268,7 @@ class VRVolumeApp glm::mat4 m_model_view; - ArcBall m_trackball; + ArcBallCamera m_trackball; bool m_lookingGlass; glm::mat4 m_object_pose; @@ -253,7 +291,7 @@ class VRVolumeApp bool m_use_multi_transfer; bool m_show_menu; - + bool m_end_load; /*Input Events*/ @@ -273,5 +311,13 @@ class VRVolumeApp std::string m_current_file_loaded; Window_Properties* m_window_properties; + + Simulation* m_simulation; + + MOVIESTATE m_current_movie_state; + bool m_stop_movie; + + APPMODE m_app_mode; + }; #endif diff --git a/include/vrapp/VolumeVisualizationApp.h b/include/vrapp/VolumeVisualizationApp.h index 8d4f779..d4a7f5d 100644 --- a/include/vrapp/VolumeVisualizationApp.h +++ b/include/vrapp/VolumeVisualizationApp.h @@ -22,7 +22,6 @@ #include #endif - #include "VRMenuHandler.h" #include "UIHelpers/transfer_function_multichannel_widget.h" #include "UIHelpers/transfer_function_widget.h" @@ -33,9 +32,6 @@ #include "render/VolumeRaycastRenderer.h" #include "render/DepthTexture.h" #include -#include "interaction/ArcBall.h" - - using namespace MinVR; @@ -51,6 +47,7 @@ using namespace MinVR; #include "../render/VolumeSliceRenderer.h" #include "../interaction/CreateMovieAction.h" + #include "ShaderProgram.h" #include "VRVolumeApp.h" @@ -60,59 +57,50 @@ class Texture; class UIView; class VRVolumeApp; -class VolumeVisualizationApp : public VRApp { +class VolumeVisualizationApp : public VRApp +{ public: - /** The constructor passes argc, argv, and a MinVR config file on to VRApp. */ - VolumeVisualizationApp(int argc, char** argv); + VolumeVisualizationApp(int argc, char **argv); virtual ~VolumeVisualizationApp(); - - /** USER INTERFACE CALLBACKS **/ - virtual void onCursorMove(const VRCursorEvent& state); + virtual void onCursorMove(const VRCursorEvent &state); - virtual void onAnalogChange(const VRAnalogEvent& state); + virtual void onAnalogChange(const VRAnalogEvent &state); - virtual void onButtonDown(const VRButtonEvent& state); + virtual void onButtonDown(const VRButtonEvent &state); - virtual void onButtonUp(const VRButtonEvent& state); + virtual void onButtonUp(const VRButtonEvent &state); - virtual void onTrackerMove(const VRTrackerEvent& state); + virtual void onTrackerMove(const VRTrackerEvent &state); - virtual void onGenericEvent(const VRDataIndex& index); + virtual void onGenericEvent(const VRDataIndex &index); /** RENDERING CALLBACKS **/ - virtual void onRenderGraphicsScene(const VRGraphicsState& state); - - virtual void onRenderGraphicsContext(const VRGraphicsState& state); - + virtual void onRenderGraphicsScene(const VRGraphicsState &state); + virtual void onRenderGraphicsContext(const VRGraphicsState &state); private: - int width; int height; - GLfloat m_light_pos[4]; - unsigned int rendercount; - - - std::chrono::steady_clock::time_point m_lastTime; + VRVolumeApp *m_vrVolumeApp; + int m_num_frames; - VRVolumeApp* m_vrVolumeApp; - + const double fps_limit = 1.0 / 60.0; + std::chrono::steady_clock::time_point last_Update_Time; // number of seconds since the last loop }; - #endif \ No newline at end of file diff --git a/libs/GLMLoader/VertexBuffer.h b/libs/GLMLoader/VertexBuffer.h index 0e492cd..2919554 100644 --- a/libs/GLMLoader/VertexBuffer.h +++ b/libs/GLMLoader/VertexBuffer.h @@ -36,7 +36,7 @@ #include #include #include -#include + class VertexBuffer { diff --git a/libs/Model/Model.cpp b/libs/Model/Model.cpp index cfee664..0838d4c 100644 --- a/libs/Model/Model.cpp +++ b/libs/Model/Model.cpp @@ -1,70 +1,60 @@ #include "Model.h" #include #include +#include "ShaderProgram.h" - -Model::Model():m_position(0),m_orientation(glm::quat()),m_scale(1), m_bounding_volumen_radius(1) +Model::Model() : m_position(0), m_orientation(glm::quat()), m_scale(1), m_bounding_volumen_radius(1) { - } - Model::~Model() { delete m_Obj_Model; - for (int i = 0 ; i < m_textures.size(); ++i) - { - delete m_textures[i]; - } - + + delete m_texture; } -VertexBuffer& Model::objModel() const +VertexBuffer &Model::objModel() const { return *m_Obj_Model; } -void Model::setObjModel(VertexBuffer* val) +void Model::setObjModel(VertexBuffer *val) { m_Obj_Model = val; } -Texture& Model::texture(int index) const +Texture &Model::texture(int index) const { - return *m_textures[index]; + return *m_texture; } -void Model::addTexture(Texture* val) +void Model::setTexture(Texture *val) { - m_textures.push_back(val); + m_texture = val; } -void Model::render(ShaderProgram& shaderProgram) +void Model::render(ShaderProgram &shaderProgram) { - - /*glm::mat4 m_model = glm::mat4(1.0f); - m_model *= glm::translate(myPosition); - m_model *= glm::toMat4(myOrientation); - m_model *= glm::scale(myScale);*/ - - //shaderProgram.setUniform("m", m_model); - shaderProgram.setUniform("mv", m_model_view_mtrx); + shaderProgram.setUniform("model_view_matrix", m_model_view_mtrx); assert(m_Obj_Model && "NO MODEL TO RENDER"); // bind texture - for (int i = 0; i < m_textures.size(); ++i) - { - m_textures[i]->Bind(i); - } + // Always load texture id 0. The model doesnt support multi texturing. + m_texture->Bind(0); - //render geometry + // render geometry if (m_Obj_Model) { m_Obj_Model->render(); } + + // Unbind Text + + m_texture->UnBind(0); } -glm::vec3& Model::position() +glm::vec3 &Model::position() { return m_position; } @@ -74,7 +64,7 @@ void Model::setPosition(glm::vec3 val) m_position = val; } -glm::quat& Model::orientation() +glm::quat &Model::orientation() { return m_orientation; } @@ -84,7 +74,7 @@ void Model::setOrientation(glm::quat val) m_orientation = val; } -glm::vec3& Model::scale() +glm::vec3 &Model::scale() { return m_scale; } @@ -104,38 +94,34 @@ void Model::setBoundingVolumenRadius(float val) m_bounding_volumen_radius = val; } -bool Model::RayInstersection(const glm::vec3& start, const glm::vec3& rayDirection) +bool Model::RayInstersection(const glm::vec3 &start, const glm::vec3 &rayDirection) { - - glm::vec3 Position = m_position; - float b = 2.f * (rayDirection.x * (start.x - Position.x) + - rayDirection.y * (start.y - Position.y) + rayDirection.z * (start.z - Position.z)); - float c = start.x * start.x - 2.f * start.x * Position.x + Position.x * Position.x - + start.y * start.y - 2.f * start.y * Position.y + Position.y * Position.y - + start.z * start.z - 2.f * start.z * Position.z + Position.z * Position.z - m_bounding_volumen_radius * m_bounding_volumen_radius; + glm::vec3 Position = m_position; + + float b = 2.f * (rayDirection.x * (start.x - Position.x) + + rayDirection.y * (start.y - Position.y) + rayDirection.z * (start.z - Position.z)); + float c = start.x * start.x - 2.f * start.x * Position.x + Position.x * Position.x + start.y * start.y - 2.f * start.y * Position.y + Position.y * Position.y + start.z * start.z - 2.f * start.z * Position.z + Position.z * Position.z - m_bounding_volumen_radius * m_bounding_volumen_radius; - float discr = (b * b - 4.f * c); - if (discr < 0.f) - { - m_selected = false; - - } - else - { - m_selected = true; - - } + float discr = (b * b - 4.f * c); + if (discr < 0.f) + { + m_selected = false; + } + else + { + m_selected = true; + } - return m_selected; + return m_selected; } bool Model::isSelected() { - return m_selected; + return m_selected; } void Model::seleted(bool selected) { - m_selected = selected; + m_selected = selected; } diff --git a/libs/Model/Model.h b/libs/Model/Model.h index ad20b17..85813c1 100644 --- a/libs/Model/Model.h +++ b/libs/Model/Model.h @@ -2,8 +2,9 @@ #define MODEL_H #include "VertexBuffer.h" #include "Texture.h" -#include "ShaderProgram.h" + +class ShaderProgram; class Model { public: @@ -15,7 +16,7 @@ class Model Texture& texture(int index) const; - void addTexture(Texture* val); + void setTexture(Texture* val); void render( ShaderProgram& shader); @@ -52,7 +53,7 @@ class Model Model(); VertexBuffer* m_Obj_Model; - std::vector m_textures; + Texture* m_texture; friend class GLMLoader; friend class AssimpLoader; diff --git a/libs/ShaderProgram/ShaderProgram.cpp b/libs/ShaderProgram/ShaderProgram.cpp index 5b5fc36..4476ed6 100644 --- a/libs/ShaderProgram/ShaderProgram.cpp +++ b/libs/ShaderProgram/ShaderProgram.cpp @@ -2,6 +2,10 @@ #include #include +#include +#include + + ShaderProgram::ShaderProgram() :m_progarm_id(0) { } diff --git a/libs/ShaderProgram/ShaderProgram.h b/libs/ShaderProgram/ShaderProgram.h index 2c1de24..c728f9d 100644 --- a/libs/ShaderProgram/ShaderProgram.h +++ b/libs/ShaderProgram/ShaderProgram.h @@ -23,17 +23,11 @@ #endif #define GLM_ENABLE_EXPERIMENTAL -#include -#include -#include -#include -#include + #include #include - - - +#include class ShaderProgram { diff --git a/libs/Texture/Texture.cpp b/libs/Texture/Texture.cpp index c006a12..535d142 100644 --- a/libs/Texture/Texture.cpp +++ b/libs/Texture/Texture.cpp @@ -3,19 +3,18 @@ #include #include -Texture::Texture(GLenum TextureTarget, const std::string& filename) : m_texture_target(TextureTarget) -, m_file_name(filename.c_str()) +Texture::Texture(GLenum TextureTarget, const std::string &filename) : m_texture_target(TextureTarget), m_file_name(filename.c_str()) { m_texture_id = Load2DTexture(); } - + Texture::~Texture() { } -void Texture::Bind(GLenum TextureUnit) +void Texture::Bind() { - glActiveTexture(GL_TEXTURE0 + TextureUnit); + glActiveTexture(GL_TEXTURE0); glBindTexture(m_texture_target, m_texture_id); } @@ -24,68 +23,126 @@ GLuint Texture::GetTextureId() return m_texture_id; } +void Texture::UnBind() +{ + glActiveTexture(GL_TEXTURE0); + glBindTexture(m_texture_target, 0); +} + int Texture::Load2DTexture() { - int width = 0; int height = 0; int bbp = 0; - //pointer to the image data - unsigned char * bits(0); + // pointer to the image data + unsigned char *bits(0); - //retrieve the image data - //if this somehow one of these failed (they shouldn't), return failure + // retrieve the image data + // if this somehow one of these failed (they shouldn't), return failure GLuint textureID = LoadTexture(m_file_name, width, height, &bits, bbp); if (textureID == -1) { assert(false && "Image failed to load 2"); } - return textureID; } -int Texture::LoadTexture(const std::string & fileName, - int & width, int & height, unsigned char ** data, int& bbp) +int Texture::Load3DTexture(const std::vector &paths) +{ + if (paths.size() == 0) + { + assert(false && "no paths to load from"); + } + + GLsizei width, height, depth = paths.size(); + + std::vector formatedImages(paths.size()); + + // load and format each image + for (int i = 0; i < paths.size(); ++i) + { + BYTE *bits(0); + int bbp = 0; + if (!LoadTexture(paths[i], width, height, &bits, bbp)) + { + assert(false && "Image failed to load 2"); + } + image img(width, height, bits); + formatedImages[i] = img; + } + + GLuint textureID; + glGenTextures(1, &textureID); + glBindTexture(GL_TEXTURE_2D_ARRAY, textureID); + // Create storage for the texture. (100 layers of 1x1 texels) + glTexStorage3D(GL_TEXTURE_2D_ARRAY, + 1, // No mipmaps as textures are 1x1 + GL_RGBA8, // Internal format + width, height, // width,height + depth // Number of layers + ); + + for (unsigned int i = 0; i < formatedImages.size(); ++i) + { + // Specify i-essim image + glTexSubImage3D(GL_TEXTURE_2D_ARRAY, + 0, // Mipmap number + 0, 0, i, // xoffset, yoffset, zoffset + formatedImages[i].imageWidth, formatedImages[i].imageHeight, 1, // width, height, depth + GL_RGB, // format + GL_UNSIGNED_BYTE, // type + formatedImages[i].imageData); // pointer to data + } + + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_REPEAT); + + glBindTexture(GL_TEXTURE_2D_ARRAY, 0); + // Return the ID of the texture we just created + return textureID; +} + +int Texture::LoadTexture(const std::string &fileName, + int &width, int &height, unsigned char **data, int &bbp) { - unsigned int texture; glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); // all upcoming GL_TEXTURE_2D operations now have effect on this texture object // set the texture wrapping parameters - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // set texture wrapping to GL_REPEAT (default wrapping method) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // set texture wrapping to GL_REPEAT (default wrapping method) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // set texture filtering parameters glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - //int width, height, nrChannels; + + // int width, height, nrChannels; stbi_set_flip_vertically_on_load(1); *data = stbi_load(fileName.c_str(), &width, &height, &bbp, 0); if (data) { if (bbp == 3) - { - //glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, *data); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height,0, GL_RGB, GL_UNSIGNED_BYTE, *data); + { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, *data); } else if (bbp == 4) { - //glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, *data); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height,0, GL_RGBA, GL_UNSIGNED_BYTE, *data); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, *data); } + - //glGenerateMipmap(GL_TEXTURE_2D); } else { std::cout << "Failed to load texture" << std::endl; return -1; } - glBindTexture(GL_TEXTURE_2D,0); + glBindTexture(GL_TEXTURE_2D, 0); stbi_image_free(*data); return texture; diff --git a/libs/Texture/Texture.h b/libs/Texture/Texture.h index f182412..490a19b 100644 --- a/libs/Texture/Texture.h +++ b/libs/Texture/Texture.h @@ -23,6 +23,7 @@ #endif #include +#include class Texture { @@ -30,8 +31,9 @@ class Texture Texture(GLenum TextureTarget, const std::string& filename); ~Texture(); - void Bind(GLenum TextureUnit); + void Bind(); GLuint GetTextureId(); + void UnBind(); int LoadTexture(const std::string& fileName, int& width, int& height, unsigned char ** data, int& bbp); @@ -48,7 +50,7 @@ class Texture }; int Load2DTexture(); - + int Load3DTexture(const std::vector& paths); GLuint m_texture_id; diff --git a/libs/UIHelpers/transfer_function_widget.cpp b/libs/UIHelpers/transfer_function_widget.cpp index 8942a2d..9c53f5c 100644 --- a/libs/UIHelpers/transfer_function_widget.cpp +++ b/libs/UIHelpers/transfer_function_widget.cpp @@ -29,7 +29,6 @@ #include "embedded_colormaps.h" #include "../../include/render/FontHandler.h" - #ifndef TFN_WIDGET_NO_STB_IMAGE_IMPL #define STB_IMAGE_IMPLEMENTATION #endif @@ -39,22 +38,22 @@ template T clamp(T x, T min, T max) { - if (x < min) { + if (x < min) + { return min; } - if (x > max) { + if (x > max) + { return max; } return x; } -Colormap::Colormap(const std::string& name, const std::vector& img) - : name(name), colormap(img) +Colormap::Colormap(const std::string &name, const std::vector &img) + : name(name), colormap(img) { } - - TransferFunctionWidget::TransferFunctionWidget() { // Load up the embedded colormaps as the default options @@ -70,19 +69,15 @@ TransferFunctionWidget::TransferFunctionWidget() load_embedded_preset(blue_gold, sizeof(blue_gold), "Blue Gold"); load_embedded_preset(ice_fire, sizeof(ice_fire), "Ice Fire"); load_embedded_preset(nic_edge, sizeof(nic_edge), "nic Edge"); - //load_embedded_preset(Algae, sizeof(Algae), "Algae"); - + // Initialize the colormap alpha channel w/ a linear ramp update_colormap(); for (int i = 0; i < 256; i++) { - //current_histogram.push_back(static_cast (rand()) / static_cast (RAND_MAX)); current_histogram.push_back(0); } - - m_min_max_val[0] = 0.0f; m_min_max_val[1] = 1.0f; @@ -90,7 +85,7 @@ TransferFunctionWidget::TransferFunctionWidget() m_quantiles[1] = 0.95f; } -void TransferFunctionWidget::add_colormap(const Colormap& map) +void TransferFunctionWidget::add_colormap(const Colormap &map) { colormaps.push_back(map); } @@ -100,16 +95,19 @@ void TransferFunctionWidget::draw_ui() update_gpu_image(); colormap_changed = false; - const ImGuiIO& io = ImGui::GetIO(); + const ImGuiIO &io = ImGui::GetIO(); ImGui::Text("Transfer Function"); ImGui::TextWrapped( - "Left click to add a point, right click remove. " - "Left click + drag to move points."); + "Left click to add a point, right click remove. " + "Left click + drag to move points."); - if (ImGui::BeginCombo("Colormap", colormaps[selected_colormap].name.c_str())) { - for (size_t i = 0; i < colormaps.size(); ++i) { - if (ImGui::Selectable(colormaps[i].name.c_str(), selected_colormap == i)) { + if (ImGui::BeginCombo("Colormap", colormaps[selected_colormap].name.c_str())) + { + for (size_t i = 0; i < colormaps.size(); ++i) + { + if (ImGui::Selectable(colormaps[i].name.c_str(), selected_colormap == i)) + { selected_colormap = i; update_colormap(); } @@ -120,13 +118,13 @@ void TransferFunctionWidget::draw_ui() vec2f canvas_size = ImGui::GetContentRegionAvail(); // Note: If you're not using OpenGL for rendering your UI, the setup for // displaying the colormap texture in the UI will need to be updated. - ImGui::Image(reinterpret_cast(colormap_img), ImVec2(canvas_size.x, 16)); + ImGui::Image(reinterpret_cast(colormap_img), ImVec2(canvas_size.x, 16)); vec2f canvas_pos = ImGui::GetCursorScreenPos(); canvas_size.y -= 80; const float point_radius = 20.f; - ImDrawList* draw_list = ImGui::GetWindowDrawList(); + ImDrawList *draw_list = ImGui::GetWindowDrawList(); draw_list->PushClipRect(canvas_pos, canvas_pos + canvas_size); const vec2f view_scale(canvas_size.x, -canvas_size.y); @@ -135,65 +133,78 @@ void TransferFunctionWidget::draw_ui() draw_list->AddRect(canvas_pos, canvas_pos + canvas_size, ImColor(180, 180, 180, 255)); ImGui::InvisibleButton("tfn_canvas", canvas_size); - if (ImGui::IsItemHovered() || selected_point != (size_t)-1) { + if (ImGui::IsItemHovered() || selected_point != (size_t)-1) + { vec2f mouse_pos = (vec2f(io.MousePos) - view_offset) / view_scale; mouse_pos.x = clamp(mouse_pos.x, 0.f, 1.f); mouse_pos.y = clamp(mouse_pos.y, 0.f, 1.f); - - if (io.MouseDown[0]) { - if (selected_point != (size_t)-1) { + if (io.MouseDown[0]) + { + if (selected_point != (size_t)-1) + { alpha_control_pts[selected_point] = mouse_pos; - //make sure point does not cross + // make sure point does not cross - // Keep the first and last control points at the edges - if (selected_point == 0) { + // Keep the first and last control points at the edges + if (selected_point == 0) + { alpha_control_pts[selected_point].x = 0.f; } - else if (selected_point == alpha_control_pts.size() - 1) { + else if (selected_point == alpha_control_pts.size() - 1) + { alpha_control_pts[selected_point].x = 1.f; } - //make sure the other points do not cross + // make sure the other points do not cross else { alpha_control_pts[selected_point].x = (alpha_control_pts[selected_point].x < alpha_control_pts[selected_point - 1].x) - ? alpha_control_pts[selected_point - 1].x + 0.01 : alpha_control_pts[selected_point].x; + ? alpha_control_pts[selected_point - 1].x + 0.01 + : alpha_control_pts[selected_point].x; alpha_control_pts[selected_point].x = (alpha_control_pts[selected_point].x > alpha_control_pts[selected_point + 1].x) - ? alpha_control_pts[selected_point + 1].x - 0.01 : alpha_control_pts[selected_point].x; + ? alpha_control_pts[selected_point + 1].x - 0.01 + : alpha_control_pts[selected_point].x; } } - else { + else + { // See if we're selecting a point or adding one - if (io.MousePos.x - canvas_pos.x <= point_radius) { + if (io.MousePos.x - canvas_pos.x <= point_radius) + { selected_point = 0; } - else if (io.MousePos.x - canvas_pos.x >= canvas_size.x - point_radius) { + else if (io.MousePos.x - canvas_pos.x >= canvas_size.x - point_radius) + { selected_point = alpha_control_pts.size() - 1; } - else { + else + { auto fnd = std::find_if( - alpha_control_pts.begin(), alpha_control_pts.end(), [&](const vec2f& p) { + alpha_control_pts.begin(), alpha_control_pts.end(), [&](const vec2f &p) + { const vec2f pt_pos = p * view_scale + view_offset; float dist = (pt_pos - vec2f(io.MousePos)).length(); - return dist <= point_radius; - }); + return dist <= point_radius; }); // No nearby point, we're adding a new one - if (fnd == alpha_control_pts.end()) { + if (fnd == alpha_control_pts.end()) + { alpha_control_pts.push_back(mouse_pos); // Keep alpha control points ordered by x coordinate, update // selected point index to match std::sort(alpha_control_pts.begin(), - alpha_control_pts.end(), - [](const vec2f& a, const vec2f& b) { return a.x < b.x; }); - if (selected_point != 0 && selected_point != alpha_control_pts.size() - 1) { + alpha_control_pts.end(), + [](const vec2f &a, const vec2f &b) + { return a.x < b.x; }); + if (selected_point != 0 && selected_point != alpha_control_pts.size() - 1) + { fnd = std::find_if( - alpha_control_pts.begin(), alpha_control_pts.end(), [&](const vec2f& p) { + alpha_control_pts.begin(), alpha_control_pts.end(), [&](const vec2f &p) + { const vec2f pt_pos = p * view_scale + view_offset; float dist = (pt_pos - vec2f(io.MousePos)).length(); - return dist <= point_radius; - }); + return dist <= point_radius; }); } } selected_point = std::distance(alpha_control_pts.begin(), fnd); @@ -201,23 +212,26 @@ void TransferFunctionWidget::draw_ui() } update_colormap(); } - else if (ImGui::IsMouseClicked(1)) { + else if (ImGui::IsMouseClicked(1)) + { selected_point = -1; // Find and remove the point auto fnd = std::find_if( - alpha_control_pts.begin(), alpha_control_pts.end(), [&](const vec2f& p) { + alpha_control_pts.begin(), alpha_control_pts.end(), [&](const vec2f &p) + { const vec2f pt_pos = p * view_scale + view_offset; float dist = (pt_pos - vec2f(io.MousePos)).length(); - return dist <= point_radius; - }); + return dist <= point_radius; }); // We also want to prevent erasing the first and last points if (fnd != alpha_control_pts.end() && fnd != alpha_control_pts.begin() && - fnd != alpha_control_pts.end() - 1) { + fnd != alpha_control_pts.end() - 1) + { alpha_control_pts.erase(fnd); } update_colormap(); } - else { + else + { selected_point = -1; } } @@ -225,17 +239,17 @@ void TransferFunctionWidget::draw_ui() // Draw the alpha control points, and build the points for the polyline // which connects them std::vector polyline_pts; - for (const auto& pt : alpha_control_pts) { + for (const auto &pt : alpha_control_pts) + { const vec2f pt_pos = pt * view_scale + view_offset; polyline_pts.push_back(pt_pos); draw_list->AddCircleFilled(pt_pos, point_radius, 0xFFFFFFFF); } - draw_list->AddPolyline(polyline_pts.data(), polyline_pts.size(), 0xFFFFFFFF, false, 2.f); draw_list->PopClipRect(); - //Add Label tick marks + // Add Label tick marks int nbTicks = 5; vec2f tick_pos = ImGui::GetCursorScreenPos(); tick_pos.y -= ImGui::GetStyle().ItemSpacing.y; @@ -243,27 +257,32 @@ void TransferFunctionWidget::draw_ui() tick_size.y = 5; draw_list->PushClipRect(tick_pos, ImVec2(tick_pos.x + tick_size.x, tick_pos.y + tick_size.y)); - for (int i = 0; i < nbTicks; i++) { + for (int i = 0; i < nbTicks; i++) + { float percentage = float(i) / (nbTicks - 1); draw_list->AddLine(ImVec2(tick_pos.x + percentage * (tick_size.x - 1), tick_size.y), - ImVec2(tick_pos.x + percentage * (tick_size.x - 1), tick_pos.y + tick_size.y), ImColor(255, 255, 255, 255), 1); + ImVec2(tick_pos.x + percentage * (tick_size.x - 1), tick_pos.y + tick_size.y), ImColor(255, 255, 255, 255), 1); } draw_list->PopClipRect(); - //Add Label text + // Add Label text const float ItemSpacing = ImGui::GetStyle().ItemSpacing.x; - for (int i = 0; i < nbTicks; i++) { + for (int i = 0; i < nbTicks; i++) + { float percentage = float(i) / (nbTicks - 1); float val = (m_min_max_val[1] - m_min_max_val[0]) * percentage + m_min_max_val[0]; std::stringstream text; text << std::fixed << std::setprecision(4) << val; - if (i == 0) { + if (i == 0) + { } - else if (i == nbTicks - 1) { + else if (i == nbTicks - 1) + { ImGui::SameLine(ImGui::GetWindowWidth() - ItemSpacing - ImGui::CalcTextSize(text.str().c_str()).x); } - else { + else + { ImGui::SameLine((ImGui::GetWindowWidth()) * percentage - ImGui::CalcTextSize(text.str().c_str()).x * 0.5); } ImGui::Text(text.str().c_str()); @@ -283,29 +302,30 @@ std::vector TransferFunctionWidget::get_colormap() std::vector TransferFunctionWidget::get_colormapf() { std::vector colormapf(current_colormap.size(), 0.f); - for (size_t i = 0; i < current_colormap.size(); ++i) { + for (size_t i = 0; i < current_colormap.size(); ++i) + { colormapf[i] = current_colormap[i] / 255.f; } return colormapf; } -void TransferFunctionWidget::setHistogram(const std::vector& hist) +void TransferFunctionWidget::setHistogram(const std::vector &hist) { current_histogram = hist; } -std::vector& TransferFunctionWidget::getHistogram() +std::vector &TransferFunctionWidget::getHistogram() { return current_histogram; } -void TransferFunctionWidget::setMinMax(const float min, const float max) { +void TransferFunctionWidget::setMinMax(const float min, const float max) +{ m_min_max_val[0] = min; m_min_max_val[1] = max; } - -void TransferFunctionWidget::setBlendedHistogram(const std::vector& hist1, const std::vector& hist2, float alpha) +void TransferFunctionWidget::setBlendedHistogram(const std::vector &hist1, const std::vector &hist2, float alpha) { if (hist1.size() != hist2.size()) return; @@ -315,12 +335,12 @@ void TransferFunctionWidget::setBlendedHistogram(const std::vector& hist1 current_histogram.push_back(hist1[i] * alpha + hist2[i] * (1.0f - alpha)); } - -void TransferFunctionWidget::get_colormapf(std::vector& color, std::vector& opacity) +void TransferFunctionWidget::get_colormapf(std::vector &color, std::vector &opacity) { color.resize((current_colormap.size() / 4) * 3); opacity.resize(current_colormap.size() / 4); - for (size_t i = 0; i < current_colormap.size() / 4; ++i) { + for (size_t i = 0; i < current_colormap.size() / 4; ++i) + { color[i * 3] = current_colormap[i * 4] / 255.f; color[i * 3 + 1] = current_colormap[i * 4 + 1] / 255.f; color[i * 3 + 2] = current_colormap[i * 4 + 2] / 255.f; @@ -328,14 +348,14 @@ void TransferFunctionWidget::get_colormapf(std::vector& color, std::vecto } } -void TransferFunctionWidget::drawLegend() { +void TransferFunctionWidget::draw_legend() +{ GLint viewport[4]; GLfloat projection[16]; GLfloat modelview[16]; - int min[2] = { 50 , 100 }; - int max[2] = { 400 , 120 }; - + int min[2] = {50, 100}; + int max[2] = {400, 120}; glGetIntegerv(GL_VIEWPORT, &viewport[0]); glGetFloatv(GL_PROJECTION_MATRIX, &projection[0]); @@ -383,12 +403,11 @@ void TransferFunctionWidget::drawLegend() { glBindTexture(GL_TEXTURE_2D, 0); - - - //Add Label tick marks + // Add Label tick marks int nbTicks = 4; float diff = (max[0] - min[0]) / nbTicks; - for (int i = 0; i <= nbTicks; i++) { + for (int i = 0; i <= nbTicks; i++) + { float pos_x = min[0] + i * diff; glBegin(GL_LINES); glColor4f(1.0f, 1.0f, 1.0f, 1.0f); @@ -410,26 +429,44 @@ void TransferFunctionWidget::drawLegend() { glLoadMatrixf(projection); glMatrixMode(GL_MODELVIEW); glLoadMatrixf(modelview); +} - - +void TransferFunctionWidget::draw_legend(float legend_pos_x, float legend_pos_y, float legend_width, float legend_height) +{ + bool show_legend = true; + ImGui::SetNextWindowPos(ImVec2(legend_pos_x, legend_pos_y)); + ImGui::SetNextWindowSize(ImVec2(legend_width, legend_height)); + ImGui::Begin("##legend", &show_legend, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoTitleBar); + ImGuiIO &io = ImGui::GetIO(); + ImTextureID my_tex_id = io.Fonts->TexID; + float texture_width = (float)io.Fonts->TexWidth; + float texture_height = (float)io.Fonts->TexHeight; + std::string max_str = std::to_string(m_min_max_val[1]); + float offset = 0.008 * (texture_width * max_str.size()); + ImGui::Image(reinterpret_cast(colormap_img), ImVec2(legend_width, 16)); + ImGui::Text("%.0f", m_min_max_val[0]); + ImGui::SameLine((legend_width / 2)); + ImGui::Text("%.0f", (m_min_max_val[0] + m_min_max_val[1]) / 2); + ImGui::SameLine(ImGui::GetWindowWidth() - offset); + ImGui::Text(" %.0f", m_min_max_val[1]); + ImGui::End(); } void TransferFunctionWidget::draw_histogram() { - const ImGuiIO& io = ImGui::GetIO(); + const ImGuiIO &io = ImGui::GetIO(); ImGui::Text("Histogram"); vec2f canvas_size = ImGui::GetContentRegionAvail(); // Note: If you're not using OpenGL for rendering your UI, the setup for // displaying the colormap texture in the UI will need to be updated. - // ImGui::Image(reinterpret_cast(colormap_img), ImVec2(canvas_size.x, 16)); + // TODO(#45) ImGui::Image(reinterpret_cast(colormap_img), ImVec2(canvas_size.x, 16)); vec2f canvas_pos = ImGui::GetCursorScreenPos(); canvas_size.y -= 250; - ImDrawList* draw_list = ImGui::GetWindowDrawList(); + ImDrawList *draw_list = ImGui::GetWindowDrawList(); draw_list->PushClipRect(canvas_pos, canvas_pos + canvas_size); const vec2f view_scale(canvas_size.x, -canvas_size.y); @@ -439,24 +476,18 @@ void TransferFunctionWidget::draw_histogram() ImGui::InvisibleButton("hstg_canvas", canvas_size); - // Draw the alpha control points, and build the points for the polyline // which connects them - - //Code to Draw histogram in the UI - for (int i = 0; i < current_histogram.size(); i++) { + // Code to Draw histogram in the UI + for (int i = 0; i < current_histogram.size(); i++) + { vec2f lp = vec2f(((float)i) / current_histogram.size(), 0.0f); vec2f hp = vec2f(((float)i + 1.0f) / current_histogram.size(), current_histogram[i]); draw_list->AddRectFilled(lp * view_scale + view_offset, hp * view_scale + view_offset, 0x77777777); } - draw_list->PopClipRect(); - - - - } void TransferFunctionWidget::update_gpu_image() @@ -464,7 +495,8 @@ void TransferFunctionWidget::update_gpu_image() GLint prev_tex_2d = 0; glGetIntegerv(GL_TEXTURE_BINDING_2D, &prev_tex_2d); - if (colormap_img == (GLuint)-1) { + if (colormap_img == (GLuint)-1) + { glGenTextures(1, &colormap_img); glBindTexture(GL_TEXTURE_2D, colormap_img); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); @@ -472,19 +504,21 @@ void TransferFunctionWidget::update_gpu_image() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } - if (colormap_changed) { + if (colormap_changed) + { glBindTexture(GL_TEXTURE_2D, colormap_img); glTexImage2D(GL_TEXTURE_2D, - 0, - GL_RGBA, - current_colormap.size() / 4, - 1, - 0, - GL_RGBA, - GL_UNSIGNED_BYTE, - current_colormap.data()); + 0, + GL_RGBA, + current_colormap.size() / 4, + 1, + 0, + GL_RGBA, + GL_UNSIGNED_BYTE, + current_colormap.data()); } - if (prev_tex_2d != 0) { + if (prev_tex_2d != 0) + { glBindTexture(GL_TEXTURE_2D, prev_tex_2d); } } @@ -498,10 +532,12 @@ void TransferFunctionWidget::update_colormap() auto a_it = alpha_control_pts.begin(); const size_t npixels = current_colormap.size() / 4; - for (size_t i = 0; i < npixels; ++i) { + for (size_t i = 0; i < npixels; ++i) + { float x = static_cast(i) / npixels; auto high = a_it + 1; - if (x > high->x) { + if (x > high->x) + { ++a_it; ++high; } @@ -517,21 +553,19 @@ void TransferFunctionWidget::set_Quantiles(float min, float max) m_quantiles[1] = max; } - -void TransferFunctionWidget::get_Quantiles(float& min, float& max) +void TransferFunctionWidget::get_Quantiles(float &min, float &max) { min = m_quantiles[0]; max = m_quantiles[1]; } -void TransferFunctionWidget::load_embedded_preset(const uint8_t* buf, - size_t size, - const std::string& name) +void TransferFunctionWidget::load_embedded_preset(const uint8_t *buf, + size_t size, + const std::string &name) { int w, h, n; - uint8_t* img_data = stbi_load_from_memory(buf, size, &w, &h, &n, 4); + uint8_t *img_data = stbi_load_from_memory(buf, size, &w, &h, &n, 4); auto img = std::vector(img_data, img_data + w * 1 * 4); stbi_image_free(img_data); colormaps.emplace_back(name, img); } - diff --git a/libs/UIHelpers/transfer_function_widget.h b/libs/UIHelpers/transfer_function_widget.h index 47ff3e7..7a15b1c 100644 --- a/libs/UIHelpers/transfer_function_widget.h +++ b/libs/UIHelpers/transfer_function_widget.h @@ -1,7 +1,6 @@ #ifndef TransferFunctionWidget_H_ #define TransferFunctionWidget_H_ - #ifdef _WIN32 #include "GL/glew.h" #include "GL/wglew.h" @@ -23,105 +22,98 @@ #include #endif - - - #include #include #include #include "imgui/imgui.h" #include "Vec2.h" -struct Colormap { - std::string name; - // An RGBA8 1D image - std::vector colormap; +struct Colormap +{ + std::string name; + // An RGBA8 1D image + std::vector colormap; - Colormap(const std::string &name, const std::vector &img); + Colormap(const std::string &name, const std::vector &img); }; -class TransferFunctionWidget { - +class TransferFunctionWidget +{ - std::vector colormaps; - - std::vector current_colormap; + std::vector colormaps; - - size_t selected_point = -1; + std::vector current_colormap; - bool colormap_changed = true; - GLuint colormap_img = -1; + size_t selected_point = -1; - std::vector current_histogram; - float m_min_max_val[2]; + bool colormap_changed = true; + GLuint colormap_img = -1; -public: + std::vector current_histogram; + float m_min_max_val[2]; - +public: size_t selected_colormap = 0; - std::vector alpha_control_pts = { vec2f(0.f), vec2f(1.f) }; + std::vector alpha_control_pts = {vec2f(0.f), vec2f(1.f)}; - TransferFunctionWidget(); + TransferFunctionWidget(); - // Add a colormap preset. The image should be a 1D RGBA8 image - void add_colormap(const Colormap &map); + // Add a colormap preset. The image should be a 1D RGBA8 image + void add_colormap(const Colormap &map); - // Add the transfer function UI into the currently active window - void draw_ui(); + // Add the transfer function UI into the currently active window + void draw_ui(); - // Returns true if the colormap was updated since the last - // call to draw_ui - bool changed() const; + // Returns true if the colormap was updated since the last + // call to draw_ui + bool changed() const; - // Get back the RGBA8 color data for the transfer function - std::vector get_colormap(); + // Get back the RGBA8 color data for the transfer function + std::vector get_colormap(); - // Get back the RGBA32F color data for the transfer function - std::vector get_colormapf(); + // Get back the RGBA32F color data for the transfer function + std::vector get_colormapf(); - void setHistogram(const std::vector &hist); + void setHistogram(const std::vector &hist); - std::vector& getHistogram(); + std::vector &getHistogram(); - void setMinMax(const float min, const float max); + void setMinMax(const float min, const float max); - void setBlendedHistogram(const std::vector& hist1, const std::vector& hist2, float alpha); + void setBlendedHistogram(const std::vector &hist1, const std::vector &hist2, float alpha); - // Get back the RGBA32F color data for the transfer function - // as separate color and opacity vectors - void get_colormapf(std::vector &color, std::vector &opacity); + // Get back the RGBA32F color data for the transfer function + // as separate color and opacity vectors + void get_colormapf(std::vector &color, std::vector &opacity); - GLint get_colormap_gpu() - { - return colormap_img; - } + GLint get_colormap_gpu() + { + return colormap_img; + } void set_colormap_gpu(GLint colormap) { colormap_img = colormap; } - - void drawLegend(); + + void draw_legend(); + + void draw_legend(float legend_pos_x, float legend_pos_y, float legend_width, float legend_height); void draw_histogram(); void update_colormap(); - void set_Quantiles(float min, float max); + void set_quantiles(float min, float max); - void get_Quantiles(float& min, float& max); + void get_quantiles(float &min, float &max); private: - void update_gpu_image(); + void update_gpu_image(); - + void load_embedded_preset(const uint8_t *buf, size_t size, const std::string &name); - void load_embedded_preset(const uint8_t *buf, size_t size, const std::string &name); - - float m_quantiles[2]; - + float m_quantiles[2]; }; - #endif \ No newline at end of file diff --git a/libs/transferfunction/transfer_function_widget.cpp b/libs/transferfunction/transfer_function_widget.cpp index 67d7aff..8ccc853 100644 --- a/libs/transferfunction/transfer_function_widget.cpp +++ b/libs/transferfunction/transfer_function_widget.cpp @@ -16,10 +16,12 @@ template T clamp(T x, T min, T max) { - if (x < min) { + if (x < min) + { return min; } - if (x > max) { + if (x > max) + { return max; } return x; @@ -73,14 +75,14 @@ TransferFunctionWidget::vec2f::operator ImVec2() const TransferFunctionWidget::TransferFunctionWidget() { // Load up the embedded colormaps as the default options - load_embedded_preset(cool_warm_extended, sizeof(cool_warm_extended), "Cool Warm Extended"); - load_embedded_preset(paraview_cool_warm, sizeof(paraview_cool_warm), "ParaView Cool Warm"); + load_embedded_preset(cool_warm_extended, sizeof(cool_warm_extended), "Cool Warm Extended"); + load_embedded_preset(paraview_cool_warm, sizeof(paraview_cool_warm), "ParaView Cool Warm"); load_embedded_preset(rainbow, sizeof(rainbow), "Rainbow"); load_embedded_preset(matplotlib_plasma, sizeof(matplotlib_plasma), "Matplotlib Plasma"); load_embedded_preset(matplotlib_virdis, sizeof(matplotlib_virdis), "Matplotlib Virdis"); load_embedded_preset(samsel_linear_green, sizeof(samsel_linear_green), "Samsel Linear Green"); load_embedded_preset(samsel_linear_ygb_1211g, sizeof(samsel_linear_ygb_1211g), "Samsel Linear YGB 1211G"); - load_embedded_preset(blackbody, sizeof(blackbody), "Black Body"); + load_embedded_preset(blackbody, sizeof(blackbody), "Black Body"); load_embedded_preset(jet, sizeof(jet), "Jet"); load_embedded_preset(blue_gold, sizeof(blue_gold), "Blue Gold"); load_embedded_preset(ice_fire, sizeof(ice_fire), "Ice Fire"); @@ -89,12 +91,11 @@ TransferFunctionWidget::TransferFunctionWidget() // Initialize the colormap alpha channel w/ a linear ramp update_colormap(); - for (int i = 0; i < 255; i++) - current_histogram.push_back(static_cast (rand()) / static_cast (RAND_MAX)); + for (int i = 0; i < 255; i++) + current_histogram.push_back(static_cast(rand()) / static_cast(RAND_MAX)); - - m_min_max_val[0] = 0.0f; - m_min_max_val[1] = 1.0f; + m_min_max_val[0] = 0.0f; + m_min_max_val[1] = 1.0f; } void TransferFunctionWidget::add_colormap(const Colormap &map) @@ -114,9 +115,12 @@ void TransferFunctionWidget::draw_ui() "Left click to add a point, right click remove. " "Left click + drag to move points."); - if (ImGui::BeginCombo("Colormap", colormaps[selected_colormap].name.c_str())) { - for (size_t i = 0; i < colormaps.size(); ++i) { - if (ImGui::Selectable(colormaps[i].name.c_str(), selected_colormap == i)) { + if (ImGui::BeginCombo("Colormap", colormaps[selected_colormap].name.c_str())) + { + for (size_t i = 0; i < colormaps.size(); ++i) + { + if (ImGui::Selectable(colormaps[i].name.c_str(), selected_colormap == i)) + { selected_colormap = i; update_colormap(); } @@ -142,83 +146,106 @@ void TransferFunctionWidget::draw_ui() draw_list->AddRect(canvas_pos, canvas_pos + canvas_size, ImColor(180, 180, 180, 255)); ImGui::InvisibleButton("tfn_canvas", canvas_size); - if (ImGui::IsItemHovered() || selected_point != (size_t)-1) { - + if (ImGui::IsItemHovered() || selected_point != (size_t)-1) + { + vec2f mouse_pos = (vec2f(io.MousePos) - view_offset) / view_scale; mouse_pos.x = clamp(mouse_pos.x, 0.f, 1.f); mouse_pos.y = clamp(mouse_pos.y, 0.f, 1.f); - //bool requires_sorting = false; - - if (io.MouseDown[0]) { - if (selected_point != (size_t)-1) { - alpha_control_pts[selected_point] = mouse_pos; - - //make sure point does not cross - + // bool requires_sorting = false; + + if (io.MouseDown[0]) + { + if (selected_point != (size_t)-1) + { + alpha_control_pts[selected_point] = mouse_pos; + + // make sure point does not cross + // Keep the first and last control points at the edges - if (selected_point == 0) { + if (selected_point == 0) + { alpha_control_pts[selected_point].x = 0.f; - } else if (selected_point == alpha_control_pts.size() - 1) { + } + else if (selected_point == alpha_control_pts.size() - 1) + { alpha_control_pts[selected_point].x = 1.f; } - //make sure the other points do not cross - else + // make sure the other points do not cross + else { - alpha_control_pts[selected_point].x = (alpha_control_pts[selected_point].x < alpha_control_pts[selected_point - 1].x) - ? alpha_control_pts[selected_point - 1].x + 0.01 : alpha_control_pts[selected_point].x; - alpha_control_pts[selected_point].x = (alpha_control_pts[selected_point].x > alpha_control_pts[selected_point + 1].x) - ? alpha_control_pts[selected_point + 1].x - 0.01 : alpha_control_pts[selected_point].x; + alpha_control_pts[selected_point].x = (alpha_control_pts[selected_point].x < alpha_control_pts[selected_point - 1].x) + ? alpha_control_pts[selected_point - 1].x + 0.01 + : alpha_control_pts[selected_point].x; + alpha_control_pts[selected_point].x = (alpha_control_pts[selected_point].x > alpha_control_pts[selected_point + 1].x) + ? alpha_control_pts[selected_point + 1].x - 0.01 + : alpha_control_pts[selected_point].x; } - } else { + } + else + { // See if we're selecting a point or adding one - if (io.MousePos.x - canvas_pos.x <= point_radius) { + if (io.MousePos.x - canvas_pos.x <= point_radius) + { selected_point = 0; - } else if (io.MousePos.x - canvas_pos.x >= canvas_size.x - point_radius) { + } + else if (io.MousePos.x - canvas_pos.x >= canvas_size.x - point_radius) + { selected_point = alpha_control_pts.size() - 1; - } else { + } + else + { auto fnd = std::find_if( - alpha_control_pts.begin(), alpha_control_pts.end(), [&](const vec2f &p) { + alpha_control_pts.begin(), alpha_control_pts.end(), [&](const vec2f &p) + { const vec2f pt_pos = p * view_scale + view_offset; float dist = (pt_pos - vec2f(io.MousePos)).length(); - return dist <= point_radius; - }); + return dist <= point_radius; }); // No nearby point, we're adding a new one - if (fnd == alpha_control_pts.end()) { + if (fnd == alpha_control_pts.end()) + { alpha_control_pts.push_back(mouse_pos); - // Keep alpha control points ordered by x coordinate, update - // selected point index to match - std::sort(alpha_control_pts.begin(), - alpha_control_pts.end(), - [](const vec2f& a, const vec2f& b) { return a.x < b.x; }); - if (selected_point != 0 && selected_point != alpha_control_pts.size() - 1) { - fnd = std::find_if( - alpha_control_pts.begin(), alpha_control_pts.end(), [&](const vec2f& p) { + // Keep alpha control points ordered by x coordinate, update + // selected point index to match + std::sort(alpha_control_pts.begin(), + alpha_control_pts.end(), + [](const vec2f &a, const vec2f &b) + { return a.x < b.x; }); + if (selected_point != 0 && selected_point != alpha_control_pts.size() - 1) + { + fnd = std::find_if( + alpha_control_pts.begin(), alpha_control_pts.end(), [&](const vec2f &p) + { const vec2f pt_pos = p * view_scale + view_offset; float dist = (pt_pos - vec2f(io.MousePos)).length(); - return dist <= point_radius; - }); - } + return dist <= point_radius; }); + } } - selected_point = std::distance(alpha_control_pts.begin(), fnd); + selected_point = std::distance(alpha_control_pts.begin(), fnd); } } update_colormap(); - } else if (ImGui::IsMouseClicked(1)) { + } + else if (ImGui::IsMouseClicked(1)) + { selected_point = -1; // Find and remove the point auto fnd = std::find_if( - alpha_control_pts.begin(), alpha_control_pts.end(), [&](const vec2f &p) { + alpha_control_pts.begin(), alpha_control_pts.end(), [&](const vec2f &p) + { const vec2f pt_pos = p * view_scale + view_offset; float dist = (pt_pos - vec2f(io.MousePos)).length(); - return dist <= point_radius; - }); + return dist <= point_radius; }); // We also want to prevent erasing the first and last points if (fnd != alpha_control_pts.end() && fnd != alpha_control_pts.begin() && - fnd != alpha_control_pts.end() - 1) { + fnd != alpha_control_pts.end() - 1) + { alpha_control_pts.erase(fnd); } update_colormap(); - } else { + } + else + { selected_point = -1; } } @@ -226,55 +253,61 @@ void TransferFunctionWidget::draw_ui() // Draw the alpha control points, and build the points for the polyline // which connects them std::vector polyline_pts; - for (const auto &pt : alpha_control_pts) { + for (const auto &pt : alpha_control_pts) + { const vec2f pt_pos = pt * view_scale + view_offset; polyline_pts.push_back(pt_pos); draw_list->AddCircleFilled(pt_pos, point_radius, 0xFFFFFFFF); } - //Code to Draw histogram in the UI - /*for (int i = 0; i < current_histogram.size(); i++) { - // vec2f lp = vec2f( ((float) i) / current_histogram.size(), 0.0f); - // vec2f hp = vec2f( ((float) i + 1.0f) / current_histogram.size(), current_histogram[i]); - // draw_list->AddRectFilled(lp * view_scale + view_offset, hp * view_scale + view_offset, 0x77777777); - //} - */ + // Code to Draw histogram in the UI + /*for (int i = 0; i < current_histogram.size(); i++) { + // vec2f lp = vec2f( ((float) i) / current_histogram.size(), 0.0f); + // vec2f hp = vec2f( ((float) i + 1.0f) / current_histogram.size(), current_histogram[i]); + // draw_list->AddRectFilled(lp * view_scale + view_offset, hp * view_scale + view_offset, 0x77777777); + //} + */ draw_list->AddPolyline(polyline_pts.data(), polyline_pts.size(), 0xFFFFFFFF, false, 2.f); draw_list->PopClipRect(); - //Add Label tick marks - int nbTicks = 5; - vec2f tick_pos = ImGui::GetCursorScreenPos(); - tick_pos.y -= ImGui::GetStyle().ItemSpacing.y; - vec2f tick_size = ImGui::GetContentRegionAvail(); - tick_size.y = 5; - draw_list->PushClipRect(tick_pos, ImVec2(tick_pos.x + tick_size.x, tick_pos.y + tick_size.y)); - - for (int i = 0; i < nbTicks; i++) { - float percentage = float(i) / (nbTicks - 1); - - draw_list->AddLine(ImVec2(tick_pos.x + percentage*(tick_size.x -1), tick_size.y), - ImVec2(tick_pos.x + percentage * (tick_size.x - 1), tick_pos.y + tick_size.y), ImColor(255, 255, 255, 255), 1); - } - draw_list->PopClipRect(); - - //Add Label text - const float ItemSpacing = ImGui::GetStyle().ItemSpacing.x; - for (int i = 0; i < nbTicks; i++) { - float percentage = float(i) / (nbTicks - 1); - float val = (m_min_max_val[1] - m_min_max_val[0]) * percentage + m_min_max_val[0]; - std::stringstream text; - text << std::fixed << std::setprecision(4) << val; - if (i == 0) { - } - else if (i == nbTicks - 1) { - ImGui::SameLine(ImGui::GetWindowWidth() - ItemSpacing - ImGui::CalcTextSize(text.str().c_str()).x); - } - else { - ImGui::SameLine((ImGui::GetWindowWidth()) * percentage - ImGui::CalcTextSize(text.str().c_str()).x * 0.5); - } - ImGui::Text(text.str().c_str()); - } + // Add Label tick marks + int nbTicks = 5; + vec2f tick_pos = ImGui::GetCursorScreenPos(); + tick_pos.y -= ImGui::GetStyle().ItemSpacing.y; + vec2f tick_size = ImGui::GetContentRegionAvail(); + tick_size.y = 5; + draw_list->PushClipRect(tick_pos, ImVec2(tick_pos.x + tick_size.x, tick_pos.y + tick_size.y)); + + for (int i = 0; i < nbTicks; i++) + { + float percentage = float(i) / (nbTicks - 1); + + draw_list->AddLine(ImVec2(tick_pos.x + percentage * (tick_size.x - 1), tick_size.y), + ImVec2(tick_pos.x + percentage * (tick_size.x - 1), tick_pos.y + tick_size.y), ImColor(255, 255, 255, 255), 1); + } + draw_list->PopClipRect(); + + // Add Label text + const float ItemSpacing = ImGui::GetStyle().ItemSpacing.x; + for (int i = 0; i < nbTicks; i++) + { + float percentage = float(i) / (nbTicks - 1); + float val = (m_min_max_val[1] - m_min_max_val[0]) * percentage + m_min_max_val[0]; + std::stringstream text; + text << std::fixed << std::setprecision(4) << val; + if (i == 0) + { + } + else if (i == nbTicks - 1) + { + ImGui::SameLine(ImGui::GetWindowWidth() - ItemSpacing - ImGui::CalcTextSize(text.str().c_str()).x); + } + else + { + ImGui::SameLine((ImGui::GetWindowWidth()) * percentage - ImGui::CalcTextSize(text.str().c_str()).x * 0.5); + } + ImGui::Text(text.str().c_str()); + } } bool TransferFunctionWidget::changed() const @@ -290,7 +323,8 @@ std::vector TransferFunctionWidget::get_colormap() std::vector TransferFunctionWidget::get_colormapf() { std::vector colormapf(current_colormap.size(), 0.f); - for (size_t i = 0; i < current_colormap.size(); ++i) { + for (size_t i = 0; i < current_colormap.size(); ++i) + { colormapf[i] = current_colormap[i] / 255.f; } return colormapf; @@ -298,31 +332,31 @@ std::vector TransferFunctionWidget::get_colormapf() void TransferFunctionWidget::setHistogram(const std::vector &hist) { - current_histogram = hist; + current_histogram = hist; } -void TransferFunctionWidget::setMinMax(const float min, const float max) { - m_min_max_val[0] = min; - m_min_max_val[1] = max; +void TransferFunctionWidget::setMinMax(const float min, const float max) +{ + m_min_max_val[0] = min; + m_min_max_val[1] = max; } - -void TransferFunctionWidget::setBlendedHistogram(const std::vector& hist1, const std::vector& hist2, float alpha) +void TransferFunctionWidget::setBlendedHistogram(const std::vector &hist1, const std::vector &hist2, float alpha) { - if (hist1.size() != hist2.size()) - return; + if (hist1.size() != hist2.size()) + return; - current_histogram.clear(); - for (int i = 0; i < hist1.size(); i++) - current_histogram.push_back(hist1[i] * alpha + hist2[i] * (1.0f - alpha)); + current_histogram.clear(); + for (int i = 0; i < hist1.size(); i++) + current_histogram.push_back(hist1[i] * alpha + hist2[i] * (1.0f - alpha)); } - void TransferFunctionWidget::get_colormapf(std::vector &color, std::vector &opacity) { color.resize((current_colormap.size() / 4) * 3); opacity.resize(current_colormap.size() / 4); - for (size_t i = 0; i < current_colormap.size() / 4; ++i) { + for (size_t i = 0; i < current_colormap.size() / 4; ++i) + { color[i * 3] = current_colormap[i * 4] / 255.f; color[i * 3 + 1] = current_colormap[i * 4 + 1] / 255.f; color[i * 3 + 2] = current_colormap[i * 4 + 2] / 255.f; @@ -330,141 +364,132 @@ void TransferFunctionWidget::get_colormapf(std::vector &color, std::vecto } } -void TransferFunctionWidget::drawLegend() { - /*GLint viewport[4]; - GLfloat projection[16]; - GLfloat modelview[16]; - - int min [2] = { 50 , 100 }; - int max [2] = { 400 , 120 }; - - - glGetIntegerv(GL_VIEWPORT, &viewport[0]); - glGetFloatv(GL_PROJECTION_MATRIX, &projection[0]); - glGetFloatv(GL_MODELVIEW_MATRIX, &modelview[0]); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0, viewport[2], 0, viewport[3], -1, 1); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - glDisable(GL_LIGHTING); - glEnable(GL_TEXTURE_2D); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - glBindTexture(GL_TEXTURE_2D, colormap_img); - glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - glBegin(GL_QUADS); - glTexCoord2f(0, 1); - glVertex3f(min[0], max[1], 0); - glTexCoord2f(1, 1); - glVertex3f(max[0], max[1], 0); - glTexCoord2f(1, 0); - glVertex3f(max[0], 0.5f * (min[1] + max[1]), 0); - glTexCoord2f(0, 0); - glVertex3f(min[0], 0.5f * (min[1] + max[1]), 0); - glEnd(); - glDisable(GL_BLEND); - glBindTexture(GL_TEXTURE_2D, 0); - - glBindTexture(GL_TEXTURE_2D, colormap_img); - glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - glBegin(GL_QUADS); - glTexCoord2f(0, 1); - glVertex3f(min[0], 0.5f * (min[1] + max[1]), 0); - glTexCoord2f(1, 1); - glVertex3f(max[0], 0.5f * (min[1] + max[1]), 0); - glTexCoord2f(1, 0); - glVertex3f(max[0], min[1], 0); - glTexCoord2f(0, 0); - glVertex3f(min[0], min[1], 0); - glEnd(); - glDisable(GL_TEXTURE_2D); - - glBindTexture(GL_TEXTURE_2D, 0); - - - - //Add Label tick marks - int nbTicks = 4; - float diff = (max[0] - min[0])/nbTicks; - for (int i = 0; i <= nbTicks; i++) { - float pos_x = min[0] + i * diff; - glBegin(GL_LINES); - glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - glVertex3f(pos_x, min[1], 0); - glVertex3f(pos_x, min[1] - 5, 0); - glEnd(); - - float percentage = float(i) / (nbTicks); - float val = (m_min_max_val[1] - m_min_max_val[0]) * percentage + m_min_max_val[0]; - std::stringstream text; - text << std::fixed << std::setprecision(4) << val; - - FontHandler::getInstance()->renderTextBox(text.str(), pos_x - 100 , min[1] - 15, 0, 200.0, 10, TextAlignment::CENTER); - } - - glEnable(GL_LIGHTING); - - glMatrixMode(GL_PROJECTION); - glLoadMatrixf(projection); - glMatrixMode(GL_MODELVIEW); - glLoadMatrixf(modelview); +void TransferFunctionWidget::drawLegend() +{ + /*GLint viewport[4]; + GLfloat projection[16]; + GLfloat modelview[16]; + + int min [2] = { 50 , 100 }; + int max [2] = { 400 , 120 }; + + + glGetIntegerv(GL_VIEWPORT, &viewport[0]); + glGetFloatv(GL_PROJECTION_MATRIX, &projection[0]); + glGetFloatv(GL_MODELVIEW_MATRIX, &modelview[0]); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, viewport[2], 0, viewport[3], -1, 1); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glDisable(GL_LIGHTING); + glEnable(GL_TEXTURE_2D); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glBindTexture(GL_TEXTURE_2D, colormap_img); + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + glBegin(GL_QUADS); + glTexCoord2f(0, 1); + glVertex3f(min[0], max[1], 0); + glTexCoord2f(1, 1); + glVertex3f(max[0], max[1], 0); + glTexCoord2f(1, 0); + glVertex3f(max[0], 0.5f * (min[1] + max[1]), 0); + glTexCoord2f(0, 0); + glVertex3f(min[0], 0.5f * (min[1] + max[1]), 0); + glEnd(); + glDisable(GL_BLEND); + glBindTexture(GL_TEXTURE_2D, 0); + + glBindTexture(GL_TEXTURE_2D, colormap_img); + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + glBegin(GL_QUADS); + glTexCoord2f(0, 1); + glVertex3f(min[0], 0.5f * (min[1] + max[1]), 0); + glTexCoord2f(1, 1); + glVertex3f(max[0], 0.5f * (min[1] + max[1]), 0); + glTexCoord2f(1, 0); + glVertex3f(max[0], min[1], 0); + glTexCoord2f(0, 0); + glVertex3f(min[0], min[1], 0); + glEnd(); + glDisable(GL_TEXTURE_2D); + + glBindTexture(GL_TEXTURE_2D, 0); + + + + //Add Label tick marks + int nbTicks = 4; + float diff = (max[0] - min[0])/nbTicks; + for (int i = 0; i <= nbTicks; i++) { + float pos_x = min[0] + i * diff; + glBegin(GL_LINES); + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + glVertex3f(pos_x, min[1], 0); + glVertex3f(pos_x, min[1] - 5, 0); + glEnd(); + + float percentage = float(i) / (nbTicks); + float val = (m_min_max_val[1] - m_min_max_val[0]) * percentage + m_min_max_val[0]; + std::stringstream text; + text << std::fixed << std::setprecision(4) << val; + + FontHandler::getInstance()->renderTextBox(text.str(), pos_x - 100 , min[1] - 15, 0, 200.0, 10, TextAlignment::CENTER); + } -*/ + glEnable(GL_LIGHTING); + glMatrixMode(GL_PROJECTION); + glLoadMatrixf(projection); + glMatrixMode(GL_MODELVIEW); + glLoadMatrixf(modelview); + +*/ } void TransferFunctionWidget::draw_histogram() { - //update_gpu_image(); - - - const ImGuiIO& io = ImGui::GetIO(); + // update_gpu_image(); - ImGui::Text("Histogram"); - - vec2f canvas_size = ImGui::GetContentRegionAvail(); - // Note: If you're not using OpenGL for rendering your UI, the setup for - // displaying the colormap texture in the UI will need to be updated. - ImGui::Image(reinterpret_cast(colormap_img), ImVec2(canvas_size.x, 16)); - vec2f canvas_pos = ImGui::GetCursorScreenPos(); - canvas_size.y -= 80; - - const float point_radius = 20.f; - - ImDrawList* draw_list = ImGui::GetWindowDrawList(); - draw_list->PushClipRect(canvas_pos, canvas_pos + canvas_size); + const ImGuiIO &io = ImGui::GetIO(); - const vec2f view_scale(canvas_size.x, -canvas_size.y); - const vec2f view_offset(canvas_pos.x, canvas_pos.y + canvas_size.y); + ImGui::Text("Histogram"); - draw_list->AddRect(canvas_pos, canvas_pos + canvas_size, ImColor(180, 180, 180, 255)); + vec2f canvas_size = ImGui::GetContentRegionAvail(); + // Note: If you're not using OpenGL for rendering your UI, the setup for + // displaying the colormap texture in the UI will need to be updated. + ImGui::Image(reinterpret_cast(colormap_img), ImVec2(canvas_size.x, 16)); + vec2f canvas_pos = ImGui::GetCursorScreenPos(); + canvas_size.y -= 80; - //ImGui::InvisibleButton("tfn_canvas", canvas_size); - + const float point_radius = 20.f; - // Draw the alpha control points, and build the points for the polyline - // which connects them - + ImDrawList *draw_list = ImGui::GetWindowDrawList(); + draw_list->PushClipRect(canvas_pos, canvas_pos + canvas_size); - //Code to Draw histogram in the UI - for (int i = 0; i < current_histogram.size(); i++) { - vec2f lp = vec2f(((float)i) / current_histogram.size(), 0.0f); - vec2f hp = vec2f(((float)i + 1.0f) / current_histogram.size(), current_histogram[i]); - draw_list->AddRectFilled(lp * view_scale + view_offset, hp * view_scale + view_offset, 0x77777777); - } + const vec2f view_scale(canvas_size.x, -canvas_size.y); + const vec2f view_offset(canvas_pos.x, canvas_pos.y + canvas_size.y); + draw_list->AddRect(canvas_pos, canvas_pos + canvas_size, ImColor(180, 180, 180, 255)); - draw_list->PopClipRect(); + // ImGui::InvisibleButton("tfn_canvas", canvas_size); - + // Draw the alpha control points, and build the points for the polyline + // which connects them - + // Code to Draw histogram in the UI + for (int i = 0; i < current_histogram.size(); i++) + { + vec2f lp = vec2f(((float)i) / current_histogram.size(), 0.0f); + vec2f hp = vec2f(((float)i + 1.0f) / current_histogram.size(), current_histogram[i]); + draw_list->AddRectFilled(lp * view_scale + view_offset, hp * view_scale + view_offset, 0x77777777); + } - + draw_list->PopClipRect(); } void TransferFunctionWidget::update_gpu_image() @@ -472,7 +497,8 @@ void TransferFunctionWidget::update_gpu_image() GLint prev_tex_2d = 0; glGetIntegerv(GL_TEXTURE_BINDING_2D, &prev_tex_2d); - if (colormap_img == (GLuint)-1) { + if (colormap_img == (GLuint)-1) + { glGenTextures(1, &colormap_img); glBindTexture(GL_TEXTURE_2D, colormap_img); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); @@ -480,7 +506,8 @@ void TransferFunctionWidget::update_gpu_image() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } - if (colormap_changed) { + if (colormap_changed) + { glBindTexture(GL_TEXTURE_2D, colormap_img); glTexImage2D(GL_TEXTURE_2D, 0, @@ -492,7 +519,8 @@ void TransferFunctionWidget::update_gpu_image() GL_UNSIGNED_BYTE, current_colormap.data()); } - if (prev_tex_2d != 0) { + if (prev_tex_2d != 0) + { glBindTexture(GL_TEXTURE_2D, prev_tex_2d); } } @@ -506,16 +534,18 @@ void TransferFunctionWidget::update_colormap() auto a_it = alpha_control_pts.begin(); const size_t npixels = current_colormap.size() / 4; - for (size_t i = 0; i < npixels; ++i) { + for (size_t i = 0; i < npixels; ++i) + { float x = static_cast(i) / npixels; auto high = a_it + 1; - if (x > high->x) { + if (x > high->x) + { ++a_it; ++high; } float t = (x - a_it->x) / (high->x - a_it->x); float alpha = (1.f - t) * a_it->y + t * high->y; - current_colormap[i * 4 + 3] = static_cast(clamp(alpha * 255.f, 0.f, 255.f)); + current_colormap[i * 4 + 3] = static_cast(clamp(alpha * 255.f, 0.f, 255.f)); } } @@ -529,4 +559,3 @@ void TransferFunctionWidget::load_embedded_preset(const uint8_t *buf, stbi_image_free(img_data); colormaps.emplace_back(name, img); } - diff --git a/shaders/lines_shader.frag b/shaders/lines_shader.frag new file mode 100644 index 0000000..7cce2a7 --- /dev/null +++ b/shaders/lines_shader.frag @@ -0,0 +1,7 @@ +#version 410 + +out vec4 frag_color; + +void main () { + frag_color = vec4 (1.0, 0.0, 0.0, 1.0); +} \ No newline at end of file diff --git a/shaders/lines_shader.vert b/shaders/lines_shader.vert new file mode 100644 index 0000000..16d434f --- /dev/null +++ b/shaders/lines_shader.vert @@ -0,0 +1,10 @@ +#version 410 + +layout (location = 0 )in vec3 vertex_position; +uniform mat4 model_view_matrix; +uniform mat4 projection_matrixp; + + +void main () { + gl_Position = projection_matrix * model_view_matrix * vec4(vertex_position,1); +} \ No newline at end of file diff --git a/shaders/shader.frag b/shaders/shader.frag index 1d2a8e3..a1aa6b9 100644 --- a/shaders/shader.frag +++ b/shaders/shader.frag @@ -1,16 +1,15 @@ #version 330 -const vec4 lightPos = vec4(0.0, 2.0, 2.0, 1.0); -const vec4 color = vec4(0.5, 0.5, 0.5, 1.0); +in vec4 vertex_pos; +in vec2 text_coord; -in vec4 pos; -in vec2 TexCoord; - -out vec4 fragColor; -uniform sampler2D myTextureSampler; +out vec4 frag_color; +uniform sampler2D texture_sampler; void main() { - - fragColor = vec4(texture( myTextureSampler, TexCoord ).rgb,1); - + frag_color = vec4(texture( texture_sampler, text_coord )); + if(frag_color.a < 0.1) + { + discard; + } } \ No newline at end of file diff --git a/shaders/shader.vert b/shaders/shader.vert index 7aa0336..e8408e6 100644 --- a/shaders/shader.vert +++ b/shaders/shader.vert @@ -4,19 +4,17 @@ layout(location = 0) in vec3 position; layout(location = 1) in vec3 normal; layout(location = 2) in vec2 uv; -uniform mat4 p; +uniform mat4 projection_matrix; uniform mat4 v; uniform mat4 m; -uniform mat4 mv; +uniform mat4 model_view_matrix; -out vec4 pos; -//out vec4 norm; -out vec2 TexCoord; +out vec4 vertex_pos; +out vec2 text_coord; void main() { - pos = mv * vec4(position, 1.0); - //norm = normalize(mv * vec4(normal, 0.0)); - TexCoord = uv; + vertex_pos = model_view_matrix * vec4(position, 1.0); + text_coord = uv; - gl_Position = p * pos; + gl_Position = p * vertex_pos; } \ No newline at end of file diff --git a/src/UI/UIView.cpp b/src/UI/UIView.cpp index a15a2f6..aea6f02 100644 --- a/src/UI/UIView.cpp +++ b/src/UI/UIView.cpp @@ -9,25 +9,32 @@ #include "loader/VRDataLoader.h" - #include "UIHelpers/stb_image.h" #include "common/common.h" +#include "../include/interaction/Simulation.h" #include - -UIView::UIView(VRVolumeApp& controllerApp) :m_controller_app(controllerApp), m_multiplier(1.0f), m_threshold(0.0f), -m_z_scale(0.16f), m_scale{ 1.0f }, m_slices(256), m_dynamic_slices(false), m_renderVolume(true), m_selectedTrnFnc(0), -m_animated(false), m_ui_frame_controller(0.0f), m_menu_handler(nullptr), m_initialized(false), m_use_transferfunction(false), -m_clip_max(1.0), m_clip_min(0.0), m_clip_ypr(0.0), m_clip_pos(0.0), m_useCustomClipPlane(false), m_rendermethod(1), m_renderchannel(0), -m_table_selection(-1), m_trn_fct_opitions_window(false), m_save_trnfct_open(false), m_trnfnct_counter(1), m_file_dialog_open(false), -m_file_load_trnsf(false), m_file_dialog_save_dir(false), m_save_session_dialog_open(false), m_current_save_modal(SAVE_NONE), -m_current_load_modal(LOAD_NONE), m_file_extension_filter(".txt"), m_non_trns_functions_selected_modal(false), -m_ui_background(false), m_column_selection_state(0), m_compute_new_histogram(true), m_histogram_point_1(0.0), -m_histogram_point_2(1.1), m_stopped(false), m_color_map_directory("colormaps"),m_show_menu(true) +#include + +#include +#include + +UIView::UIView(VRVolumeApp &controllerApp) : m_controller_app(controllerApp), m_multiplier(1.0f), m_threshold(0.0f), + m_z_scale(0.16f), m_scale{1.0f}, m_slices(256), m_dynamic_slices(false), m_renderVolume(true), m_selectedTrnFnc(0), + m_animated(false), m_ui_frame_controller(0.0f), m_menu_handler(nullptr), m_initialized(false), m_use_transferfunction(false), + m_clip_max(1.0), m_clip_min(0.0), m_clip_ypr(0.0), m_clip_pos(0.0), m_useCustomClipPlane(false), m_rendermethod(1), m_renderchannel(0), + m_trnfnc_table_selection(-1), m_transfer_function_options_window(false), m_save_transfer_function_open(false), m_trnfnct_counter(1), m_file_dialog_open(false), + m_file_load_trnsf(false), m_file_dialog_save_dir(false), m_save_session_dialog_open(false), m_current_save_modal(SAVE_NONE), + m_current_load_modal(LOAD_NONE), m_file_extension_filter(".txt"), m_non_trns_functions_selected_modal(false), + m_ui_background(false), m_column_selection_state(0), m_compute_new_histogram(true), m_histogram_point_1(0.0), + m_histogram_point_2(1.1), m_stopped(false), m_color_map_directory("colormaps"), m_show_menu(true), m_camera_poi_table_selection(0), + m_camera_name_window_open(false), m_camera_button_action(BUTTON_ACTION::NONE), m_num_animation_frames(0), m_animation_step(1.0f), + m_camera_animation_duration_open(false), m_show_clock(false), m_clock_width(250), m_clock_height(200), + m_time_info(""), m_day_info(""), m_time_frame_edited(false), m_show_movie_saved_pop_up(false) { - m_ocean_color_maps_names = { "algae.png","amp.png","balance.png","curl.png","deep.png","delta.png","dense.png", -"diff.png","gray.png","haline.png","ice.png","matter.png","oxy.png","phase.png","rain.png","solar.png","speed.png","tarn.png","tempo.png", -"thermal.png","topo.png","turbid.png" }; + m_ocean_color_maps_names = {"algae.png", "amp.png", "balance.png", "curl.png", "deep.png", "delta.png", "dense.png", + "diff.png", "gray.png", "haline.png", "ice.png", "matter.png", "oxy.png", "phase.png", "rain.png", "solar.png", "speed.png", "tarn.png", "tempo.png", + "thermal.png", "topo.png", "turbid.png"}; m_histogram_quantiles[0] = 0.05; m_histogram_quantiles[1] = 0.95; } @@ -35,7 +42,6 @@ m_histogram_point_2(1.1), m_stopped(false), m_color_map_directory("colormaps"),m UIView::~UIView() { delete m_menu_handler; - } void UIView::draw_ui_callback() @@ -45,596 +51,866 @@ void UIView::draw_ui_callback() return; } - - m_ui_background = m_menu_handler->windowIsActive() ? true : false; - - - int flags = ImGuiWindowFlags_NoResize; - if (!m_ui_background) - { - flags |= ImGuiWindowFlags_NoBackground; - } - ImGui::SetNextWindowSize(ImVec2(544, 798)); - ImGui::Begin("Volumeviewer", NULL, flags); - ImGui::BeginTabBar("##tabs"); - if (ImGui::BeginTabItem("General")) + if (m_controller_app.is_show_menu()) { - if (ImGui::Button("load file", ImVec2(ImGui::GetWindowSize().x * 0.5f - 1.5 * ImGui::GetStyle().ItemSpacing.x, 0.0f))) - { - m_file_dialog_open = true; - m_file_extension_filter = ".txt"; - } + m_ui_background = m_menu_handler->windowIsActive() ? true : false; - ImGui::SameLine(); - if (ImGui::Button("Clear all", ImVec2(ImGui::GetWindowSize().x * 0.5f - 1.5 * ImGui::GetStyle().ItemSpacing.x, 0.0f))) + int flags = ImGuiWindowFlags_NoResize; + if (!m_ui_background) { - m_controller_app.clear_data(); + flags |= ImGuiWindowFlags_NoBackground; } + ImGui::SetNextWindowSize(ImVec2(544, 798)); + ImGui::Begin("Volumeviewer", NULL, flags); + ImGui::BeginTabBar("##tabs"); + if (ImGui::BeginTabItem("General")) + { + if (ImGui::Button("load file", ImVec2(ImGui::GetWindowSize().x * 0.5f - 1.5 * ImGui::GetStyle().ItemSpacing.x, 0.0f))) + { + m_file_dialog_open = true; + m_file_extension_filter = ".txt"; + } - ImGui::SliderFloat("alpha multiplier", &m_multiplier, 0.0f, 1.0f, "%.3f"); - ImGui::SliderFloat("threshold", &m_threshold, 0.0f, 1.0f, "%.3f"); - ImGui::SliderFloat("scale", &m_scale, 0.001f, 5.0f, "%.3f"); - ImGui::SliderFloat("z - scale", &m_z_scale, 0.001f, 5.0f, "%.3f"); - ImGui::SliderInt("Slices", &m_slices, 10, 1024, "%d"); - ImGui::Checkbox("automatic slice adjustment", &m_dynamic_slices); + ImGui::SameLine(); + if (ImGui::Button("Clear all", ImVec2(ImGui::GetWindowSize().x * 0.5f - 1.5 * ImGui::GetStyle().ItemSpacing.x, 0.0f))) + { + m_controller_app.clear_data(); + } - ImGui::SameLine(ImGui::GetWindowSize().x * 0.5f, 0); - ImGui::Text("FPS = %f", m_controller_app.get_fps()); - const char* items[] = { "sliced" , "raycast" }; - ImGui::Combo("RenderMethod", &m_rendermethod, items, IM_ARRAYSIZE(items)); + ImGui::SliderFloat("alpha multiplier", &m_multiplier, 0.0f, 1.0f, "%.3f"); + ImGui::SliderFloat("threshold", &m_threshold, 0.0f, 1.0f, "%.3f"); + ImGui::SliderFloat("scale", &m_scale, 0.001f, 5.0f, "%.3f"); + ImGui::SliderFloat("z - scale", &m_z_scale, 0.001f, 5.0f, "%.3f"); + ImGui::SliderInt("Slices", &m_slices, 10, 1024, "%d"); + ImGui::Checkbox("automatic slice adjustment", &m_dynamic_slices); + ImGui::Checkbox("Show Clock", &m_show_clock); - const char* items_channel[] = { "based on data" , "red", "green" , "blue", "alpha", "rgba", "rgba with alpha as max rgb" }; - ImGui::Combo("Render Channel", &m_renderchannel, items_channel, IM_ARRAYSIZE(items_channel)); + ImGui::SameLine(ImGui::GetWindowSize().x * 0.5f, 0); + ImGui::Text("FPS = %f", m_controller_app.get_fps()); + const char *items[] = {"sliced", "raycast"}; + ImGui::Combo("RenderMethod", &m_rendermethod, items, IM_ARRAYSIZE(items)); - ImGui::Checkbox("Render Volume data", &m_renderVolume); + const char *items_channel[] = {"based on data", "red", "green", "blue", "alpha", "rgba", "rgba with alpha as max rgb"}; + ImGui::Combo("Render Channel", &m_renderchannel, items_channel, IM_ARRAYSIZE(items_channel)); - int numVolumes = m_controller_app.get_num_volumes(); + ImGui::Checkbox("Render Volume data", &m_renderVolume); + int numVolumes = m_controller_app.get_num_volumes(); - if (numVolumes > 0) { - if (ImGui::SmallButton("Save Session")) { - m_save_session_dialog_open = true; + if (numVolumes > 0) + { + if (ImGui::SmallButton("Save Session")) + { + m_save_session_dialog_open = true; + } + ImGui::SameLine(); } - ImGui::SameLine(); - } + if (ImGui::SmallButton("Load Session")) + { + m_file_load_trnsf = true; + m_current_load_modal = LOAD_MODAL::LOAD_SESSION; + m_file_extension_filter = ".usr"; + } - if (ImGui::SmallButton("Load Session")) { - m_file_load_trnsf = true; - m_current_load_modal = LOAD_MODAL::LOAD_SESSION; - m_file_extension_filter = ".usr"; - } - - if (numVolumes > 0) - { - if (ImGui::SmallButton("Add Function")) { - tfn_widget.push_back(TransferFunctionWidget()); - tfn_widget_multi.push_back(TransferFunctionMultiChannelWidget()); - int index = m_selected_volume_TrFn.size(); - m_selected_volume_TrFn.push_back(std::vector(numVolumes)); - for (int i = 0; i < numVolumes; i++) + if (numVolumes > 0) + { + if (ImGui::SmallButton("Add Function")) { - m_selected_volume_TrFn[index][i] = false; - } + tfn_widget.push_back(TransferFunctionWidget()); + tfn_widget_multi.push_back(TransferFunctionMultiChannelWidget()); + int index = m_selected_volume_TrFn.size(); + m_selected_volume_TrFn.push_back(std::vector(numVolumes)); + for (int i = 0; i < numVolumes; i++) + { + m_selected_volume_TrFn[index][i] = false; + } - addTransferFunction(); - if (m_tfns.size() == 1) + add_transfer_function(); + if (m_tfns.size() == 1) m_trnfnc_table_selection = 0; + + }; + ImGui::SameLine(); + if (ImGui::SmallButton("Remove Function")) { - m_table_selection = 0; - } - }; - ImGui::SameLine(); - if (ImGui::SmallButton("Remove Function")) { + if (m_tfns.size() == 1) + { + // there should be one by default + tfn_widget.clear(); + tfn_widget_multi.clear(); + m_tfns.clear(); + tfn_widget.push_back(TransferFunctionWidget()); + tfn_widget_multi.push_back(TransferFunctionMultiChannelWidget()); + add_transfer_function(); + m_trnfnc_table_selection = 0; + } + else if (m_tfns.size() > 1 && m_trnfnc_table_selection >= 0) + { + tfn_widget.erase(tfn_widget.begin() + m_trnfnc_table_selection); + ; + tfn_widget_multi.erase(tfn_widget_multi.begin() + m_trnfnc_table_selection); + m_tfns.erase(m_tfns.begin() + m_trnfnc_table_selection); + if (m_trnfnc_table_selection != 0) + { + m_trnfnc_table_selection = m_trnfnc_table_selection - 1; + } + } + }; - if (m_tfns.size() == 1) + if (ImGui::SmallButton("Clear All Functions")) { - //there should be one by default tfn_widget.clear(); tfn_widget_multi.clear(); m_tfns.clear(); tfn_widget.push_back(TransferFunctionWidget()); tfn_widget_multi.push_back(TransferFunctionMultiChannelWidget()); - addTransferFunction(); - m_table_selection = 0; - } - else if (m_tfns.size() > 1 && m_table_selection >= 0) - { - tfn_widget.erase(tfn_widget.begin() + m_table_selection); ; - tfn_widget_multi.erase(tfn_widget_multi.begin() + m_table_selection); - m_tfns.erase(m_tfns.begin() + m_table_selection); - if (m_table_selection != 0) + MyTransFerFunctions trfntc; + char label[32]; + sprintf(label, "TF%d", (int)tfn_widget.size()); + trfntc.ID = tfn_widget.size(); + trfntc.Name = label; + for (int i = 0; i < numVolumes; i++) { - m_table_selection = m_table_selection - 1; + trfntc.volumes.push_back(false); } + m_tfns.push_back(trfntc); + m_trnfnc_table_selection = 0; + }; - } - }; - - - - if (ImGui::SmallButton("Clear All Functions")) { - tfn_widget.clear(); - tfn_widget_multi.clear(); - m_tfns.clear(); - tfn_widget.push_back(TransferFunctionWidget()); - tfn_widget_multi.push_back(TransferFunctionMultiChannelWidget()); - MyTransFerFunctions trfntc; - char label[32]; - sprintf(label, "TF%d", (int)tfn_widget.size()); - trfntc.ID = tfn_widget.size(); - trfntc.Name = label; - for (int i = 0; i < numVolumes; i++) + ImGui::SameLine(); + if (ImGui::SmallButton("Save Functions")) { - trfntc.volumes.push_back(false); - } - m_tfns.push_back(trfntc); - m_table_selection = 0; - }; - - ImGui::SameLine(); - if (ImGui::SmallButton("Save Functions")) { - m_save_trnfct_open = true; - m_non_trns_functions_selected_modal = !m_use_transferfunction; - }; - - ImGui::SameLine(); - if (ImGui::SmallButton("Load Functions")) { + m_save_transfer_function_open = true; + m_non_trns_functions_selected_modal = !m_use_transferfunction; + }; - m_file_load_trnsf = true; - m_current_load_modal = LOAD_MODAL::LOAD_TRFR_FNC; - m_file_extension_filter = ".fnc"; - }; + ImGui::SameLine(); + if (ImGui::SmallButton("Load Functions")) + { - int selection = 0; + m_file_load_trnsf = true; + m_current_load_modal = LOAD_MODAL::LOAD_TRFR_FNC; + m_file_extension_filter = ".fnc"; + }; - ImGui::BeginTable("##Transfer Function Editor", numVolumes + 1, ImGuiTableFlags_Borders); - ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed, 120.0f); + int selection = 0; - for (int column = 0; column < numVolumes; column++) - { - ImGui::TableSetupColumn(m_dataLabels[column].c_str()); - } - ImGui::TableNextRow(ImGuiTableRowFlags_Headers); - for (int column = 1; column < numVolumes + 1; column++) - { - ImGui::TableSetColumnIndex(column); - const char* column_name = ImGui::TableGetColumnName(column); - ImGui::PushID(column); - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); - //ImGui::RadioButton("", &m_column_selected, column-1); ImGui::SameLine(); - ImGui::Checkbox("##checkall", &m_column_selected[column - 1]); ImGui::SameLine(); - ImGui::PopStyleVar(); - ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); - ImGui::TableHeader(column_name); - ImGui::PopID(); + ImGui::BeginTable("##Transfer Function Editor", numVolumes + 1, ImGuiTableFlags_Borders); + ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed, 120.0f); - } + for (int column = 0; column < numVolumes; column++) + { + ImGui::TableSetupColumn(m_dataLabels[column].c_str()); + } + ImGui::TableNextRow(ImGuiTableRowFlags_Headers); + for (int column = 1; column < numVolumes + 1; column++) + { + ImGui::TableSetColumnIndex(column); + const char *column_name = ImGui::TableGetColumnName(column); + ImGui::PushID(column); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); + ImGui::Checkbox("##checkall", &m_column_selected[column - 1]); + ImGui::SameLine(); + ImGui::PopStyleVar(); + ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); + ImGui::TableHeader(column_name); + ImGui::PopID(); + } - compute_new_histogram_view(); + compute_new_histogram_view(); + /* check state of check boxes */ + int colum_select_check_sum = 0; + for (int column_select = 1; column_select <= numVolumes; column_select++) + { - /* check state of check boxes */ - int colum_select_check_sum = 0; - for (int column_select = 1; column_select <= numVolumes; column_select++) - { + if (m_column_selected[column_select - 1]) + { + colum_select_check_sum |= column_select; + } + } - if (m_column_selected[column_select - 1]) + if (colum_select_check_sum != m_column_selection_state) { - colum_select_check_sum |= column_select; + m_compute_new_histogram = true; + m_column_selection_state = colum_select_check_sum; } - } - - if (colum_select_check_sum != m_column_selection_state) - { - m_compute_new_histogram = true; - m_column_selection_state = colum_select_check_sum; - } - else - { - m_compute_new_histogram = false; - } - - for (int row = 0; row < m_tfns.size(); row++) - { - ImGui::TableNextRow(); - for (int col = 0; col < numVolumes + 1; col++) + else { - ImGui::TableSetColumnIndex(col); + m_compute_new_histogram = false; + } - if (col == 0) + for (int row = 0; row < m_tfns.size(); row++) + { + ImGui::TableNextRow(); + for (int col = 0; col < numVolumes + 1; col++) { + ImGui::TableSetColumnIndex(col); - ImGuiSelectableFlags selectable_flags = ImGuiSelectableFlags_AllowDoubleClick; - bool item_is_selected = (row == m_table_selection) ? true : false; - if (ImGui::Selectable(m_tfns[row].Name.c_str(), item_is_selected, selectable_flags)) + if (col == 0) { - m_table_selection = row; - if (ImGui::IsMouseDoubleClicked(0)) + ImGuiSelectableFlags selectable_flags = ImGuiSelectableFlags_AllowDoubleClick; + bool item_is_selected = (row == m_trnfnc_table_selection) ? true : false; + if (ImGui::Selectable(m_tfns[row].Name.c_str(), item_is_selected, selectable_flags)) { - m_copy_trnfnct_name = m_tfns[row].Name; - float q_min = 0; - float q_max = 0; - tfn_widget[m_table_selection].get_Quantiles(q_min, q_max); - m_histogram_quantiles[0] = q_min; - m_histogram_quantiles[1] = q_max; - m_trn_fct_opitions_window = true; + m_trnfnc_table_selection = row; + if (ImGui::IsMouseDoubleClicked(0)) + { + m_copy_trnfnct_name = m_tfns[m_trnfnc_table_selection].Name; + float q_min = 0; + float q_max = 0; + tfn_widget[m_trnfnc_table_selection].get_quantiles(q_min, q_max); + m_histogram_quantiles[0] = q_min; + m_histogram_quantiles[1] = q_max; + m_transfer_function_options_window = true; + } } - - } + else + { + char buf[32]; + sprintf(buf, "##On%d%d", col, row); + bool b = m_tfns[row].volumes[col - 1]; + ImGui::Checkbox(buf, &b); + m_tfns[row].volumes[col - 1] = b; + } + } + } + + ImGui::EndTable(); + if (m_save_session_dialog_open) + { + m_current_save_modal = SAVE_SESSION; + std::string save_user_session_window_id = "Save User Session"; + std::string extension = ".usr"; + auto save_funtion = std::bind(&UIView::save_user_session, this, std::placeholders::_1); + open_save_modal_dialog(save_user_session_window_id, m_save_session_dialog_open, save_funtion, extension); + } + if (m_save_transfer_function_open) + { + m_current_save_modal = SAVE_TRANSFER_FUNCTION; + std::string save_Trnf_window_id = "Save Transfer Functions"; + if (m_use_transferfunction) + { + std::string extension = ".fnc"; + auto save_funtion = std::bind(&UIView::save_transfer_functions, this, std::placeholders::_1); + open_save_modal_dialog(save_Trnf_window_id, m_save_transfer_function_open, save_funtion, extension); } else { - char buf[32]; - sprintf(buf, "##On%d%d", col, row); - bool b = m_tfns[row].volumes[col - 1]; - ImGui::Checkbox(buf, &b); - m_tfns[row].volumes[col - 1] = b; - + ImGui::OpenPopup("No Functions Selected"); + ImGui::SetNextWindowSize(ImVec2(150, 70), ImGuiCond_FirstUseEver); + if (ImGui::BeginPopupModal("No Functions Selected", &m_non_trns_functions_selected_modal)) + { + ImGui::Text("Transfer functions are not enabled."); + ImGui::Text("Please, check the 'Use Transfer function' option."); + if (ImGui::Button("Close")) + { + m_non_trns_functions_selected_modal = false; + m_save_transfer_function_open = false; + ImGui::CloseCurrentPopup(); + } + ImGui::EndPopup(); + } } - } - } - ImGui::EndTable(); - if (m_save_session_dialog_open) - { - m_current_save_modal = SAVE_SESSION; - std::string save_user_session_window_id = "Save User Session"; + if (m_transfer_function_options_window) + { + ImGui::OpenPopup("Transfer Function Options"); + ImGui::SetNextWindowSize(ImVec2(350, 400), ImGuiCond_FirstUseEver); + if (ImGui::BeginPopupModal("Transfer Function Options", &m_transfer_function_options_window)) + { + ImGui::Text("Change Name"); + ImGui::InputText("##text1", &m_copy_trnfnct_name); + ImGui::IsItemActive(); - std::string extension = ".usr"; - auto save_funtion = std::bind(&UIView::save_user_session, this, std::placeholders::_1); - open_save_modal_dialog(save_user_session_window_id, m_save_session_dialog_open, save_funtion, extension); + ImGui::Separator(); - } + ImGui::Text("Quantiles"); + ImGui::SliderFloat2("##Quantiles", m_histogram_quantiles, 0.05f, 0.95f); - if (m_save_trnfct_open) - { - m_current_save_modal = SAVE_TRFR_FNC; - std::string save_Trnf_window_id = "Save Transfer Functions"; - if (m_use_transferfunction) - { - std::string extension = ".fnc"; - auto save_funtion = std::bind(&UIView::save_trans_functions, this, std::placeholders::_1); - open_save_modal_dialog(save_Trnf_window_id, m_save_trnfct_open, save_funtion, extension); - } - else - { - ImGui::OpenPopup("No Functions Selected"); - ImGui::SetNextWindowSize(ImVec2(150, 70), ImGuiCond_FirstUseEver); - if (ImGui::BeginPopupModal("No Functions Selected", &m_non_trns_functions_selected_modal)) - { - ImGui::Text("Transfer functions are not enabled."); - ImGui::Text("Please, check the 'Use Transfer function' option."); - if (ImGui::Button("Close")) + if (ImGui::Button("Adjust to Histogram")) + { + adjust_transfer_function_to_histogram(); + tfn_widget[m_trnfnc_table_selection].alpha_control_pts.clear(); + tfn_widget[m_trnfnc_table_selection].alpha_control_pts.push_back(vec2f(0.0, 0.0)); + tfn_widget[m_trnfnc_table_selection].alpha_control_pts.push_back(m_histogram_point_1); + tfn_widget[m_trnfnc_table_selection].alpha_control_pts.push_back(m_histogram_point_2); + tfn_widget[m_trnfnc_table_selection].alpha_control_pts.push_back(vec2f(1.0, 1.0)); + tfn_widget[m_trnfnc_table_selection].set_quantiles(m_histogram_quantiles[0], m_histogram_quantiles[1]); + ImGui::OpenPopup("Confirmation"); + ImGui::SetNextWindowSize(ImVec2(350, 400), ImGuiCond_FirstUseEver); + } + + bool unused_open = true; + if (ImGui::BeginPopupModal("Confirmation", &unused_open)) { - m_non_trns_functions_selected_modal = false; - m_save_trnfct_open = false; + ImGui::Text("Change Applied"); + if (ImGui::Button("Close")) + { + ImGui::CloseCurrentPopup(); + } + ImGui::EndPopup(); + } + + if (ImGui::Button("Ok")) + { + m_tfns[m_trnfnc_table_selection].Name = m_copy_trnfnct_name; + m_transfer_function_options_window = false; + m_current_save_modal = SAVE_MODAL::SAVE_NONE; + ImGui::CloseCurrentPopup(); + } + ImGui::SameLine(); + if (ImGui::Button("Cancel")) + { + m_transfer_function_options_window = false; + m_current_save_modal = SAVE_MODAL::SAVE_NONE; ImGui::CloseCurrentPopup(); } + ImGui::EndPopup(); } } - - } - - if (m_trn_fct_opitions_window) - { - ImGui::OpenPopup("Transfer Function Options"); - ImGui::SetNextWindowSize(ImVec2(350, 400), ImGuiCond_FirstUseEver); - if (ImGui::BeginPopupModal("Transfer Function Options", &m_trn_fct_opitions_window)) + ImGui::Checkbox("use transferfunction", &m_use_transferfunction); + if (m_use_transferfunction) { - ImGui::Text("Change Name"); - char* writable = new char[m_copy_trnfnct_name.size() + 1]; - std::copy(m_copy_trnfnct_name.begin(), m_copy_trnfnct_name.end(), writable); - writable[m_copy_trnfnct_name.size()] = '\0'; // don't forget the terminating 0 - //ImGui::PushItemWidth(-1); - ImGui::InputText("##text1", writable, IM_ARRAYSIZE(writable)); - ImGui::IsItemActive(); - //ImGui::PopItemWidth(); - - ImGui::Separator(); - /*float q_min = 0; - float q_max = 0; - tfn_widget[m_table_selection].get_Quantiles(q_min, q_max); - m_histogram_quantiles[0] = q_min; - m_histogram_quantiles[1] = q_max;*/ - - ImGui::Text("Quantiles"); - ImGui::SliderFloat2("##Quantiles", m_histogram_quantiles, 0.05f, 0.95f); - - if (ImGui::Button("Adjust to Histogram")) - { - adjust_transfer_function_to_histogram(); - tfn_widget[m_table_selection].alpha_control_pts.clear(); - tfn_widget[m_table_selection].alpha_control_pts.push_back(vec2f(0.0, 0.0)); - tfn_widget[m_table_selection].alpha_control_pts.push_back(m_histogram_point_1); - tfn_widget[m_table_selection].alpha_control_pts.push_back(m_histogram_point_2); - tfn_widget[m_table_selection].alpha_control_pts.push_back(vec2f(1.0, 1.0)); - tfn_widget[m_table_selection].set_Quantiles(m_histogram_quantiles[0], m_histogram_quantiles[1]); - ImGui::OpenPopup("Confirmation"); - ImGui::SetNextWindowSize(ImVec2(350, 400), ImGuiCond_FirstUseEver); - } - bool unused_open = true; - if (ImGui::BeginPopupModal("Confirmation", &unused_open)) + bool is_multi_channel = m_controller_app.data_is_multi_channel(); + if (is_multi_channel) { - ImGui::Text("Change Applied"); - if (ImGui::Button("Close")) + for (int i = 0; i < 3; i++) { - ImGui::CloseCurrentPopup(); + if (m_animated) + { + /* + TODO: + + Fix frame by frame animation + + unsigned int active_volume = floor(m_frame); + unsigned int active_volume2 = ceil(m_frame); + double alpha = m_frame - active_volume; + if (active_volume < m_volumes[m_selectedVolume].size() && active_volume2 < m_volumes[m_selectedVolume].size()) + { + tfn_widget_multi[m_selectedVolume].setBlendedHistogram( + m_volumes[m_selectedVolume][active_volume]->getTransferfunction(i), + m_volumes[m_selectedVolume][active_volume2]->getTransferfunction(i), alpha, i); + }*/ + } + } - ImGui::EndPopup(); + m_controller_app.set_multi_transfer(true); + tfn_widget_multi[m_trnfnc_table_selection].draw_ui(); } + else + { + if (m_animated) + { + /* + TODO: + + The base code to fix frame by frame animation + + unsigned int active_volume = floor(m_frame); + unsigned int active_volume2 = ceil(m_frame); + double alpha = m_frame - active_volume; + tfn_widget[m_selectedVolume].setMinMax(m_volumes[m_selectedVolume][active_volume]->getMin() * alpha + m_volumes[m_selectedVolume][active_volume2]->getMin() * (1.0 - alpha), + m_volumes[m_selectedVolume][active_volume]->getMax() * alpha + m_volumes[m_selectedVolume][active_volume2]->getMax() * (1.0 - alpha)); + if (active_volume < m_volumes[m_selectedVolume].size() && active_volume2 < m_volumes[m_selectedVolume].size()) + tfn_widget[m_selectedVolume].setBlendedHistogram(m_volumes[m_selectedVolume][active_volume]->getTransferfunction(0), m_volumes[m_selectedVolume][active_volume2]->getTransferfunction(0), alpha);*/ + } + m_controller_app.set_multi_transfer(false); + m_histogram.draw_histogram(); + tfn_widget[m_trnfnc_table_selection].draw_ui(); + + } + } + } - if (ImGui::Button("Ok")) + if (m_animated) + { + ImGui::Text("Timestep"); + ImGui::SameLine(); + ImGui::SetNextItemWidth(-100 - ImGui::GetStyle().ItemSpacing.x); + float frame_tmp = m_controller_app.get_current_frame() + 1; + // controls animated multi datasets + ImGui::SliderFloat("##Timestep", &frame_tmp, 1, m_num_animation_frames); + m_ui_frame_controller = (frame_tmp)-1; + m_controller_app.set_frame(m_ui_frame_controller); + + std::string text = m_stopped ? "Play" : "Stop"; + if (ImGui::Button(text.c_str(), ImVec2(50, 0))) + { + m_stopped = !m_stopped; + } + ImGui::SameLine(); + int value = int(m_animation_step * 100.0 + .5); + std::string speed_text = ">>X " + std::to_string(value / 100); + if (ImGui::Button(speed_text.c_str(), ImVec2(80, 0))) + { + m_animation_step += 0.5; + if (m_animation_step > 4.0f) { - m_tfns[m_table_selection].Name = m_copy_trnfnct_name; - m_trn_fct_opitions_window = false; - m_current_save_modal = SAVE_MODAL::SAVE_NONE; - ImGui::CloseCurrentPopup(); + m_animation_step = 1.0f; } - ImGui::SameLine(); - if (ImGui::Button("Cancel")) + m_controller_app.set_volume_animation_scale_factor(m_animation_step); + } + +#if (!defined(__APPLE__)) + std::string movie_button_label = m_controller_app.get_movie_state_label(); + if (movie_button_label == "Write Movie") + { + if (ImGui::Button(movie_button_label.c_str())) { - m_trn_fct_opitions_window = false; - m_current_save_modal = SAVE_MODAL::SAVE_NONE; - ImGui::CloseCurrentPopup(); + m_controller_app.run_movie(false); + } + } + else + { + if (ImGui::Button(movie_button_label.c_str())) + { + m_controller_app.stop_movie(); } - - ImGui::EndPopup(); } - } - +#endif + } + ImGui::EndTabItem(); + } - ImGui::Checkbox("use transferfunction", &m_use_transferfunction); - if (m_use_transferfunction) + if (ImGui::BeginTabItem("Clipping")) + { + ImGui::Text("Axis aligned clip"); + glm::vec2 bound = {m_clip_min.x * 100, m_clip_max.x * 100}; + ImGui::DragFloatRange2("X", &bound.x, &bound.y, 0.1f, 0.0f, 100.0f, "Min: %.1f %%", "Max: %.1f %%"); + m_clip_min.x = bound.x / 100; + m_clip_max.x = bound.y / 100; + + bound = {m_clip_min.y * 100, m_clip_max.y * 100}; + ImGui::DragFloatRange2("Y", &bound.x, &bound.y, 0.1f, 0.0f, 100.0f, "Min: %.1f %%", "Max: %.1f %%"); + m_clip_min.y = bound.x / 100; + m_clip_max.y = bound.y / 100; + + bound = {m_clip_min.z * 100, m_clip_max.z * 100}; + ImGui::DragFloatRange2("Z", &bound.x, &bound.y, 0.1f, 0.0f, 100.0f, "Min: %.1f %%", "Max: %.1f %%"); + m_clip_min.z = bound.x / 100; + m_clip_max.z = bound.y / 100; + + if (ImGui::Button("Reset")) { + m_clip_min = glm::vec3(0.0f); + m_clip_max = glm::vec3(1.0f); + } + ImGui::Checkbox("Custom Clipping plane", &m_useCustomClipPlane); + if (m_useCustomClipPlane) + { + ImGui::SliderAngle("Pitch", &m_clip_ypr.y, -90, 90); + ImGui::SliderAngle("Roll", &m_clip_ypr.z, -180, 180); - bool is_multi_channel = m_controller_app.data_is_multi_channel(); - if (is_multi_channel) + ImGui::SliderFloat("Position X", &m_clip_pos.x, -0.5, 0.5); + ImGui::SliderFloat("Position y", &m_clip_pos.y, -0.5, 0.5); + ImGui::SliderFloat("Position z", &m_clip_pos.z, -0.5, 0.5); + if (ImGui::Button("Reset##Reset2")) { - for (int i = 0; i < 3; i++) { - if (m_animated) - { - /* - frame by frame animation + m_clip_ypr = glm::vec3(0.0f); + m_clip_pos = glm::vec3(0.0f); + } + } + ImGui::EndTabItem(); + } - unsigned int active_volume = floor(m_frame); - unsigned int active_volume2 = ceil(m_frame); - double alpha = m_frame - active_volume; - if (active_volume < m_volumes[m_selectedVolume].size() && active_volume2 < m_volumes[m_selectedVolume].size()) - { - tfn_widget_multi[m_selectedVolume].setBlendedHistogram( - m_volumes[m_selectedVolume][active_volume]->getTransferfunction(i), - m_volumes[m_selectedVolume][active_volume2]->getTransferfunction(i), alpha, i); - }*/ + if (ImGui::BeginTabItem("Animation")) + { - } - else { - /* tfn_widget_multi[m_selectedVolume].setHistogram(m_volumes[m_selectedVolume][0]->getTransferfunction(i), i);*/ - } + ImGui::Text("Time Frames"); + + if (ImGui::Button("Add")) + { + m_camera_name_window_open = true; + m_camera_button_action = BUTTON_ACTION::ADD; + } + ImGui::SameLine(); + if (ImGui::Button("Remove")) + { + if (m_controller_app.get_simulation().get_simulation_states().size() > 0) + { + m_controller_app.get_simulation().remove_simulation_state(m_simulation_state_selection); + if (m_simulation_state_selection - 1 < 0) + { + m_simulation_state_selection = 0; + } + else + { + m_simulation_state_selection--; + SimulationState next_sim_state = m_controller_app.get_simulation().get_simulation_state_at(m_simulation_state_selection); + m_controller_app.get_trackball_camera().set_current_poi(next_sim_state.poi); } - m_controller_app.set_multi_transfer(true); - //tfn_widget_multi[m_selectedTrnFnc].draw_histogram(); - tfn_widget_multi[m_table_selection].draw_ui(); } - else + } + ImGui::SameLine(); + if (ImGui::Button("Reset Camera")) + { + m_controller_app.get_trackball_camera().reset_camera(); + } + ImGui::BeginTable("##Camera Point of interest (POI) Editor", 1, ImGuiTableFlags_Borders); + ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed, 120.0f); + + for (int row = 0; row < m_controller_app.get_simulation().get_simulation_states().size(); ++row) + { + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); + bool item_is_selected = (row == m_simulation_state_selection) ? true : false; + SimulationState sim_state = m_controller_app.get_simulation().get_simulation_state_at(row); + if (ImGui::Selectable(sim_state.poi.label.c_str(), item_is_selected, ImGuiSelectableFlags_AllowDoubleClick)) { - if (m_animated) + m_simulation_state_selection = row; + m_controller_app.get_trackball_camera().set_current_poi(sim_state.poi); + m_clip_min = sim_state.min_clip; + m_clip_max = sim_state.max_clip; + if (ImGui::IsMouseDoubleClicked(0)) { - /* - frame by frame animation + m_copy_camera_name = sim_state.poi.label; + m_camera_name_window_open = true; + m_camera_button_action = BUTTON_ACTION::EDIT; + } + } + } + ImGui::EndTable(); - unsigned int active_volume = floor(m_frame); - unsigned int active_volume2 = ceil(m_frame); - double alpha = m_frame - active_volume; - tfn_widget[m_selectedVolume].setMinMax(m_volumes[m_selectedVolume][active_volume]->getMin() * alpha + m_volumes[m_selectedVolume][active_volume2]->getMin() * (1.0 - alpha), - m_volumes[m_selectedVolume][active_volume]->getMax() * alpha + m_volumes[m_selectedVolume][active_volume2]->getMax() * (1.0 - alpha)); - if (active_volume < m_volumes[m_selectedVolume].size() && active_volume2 < m_volumes[m_selectedVolume].size()) - tfn_widget[m_selectedVolume].setBlendedHistogram(m_volumes[m_selectedVolume][active_volume]->getTransferfunction(0), m_volumes[m_selectedVolume][active_volume2]->getTransferfunction(0), alpha);*/ + if (m_controller_app.get_simulation().get_simulation_states().size() > 0) + { + SimulationState &sim_state = m_controller_app.get_simulation().get_simulation_state_at(m_simulation_state_selection); + std::string edit_text = "Edit Time Frame " + sim_state.poi.label; + ImGui::Text(edit_text.c_str()); + + ImGui::Text("Axis aligned clip"); + glm::vec2 bound = {m_clip_min.x * 100, m_clip_max.x * 100}; + ImGui::DragFloatRange2("X", &bound.x, &bound.y, 0.1f, 0.0f, 100.0f, "Min: %.1f %%", "Max: %.1f %%"); + m_clip_min.x = bound.x / 100; + m_clip_max.x = bound.y / 100; + + ImGui::SameLine(); + if (ImGui::Button("Reset##XAXIS")) + { + m_clip_min.x = 0.0f; + m_clip_max.x = 1.0f; + } - } + bound = {m_clip_min.y * 100, m_clip_max.y * 100}; + ImGui::DragFloatRange2("Y", &bound.x, &bound.y, 0.1f, 0.0f, 100.0f, "Min: %.1f %%", "Max: %.1f %%"); + m_clip_min.y = bound.x / 100; + m_clip_max.y = bound.y / 100; + ImGui::SameLine(); + if (ImGui::Button("Reset##YAXIS")) + { + m_clip_min.y = 0.0f; + m_clip_max.y = 1.0f; + } - m_controller_app.set_multi_transfer(false); + bound = {m_clip_min.z * 100, m_clip_max.z * 100}; + ImGui::DragFloatRange2("Z", &bound.x, &bound.y, 0.1f, 0.0f, 100.0f, "Min: %.1f %%", "Max: %.1f %%"); + m_clip_min.z = bound.x / 100; + m_clip_max.z = bound.y / 100; + ImGui::SameLine(); + if (ImGui::Button("Reset##ZAXIS")) + { + m_clip_min.z = 0.0f; + m_clip_max.z = 1.0f; + } - m_histogram.draw_histogram(); - tfn_widget[m_table_selection].draw_ui(); + if (ImGui::Button("Save Changes##EDITTIMEFRAME")) + { + sim_state.min_clip = m_clip_min; + sim_state.max_clip = m_clip_max; + sim_state.poi = m_controller_app.get_trackball_camera().get_current_poi(); + m_time_frame_edited = true; } } + // Simulation animator + std::string is_animation_playing = m_controller_app.get_simulation().get_camera_animation_state(); - } + if (ImGui::Button(is_animation_playing.c_str())) + { + m_controller_app.get_simulation().set_animation_state(); + } - if (m_animated) { - ImGui::Text("Timestep"); - ImGui::SameLine(); - ImGui::SetNextItemWidth(-100 - ImGui::GetStyle().ItemSpacing.x); - float frame_tmp = m_controller_app.get_current_frame() + 1; - //controls animated multi datasets - //ImGui::SliderFloat("##Timestep", &frame_tmp, 1, m_volumes[m_selectedVolume].size()); - m_ui_frame_controller = frame_tmp - 1; - m_controller_app.set_frame(m_ui_frame_controller); - ImGui::SameLine(); + ImGui::Text("Duration (seconds)"); - std::string text = m_stopped ? "Play" : "Stop"; - if (ImGui::Button(text.c_str(), ImVec2(100, 0))) { - m_stopped = !m_stopped; + std::stringstream text; + text << std::fixed << std::setprecision(1) << m_controller_app.get_simulation().get_animation_duration(); + std::string str_animation_duration = text.str(); + + if (ImGui::Button(str_animation_duration.c_str())) + { + m_camera_animation_duration_open = true; + m_string_animation_duration = str_animation_duration; } #if (!defined(__APPLE__)) - if (ImGui::Button("Write Movie")) + std::string movie_button_label = m_controller_app.get_movie_state_label(); + if (movie_button_label == "Write Movie") + { + if (ImGui::Button(movie_button_label.c_str())) + { + m_controller_app.get_simulation().set_animation_state(); + m_controller_app.run_movie(true); + } + } + else { - m_controller_app.run_movie(); + if (ImGui::Button(movie_button_label.c_str())) + { + m_controller_app.stop_movie(); + } } #endif - } - ImGui::EndTabItem(); - } - if (ImGui::BeginTabItem("Clipping")) - { - ImGui::Text("Axis aligned clip"); - glm::vec2 bound = { m_clip_min.x * 100 ,m_clip_max.x * 100 }; - ImGui::DragFloatRange2("X", &bound.x, &bound.y, 0.1f, 0.0f, 100.0f, "Min: %.1f %%", "Max: %.1f %%"); - m_clip_min.x = bound.x / 100; - m_clip_max.x = bound.y / 100; - - bound = { m_clip_min.y * 100 ,m_clip_max.y * 100 }; - ImGui::DragFloatRange2("Y", &bound.x, &bound.y, 0.1f, 0.0f, 100.0f, "Min: %.1f %%", "Max: %.1f %%"); - m_clip_min.y = bound.x / 100; - m_clip_max.y = bound.y / 100; - - bound = { m_clip_min.z * 100 ,m_clip_max.z * 100 }; - ImGui::DragFloatRange2("Z", &bound.x, &bound.y, 0.1f, 0.0f, 100.0f, "Min: %.1f %%", "Max: %.1f %%"); - m_clip_min.z = bound.x / 100; - m_clip_max.z = bound.y / 100; - - if (ImGui::Button("Reset")) { - m_clip_min = glm::vec3(0.0f); - m_clip_max = glm::vec3(1.0f); + ImGui::EndTabItem(); } - ImGui::Checkbox("Custom Clipping plane", &m_useCustomClipPlane); - if (m_useCustomClipPlane) { - ImGui::SliderAngle("Pitch", &m_clip_ypr.y, -90, 90); - ImGui::SliderAngle("Roll", &m_clip_ypr.z, -180, 180); - - ImGui::SliderFloat("Position X", &m_clip_pos.x, -0.5, 0.5); - ImGui::SliderFloat("Position y", &m_clip_pos.y, -0.5, 0.5); - ImGui::SliderFloat("Position z", &m_clip_pos.z, -0.5, 0.5); - if (ImGui::Button("Reset##Reset2")) { - m_clip_ypr = glm::vec3(0.0f); - m_clip_pos = glm::vec3(0.0f); - } + ImGui::EndTabBar(); + if (m_time_frame_edited) + { + ImGui::OpenPopup("Time frame Changed##successchange"); + ImGui::SetNextWindowSize(ImVec2(350, 400), ImGuiCond_FirstUseEver); + if (ImGui::BeginPopupModal("Time frame Changed##successchange", &m_time_frame_edited)) + { + ImGui::Text("Changes saved"); + if (ImGui::Button("Ok")) + { + m_time_frame_edited = false; + ImGui::CloseCurrentPopup(); + } + ImGui::EndPopup(); + } } - ImGui::EndTabItem(); - } - ImGui::EndTabBar(); - //file loading - if (m_file_dialog_open) - { - ImGui::OpenPopup("Open File"); - m_file_dialog_open = false; - } + if (m_camera_name_window_open) + { + std::string modal_window_name; + switch (m_camera_button_action) + { + case ADD: + modal_window_name = "Add Simulation State"; + break; + case EDIT: + modal_window_name = "Edit Simulation Name"; + break; + default: + break; + } + ImGui::OpenPopup(modal_window_name.c_str()); + ImGui::SetNextWindowSize(ImVec2(350, 400), ImGuiCond_FirstUseEver); + if (ImGui::BeginPopupModal(modal_window_name.c_str(), &m_camera_name_window_open)) + { + ImGui::Text("Camera Name"); + ImGui::InputText("##textcameraname", &m_copy_camera_name); + if (ImGui::Button("Ok")) + { - if (fileDialog.showFileDialog("Open File", imgui_addons::ImGuiFileBrowser::DialogMode::OPEN, ImVec2(700, 310), m_file_extension_filter)) - { + if (m_camera_button_action == ADD) + { + SimulationState sim_state; + sim_state.poi = m_controller_app.get_trackball_camera().get_current_poi(); + sim_state.poi.label = m_copy_camera_name; + sim_state.max_clip = m_clip_max; + sim_state.min_clip = m_clip_min; + m_controller_app.get_simulation().add_simulation_state(sim_state); + + m_copy_camera_name.clear(); + m_simulation_state_selection = m_controller_app.get_simulation().get_simulation_states().size() - 1; + } + else if (m_camera_button_action == EDIT) + { + m_controller_app.get_simulation().get_simulation_state_at(m_camera_poi_table_selection).poi.label = m_copy_camera_name; + } + m_camera_name_window_open = false; + ImGui::CloseCurrentPopup(); + } + ImGui::SameLine(); + if (ImGui::Button("Cancel")) + { + m_camera_name_window_open = false; + m_copy_camera_name.clear(); + ImGui::CloseCurrentPopup(); + } + ImGui::EndPopup(); + } + } - if (helper::ends_with_string(fileDialog.selected_fn, ".txt")) + if (m_camera_animation_duration_open) { - VRDataLoader::get_instance()->load_txt_file(m_controller_app, fileDialog.selected_path); - - // m_controller_app.load_txt_file(fileDialog.GetSelected().string()); + ImGui::OpenPopup("Animation Time"); + ImGui::SetNextWindowSize(ImVec2(350, 400), ImGuiCond_FirstUseEver); + if (ImGui::BeginPopupModal("Animation Time", &m_camera_animation_duration_open)) + { + ImGui::Text("Camera Name"); + ImGui::InputText("##textanimationtime", &m_string_animation_duration, ImGuiInputTextFlags_CharsDecimal); + if (ImGui::Button("Ok")) + { + m_controller_app.get_simulation().set_simulation_duration(std::stof(m_string_animation_duration)); + m_string_animation_duration.clear(); + m_camera_animation_duration_open = false; + ImGui::CloseCurrentPopup(); + } + if (ImGui::Button("Cancel")) + { + m_camera_animation_duration_open = false; + m_string_animation_duration.clear(); + ImGui::CloseCurrentPopup(); + } + ImGui::EndPopup(); + } } -#ifdef WITH_TEEM - else if (helper::ends_with_string(fileDialog.selected_fn, ".nrrd")) { - std::vector vals; - /* vals.push_back(fileDialog.GetSelected().string()); - promises.push_back(new std::promise); - futures.push_back(promises.back()->get_future()); - threads.push_back(new std::thread(&VolumeVisualizationApp::loadVolume, this, vals, promises.back()));*/ + + // file loading + if (m_file_dialog_open) + { + ImGui::OpenPopup("Open File"); + m_file_dialog_open = false; } -#endif - } + if (fileDialog.showFileDialog("Open File", imgui_addons::ImGuiFileBrowser::DialogMode::OPEN, ImVec2(700, 310), m_file_extension_filter)) + { + if (helper::ends_with_string(fileDialog.selected_fn, ".txt")) + { + VRDataLoader::load_txt_file(m_controller_app, fileDialog.selected_path); + } +#ifdef WITH_TEEM + else if (helper::ends_with_string(fileDialog.selected_fn, ".nrrd")) + { + std::vector vals; + vals.push_back(fileDialog.GetSelected().string()); + promises.push_back(new std::promise); + futures.push_back(promises.back()->get_future()); + threads.push_back(new std::thread(&VolumeVisualizationApp::loadVolume, this, vals, promises.back())); + } +#endif + } + if (m_file_dialog_save_dir) + { + ImGui::OpenPopup("Save File"); + m_file_dialog_save_dir = false; + switch (m_current_save_modal) + { + case SAVE_SESSION: + m_save_session_dialog_open = false; + break; + case SAVE_TRANSFER_FUNCTION: + m_save_transfer_function_open = false; + break; + default: + break; + } + } - if (m_file_dialog_save_dir) - { - ImGui::OpenPopup("Save File"); - m_file_dialog_save_dir = false; - switch (m_current_save_modal) + if (m_file_load_trnsf) { - case SAVE_SESSION: - m_save_session_dialog_open = false; - break; - case SAVE_TRFR_FNC: - m_save_trnfct_open = false; - break; - default: - break; + ImGui::OpenPopup("Load File"); + m_file_load_trnsf = false; + } + if (saveDialogLoadTrnsFnc.showFileDialog("Save File", imgui_addons::ImGuiFileBrowser::DialogMode::SELECT, + ImVec2(700, 310))) + { + m_dir_to_save = saveDialogLoadTrnsFnc.selected_path; + switch (m_current_save_modal) + { + case SAVE_SESSION: + m_save_session_dialog_open = true; + break; + case SAVE_TRANSFER_FUNCTION: + m_save_transfer_function_open = true; + break; + default: + break; + } } + if (fileDialogLoadTrnsFnc.showFileDialog("Load File", imgui_addons::ImGuiFileBrowser::DialogMode::OPEN, + ImVec2(700, 310), m_file_extension_filter)) + { - } + if (m_current_load_modal == LOAD_MODAL::LOAD_TRFR_FNC) + { + if (helper::ends_with_string(fileDialogLoadTrnsFnc.selected_fn, ".fnc")) + { - if (m_file_load_trnsf) - { - ImGui::OpenPopup("Load File"); - m_file_load_trnsf = false; + tfn_widget.clear(); + tfn_widget_multi.clear(); + m_tfns.clear(); + std::string filePath = fileDialogLoadTrnsFnc.selected_path; + std::ifstream fileToLoad(filePath); + load_transfer_functions(fileToLoad); + m_trnfnc_table_selection = 0; + m_current_load_modal = LOAD_NONE; + } + } + if (m_current_load_modal == LOAD_MODAL::LOAD_SESSION) + { + if (helper::ends_with_string(fileDialogLoadTrnsFnc.selected_fn, ".usr")) + { - } - if (saveDialogLoadTrnsFnc.showFileDialog("Save File", imgui_addons::ImGuiFileBrowser::DialogMode::SELECT, - ImVec2(700, 310))) - { - m_dir_to_save = saveDialogLoadTrnsFnc.selected_path; - switch (m_current_save_modal) - { - case SAVE_SESSION: - m_save_session_dialog_open = true; - break; - case SAVE_TRFR_FNC: - m_save_trnfct_open = true; - break; - default: - break; + tfn_widget.clear(); + tfn_widget_multi.clear(); + m_tfns.clear(); + load_user_session(fileDialogLoadTrnsFnc.selected_path); + m_trnfnc_table_selection = 0; + m_current_load_modal = LOAD_NONE; + } + } } + ImGui::End(); } - - if (fileDialogLoadTrnsFnc.showFileDialog("Load File", imgui_addons::ImGuiFileBrowser::DialogMode::OPEN, - ImVec2(700, 310), m_file_extension_filter)) + if (m_show_movie_saved_pop_up) { - - if (m_current_load_modal == LOAD_MODAL::LOAD_TRFR_FNC) + ImGui::OpenPopup("Movie saved##POPUP"); + ImGui::SetNextWindowSize(ImVec2(350, 400), ImGuiCond_FirstUseEver); + if (ImGui::BeginPopupModal("Movie saved##POPUP", &m_show_movie_saved_pop_up)) { - if (helper::ends_with_string(fileDialogLoadTrnsFnc.selected_fn, ".fnc")) + ImGui::Text("Movie saved"); + if (ImGui::Button("Ok")) { - - tfn_widget.clear(); - tfn_widget_multi.clear(); - m_tfns.clear(); - std::string filePath = fileDialogLoadTrnsFnc.selected_path; - std::ifstream fileToLoad(filePath); - load_trans_functions(fileToLoad); - m_table_selection = 0; - m_current_load_modal = LOAD_NONE; + m_show_movie_saved_pop_up = false; + ImGui::CloseCurrentPopup(); } + ImGui::EndPopup(); } - if (m_current_load_modal == LOAD_MODAL::LOAD_SESSION) - { - if (helper::ends_with_string(fileDialogLoadTrnsFnc.selected_fn, ".usr")) - { + } - tfn_widget.clear(); - tfn_widget_multi.clear(); - m_tfns.clear(); - load_user_session(fileDialogLoadTrnsFnc.selected_path); - m_table_selection = 0; - m_current_load_modal = LOAD_NONE; - } - } + if (m_show_clock) + { + ImGui::SetNextWindowPos(ImVec2(m_clock_pos_x, m_clock_pos_y)); + ImGui::SetNextWindowSize(ImVec2(m_clock_width, m_clock_height)); + ImGui::Begin("##clock", &m_show_clock, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoTitleBar); + ImGui::SetWindowFontScale(1.3f); + ImGui::Text(m_time_info.c_str()); + ImGui::Text(m_day_info.c_str()); + ImGui::End(); } - ImGui::End(); + if (m_use_transferfunction) + { + tfn_widget[0].draw_legend(0, m_legend_pos_y + 80, m_clock_width + 50, m_clock_height - 140); + } } void UIView::init_ui(bool is2D, bool lookingGlass) @@ -642,28 +918,29 @@ void UIView::init_ui(bool is2D, bool lookingGlass) if (!m_initialized) { - //fileDialog.SetTitle("load data"); #ifdef WITH_NRRD - fileDialog.SetTypeFilters({ ".txt", ".nrrd" }); - #elseif - fileDialog.SetTypeFilters({ ".txt" }); + fileDialog.SetTypeFilters({".txt", ".nrrd"}); +#elseif + fileDialog.SetTypeFilters({".txt"}); #endif float fontsize = 2.0; - if (is2D) { + if (is2D) + { fontsize = 1.0; } - if (lookingGlass) { + if (lookingGlass) + { fontsize = 3.0; } std::cout << "is2d: " << (is2D ? "true" : "false") << std::endl; m_menu_handler = new VRMenuHandler(is2D); if (!m_menu_handler) { - std::cout << "m_menu_handler: " << "NULL" << std::endl; - + std::cout << "m_menu_handler: " + << "NULL" << std::endl; } - VRMenu* menu = m_menu_handler->addNewMenu(std::bind(&UIView::draw_ui_callback, this), 1024, 1024, 1, 1, fontsize); + VRMenu *menu = m_menu_handler->addNewMenu(std::bind(&UIView::draw_ui_callback, this), 1024, 1024, 1, 1, fontsize); menu->setMenuPose(glm::mat4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 2, -1, 1)); m_dir_to_save = m_controller_app.get_directory_path().c_str(); @@ -673,11 +950,7 @@ void UIView::init_ui(bool is2D, bool lookingGlass) } m_initialized = true; - - } - - } void UIView::update_ui(int numVolumes) @@ -685,12 +958,12 @@ void UIView::update_ui(int numVolumes) tfn_widget_multi.resize(1); tfn_widget.resize(1); m_use_transferfunction = true; - /* m_selected_volume_TrFn.resize(1); - m_selected_volume_TrFn[0].resize(numVolumes); - for (int i = 0; i < numVolumes; i++) - { - m_selected_volume_TrFn[0][i] = false; - }*/ + m_selected_volume_TrFn.resize(1); + m_selected_volume_TrFn[0].resize(numVolumes); + for (int i = 0; i < numVolumes; i++) + { + m_selected_volume_TrFn[0][i] = false; + } MyTransFerFunctions trfntc; char label[32]; @@ -702,48 +975,40 @@ void UIView::update_ui(int numVolumes) trfntc.volumes.push_back(false); } m_tfns.push_back(trfntc); - m_table_selection = 0; + m_trnfnc_table_selection = 0; load_ocean_color_maps(); } -void UIView::render_2D(Window_Properties& window_properties) +void UIView::render_2D(Window_Properties &window_properties) { - if (m_show_menu) - { - - m_menu_handler->drawMenu(window_properties.window_w, window_properties.window_h, - window_properties.framebuffer_w, window_properties.framebuffer_h); - - if (m_use_transferfunction) { - tfn_widget[m_selectedTrnFnc].drawLegend(); - } - } + m_clock_pos_x = window_properties.window_w - m_clock_width; + m_clock_pos_y = window_properties.window_h - m_clock_height; + m_legend_pos_y = window_properties.window_h - m_clock_height; + m_menu_handler->drawMenu(window_properties.window_w, window_properties.window_h, + window_properties.framebuffer_w, window_properties.framebuffer_h); } -void UIView::render_3D(glm::mat4& space_matrix, Window_Properties& window_properties) +void UIView::render_3D(glm::mat4 &space_matrix, Window_Properties &window_properties) { - //render menu + // render menu if (m_show_menu) { - glMatrixMode(GL_MODELVIEW); - glLoadMatrixf(glm::value_ptr(space_matrix)); + m_menu_handler->drawMenu(window_properties.window_w, window_properties.window_h, - window_properties.framebuffer_w, window_properties.framebuffer_h); + window_properties.framebuffer_w, window_properties.framebuffer_h); } - } - void UIView::update_3D_ui_frame() { m_menu_handler->renderToTexture(); } -void UIView::set_cursor_pos(glm::vec2& mPos) +void UIView::set_cursor_pos(glm::vec2 &mPos) { if (m_menu_handler) { @@ -766,7 +1031,6 @@ int UIView::get_num_transfer_functions() bool UIView::is_transfer_function_enabled(int tfn, int vol) { - //return m_selected_volume_TrFn[tfn][vol]; return m_tfns[tfn].volumes[vol]; } @@ -806,7 +1070,6 @@ void UIView::set_button_click(int button, int state) { m_menu_handler->setButtonClick(button, state); } - } void UIView::set_enable_render_volume() @@ -814,13 +1077,12 @@ void UIView::set_enable_render_volume() m_renderVolume = !m_renderVolume; } -void UIView::set_controller_pose(glm::mat4& pose) +void UIView::set_controller_pose(glm::mat4 &pose) { if (m_menu_handler) { m_menu_handler->setControllerPose(pose); } - } void UIView::set_dynamic_slices(bool dynamicSlices) @@ -871,13 +1133,12 @@ void UIView::update_animation(float speed, int numFrames) { m_ui_frame_controller = 0.0f; - } m_controller_app.set_frame(m_ui_frame_controller); } } -void UIView::add_data_label(std::string& dataLabel) +void UIView::add_data_label(std::string &dataLabel) { m_dataLabels.push_back(dataLabel); } @@ -932,49 +1193,89 @@ glm::vec3 UIView::get_clip_max() return m_clip_max; } -void UIView::set_chracter(char c) +void UIView::set_clip_min(glm::vec3 clip_min) +{ + m_clip_min = clip_min; +} + +void UIView::set_clip_max(glm::vec3 clip_max) +{ + m_clip_max = clip_max; +} + +void UIView::add_character(char c) { - if (m_trn_fct_opitions_window) + if (m_transfer_function_options_window) { + ImGui::ClearActiveID(); m_copy_trnfnct_name += c; } - if (m_save_trnfct_open || m_save_session_dialog_open) + if (m_save_transfer_function_open || m_save_session_dialog_open) { + ImGui::ClearActiveID(); m_save_file_name += c; } + + if (m_camera_name_window_open) + { + ImGui::ClearActiveID(); + m_copy_camera_name += c; + } + + if (m_camera_animation_duration_open) + { + ImGui::ClearActiveID(); + if ((c >= '0' && c <= '9') || (c == '.')) + { + m_string_animation_duration += c; + } + } } void UIView::remove_character() { - if (m_trn_fct_opitions_window) + if (m_transfer_function_options_window) { if (!m_copy_trnfnct_name.empty()) { m_copy_trnfnct_name.pop_back(); } - } - if (m_save_trnfct_open || m_save_session_dialog_open) + if (m_save_transfer_function_open || m_save_session_dialog_open) { if (!m_save_file_name.empty()) { m_save_file_name.pop_back(); } + } + if (m_camera_name_window_open) + { + if (!m_copy_camera_name.empty()) + { + m_copy_camera_name.pop_back(); + } + } + + if (m_camera_animation_duration_open) + { + if (!m_string_animation_duration.empty()) + { + ImGui::ClearActiveID(); + m_string_animation_duration.pop_back(); + } } } -void UIView::open_save_modal_dialog(std::string& id, bool& window_state, - std::function save_function, std::string& extension) +void UIView::open_save_modal_dialog(std::string &id, bool &window_state, + std::function save_function, std::string &extension) { ImGui::OpenPopup(id.c_str()); ImGui::SetNextWindowSize(ImVec2(350, 200), ImGuiCond_FirstUseEver); if (ImGui::BeginPopupModal(id.c_str(), &window_state)) { - char* writable = new char[m_save_file_name.size() + 1]; - std::copy(m_save_file_name.begin(), m_save_file_name.end(), writable); - writable[m_save_file_name.size()] = '\0'; + ImGui::Text(m_dir_to_save.c_str()); ImGui::SameLine(); if (ImGui::Button("...")) @@ -982,10 +1283,9 @@ void UIView::open_save_modal_dialog(std::string& id, bool& window_state, m_file_dialog_save_dir = true; } - ImGui::InputText("##filename", writable, IM_ARRAYSIZE(writable)); + ImGui::InputText("##filename", &m_save_file_name); ImGui::IsItemActive(); - if (ImGui::Button("Save")) { std::string fileName = m_dir_to_save + helper::get_OS_path_separator() + m_save_file_name + extension; @@ -1004,12 +1304,11 @@ void UIView::open_save_modal_dialog(std::string& id, bool& window_state, } } -void UIView::add_trans_function() +void UIView::add_transfer_function() { - } -void UIView::save_trans_functions(std::ofstream& saveFile) +void UIView::save_transfer_functions(std::ofstream &saveFile) { std::string pointsLine; if (saveFile.is_open()) @@ -1017,22 +1316,9 @@ void UIView::save_trans_functions(std::ofstream& saveFile) saveFile << "numFunction " << std::to_string(m_tfns.size()) << "\n"; for (int i = 0; i < m_tfns.size(); i++) { - //savefile << m_tfns[i].ID + ","; + saveFile << "FuncName " + std::to_string(i + 1) + " " + m_tfns[i].Name + " " + std::to_string(tfn_widget[i].get_colormap_gpu()) + "\n"; - /* for (int j = 0; j < tfn_widget_multi[i].alpha_control_pts.size(); j++) - { - if (j != tfn_widget_multi[i].alpha_control_pts.size()-1) - { - savefile << std::to_string(tfn_widget_multi[i].alpha_control_pts[j][0].x) +","+ std::to_string(tfn_widget_multi[i].alpha_control_pts[j][0].y) + - std::to_string(tfn_widget_multi[i].alpha_control_pts[j][1].x) + "," + std::to_string(tfn_widget_multi[i].alpha_control_pts[j][1].y); - } - else - { - savefile << std::to_string(tfn_widget_multi[i].alpha_control_pts[j][0].x) + "," + std::to_string(tfn_widget_multi[i].alpha_control_pts[j][0].y )+ - std::to_string(tfn_widget_multi[i].alpha_control_pts[j][1].x) + "," + std::to_string(tfn_widget_multi[i].alpha_control_pts[j][1].y) +";"; - } - - }*/ + saveFile << "FuncPoints " << std::to_string(i + 1) << " "; for (int j = 0; j < tfn_widget[i].alpha_control_pts.size(); j++) { @@ -1044,15 +1330,13 @@ void UIView::save_trans_functions(std::ofstream& saveFile) { saveFile << std::to_string(tfn_widget[i].alpha_control_pts[j].x) + "," + std::to_string(tfn_widget[i].alpha_control_pts[j].y); } - } saveFile << "\n"; } - saveFile.close(); } } -void UIView::save_user_session(std::ofstream& savefile) +void UIView::save_user_session(std::ofstream &savefile) { if (savefile.is_open()) @@ -1079,17 +1363,25 @@ void UIView::save_user_session(std::ofstream& savefile) savefile << "ClipZmax " << std::to_string(m_clip_max.z) << "\n"; savefile << "Use_transferfunction " << std::to_string(m_use_transferfunction) << "\n"; + int num_camera_poi = m_controller_app.get_simulation().get_simulation_states().size(); + if (num_camera_poi > 0) + { + savefile << "SIM " << num_camera_poi << "\n"; + save_simulation_states(savefile, num_camera_poi); + } + if (m_use_transferfunction) { - savefile << "Trnfncs" << "\n"; - save_trans_functions(savefile); + savefile << "Trnfncs" + << "\n"; + save_transfer_functions(savefile); } savefile.close(); } } -void UIView::load_trans_functions(std::ifstream& loadFile) +void UIView::load_transfer_functions(std::ifstream &loadFile) { std::string line; @@ -1099,11 +1391,12 @@ void UIView::load_trans_functions(std::ifstream& loadFile) { while (std::getline(loadFile, line)) { - std::vector vals; // Create vector to hold our words + std::vector vals; std::stringstream ss(line); std::string buf; - while (ss >> buf) { + while (ss >> buf) + { vals.push_back(buf); } @@ -1118,8 +1411,6 @@ void UIView::load_trans_functions(std::ifstream& loadFile) tfn_widget_multi.resize(numFunctions); m_tfns.resize(numFunctions); m_trnfnct_counter = numFunctions + 1; - - } if (tag == "FuncName") { @@ -1140,11 +1431,13 @@ void UIView::load_trans_functions(std::ifstream& loadFile) size_t pos = 0; std::string token; std::string delimiter = ";"; - size_t last = 0; size_t next = 0; + size_t last = 0; + size_t next = 0; std::string point; int poinCounter = 0; tfn_widget[index].alpha_control_pts.clear(); - while ((next = points.find(delimiter, last)) != std::string::npos) { + while ((next = points.find(delimiter, last)) != std::string::npos) + { point = points.substr(last, next - last); int comaPos = point.find(","); @@ -1152,7 +1445,6 @@ void UIView::load_trans_functions(std::ifstream& loadFile) float pointY = std::stof(point.substr(comaPos + 1)); tfn_widget[index].alpha_control_pts.push_back(vec2f(pointX, pointY)); - last = next + 1; poinCounter++; } @@ -1162,14 +1454,11 @@ void UIView::load_trans_functions(std::ifstream& loadFile) float pointY = std::stof(point.substr(comaPos + 1)); tfn_widget[index].alpha_control_pts.push_back(vec2f(pointX, pointY)); std::cout << points.substr(last) << std::endl; - } - } } loadFile.close(); } - } void UIView::load_user_session(std::string filePath) @@ -1177,7 +1466,6 @@ void UIView::load_user_session(std::string filePath) std::string line; std::ifstream loadFile(filePath); - if (loadFile.is_open()) { while (std::getline(loadFile, line)) @@ -1186,74 +1474,173 @@ void UIView::load_user_session(std::string filePath) std::stringstream ss(line); std::string buf; - while (ss >> buf) { + while (ss >> buf) + { vals.push_back(buf); } std::string tag = vals[0]; - if (tag == "volume_loaded") { std::string fileToLoad = vals[1]; - VRDataLoader::get_instance()->load_txt_file(m_controller_app, fileToLoad); + VRDataLoader::load_txt_file(m_controller_app, fileToLoad); } - else if (tag == "alpha_multiplier") { + else if (tag == "alpha_multiplier") + { m_multiplier = std::stof(vals[1]); } - else if (tag == "threshold") { + else if (tag == "threshold") + { m_threshold = std::stof(vals[1]); } - else if (tag == "scale") { + else if (tag == "scale") + { m_scale = std::stof(vals[1]); } - else if (tag == "z-scale") { + else if (tag == "z-scale") + { m_z_scale = std::stof(vals[1]); } - else if (tag == "Slices") { + else if (tag == "Slices") + { m_slices = std::stof(vals[1]); } - else if (tag == "automatic _slice adjustment") { + else if (tag == "automatic _slice adjustment") + { m_dynamic_slices = std::stof(vals[1]); } - else if (tag == "RenderMethod") { + else if (tag == "RenderMethod") + { m_rendermethod = std::stof(vals[1]); } - else if (tag == "Render_Channel") { + else if (tag == "Render_Channel") + { m_renderchannel = std::stof(vals[1]); } - else if (tag == "Render_Volume_data") { + else if (tag == "Render_Volume_data") + { m_renderVolume = std::stoi(vals[1]); } - else if (tag == "ClipXmin") { + else if (tag == "ClipXmin") + { m_clip_min.x = std::stof(vals[1]); } - else if (tag == "ClipXmax") { + else if (tag == "ClipXmax") + { m_clip_max.x = std::stof(vals[1]); } - else if (tag == "ClipYmin") { + else if (tag == "ClipYmin") + { m_clip_min.y = std::stof(vals[1]); } - else if (tag == "ClipYmax") { + else if (tag == "ClipYmax") + { m_clip_max.y = std::stof(vals[1]); } - else if (tag == "ClipZmin") { + else if (tag == "ClipZmin") + { m_clip_min.z = std::stof(vals[1]); } - else if (tag == "ClipZmax") { + else if (tag == "ClipZmax") + { m_clip_max.z = std::stof(vals[1]); } else if (tag == "Trnfncs") { - load_trans_functions(loadFile); + load_transfer_functions(loadFile); + } + else if (tag == "POI") + { + load_camera_poi(loadFile, std::stoi(vals[1])); } } loadFile.close(); + m_controller_app.get_trackball_camera().reset_camera(); + } +} +void UIView::save_simulation_states(std::ofstream &saveFile, int num_camera_poi) +{ + if (saveFile.is_open()) + { + + auto sim_iterator = m_controller_app.get_simulation().get_simulation_states().begin(); + for (sim_iterator; sim_iterator != m_controller_app.get_simulation().get_simulation_states().end(); sim_iterator++) + { + saveFile << sim_iterator->poi.label << " " + << std::to_string(sim_iterator->poi.eye.x) + " " + std::to_string(sim_iterator->poi.eye.y) + " " + std::to_string(sim_iterator->poi.eye.z) + " " + << std::to_string(sim_iterator->poi.target.x) + " " + std::to_string(sim_iterator->poi.target.y) + " " + std::to_string(sim_iterator->poi.target.z) + " " + << std::to_string(sim_iterator->poi.up.x) + " " + std::to_string(sim_iterator->poi.up.y) + " " + std::to_string(sim_iterator->poi.up.z) + " " + << std::to_string(sim_iterator->poi.radius) + " " + << std::to_string(sim_iterator->min_clip.x) + " " + std::to_string(sim_iterator->min_clip.y) + " " + std::to_string(sim_iterator->min_clip.z) + " " + << std::to_string(sim_iterator->max_clip.x) + " " + std::to_string(sim_iterator->max_clip.y) + " " + std::to_string(sim_iterator->max_clip.z) + "\n"; + } } } +void UIView::load_camera_poi(std::ifstream &loadFile, int num_poi) +{ + std::string line; + if (loadFile.is_open()) + { + for (int i = 0; i < num_poi; ++i) + { + std::getline(loadFile, line); + std::vector poiVals; + read_file_line(line, poiVals); + + if (poiVals.size() > 0) + { + std::string label = poiVals[0]; + float eye_x = std::stof(poiVals[1]); + float eye_y = std::stof(poiVals[2]); + float eye_z = std::stof(poiVals[3]); + float target_x = std::stof(poiVals[4]); + float target_y = std::stof(poiVals[5]); + float target_z = std::stof(poiVals[6]); + float up_x = std::stof(poiVals[7]); + float up_y = std::stof(poiVals[8]); + float up_z = std::stof(poiVals[9]); + float radius = std::stof(poiVals[10]); + float min_clip_x = std::stof(poiVals[11]); + float min_clip_y = std::stof(poiVals[12]); + float min_clip_z = std::stof(poiVals[13]); + float max_clip_x = std::stof(poiVals[14]); + float max_clip_y = std::stof(poiVals[15]); + float max_clip_z = std::stof(poiVals[16]); + + SimulationState sim; + sim.poi.label = label; + sim.poi.eye = glm::vec3(eye_x, eye_y, eye_z); + sim.poi.target = glm::vec3(target_x, target_y, target_z); + sim.poi.up = glm::vec3(up_x, up_y, up_z); + sim.poi.radius = radius; + sim.min_clip = glm::vec3(min_clip_x, min_clip_y, min_clip_z); + sim.max_clip = glm::vec3(max_clip_x, max_clip_y, max_clip_z); + m_controller_app.get_simulation().add_simulation_state(sim); + } + } + } +} + +void UIView::read_file_line(std::string &line, std::vector &values) +{ + std::stringstream ss(line); + std::string buf; + + while (ss >> buf) + { + values.push_back(buf); + } +} + +void UIView::set_animation_length(int num_frames) +{ + m_num_animation_frames = num_frames; +} + void UIView::adjust_transfer_function_to_histogram() { @@ -1269,7 +1656,7 @@ void UIView::adjust_transfer_function_to_histogram() const std::size_t pos1 = std::floor(m_histogram_quantiles[0] * std::distance(histogram_copy.begin(), histogram_copy.end())); const std::size_t pos2 = std::floor(m_histogram_quantiles[1] * std::distance(histogram_copy.begin(), histogram_copy.end())); - if (histogram_copy.size() > pos1&& histogram_copy.size() > pos2) + if (histogram_copy.size() > pos1 && histogram_copy.size() > pos2) { std::nth_element(histogram_copy.begin(), histogram_copy.begin() + pos1, histogram_copy.end()); @@ -1279,7 +1666,6 @@ void UIView::adjust_transfer_function_to_histogram() m_histogram_point_1.x = index1; m_histogram_point_1.y = 0.0f; - std::nth_element(histogram_copy.begin(), histogram_copy.begin() + pos2, histogram_copy.end()); std::vector::iterator it2 = std::find(m_histogram.getHistogram().begin(), m_histogram.getHistogram().end(), histogram_copy[pos2]); @@ -1287,11 +1673,9 @@ void UIView::adjust_transfer_function_to_histogram() m_histogram_point_2.x = index2; m_histogram_point_2.y = 1.0f; - } } - void UIView::compute_new_histogram_view() { if (!m_compute_new_histogram) @@ -1305,7 +1689,6 @@ void UIView::compute_new_histogram_view() for (int i = 0; i < m_controller_app.get_num_volumes(); i++) { - if (m_column_selected[i]) { if (m_controller_app.get_volume(i)[0]->getMin() < global_min) @@ -1323,9 +1706,7 @@ void UIView::compute_new_histogram_view() { histogram[j] += current_histogram[j]; } - } - } m_histogram.setHistogram(histogram); @@ -1333,8 +1714,7 @@ void UIView::compute_new_histogram_view() m_compute_new_histogram = false; } - -void UIView::addTransferFunction() +void UIView::add_transfer_function() { int numVolumes = m_controller_app.get_num_volumes(); MyTransFerFunctions trfntc; @@ -1348,6 +1728,58 @@ void UIView::addTransferFunction() } m_tfns.push_back(trfntc); } + +void UIView::get_quantiles(int row) +{ + m_copy_trnfnct_name = m_tfns[row].Name; + float q_min = 0; + float q_max = 0; + tfn_widget[m_trnfnc_table_selection].get_quantiles(q_min, q_max); + m_histogram_quantiles[0] = q_min; + m_histogram_quantiles[1] = q_max; + m_transfer_function_options_window = true; +} + +void UIView::set_volume_time_info(time_t time) +{ + + tm *time_info = localtime(&time); + if (time_info) + { + bool pm = time_info->tm_hour >= 12; + int hour_12 = (time_info->tm_hour >= 13) ? time_info->tm_hour - 12 : time_info->tm_hour; + + std::stringstream ss_time; + ss_time << std::setw(2) << std::setfill('0') << hour_12 << ":"; + ss_time << std::setw(2) << std::setfill('0') << time_info->tm_min << " "; + ss_time << (pm ? "PM" : "AM"); + + std::stringstream ss_day; + ss_day << m_months[time_info->tm_mon] << " "; + ss_day << std::setw(2) << std::setfill('0') << time_info->tm_mday; + ss_day << ", " << time_info->tm_year + 1900; + + m_time_info = ss_time.str(); + m_day_info = ss_day.str(); + } +} + +void UIView::draw_transfer_function_legend() +{ + if (m_use_transferfunction) + { + tfn_widget[0].draw_legend(); + } +} + +void UIView::set_transfer_function_min_max(float min, float max) +{ + if (m_use_transferfunction) + { + tfn_widget[0].setMinMax(min, max); + } +} + void UIView::load_ocean_color_maps() { int w, h, n; @@ -1356,11 +1788,11 @@ void UIView::load_ocean_color_maps() for (std::string color_map_name : m_ocean_color_maps_names) { std::string file_name_path = m_controller_app.get_directory_path() + OS_SLASH + m_color_map_directory + OS_SLASH + color_map_name; - uint8_t* img_data = stbi_load(file_name_path.c_str(), &w, &h, &comp, 4); + uint8_t *img_data = stbi_load(file_name_path.c_str(), &w, &h, &comp, 4); auto img = std::vector(img_data, img_data + w * 1 * 4); stbi_image_free(img_data); - //set name + // set name std::string name = color_map_name.substr(0, color_map_name.find_first_of(".")); @@ -1368,4 +1800,3 @@ void UIView::load_ocean_color_maps() tfn_widget[0].add_colormap(color_map); } } - diff --git a/src/interaction/ArcBall.cpp b/src/interaction/ArcBall.cpp deleted file mode 100644 index 13ef64d..0000000 --- a/src/interaction/ArcBall.cpp +++ /dev/null @@ -1,181 +0,0 @@ -// ---------------------------------- -// Copyright © 2017, Brown University, Providence, RI. -// -// All Rights Reserved -// -// Use of the software is provided under the terms of the GNU General Public License version 3 -// as published by the Free Software Foundation at http://www.gnu.org/licenses/gpl-3.0.html, provided -// that this copyright notice appear in all copies and that the name of Brown University not be used in -// advertising or publicity pertaining to the use or distribution of the software without specific written -// prior permission from Brown University. -// -// See license.txt for further information. -// -// BROWN UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE WHICH IS -// PROVIDED “AS IS”, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -// FOR ANY PARTICULAR PURPOSE. IN NO EVENT SHALL BROWN UNIVERSITY BE LIABLE FOR ANY -// SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR FOR ANY DAMAGES WHATSOEVER RESULTING -// FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR -// OTHER TORTIOUS ACTION, OR ANY OTHER LEGAL THEORY, ARISING OUT OF OR IN CONNECTION -// WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -// ---------------------------------- -// -///\file ArcBall.cpp -///\author Benjamin Knorlein -///\date 10/17/2019 - - -#include "../../include/interaction/ArcBall.h" -#include -#include "glm/ext.hpp" -#include -#define GLM_ENABLE_EXPERIMENTAL -#include - -#ifndef _PI -#define _PI 3.141592653 -#endif - -ArcBall::ArcBall() : m_radius(1), m_mouse_left_pressed(false), m_mouse_center_pressed(false), m_mouse_right_pressed(false), last_x(0), last_y(0) -, m_PanFactor(1), m_RotateFactor(1), m_cameraScrollFactor(0.1), m_target(0, 0, 0), m_eye(0, 0, 1), m_up(0, 1, 0), m_rotate_camera_center{ false } -{ - - -} - -ArcBall::~ArcBall() -{ - -} - -void ArcBall::updateCameraMatrix() -{ - m_eye = glm::normalize(m_eye); - viewmatrix = glm::lookAt(m_radius * m_eye + m_target, m_target, m_up); -} - -void ArcBall::mouse_pressed(int button, bool isDown) -{ - if (button == 0) //left -> rotate - { - m_mouse_left_pressed = isDown; - } - else if (button == 1) // right ->pan - { - m_mouse_right_pressed = isDown; - - } - else if (button == 2) - { - - m_mouse_center_pressed = isDown; - } -} - -void ArcBall::mouse_move(float x, float y) { - if (m_mouse_left_pressed) { - // Calculate the new phi and theta based on mouse position relative to where the user clicked - float dx = ((float)(last_x - x)) / 300.0f; - float dy = ((float)(last_y - y)) / 300.0f; - - Rotate(dx * m_RotateFactor, -dy * m_RotateFactor); - } - else if (m_mouse_center_pressed) { - float dy = ((float)(last_y - y)) / 300.0f; - - RotateEyeAxis(dy * m_RotateFactor); - } - else if (m_mouse_right_pressed) { - float dx = ((float)(last_x - x)) / 300.0f; - float dy = ((float)(last_y - y)) / 300.0f; - - Pan(-dx * m_PanFactor, -dy * m_PanFactor); - } - - last_x = x; - last_y = y; -} - -void ArcBall::mouse_scroll(float dist) { - Zoom(dist); -} - -void ArcBall::setCameraCenterRotation(bool useCameraCenter) { - if (useCameraCenter != m_rotate_camera_center) { - m_rotate_camera_center = useCameraCenter; - if (!m_rotate_camera_center) { - m_target = glm::vec3{ 0.0 }; - } - } -} - -void ArcBall::wasd_pressed(int awsd) { - glm::vec3 dir = glm::normalize(-m_eye); - glm::vec3 right = glm::cross(dir, m_up); - - if (W & awsd) { - m_target = m_target + dir * glm::vec3(0.001); - updateCameraMatrix(); - } - if (S & awsd) { - m_target = m_target - dir * glm::vec3(0.001); - updateCameraMatrix(); - } - if (A & awsd) { - m_target = m_target - (right)*glm::vec3(0.001); - updateCameraMatrix(); - } - if (D & awsd) { - m_target = m_target + (right)*glm::vec3(0.001); - updateCameraMatrix(); - } - if (Q & awsd) { - m_target = m_target - (m_up)*glm::vec3(0.001); - updateCameraMatrix(); - } - if (E & awsd) { - m_target = m_target + (m_up)*glm::vec3(0.001); - updateCameraMatrix(); - } -} - -void ArcBall::Rotate(float dx, float dy) { - glm::vec3 right = glm::cross(glm::normalize(m_eye), m_up); - glm::mat4 rot = glm::mat4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); - rot = glm::rotate(rot, dx, m_up); - rot = glm::rotate(rot, dy, right); - - if (m_rotate_camera_center) - m_target += m_radius * glm::normalize(m_eye); - - m_eye = rot * glm::vec4(m_eye, 1); - m_up = rot * glm::vec4(m_up, 1); - - if (m_rotate_camera_center) - m_target -= m_radius * glm::normalize(m_eye); - else - m_target = rot * glm::vec4(m_target, 1); -} - -void ArcBall::RotateEyeAxis(float dy) { - glm::mat4 rot = glm::mat4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); - rot = glm::rotate(rot, dy, m_eye); - m_up = rot * glm::vec4(m_up, 1); -} - -void ArcBall::Zoom(float distance) { - m_radius -= distance; - - if (m_radius < 0) - m_radius = 0.000001; -} - -void ArcBall::Pan(float dx, float dy) { - - glm::vec3 right = glm::cross(m_eye, m_up); - - m_target = m_target + (right * dx) + (m_up * dy); -} - - - diff --git a/src/interaction/ArcBallCamera.cpp b/src/interaction/ArcBallCamera.cpp new file mode 100644 index 0000000..b623cb2 --- /dev/null +++ b/src/interaction/ArcBallCamera.cpp @@ -0,0 +1,249 @@ +// ---------------------------------- +// Copyright © 2017, Brown University, Providence, RI. +// +// All Rights Reserved +// +// Use of the software is provided under the terms of the GNU General Public License version 3 +// as published by the Free Software Foundation at http://www.gnu.org/licenses/gpl-3.0.html, provided +// that this copyright notice appear in all copies and that the name of Brown University not be used in +// advertising or publicity pertaining to the use or distribution of the software without specific written +// prior permission from Brown University. +// +// See license.txt for further information. +// +// BROWN UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE WHICH IS +// PROVIDED "AS IS", INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR ANY PARTICULAR PURPOSE. IN NO EVENT SHALL BROWN UNIVERSITY BE LIABLE FOR ANY +// SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR FOR ANY DAMAGES WHATSOEVER RESULTING +// FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +// OTHER TORTIOUS ACTION, OR ANY OTHER LEGAL THEORY, ARISING OUT OF OR IN CONNECTION +// WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +// ---------------------------------- +// +///\file ArcBall.cpp +///\author Benjamin Knorlein +///\date 10/17/2019 + +#include "../../include/interaction/ArcBallCamera.h" +#include +#include "glm/ext.hpp" +#include +#define GLM_ENABLE_EXPERIMENTAL +#include +#include "../../include/vrapp/VRVolumeApp.h" + +#ifndef _PI +#define _PI 3.141592653 +#endif + +ArcBallCamera::ArcBallCamera() : m_radius(1), m_mouse_left_pressed(false), m_mouse_center_pressed(false), m_mouse_right_pressed(false), last_x(0), last_y(0), m_PanFactor(1), m_RotateFactor(1), m_cameraScrollFactor(0.1), m_target(0, 0, 0), m_eye(0, 0, 1), m_up(0, 1, 0), m_rotate_camera_center{false} +{ +} + +ArcBallCamera::~ArcBallCamera() +{ +} + +void ArcBallCamera::update_camera_matrix() +{ + if (m_app_mode == 0) + { + m_viewmatrix = glm::lookAt(m_current_poi.get_camera_position(), m_current_poi.target, m_current_poi.up); + } + else + { + m_viewmatrix = glm::lookAt(m_simulation_poi.get_camera_position(), m_simulation_poi.target, m_simulation_poi.up); + } +} + +void ArcBallCamera::update_sim_poi(PointOfInterest &poi) +{ + m_simulation_poi = poi; +} + +void ArcBallCamera::mouse_pressed(int button, bool isDown) +{ + if (m_app_mode == 0) + { + if (button == 0) // left -> rotate + { + m_mouse_left_pressed = isDown; + } + else if (button == 1) // right ->pan + { + m_mouse_right_pressed = isDown; + } + else if (button == 2) + { + + m_mouse_center_pressed = isDown; + } + } +} + +void ArcBallCamera::mouse_move(float x, float y) +{ + if (m_app_mode == 0) + { + if (m_mouse_left_pressed) + { + // Calculate the new phi and theta based on mouse position relative to where the user clicked + float dx = ((float)(last_x - x)) / 300.0f; + float dy = ((float)(last_y - y)) / 300.0f; + + Rotate(dx * m_RotateFactor, -dy * m_RotateFactor); + } + else if (m_mouse_center_pressed) + { + float dy = ((float)(last_y - y)) / 300.0f; + + RotateEyeAxis(dy * m_RotateFactor); + } + else if (m_mouse_right_pressed) + { + float dx = ((float)(last_x - x)) / 300.0f; + float dy = ((float)(last_y - y)) / 300.0f; + + Pan(-dx * m_PanFactor, -dy * m_PanFactor); + } + + last_x = x; + last_y = y; + } +} + +void ArcBallCamera::mouse_scroll(float dist) +{ + if (m_app_mode == 0) + { + Zoom(dist); + } +} + +void ArcBallCamera::setCameraCenterRotation(bool useCameraCenter) +{ + if (useCameraCenter != m_rotate_camera_center) + { + m_rotate_camera_center = useCameraCenter; + if (!m_rotate_camera_center) + { + m_current_poi.target = glm::vec3{0.0}; + } + } +} + +void ArcBallCamera::wasd_pressed(int wasd) +{ + + if (m_app_mode == 0) + { + glm::vec3 dir = glm::normalize(-m_current_poi.eye); + glm::vec3 right = glm::cross(dir, m_current_poi.up); + + if (W & wasd) + { + m_current_poi.target = m_current_poi.target + dir * glm::vec3(0.001); + update_camera_matrix(); + } + if (S & wasd) + { + m_current_poi.target = m_current_poi.target - dir * glm::vec3(0.001); + update_camera_matrix(); + } + if (A & wasd) + { + m_current_poi.target = m_current_poi.target - (right)*glm::vec3(0.001); + update_camera_matrix(); + } + { + if (D & wasd) + m_current_poi.target = m_current_poi.target + (right)*glm::vec3(0.001); + update_camera_matrix(); + } + if (Q & wasd) + { + m_current_poi.target = m_target - m_current_poi.up * glm::vec3(0.001); + update_camera_matrix(); + } + if (E & wasd) + { + m_current_poi.target = m_target + m_current_poi.up * glm::vec3(0.001); + update_camera_matrix(); + } + } +} + +void ArcBallCamera::Rotate(float dx, float dy) +{ + glm::vec3 right = glm::cross(glm::normalize(m_current_poi.eye), m_current_poi.up); + glm::mat4 rot = glm::mat4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); + rot = glm::rotate(rot, dx, m_current_poi.up); + rot = glm::rotate(rot, dy, right); + + if (m_rotate_camera_center) + m_current_poi.target += m_current_poi.radius * glm::normalize(m_current_poi.eye); + + m_current_poi.eye = rot * glm::vec4(m_current_poi.eye, 1); + m_current_poi.up = rot * glm::vec4(m_current_poi.up, 1); + + if (m_rotate_camera_center) + m_current_poi.target -= m_current_poi.radius * glm::normalize(m_current_poi.eye); + else + m_current_poi.target = rot * glm::vec4(m_current_poi.target, 1); +} + +void ArcBallCamera::RotateEyeAxis(float dy) +{ + glm::mat4 rot = glm::mat4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); + rot = glm::rotate(rot, dy, m_current_poi.eye); + m_current_poi.up = rot * glm::vec4(m_current_poi.up, 1); +} + +void ArcBallCamera::Zoom(float distance) +{ + m_current_poi.radius -= distance; + + if (m_current_poi.radius < 0) + { + m_current_poi.radius = 0.000001; + } + + std::cout << m_current_poi.radius << std::endl; +} + +void ArcBallCamera::Pan(float dx, float dy) +{ + + glm::vec3 right = glm::cross(m_current_poi.eye, m_current_poi.up); + + m_current_poi.target = m_current_poi.target + (right * dx) + (m_current_poi.up * dy); +} + +PointOfInterest &ArcBallCamera::get_current_poi() +{ + return m_current_poi; +} + +void ArcBallCamera::set_current_poi(const PointOfInterest &poi) +{ + // deep copy + m_current_poi = poi; +} + +void ArcBallCamera::reset_camera() +{ + last_x = 0; + last_y = 0; + m_PanFactor = 1; + m_RotateFactor = 1; + m_cameraScrollFactor = 0.1; + m_target = glm::vec3(0, 0, 0); + m_eye = glm::vec3(0, 0, 1); + m_up = glm::vec3(0, 1, 0); + m_current_poi = PointOfInterest(); +} + +void ArcBallCamera::set_app_mode(unsigned int mode) +{ + m_app_mode = mode; +} diff --git a/src/interaction/LabelManager.cpp b/src/interaction/LabelManager.cpp new file mode 100644 index 0000000..2537f5f --- /dev/null +++ b/src/interaction/LabelManager.cpp @@ -0,0 +1,194 @@ +// ---------------------------------- +// Copyright © 2015, Brown University, Providence, RI. +// +// All Rights Reserved +// +// Use of the software is provided under the terms of the GNU General Public License version 3 +// as published by the Free Software Foundation at http://www.gnu.org/licenses/gpl-3.0.html, provided +// that this copyright notice appear in all copies and that the name of Brown University not be used in +// advertising or publicity pertaining to the use or distribution of the software without specific written +// prior permission from Brown University. +// +// See license.txt for further information. +// +// BROWN UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE WHICH IS +// PROVIDED “AS IS”, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR ANY PARTICULAR PURPOSE. IN NO EVENT SHALL BROWN UNIVERSITY BE LIABLE FOR ANY +// SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR FOR ANY DAMAGES WHATSOEVER RESULTING +// FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +// OTHER TORTIOUS ACTION, OR ANY OTHER LEGAL THEORY, ARISING OUT OF OR IN CONNECTION +// WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +// ---------------------------------- +// +///\file Labels.cpp +///\author Benjamin Knorlein +///\date 6/25/2019 +///\author Camilo Diaz +///\date 4/28/2022 + +#pragma once + +#ifdef _MSC_VER +#define _CRT_SECURE_NO_WARNINGS +#endif +#define M_PI 3.14159265358979323846 +#define MARKER_HEIGHT 0.05 + +#if defined(WIN32) +#define NOMINMAX +#include +#include "GL/glew.h" +#include "GL/wglew.h" +#elif defined(__APPLE__) +#include +#include +#else +#define GL_GLEXT_PROTOTYPES +#include +#include +#endif + +#include "../../include/interaction/LabelManager.h" +#include +#include +#include "../../include/render/FontHandler.h" +#include "GLMLoader.h" +#include +#include + +LabelManager::LabelManager(ShaderProgram &lines_shader, ShaderProgram &plane_shader) : m_init_plane_model(false), m_lines_shader_program(lines_shader), m_plane_shader_program(plane_shader), m_plane_model(nullptr) +{ +} + +LabelManager::~LabelManager() +{ + clear(); + std::map::iterator it; + for (it = m_texture_cache.begin(); it != m_texture_cache.end(); it++) + { + delete it->second; + } + delete m_plane_model; +} + +void LabelManager::clear() +{ + m_text.clear(); + m_position.clear(); + m_position2.clear(); + m_size.clear(); + m_volume.clear(); +} + +void LabelManager::set_parent_directory(std::string &directory) +{ + m_parent_directory = directory; +} + +unsigned int LabelManager::create_line_vba(glm::vec3 &start, glm::vec3 &end) +{ + unsigned int vba; + unsigned int vbo; + glGenVertexArrays(1, &vba); + glGenBuffers(1, &vbo); + + std::vector line; + line.push_back(start); + line.push_back(end); + + glBindVertexArray(vba); + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBufferData( + GL_ARRAY_BUFFER, + sizeof(glm::vec3) * 2, + &line[0], + GL_STATIC_DRAW); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL); + glEnableVertexAttribArray(0); + + m_lines_vba.push_back(vba); + m_lines_vbo.push_back(vbo); + + return vba; +} + +void LabelManager::add_label(std::string texture_path, float x, float y, float z, float textPosZ, float size, int volume) +{ + if (!m_init_plane_model) + { + std::string plane_obj_path = m_parent_directory + "Resources/Models/plane.obj"; + m_plane_model = GLMLoader::loadObjModel(plane_obj_path); + m_init_plane_model = true; + } + + if (m_texture_cache.find(texture_path) == m_texture_cache.end()) + { + + Texture *texture = new Texture(GL_TEXTURE_2D, texture_path); + m_texture_cache[texture_path] = texture; + } + + BillboardLabel billboard; + glm::vec3 line_start(x, y, z); + glm::vec3 line_end(x, y, textPosZ + 200); + unsigned int line_vba = create_line_vba(line_start, line_end); + billboard.line_vba = line_vba; + billboard.label_texture = m_texture_cache[texture_path]; + billboard.label_model = m_plane_model; + billboard.position = glm::vec3(x, y, textPosZ + 250); + m_billboard_labels.push_back(billboard); + + m_position.push_back(glm::vec3(x, y, z)); + m_position2.push_back(glm::vec3(x, y, textPosZ)); + m_size.push_back(size); + m_volume.push_back(volume); +} + +void LabelManager::draw_labels(glm::mat4 volume_mv, glm::mat4 projection_matrix, glm::mat4 &headpose, float z_scale) +{ + for (int i = 0; i < m_billboard_labels.size(); i++) + { + // draw line + m_lines_shader_program.start(); + m_lines_shader_program.setUniform("p", projection_matrix); + m_lines_shader_program.setUniform("mv", volume_mv); + glLineWidth(2); + glBindVertexArray(m_billboard_labels[i].line_vba); + glDrawArrays(GL_LINES, 0, 2); + glBindVertexArray(0); + m_lines_shader_program.stop(); + + glm::vec4 markerpos = volume_mv * glm::vec4(m_billboard_labels[i].position.x, m_billboard_labels[i].position.y, 1, 1); + glm::vec4 headpos = headpose * glm::vec4(0, 0, 0, 1); + glm::vec4 dir = headpos / headpos.w - markerpos / markerpos.w; + dir.w = 0; + dir = inverse(volume_mv) * dir; + dir.z = 0; + dir = normalize(dir); + float angle = 180.0f / M_PI * atan2(dir.x, dir.y); + glm::mat4 label_model_view_matrix; + + label_model_view_matrix = glm::translate(volume_mv, m_billboard_labels[i].position); + label_model_view_matrix = glm::scale(label_model_view_matrix, glm::vec3(50.0f, 50.0f, 100.0f)); + label_model_view_matrix = glm::rotate(label_model_view_matrix, glm::radians(180.0f - angle), glm::vec3(0.0f, 0.0f, 1.0f)); + label_model_view_matrix = glm::rotate(label_model_view_matrix, glm::radians(90.0f), glm::vec3(0.0f, 1.0f, 0.0f)); + + m_plane_shader_program.start(); + m_plane_shader_program.setUniform("p", projection_matrix); + m_plane_model->setMVMatrix(label_model_view_matrix); + m_billboard_labels[i].label_model->setTexture(m_billboard_labels[i].label_texture); + m_billboard_labels[i].label_model->render(m_plane_shader_program); + m_plane_shader_program.stop(); + } +} + +void LabelManager::draw_lines() +{ + + for (size_t i = 0; i < m_lines_vba.size(); ++i) + { + glBindVertexArray(m_lines_vba[i]); + glDrawArrays(GL_LINES, 0, 2); + glBindVertexArray(0); + } +} diff --git a/src/interaction/Labels.cpp b/src/interaction/Labels.cpp deleted file mode 100644 index e60d6cd..0000000 --- a/src/interaction/Labels.cpp +++ /dev/null @@ -1,121 +0,0 @@ -// ---------------------------------- -// Copyright © 2015, Brown University, Providence, RI. -// -// All Rights Reserved -// -// Use of the software is provided under the terms of the GNU General Public License version 3 -// as published by the Free Software Foundation at http://www.gnu.org/licenses/gpl-3.0.html, provided -// that this copyright notice appear in all copies and that the name of Brown University not be used in -// advertising or publicity pertaining to the use or distribution of the software without specific written -// prior permission from Brown University. -// -// See license.txt for further information. -// -// BROWN UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE WHICH IS -// PROVIDED “AS IS”, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -// FOR ANY PARTICULAR PURPOSE. IN NO EVENT SHALL BROWN UNIVERSITY BE LIABLE FOR ANY -// SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR FOR ANY DAMAGES WHATSOEVER RESULTING -// FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR -// OTHER TORTIOUS ACTION, OR ANY OTHER LEGAL THEORY, ARISING OUT OF OR IN CONNECTION -// WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -// ---------------------------------- -// -///\file Labels.cpp -///\author Benjamin Knorlein -///\date 6/25/2019 - -#pragma once - -#ifdef _MSC_VER -#define _CRT_SECURE_NO_WARNINGS -#endif -#define M_PI 3.14159265358979323846 -#define MARKER_HEIGHT 0.05 - -#if defined(WIN32) -#define NOMINMAX -#include -#include -#include -#elif defined(__APPLE__) -#include -#include -#else -#define GL_GLEXT_PROTOTYPES -#include -#include -#endif - -#include "../../include/interaction/Labels.h" -#include -#include -#include "../../include/render/FontHandler.h" -#include - -Labels::Labels() -{ - -} - -Labels::~Labels() -{ - clear(); -} - -void Labels::clear() { - m_text.clear(); - m_position.clear(); - m_position2.clear(); - m_size.clear(); - m_volume.clear(); -} - -void Labels::add(std::string text, float x, float y, float z, float textPosZ, float size, int volume) -{ - m_text.push_back(text); - m_position.push_back(glm::vec3(x, y, z)); - m_position2.push_back(glm::vec3(x, y, textPosZ)); - m_size.push_back(size); - m_volume.push_back(volume); -} - -void Labels::draw(std::vector& MV, glm::mat4& headpose, float z_scale) -{ - for (int i = 0; i < m_text.size(); i++) - { - glm::vec4 markerpos = MV[m_volume[i]] * glm::vec4(m_position[i].x, m_position[i].y, 1, 1); - glm::vec4 headpos = headpose * glm::vec4(0, 0, 0, 1); - glm::vec4 dir = headpos / headpos.w - markerpos / markerpos.w; - dir.w = 0; - dir = inverse(MV[m_volume[i]]) * dir; - dir.z = 0; - dir = normalize(dir); - double angle = 180.0f / M_PI * atan2(dir.x, dir.y); - - glDisable(GL_LIGHTING); - glPushMatrix(); - glMatrixMode(GL_MODELVIEW); - glLoadMatrixf(glm::value_ptr(MV[m_volume[i]])); - glLineWidth(2); - glBegin(GL_LINES); - glColor4f(1.0f, 0.0f, 0.0f, 1.0f); - // Yellow - glVertex3f(m_position[i].x, m_position[i].y, m_position[i].z); - glVertex3f(m_position[i].x, m_position[i].y, m_position2[i].z - 3); - glEnd(); - - glPushMatrix(); - glTranslatef(m_position[i].x, m_position[i].y, m_position2[i].z); - glRotatef(180 - angle, 0, 0, 1); - glRotatef(90, 1, 0, 0); - glScalef(1.0f, 1.0f / z_scale, 1.0f); - FontHandler::getInstance()->renderTextBox(m_text[i], -1000.0, 0, 0, 2000.0, m_size[i], TextAlignment::CENTER); - glEnable(GL_LIGHTING); - - - - - glPopMatrix(); - glPopMatrix(); - } -} diff --git a/src/interaction/Simulation.cpp b/src/interaction/Simulation.cpp new file mode 100644 index 0000000..8179bb2 --- /dev/null +++ b/src/interaction/Simulation.cpp @@ -0,0 +1,183 @@ +#include "../include/interaction/Simulation.h" +#include "../include/vrapp/VRVolumeApp.h" + +Simulation::Simulation(VRVolumeApp &controller_app, float time) : m_simulation_duration(time), m_controller_app(controller_app), + animation_button_label("ANIMATE"), m_animation_state(STOP) +{ +} + +void Simulation::add_simulation_state(SimulationState &simulationState) +{ + float time = m_simulation_states.size() * m_simulation_duration; + + int mins = (int)time / 60; + int seconds = (int)time % 60; + + simulationState.time_label = std::to_string(mins) + ":" + std::to_string(seconds); + m_simulation_states.push_back(simulationState); +} + +void Simulation::create_simulation_time_frames() +{ + if (m_simulation_states.size() > 1) + { + SimulationState first_position = m_simulation_states.front(); + ch::Sequence sequence_eye(first_position.poi.eye); + ch::Sequence sequence_target(first_position.poi.target); + ch::Sequence sequence_up(first_position.poi.up); + ch::Sequence sequence_radius(first_position.poi.radius); + ch::Sequence sequence_clip_max(first_position.max_clip); + ch::Sequence sequence_clip_min(first_position.min_clip); + + for (auto iterator = std::next(m_simulation_states.begin()); iterator != m_simulation_states.end(); ++iterator) + { + sequence_eye.then(iterator->poi.eye, m_simulation_duration); + sequence_target.then(iterator->poi.target, m_simulation_duration); + sequence_up.then(iterator->poi.up, m_simulation_duration); + sequence_radius.then(iterator->poi.radius, m_simulation_duration); + sequence_clip_max.then(iterator->max_clip, m_simulation_duration); + sequence_clip_min.then(iterator->min_clip, m_simulation_duration); + } + + auto group = std::make_shared(); + group->apply(&m_eye_animation, sequence_eye); + group->apply(&m_target_animation, sequence_target); + group->apply(&m_up_animation, sequence_up); + group->apply(&m_radius_animation, sequence_radius); + group->apply(&m_max_clip_animation, sequence_clip_max); + group->apply(&m_min_clip_animation, sequence_clip_min); + + m_timeline.addShared(group); + } +} + +void Simulation::update_simulation() +{ + if (m_animation_state != PAUSE) + { + update_time_step(); + } + if (m_timeline.isFinished()) + { + m_animation_state = STOP; + animation_button_label = "Animate"; + m_controller_app.set_app_mode(MANUAL); + m_timeline.resetTime(); + if (m_controller_app.get_movie_state() == MOVIE_RECORD) + { + m_controller_app.stop_movie(); + } + } +} + +void Simulation::update_time_step() +{ + m_timeline.step(1.0 / SIMULATION_TIME_STEP); +} + +void Simulation::set_animation_state() +{ + if (m_animation_state == STOP) + { + create_simulation_time_frames(); + m_controller_app.set_app_mode(SIMULATION); + m_animation_state = PLAYING; + animation_button_label = "PAUSE"; + } + else if (m_animation_state == PLAYING) + { + if (!m_timeline.isFinished()) + { + m_animation_state = PAUSE; + animation_button_label = "ANIMATE"; + } + } + else if (m_animation_state == PAUSE) + { + m_animation_state = PLAYING; + animation_button_label = "PAUSE"; + } + + m_is_animate_path = true; +} + +ANIMATION_STATE Simulation::get_animation_state() +{ + switch (m_timeline.isFinished()) + { + case true: + return STOP; + case false: + { + if (m_animation_state == STOP) + { + return PAUSE; + } + else + { + return PLAYING; + } + } + default: + return STOP; + } + +} + +std::string Simulation::get_camera_animation_state() +{ + return animation_button_label; +} + +float Simulation::get_simulation_duration() +{ + return m_simulation_duration; +} + +void Simulation::set_simulation_duration(float duration) +{ + m_simulation_duration = duration; +} + +const std::list &Simulation::get_simulation_states() +{ + return m_simulation_states; +} + +SimulationState &Simulation::get_simulation_state_at(unsigned int index) +{ + auto poi_iterator = m_simulation_states.begin(); + std::advance(poi_iterator, index); + return *poi_iterator; +} + +SimulationState Simulation::get_current_simulation_state() +{ + PointOfInterest poi(m_eye_animation.value(), m_target_animation.value(), m_up_animation.value(), m_radius_animation.value()); + + SimulationState current_state; + current_state.poi = poi; + current_state.max_clip = m_max_clip_animation; + current_state.min_clip = m_min_clip_animation; + + return current_state; +} + +void Simulation::remove_simulation_state(unsigned int index) +{ + auto poi_iterator = m_simulation_states.begin(); + std::advance(poi_iterator, index); + std::string time_label = poi_iterator->time_label; + poi_iterator = m_simulation_states.erase(poi_iterator); + for (poi_iterator; poi_iterator != m_simulation_states.end(); poi_iterator++) + { + std::string current_time_label = poi_iterator->time_label; + poi_iterator->time_label = time_label; + time_label = current_time_label; + } +} + +float Simulation::get_animation_duration() +{ + return m_simulation_duration; +} diff --git a/src/loader/VRDataLoader.cpp b/src/loader/VRDataLoader.cpp index aa9295c..23edbb7 100644 --- a/src/loader/VRDataLoader.cpp +++ b/src/loader/VRDataLoader.cpp @@ -1,12 +1,11 @@ #include "loader/VRDataLoader.h" #include - //#include #include #include -#include +#include #include "vrapp/VRVolumeApp.h" #ifdef _MSC_VER @@ -20,43 +19,34 @@ #endif - -VRDataLoader* VRDataLoader::m_instance = nullptr; - VRDataLoader::VRDataLoader() { - } -VRDataLoader* VRDataLoader::get_instance() +void VRDataLoader::load_txt_file(VRVolumeApp &vrVolumeApp, std::string &filename) { - if (!m_instance) - { - m_instance = new VRDataLoader; - } - return m_instance; -} -void VRDataLoader::load_txt_file(VRVolumeApp& vrVolumeApp, std::string& filename) -{ std::ifstream inFile; inFile.open(filename); std::string line; - //std::filesystem::path p_filename(filename); cppfs::FilePath p_filename(filename); - while (getline(inFile, line)) { - if (line[0] != '#') { + while (getline(inFile, line)) + { + if (line[0] != '#') + { std::vector vals; // Create vector to hold our words std::stringstream ss(line); std::string buf; - while (ss >> buf) { + while (ss >> buf) + { vals.push_back(buf); } - if (vals.size() > 0) { + if (vals.size() > 0) + { std::string tag = vals[0]; if (tag == "animated") { @@ -73,7 +63,7 @@ void VRDataLoader::load_txt_file(VRVolumeApp& vrVolumeApp, std::string& filename std::cerr << "text at position " << vals[2] << " , " << vals[3] << " , " << vals[5] << std::endl; std::cerr << "text Size " << vals[6] << std::endl; std::cerr << "for Volume " << vals[7] << std::endl; - std::string label = vals[1]; + std::string label = p_filename.directoryPath() + OS_SLASH_LOCAL + vals[1]; vrVolumeApp.add_label(label, stof(vals[2]), stof(vals[3]), stof(vals[4]), stof(vals[5]), stof(vals[6]), stoi(vals[7]) - 1); } if (tag == "desc") @@ -83,29 +73,19 @@ void VRDataLoader::load_txt_file(VRVolumeApp& vrVolumeApp, std::string& filename int descHeight = stoi(vals[2]); std::string fileName = vals[1]; vrVolumeApp.set_description(descHeight, fileName); - } if (tag == "mesh") { - // std::cerr << "Load Mesh " << vals[1] << std::endl; - // std::cerr << "for Volume " << vals[2] << std::endl; - - //std::string fullPath = p_filename.parent_path().string() + OS_SLASH_LOCAL + vals[1]; std::string fullPath = p_filename.directoryPath() + OS_SLASH_LOCAL + vals[1]; std::cerr << "Load Mesh " << fullPath << std::endl; std::string shaderFilePath = p_filename.directoryPath() + OS_SLASH_LOCAL + "shaders"; vrVolumeApp.set_mesh(stoi(vals[2]), fullPath, shaderFilePath); - } if (tag == "texture") { - - //std::cerr << "for Volume " << vals[2] << std::endl; std::string fullPath = p_filename.directoryPath() + OS_SLASH_LOCAL + vals[1]; vrVolumeApp.set_texture(fullPath); - - } if (tag == "numVolumes") { @@ -116,7 +96,6 @@ void VRDataLoader::load_txt_file(VRVolumeApp& vrVolumeApp, std::string& filename { vrVolumeApp.add_data_label(vals[i + 2]); } - } else if (tag.rfind("volume") == 0) { @@ -126,20 +105,17 @@ void VRDataLoader::load_txt_file(VRVolumeApp& vrVolumeApp, std::string& filename std::string strVolumeIndex = tag.substr(6); size_t volumeIndex = std::stoi(strVolumeIndex); - vals[1] = p_filename.directoryPath() + OS_SLASH_LOCAL + vals[1]; - - - std::vector*>& v = vrVolumeApp.get_promise(volumeIndex); - std::promise* pm = new std::promise(); + std::vector *> &v = vrVolumeApp.get_promise(volumeIndex); + std::promise *pm = new std::promise(); v.push_back(pm); - std::vector>* fut; + std::vector> *fut; if (!vrVolumeApp.get_future(volumeIndex)) { - vrVolumeApp.set_future(volumeIndex, new std::vector>); + vrVolumeApp.set_future(volumeIndex, new std::vector>); } fut = vrVolumeApp.get_future(volumeIndex); @@ -149,12 +125,9 @@ void VRDataLoader::load_txt_file(VRVolumeApp& vrVolumeApp, std::string& filename vrVolumeApp.set_future(volumeIndex, fut); vrVolumeApp.init_volume_loading(volumeIndex, vals); - - } } } - } inFile.close(); vrVolumeApp.set_loaded_file(filename); diff --git a/src/main.cpp b/src/main.cpp index 4e30369..29eaf21 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -17,7 +17,7 @@ int main(int argc, char **argv) { int num_parameters = 4; char * arguments[] = { argv[0],"-c","desktop_observer.minvr", "use2DUI"}; - + VolumeVisualizationApp app(num_parameters, arguments); diff --git a/src/render/VolumeRaycastShader.cpp b/src/render/VolumeRaycastShader.cpp index d532ede..a101e40 100644 --- a/src/render/VolumeRaycastShader.cpp +++ b/src/render/VolumeRaycastShader.cpp @@ -1,26 +1,26 @@ // ----------------------------------. // Copyright © 2015, Brown University, Providence, RI. -// +// // All Rights Reserved -// -// Use of the software is provided under the terms of the GNU General Public License version 3 -// as published by the Free Software Foundation at http://www.gnu.org/licenses/gpl-3.0.html, provided -// that this copyright notice appear in all copies and that the name of Brown University not be used in -// advertising or publicity pertaining to the use or distribution of the software without specific written +// +// Use of the software is provided under the terms of the GNU General Public License version 3 +// as published by the Free Software Foundation at http://www.gnu.org/licenses/gpl-3.0.html, provided +// that this copyright notice appear in all copies and that the name of Brown University not be used in +// advertising or publicity pertaining to the use or distribution of the software without specific written // prior permission from Brown University. -// +// // See license.txt for further information. -// -// BROWN UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE WHICH IS -// PROVIDED “AS IS”, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -// FOR ANY PARTICULAR PURPOSE. IN NO EVENT SHALL BROWN UNIVERSITY BE LIABLE FOR ANY -// SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR FOR ANY DAMAGES WHATSOEVER RESULTING -// FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR -// OTHER TORTIOUS ACTION, OR ANY OTHER LEGAL THEORY, ARISING OUT OF OR IN CONNECTION -// WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +// +// BROWN UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE WHICH IS +// PROVIDED “AS IS”, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR ANY PARTICULAR PURPOSE. IN NO EVENT SHALL BROWN UNIVERSITY BE LIABLE FOR ANY +// SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR FOR ANY DAMAGES WHATSOEVER RESULTING +// FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +// OTHER TORTIOUS ACTION, OR ANY OTHER LEGAL THEORY, ARISING OUT OF OR IN CONNECTION +// WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. // ---------------------------------- -// +// ///\file VolumeRaycastShader.cpp ///\author Benjamin Knorlein ///\date 11/30/2017 @@ -31,217 +31,216 @@ #include "render/VolumeRaycastShader.h" - #include -VolumeRaycastShader::VolumeRaycastShader() : m_use_blending{ false }, m_blend_volume{ 0 }, m_blending_alpha{ 0 }, m_clip_min{ 0.0 }, m_clip_max{ 1.0 } -//: m_threshold{ 0.0f }, m_multiplier{ 0.5 } +VolumeRaycastShader::VolumeRaycastShader() : m_use_blending{false}, m_blend_volume{0}, m_blending_alpha{0}, m_clip_min{0.0}, m_clip_max{1.0} { - /*m_viewport[0] = 1.0; - m_viewport[1] = 1.0;*/ - m_shader = "VolumeRaycastShader"; m_vertexShader = "#version 330 core\n" - "layout(location = 0) in vec3 vVertex;\n" //object space vertex position - "uniform mat4 MVP; \n" //combined modelview projection matrix - "smooth out vec3 vUV; \n" //3D texture coordinates for texture lookup in the fragment shader - "void main()\n" - "{\n" - //get the clipspace position - "gl_Position = MVP*vec4(vVertex, 1); \n" - //get the 3D texture coordinates by adding (0.5,0.5,0.5) to the object space - //vertex position. Since the unit cube is at origin (min: (-0.5,-0.5,-0.5) and max: (0.5,0.5,0.5)) - //adding (0.5,0.5,0.5) to the unit cube object space position gives us values from (0,0,0) to - //(1,1,1) - "vUV = vVertex + vec3(0.5); \n" - "}\n"; + "layout(location = 0) in vec3 vVertex;\n" // object space vertex position + "uniform mat4 MVP; \n" // combined modelview projection matrix + "smooth out vec3 vUV; \n" // 3D texture coordinates for texture lookup in the fragment shader + "void main()\n" + "{\n" + // get the clipspace position + "gl_Position = MVP*vec4(vVertex, 1); \n" + // get the 3D texture coordinates by adding (0.5,0.5,0.5) to the object space + // vertex position. Since the unit cube is at origin (min: (-0.5,-0.5,-0.5) and max: (0.5,0.5,0.5)) + // adding (0.5,0.5,0.5) to the unit cube object space position gives us values from (0,0,0) to + //(1,1,1) + "vUV = vVertex + vec3(0.5); \n" + "}\n"; m_fragmentShader = - "#version 330 core\n" - "vec2 intersect_box(vec3 orig, vec3 dir, vec3 clip_min, vec3 clip_max) { \n" - "vec3 inv_dir = 1.0 / dir; \n" - "vec3 tmin_tmp = (clip_min - orig) * inv_dir; \n" - "vec3 tmax_tmp = (clip_max - orig) * inv_dir; \n" - "vec3 tmin = min(tmin_tmp, tmax_tmp); \n" - "vec3 tmax = max(tmin_tmp, tmax_tmp); \n" - "float t0 = max(tmin.x, max(tmin.y, tmin.z)); \n" - "float t1 = min(tmax.x, min(tmax.y, tmax.z)); \n" - "return vec2(t0, t1); \n" - "}\n" - - "layout(location = 0) out vec4 vFragColor; \n" //fragment shader output - "smooth in vec3 vUV; \n" //3D texture coordinates form vertex shader interpolated by rasterizer - "uniform sampler3D volume;\n" //volume dataset - "uniform mat4 clipPlane; \n" - "uniform bool clipping;\n" - "uniform float threshold;\n" - "uniform float multiplier;\n" - "uniform vec3 camPos;\n" //camera position - "uniform vec3 step_size;\n" //ray step size - "const int MAX_SAMPLES = 3000;\n" //total samples for each ray march step - "uniform int channel;\n" - "uniform sampler2D lut;\n" //transferfunction - "uniform bool useLut;\n" - "uniform bool useMultiLut;\n" - "uniform sampler2D depth;\n" - "uniform vec2 viewport;\n" - "uniform mat4 P_inv; \n" - "uniform bool useBlend;\n" - "uniform sampler3D blendVolume;\n" //volume dataset - "uniform float blendAlpha;\n" - "uniform vec3 clip_min;\n" - "uniform vec3 clip_max;\n" - "void main()\n" - "{\n" - //get the 3D texture coordinates for lookup into the volume dataset - "vec3 dataPos = vUV; \n" - - //get the object space position by subracting 0.5 from the - //3D texture coordinates. Then subtraact it from camera position - //and normalize to get the ray marching direction - "vec3 geomDir = normalize( dataPos - camPos); \n" - - //get the t values for the intersection with the box" - "vec2 t_hit = intersect_box(camPos, geomDir,clip_min,clip_max); \n" - - // We don't want to sample voxels behind the eye if it's - // inside the volume, so keep the starting point at or in front - // of the eye - "if(t_hit.x < 0.0f) t_hit.x= max(t_hit.x, 0.0); \n" - - //We not know if the ray was cast from the back or the front face. (Note: For now we also render the back face only) - //To ensure we update dataPos and t_hit to reflect a ray from entry point to exit - "dataPos = camPos + t_hit.x * geomDir;\n" - "t_hit.y = t_hit.y-t_hit.x; \n" - "t_hit.x = 0.0f; \n" - - //get t for the clipping plane and overwrite the entry point - "if(clipping){ \n" - "vec4 p_in = clipPlane * vec4(dataPos + t_hit.x * geomDir, 1);\n" - "vec4 p_out = clipPlane * vec4(dataPos + t_hit.y * geomDir, 1);\n" - "if(p_in.y * p_out.y < 0.0f ){\n" - //both points lie on different sides of the plane - //we need to compute a new clippoint - "vec4 c_pos = clipPlane * vec4(dataPos, 1);\n" - "vec4 c_dir = clipPlane * vec4(geomDir, 0);\n" - "float t_clip = -c_pos.y / c_dir.y ;\n" - //update either entry or exit based on which is on the clipped side - "if (p_in.y > 0.0f){\n" - "t_hit.x = t_clip; \n" - "}else{\n" - "t_hit.y = t_clip; \n" - "}\n" - "}else{\n" - //both points lie on the same side of the plane. - //if one of them is on the wrong side they can be clipped - "if(p_in.y > 0.0f)\n" - "discard;\n" - "}\n" - "}\n" - - //Compute occlusion point in volume coordinates - "float d = texture(depth, vec2(gl_FragCoord.x/viewport.x,gl_FragCoord.y/viewport.y)).r; \n" - "vec4 d_ndc = vec4((gl_FragCoord.x / viewport.x - 0.5) * 2.0,(gl_FragCoord.y / viewport.y - 0.5) * 2.0, (d - 0.5) * 2.0, 1.0); \n" - "d_ndc = P_inv * d_ndc; \n " - "d_ndc = d_ndc / d_ndc.w; \n" - - //compute t_occ and check if it closer than the exit point - "float t_occ = ((d_ndc.x + 0.5) - dataPos.x) / geomDir.x; \n" - "t_hit.y = min(t_hit.y, t_occ); \n" - - //first value should always be lower by definition and this case should never occur. If it does discard the fragment. - "if (t_hit.x > t_hit.y) \n" - "discard; \n" - - //compute step size as the minimum of the stepsize - "float dt = min(step_size.x, min(step_size.y, step_size.z)) ;\n" - - // Step 4: Starting from the entry point, march the ray through the volume - // and sample it - "dataPos = dataPos + t_hit.x * geomDir; \n" - "for (float t = t_hit.x; t < t_hit.y; t += dt) {\n" - // data fetching from the red channel of volume texture - "vec4 sample; \n" - "if (channel == 1){ \n" - "sample = texture(volume, dataPos).rrrr; \n" - "}else if (channel == 2){ \n" - "sample = texture(volume, dataPos).gggg; \n" - "}else if (channel == 3){ \n" - "sample = texture(volume, dataPos).bbbb; \n" - "}else if (channel == 4){ \n" - "sample = texture(volume, dataPos).aaaa; \n" - "}else if (channel == 5){ \n" - "sample = texture(volume, dataPos); \n" - "}else{ \n" - "sample = texture(volume, dataPos); \n" - "sample.a = max(sample.r, max(sample.g,sample.b)) ; " - "}\n" - - "if(useBlend){ \n" - "vec4 sample_blend; \n" - "if (channel == 1){ \n" - "sample_blend = texture(blendVolume, dataPos).rrrr; \n" - "}else if (channel == 2){ \n" - "sample_blend = texture(blendVolume, dataPos).gggg; \n" - "}else if (channel == 3){ \n" - "sample_blend = texture(blendVolume, dataPos).bbbb; \n" - "}else if (channel == 4){ \n" - "sample_blend = texture(blendVolume, dataPos).aaaa; \n" - "}else if (channel == 5){ \n" - "sample_blend = texture(blendVolume, dataPos); \n" - "}else{ \n" - "sample_blend = texture(blendVolume, dataPos); \n" - "sample_blend.a = max(sample_blend.r, max(sample_blend.g,sample_blend.b)) ; " - "}\n" - - "sample = (vec4(1.0f - blendAlpha) * sample) + (vec4(blendAlpha) * sample_blend);\n" - "}\n" - - - //threshold based on alpha - "sample.a = (sample.a > threshold) ? sample.a : 0.0f ;\n" - - //transferfunction - "if(useLut) {\n" - "if(useMultiLut){\n" - "sample.r = texture(lut, vec2(sample.r,0.5)).r;" - "sample.g = texture(lut, vec2(sample.g,0.5)).g;" - "sample.b = texture(lut, vec2(sample.b,0.5)).b;" - "sample.a = max(sample.r, max(sample.g,sample.b)) ; " - "}else{\n" - "sample = texture(lut, vec2(sample.a,0.5));" - "}\n" - "}\n" - - //assume alpha is the highest channel and gamma correction - "sample.a = sample.a * multiplier; \n" ///needs changing - - - //blending (front to back) - "vFragColor.rgb += (1.0 - vFragColor.a) * sample.a * sample.rgb;\n" - "vFragColor.a += (1.0 - vFragColor.a) * sample.a;\n" - - //early exit if opacity is reached - "if (vFragColor.a >= 0.95) \n" - "break;\n" - - //advance point - "dataPos += geomDir * dt; \n" - "} \n" - - //remove fragments for correct depthbuffer - "if (vFragColor.a == 0.0f)" - "discard;" - "}\n"; + "#version 330 core\n" + "vec2 intersect_box(vec3 orig, vec3 dir, vec3 clip_min, vec3 clip_max) { \n" + "dir += vec3(0.0000001); \n" + "vec3 inv_dir = 1.0 / dir; \n" + "vec3 tmin_tmp = (clip_min - orig) * inv_dir; \n" + "vec3 tmax_tmp = (clip_max - orig) * inv_dir; \n" + "vec3 tmin = min(tmin_tmp, tmax_tmp); \n" + "vec3 tmax = max(tmin_tmp, tmax_tmp); \n" + "float t0 = max(tmin.x, max(tmin.y, tmin.z)); \n" + "float t1 = min(tmax.x, min(tmax.y, tmax.z)); \n" + "return vec2(t0, t1); \n" + "}\n" + + "layout(location = 0) out vec4 vFragColor; \n" // fragment shader output + "smooth in vec3 vUV; \n" // 3D texture coordinates form vertex shader interpolated by rasterizer + "uniform sampler3D volume;\n" // volume dataset + "uniform mat4 clipPlane; \n" + "uniform bool clipping;\n" + "uniform float threshold;\n" + "uniform float multiplier;\n" + "uniform vec3 camPos;\n" // camera position + "uniform vec3 step_size;\n" // ray step size + "const int MAX_SAMPLES = 3000;\n" // total samples for each ray march step + "uniform int channel;\n" + "uniform sampler2D lut;\n" // transferfunction + "uniform bool useLut;\n" + "uniform bool useMultiLut;\n" + "uniform sampler2D depth;\n" + "uniform vec2 viewport;\n" + "uniform mat4 P_inv; \n" + "uniform bool useBlend;\n" + "uniform sampler3D blendVolume;\n" // volume dataset + "uniform float blendAlpha;\n" + "uniform vec3 clip_min;\n" + "uniform vec3 clip_max;\n" + "void main()\n" + "{\n" + // get the 3D texture coordinates for lookup into the volume dataset + "vec3 dataPos = vUV; \n" + + // get the object space position by subracting 0.5 from the + // 3D texture coordinates. Then subtraact it from camera position + // and normalize to get the ray marching direction + "vec3 geomDir = normalize( dataPos - camPos); \n" + + // get the t values for the intersection with the box" + "vec2 t_hit = intersect_box(camPos, geomDir,clip_min,clip_max); \n" + + // We don't want to sample voxels behind the eye if it's + // inside the volume, so keep the starting point at or in front + // of the eye + "if(t_hit.x < 0.0f) t_hit.x= max(t_hit.x, 0.0); \n" + + // We not know if the ray was cast from the back or the front face. (Note: For now we also render the back face only) + // To ensure we update dataPos and t_hit to reflect a ray from entry point to exit + "dataPos = camPos + t_hit.x * geomDir;\n" + "t_hit.y = t_hit.y-t_hit.x; \n" + + // slightly move the ray to not collide with viewport culling front plane. + "t_hit.x = 0.0001f; \n" + + // get t for the clipping plane and overwrite the entry point + "if(clipping){ \n" + "vec4 p_in = clipPlane * vec4(dataPos + t_hit.x * geomDir, 1);\n" + "vec4 p_out = clipPlane * vec4(dataPos + t_hit.y * geomDir, 1);\n" + "if(p_in.y * p_out.y < 0.0f ){\n" + // both points lie on different sides of the plane + // we need to compute a new clippoint + "vec4 c_pos = clipPlane * vec4(dataPos, 1);\n" + "vec4 c_dir = clipPlane * vec4(geomDir, 0);\n" + "float t_clip = -c_pos.y / c_dir.y ;\n" + // update either entry or exit based on which is on the clipped side + "if (p_in.y > 0.0f){\n" + "t_hit.x = t_clip; \n" + "}else{\n" + "t_hit.y = t_clip; \n" + "}\n" + "}else{\n" + // both points lie on the same side of the plane. + // if one of them is on the wrong side they can be clipped + "if(p_in.y > 0.0f)\n" + "discard;\n" + "}\n" + "}\n" + + // Compute occlusion point in volume coordinates + "float d = texture(depth, vec2(gl_FragCoord.x/viewport.x,gl_FragCoord.y/viewport.y)).r; \n" + "vec4 d_ndc = vec4((gl_FragCoord.x / viewport.x - 0.5) * 2.0,(gl_FragCoord.y / viewport.y - 0.5) * 2.0, (d - 0.5) * 2.0, 1.0); \n" + "d_ndc = P_inv * d_ndc; \n " + "d_ndc = d_ndc / d_ndc.w; \n" + + // compute t_occ and check if it closer than the exit point + // The code below ocludes portion of the voxels at the center of the unit cube. + // Removing this lines fixes the issue, but it generates artifacts in the APPLE rendering. + // Do some research why the ray caster is occliding those specific voxels + /*"float t_occ = ((d_ndc.x + 0.5) - dataPos.x) / geomDir.x; \n" + "t_hit.y = min(t_hit.y, t_occ); \n"*/ + + // first value should always be lower by definition and this case should never occur. If it does discard the fragment. + "if (t_hit.x > t_hit.y) \n" + "discard; \n" + + // compute step size as the minimum of the stepsize + "float dt = min(step_size.x, min(step_size.y, step_size.z)) ;\n" + + // Step 4: Starting from the entry point, march the ray through the volume + // and sample it + "dataPos = dataPos + t_hit.x * geomDir; \n" + "for (float t = t_hit.x; t < t_hit.y; t += dt) {\n" + // data fetching from the red channel of volume texture + "vec4 sample; \n" + "if (channel == 1){ \n" + "sample = texture(volume, dataPos).rrrr; \n" + "}else if (channel == 2){ \n" + "sample = texture(volume, dataPos).gggg; \n" + "}else if (channel == 3){ \n" + "sample = texture(volume, dataPos).bbbb; \n" + "}else if (channel == 4){ \n" + "sample = texture(volume, dataPos).aaaa; \n" + "}else if (channel == 5){ \n" + "sample = texture(volume, dataPos); \n" + "}else{ \n" + "sample = texture(volume, dataPos); \n" + "sample.a = max(sample.r, max(sample.g,sample.b)) ; " + "}\n" + + "if(useBlend){ \n" + "vec4 sample_blend; \n" + "if (channel == 1){ \n" + "sample_blend = texture(blendVolume, dataPos).rrrr; \n" + "}else if (channel == 2){ \n" + "sample_blend = texture(blendVolume, dataPos).gggg; \n" + "}else if (channel == 3){ \n" + "sample_blend = texture(blendVolume, dataPos).bbbb; \n" + "}else if (channel == 4){ \n" + "sample_blend = texture(blendVolume, dataPos).aaaa; \n" + "}else if (channel == 5){ \n" + "sample_blend = texture(blendVolume, dataPos); \n" + "}else{ \n" + "sample_blend = texture(blendVolume, dataPos); \n" + "sample_blend.a = max(sample_blend.r, max(sample_blend.g,sample_blend.b)) ; " + "}\n" + + "sample = (vec4(1.0f - blendAlpha) * sample) + (vec4(blendAlpha) * sample_blend);\n" + "}\n" + + // threshold based on alpha + "sample.a = (sample.a > threshold) ? sample.a : 0.0f ;\n" + + // transferfunction + "if(useLut) {\n" + "if(useMultiLut){\n" + "sample.r = texture(lut, vec2(sample.r,0.5)).r;" + "sample.g = texture(lut, vec2(sample.g,0.5)).g;" + "sample.b = texture(lut, vec2(sample.b,0.5)).b;" + "sample.a = max(sample.r, max(sample.g,sample.b)) ; " + "}else{\n" + "sample = texture(lut, vec2(sample.a,0.5));" + "}\n" + "}\n" + + // assume alpha is the highest channel and gamma correction + "sample.a = sample.a * multiplier; \n" /// needs changing + + // blending (front to back) + "vFragColor.rgb += (1.0 - vFragColor.a) * sample.a * sample.rgb;\n" + "vFragColor.a += (1.0 - vFragColor.a) * sample.a;\n" + + // early exit if opacity is reached + "if (vFragColor.a >= 0.95) \n" + "break;\n" + + // advance point + "dataPos += geomDir * dt; \n" + "} \n" + + // remove fragments for correct depthbuffer + "if (vFragColor.a == 0.0f)" + "discard;" + "}\n"; } VolumeRaycastShader::~VolumeRaycastShader() { } -void VolumeRaycastShader::render(glm::mat4& MVP, glm::mat4& clipPlane, glm::vec3& camPos) +void VolumeRaycastShader::render(glm::mat4 &MVP, glm::mat4 &clipPlane, glm::vec3 &camPos) { if (m_use_blending) { @@ -291,7 +290,7 @@ void VolumeRaycastShader::initGL() bindProgram(); - //add attributes and uniforms + // add attributes and uniforms m_volume_uniform = glGetUniformLocation(m_programID, "volume"); m_MVP_uniform = glGetUniformLocation(m_programID, "MVP"); m_clipPlane_uniform = glGetUniformLocation(m_programID, "clipPlane"); @@ -317,7 +316,6 @@ void VolumeRaycastShader::initGL() m_clip_min_uniform = glGetUniformLocation(m_programID, "clip_min"); m_clip_max_uniform = glGetUniformLocation(m_programID, "clip_max"); - ////pass constant uniforms at initialization glUniform1i(m_volume_uniform, 0); glUniform1i(m_lut_uniform, 1); @@ -325,5 +323,4 @@ void VolumeRaycastShader::initGL() glUniform1i(m_blendVolume_uniform, 3); unbindProgram(); - } diff --git a/src/vrapp/VRVolumeApp.cpp b/src/vrapp/VRVolumeApp.cpp index 9cd822f..5a7559f 100644 --- a/src/vrapp/VRVolumeApp.cpp +++ b/src/vrapp/VRVolumeApp.cpp @@ -10,6 +10,8 @@ #include "interaction/HelperFunctions.h" #include "render/FontHandler.h" #include "interaction/CreateMovieAction.h" +#include "interaction/Simulation.h" +#include "interaction/Labels.h" #ifdef _WIN32 #include "GL/glew.h" @@ -36,20 +38,22 @@ #include #endif -#include -#include +#include +#include #include "GLMLoader.h" #include - +#include #include +#include "Model.h" +#include "Texture.h" -VRVolumeApp::VRVolumeApp() :m_mesh_model(nullptr), m_clip_max{ 1.0f }, m_clip_min{ 0.0f }, m_clip_ypr{ 0.0f }, m_clip_pos{ 0.0 }, m_wasd_pressed(0), -m_lookingGlass(false), m_isInitailized(false), m_speed(0.01f), m_movieAction(nullptr), m_moviename("movie.mp4"), m_noColor(0.0f), -m_ambient(0.2f, 0.2f, 0.2f, 1.0f), m_diffuse(0.5f, 0.5f, 0.5f, 1.0f), m_ui_view(nullptr), m_animated(false), m_numVolumes(0), m_selectedVolume(0), -m_multiplier(1.0f), m_threshold(0.0f), m_frame(0.0f), m_use_multi_transfer(false), m_clipping(false), m_show_menu(true), -m_window_properties(nullptr) +VRVolumeApp::VRVolumeApp() : m_mesh_model(nullptr), m_clip_max{1.0f}, m_clip_min{0.0f}, m_clip_ypr{0.0f}, m_clip_pos{0.0}, m_wasd_pressed(0), + m_lookingGlass(false), m_isInitailized(false), m_speed(0.01f), m_movieAction(nullptr), m_moviename("movie.mp4"), m_noColor(0.0f), + m_ambient(0.2f, 0.2f, 0.2f, 1.0f), m_diffuse(0.5f, 0.5f, 0.5f, 1.0f), m_ui_view(nullptr), m_animated(false), m_numVolumes(0), m_selectedVolume(0), + m_multiplier(1.0f), m_threshold(0.0f), m_frame(0.0f), m_use_multi_transfer(false), m_clipping(false), m_show_menu(true), + m_window_properties(nullptr), m_volume_animation_scale_factor(1.0f), m_current_movie_state(MOVIE_STOP), m_app_mode(MANUAL), m_end_load(false) { m_renders.push_back(new VolumeSliceRenderer()); m_renders.push_back(new VolumeRaycastRenderer()); @@ -57,37 +61,46 @@ m_window_properties(nullptr) VRVolumeApp::~VRVolumeApp() { - if (m_ui_view) + + for (int i = 0; i < m_volumes.size(); i++) { - delete m_ui_view; + std::vector v = m_volumes[i]; + for (int j = 0; j < v.size(); j++) + { + delete v[j]; + } } + m_volumes.clear(); + if (m_ui_view) + delete m_ui_view; delete m_window_properties; } - void VRVolumeApp::initialize() { - if (!m_isInitailized) { - // std::cout << "initialize 1" << std::endl; + m_object_pose = glm::mat4(1.0f); initialize_GL(); - // std::cout << "initialize 2" << std::endl; + if (!m_ui_view) { std::cout << "initialize UI " << std::endl; - m_ui_view = new UIView(*this); + m_ui_view = new UIView(*this); m_ui_view->init_ui(m_is2d, m_lookingGlass); } m_window_properties = new Window_Properties(); + m_simulation = new Simulation(*this); + m_labels = new Labels(m_line_shader, m_simple_texture_shader); + m_labels->set_parent_directory(get_directory_path()); + m_isInitailized = true; m_rendercount = 0; std::cout << "initialize end" << std::endl; } - } void VRVolumeApp::initialize_GL() @@ -97,7 +110,6 @@ void VRVolumeApp::initialize_GL() ren->initGL(); } - glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glLightfv(GL_LIGHT0, GL_AMBIENT, glm::value_ptr(m_ambient)); @@ -110,24 +122,19 @@ void VRVolumeApp::initialize_GL() glClearDepth(1.0f); glDepthFunc(GL_LEQUAL); glClearColor(0.0, 0.0, 0.0, 1); - } - - void VRVolumeApp::load_mesh_model() { - for (std::string filename : m_models_filenames) { + for (std::string filename : m_models_filenames) + { m_mesh_model = GLMLoader::loadObjModel(filename); - if (m_texture) { - m_mesh_model->addTexture(m_texture); + m_mesh_model->setTexture(m_texture); } - - } m_models_filenames.clear(); } @@ -139,21 +146,27 @@ void VRVolumeApp::load_shaders() std::string vertexShaderFolderPath = m_shader_file_path + OS_SLASH + std::string("shader.vert"); std::string fragmentShaderFolderPath = m_shader_file_path + OS_SLASH + std::string("shader.frag"); m_simple_texture_shader.LoadShaders(vertexShaderFolderPath.c_str(), fragmentShaderFolderPath.c_str()); - m_simple_texture_shader.addUniform("p"); - m_simple_texture_shader.addUniform("mv"); + m_simple_texture_shader.addUniform("projection_matrix"); + m_simple_texture_shader.addUniform("model_view_matrix"); + + std::string linesVertexShaderFolderPath = m_shader_file_path + OS_SLASH + std::string("lines_shader.vert"); + std::string linesFragmentShaderFolderPath = m_shader_file_path + OS_SLASH + std::string("lines_shader.frag"); + m_line_shader.LoadShaders(linesVertexShaderFolderPath.c_str(), linesFragmentShaderFolderPath.c_str()); + m_line_shader.addUniform("projection_matrix"); + m_line_shader.addUniform("model_view_matrix"); } void VRVolumeApp::initialize_textures() { add_lodaded_textures(); - for (int i = 0; i < m_volumes.size(); i++) { - std::vector< Volume* > vlm = m_volumes[i]; + for (int i = 0; i < m_volumes.size(); i++) + { + std::vector vlm = m_volumes[i]; for (int j = 0; j < vlm.size(); j++) { vlm[j]->initGL(); } - } } @@ -166,12 +179,11 @@ void VRVolumeApp::update_trackBall_state() { if (m_wasd_pressed) { - m_trackball.wasd_pressed(m_wasd_pressed); + get_trackball_camera().wasd_pressed(m_wasd_pressed); } - } -void VRVolumeApp::update_animation() +void VRVolumeApp::update_animation(float fps) { if (m_ui_view) { @@ -183,7 +195,7 @@ void VRVolumeApp::update_animation() } #if (!defined(__APPLE__)) -void VRVolumeApp::run_movie() +void VRVolumeApp::run_movie(bool is_animation) { #ifndef _MSC_VER fs::create_directory("movie"); @@ -193,8 +205,25 @@ void VRVolumeApp::run_movie() m_movieAction = new CreateMovieAction(); m_frame = 0; - m_show_menu = false; + if (is_animation) + { + m_show_menu = false; + } + m_current_movie_state = MOVIE_RECORD; } + +void VRVolumeApp::stop_movie() +{ + m_current_movie_state = MOVIE_STOP; +#ifdef _MSC_VER + m_movieAction->save(m_moviename); + m_ui_view->set_show_movie_saved_pop_up(true); +#endif + delete m_movieAction; + m_movieAction = nullptr; + m_show_menu = true; +} + #endif void VRVolumeApp::set_render_count(unsigned int rendercount) @@ -212,17 +241,17 @@ void VRVolumeApp::set_frame(float frame) m_frame = frame; } -glm::vec4& VRVolumeApp::get_no_color() +glm::vec4 &VRVolumeApp::get_no_color() { return m_noColor; } -glm::vec4& VRVolumeApp::get_ambient() +glm::vec4 &VRVolumeApp::get_ambient() { return m_ambient; } -glm::vec4& VRVolumeApp::get_diffuse() +glm::vec4 &VRVolumeApp::get_diffuse() { return m_diffuse; } @@ -262,30 +291,31 @@ void VRVolumeApp::set_threshold(float threshold) m_threshold = threshold; } -void VRVolumeApp::add_label(std::string& text, float x, float y, float z, float textPosZ, float size, int volume) +void VRVolumeApp::add_label(std::string &text, float x, float y, float z, float textPosZ, float size, int volume) { - m_labels.add(text, x, y, z, textPosZ, size, volume); + if (m_labels) + { + m_labels->add(text, x, y, z, textPosZ, size, volume); + } } -void VRVolumeApp::set_description(int descriptionHeight, std::string& descriptionFilename) +void VRVolumeApp::set_description(int descriptionHeight, std::string &descriptionFilename) { m_descriptionHeight = descriptionHeight; m_descriptionFilename = descriptionFilename; - m_description = LoadDescriptionAction(m_descriptionFilename).run(); - // std::cerr << m_description[0] << std::endl; + m_description = LoadDescriptionAction(m_descriptionFilename).run(); } -void VRVolumeApp::set_mesh(int volumeId, std::string& fileName, std::string& shaderFilePath) +void VRVolumeApp::set_mesh(int volumeId, std::string &fileName, std::string &shaderFilePath) { m_models_volumeID.push_back(volumeId - 1); m_models_filenames.push_back(fileName); m_models_MV.push_back(glm::mat4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)); m_shader_file_path = shaderFilePath; - } -void VRVolumeApp::set_texture(std::string& fileNamePath) +void VRVolumeApp::set_texture(std::string &fileNamePath) { std::cerr << "Load texture " << fileNamePath << std::endl; m_texture = new Texture(GL_TEXTURE_2D, fileNamePath); @@ -294,7 +324,6 @@ void VRVolumeApp::set_texture(std::string& fileNamePath) void VRVolumeApp::init_num_volumes(int nVolumes) { m_numVolumes = nVolumes; - //m_data_labels.resize(m_numVolumes); m_volumes.resize(m_numVolumes); m_promises.resize(m_numVolumes); m_futures.resize(m_numVolumes); @@ -305,44 +334,42 @@ void VRVolumeApp::init_num_volumes(int nVolumes) m_ui_view->init_ui(m_is2d, m_lookingGlass); m_ui_view->update_ui(m_numVolumes); } - - } -void VRVolumeApp::add_data_label(std::string& label) +void VRVolumeApp::add_data_label(std::string &label) { m_ui_view->add_data_label(label); } -std::vector*>& VRVolumeApp::get_promise(int index) +std::vector *> &VRVolumeApp::get_promise(int index) { return m_promises[index - 1]; } -std::vector>* VRVolumeApp::get_future(int index) +std::vector> *VRVolumeApp::get_future(int index) { return m_futures[index - 1]; } -void VRVolumeApp::set_future(int index, std::vector>* futures) +void VRVolumeApp::set_future(int index, std::vector> *futures) { m_futures[index - 1] = futures; } -std::vector & VRVolumeApp::get_thread(int index) +std::vector &VRVolumeApp::get_thread(int index) { - return m_threads[index - 1]; + return m_threads[index - 1]; } void VRVolumeApp::init_volume_loading(int index, std::vector vals) { - std::vector & ths = m_threads[index - 1]; - std::vector*> v2 = m_promises[index - 1]; + std::vector &ths = m_threads[index - 1]; + std::vector *> v2 = m_promises[index - 1]; ths.emplace_back(new std::thread(&VRVolumeApp::load_volume, this, vals, v2.back())); } -void VRVolumeApp::set_character_state(std::string& eventName, int state) +void VRVolumeApp::set_character_state(std::string &eventName, int state) { size_t pos = eventName.find("Kbd"); size_t pos_ = eventName.find("_"); @@ -354,7 +381,7 @@ void VRVolumeApp::set_character_state(std::string& eventName, int state) if (keyStr.size() == 1) { int keyCode = keyStr[0]; - ImGuiIO& io = ImGui::GetIO(); + ImGuiIO &io = ImGui::GetIO(); if (state == 1) { io.KeysDown[keyCode] = true; @@ -368,16 +395,9 @@ void VRVolumeApp::set_character_state(std::string& eventName, int state) { if (m_ui_view) { - m_ui_view->set_chracter(keyStr[0]); + m_ui_view->add_character(keyStr[0]); } } - /* if (std::isalpha(keyStr[0], loc) || isdigit(keyStr[0])) - { - if (m_ui_view) - { - m_ui_view->set_chracter(keyStr[0]); - } - }*/ } else { @@ -386,44 +406,37 @@ void VRVolumeApp::set_character_state(std::string& eventName, int state) if (keyStr == "Backspace" || keyStr == "Del") { m_ui_view->remove_character(); - //_keyBoardInputText->deleteCharacters(_keyBoardInputText->getTextSize() - 1, 1); } else if (keyStr == "Space") { - m_ui_view->set_chracter(32); - /*std::string space(" "); - addTextToInputField(space);*/ + m_ui_view->add_character(32); } } - } - } - - } -void VRVolumeApp::set_directory_path(std::string& dir_path) +void VRVolumeApp::set_directory_path(std::string &dir_path) { m_directiort_path = dir_path; } -std::string& VRVolumeApp::get_directory_path() +std::string &VRVolumeApp::get_directory_path() { return m_directiort_path; } -void VRVolumeApp::set_loaded_file(std::string& dir_path) +void VRVolumeApp::set_loaded_file(std::string &dir_path) { m_current_file_loaded = dir_path; } -std::string& VRVolumeApp::get_loaded_file() +std::string &VRVolumeApp::get_loaded_file() { return m_current_file_loaded; } -std::vector< Volume* >& VRVolumeApp::get_volume(int volume) +std::vector &VRVolumeApp::get_volume(int volume) { return m_volumes[volume]; } @@ -434,23 +447,23 @@ void VRVolumeApp::intialize_ui() { m_ui_view->init_ui(m_is2d, m_lookingGlass); } - } - -void VRVolumeApp::load_volume(std::vector vals, std::promise* promise) +void VRVolumeApp::load_volume(std::vector vals, std::promise *promise) { if (vals.size() == 1 && helper::ends_with_string(vals[0], ".nrrd")) { #ifdef WITH_TEEM - Volume* volume = LoadNrrdAction(vals[0]).run(); - volume->set_volume_position({ 0.0, 0.0, 0.0 }); - volume->set_volume_scale({ 0.0, 0.0, 0.0 }); + Volume *volume = LoadNrrdAction(vals[0]).run(); + volume->set_volume_position({0.0, 0.0, 0.0}); + volume->set_volume_scale({0.0, 0.0, 0.0}); volume->set_volume_mv(glm::mat4()); - promise->set_value(volume);; + promise->set_value(volume); + ; #endif } - else { + else + { std::cerr << "Load volume " << vals[1] << std::endl; std::cerr << "Position " << vals[5] << " , " << vals[6] << " , " << vals[7] << std::endl; std::cerr << "Resolution " << vals[2] << " , " << vals[3] << " , " << vals[4] << std::endl; @@ -460,10 +473,10 @@ void VRVolumeApp::load_volume(std::vector vals, std::promiseset_volume_position({ stof(vals[5]), stof(vals[6]), stof(vals[7]) }); - volume->set_volume_scale({ 0.0, 0.0, 0.0 }); + volume->set_volume_position({stof(vals[5]), stof(vals[6]), stof(vals[7])}); + volume->set_volume_scale({0.0, 0.0, 0.0}); volume->set_volume_mv(glm::mat4()); if (vals.size() > 9) @@ -471,28 +484,28 @@ void VRVolumeApp::load_volume(std::vector vals, std::promiseset_render_channel(std::stoi(vals[9])); } - promise->set_value(volume);; + promise->set_value(volume); + ; std::cerr << "end load" << std::endl; } } - -void VRVolumeApp::load_nrrd_file(std::string& filename) +void VRVolumeApp::load_nrrd_file(std::string &filename) { std::vector vals; vals.push_back(filename); - std::vector*> v; - std::promise* pm = new std::promise(); + std::vector *> v; + std::promise *pm = new std::promise(); v.push_back(pm); m_promises.push_back(v); - std::vector>* fut = new std::vector>; + std::vector> *fut = new std::vector>; fut->push_back(pm->get_future()); m_futures.push_back(fut); - std::vector ths; - std::vector*> v2 = m_promises.back(); + std::vector ths; + std::vector *> v2 = m_promises.back(); ths.emplace_back(new std::thread(&VRVolumeApp::load_volume, this, vals, v2.back())); m_threads.push_back(ths); m_numVolumes = 1; @@ -501,14 +514,26 @@ void VRVolumeApp::load_nrrd_file(std::string& filename) { m_ui_view->update_ui(m_numVolumes); } - - } -void VRVolumeApp::render(const MinVR::VRGraphicsState& renderState) +void VRVolumeApp::render(const MinVR::VRGraphicsState &render_state) { - if (m_is2d) { - m_headpose = glm::make_mat4(renderState.getViewMatrix()); + m_trackball.set_app_mode(m_app_mode); + if (m_app_mode == SIMULATION) + { + if (m_simulation) + { + m_simulation->update_simulation(); + SimulationState sim_state = m_simulation->get_current_simulation_state(); + m_trackball.update_sim_poi(sim_state.poi); + m_ui_view->set_clip_max(sim_state.max_clip); + m_ui_view->set_clip_min(sim_state.min_clip); + } + } + + if (m_is2d) + { + m_headpose = glm::make_mat4(render_state.getViewMatrix()); m_headpose = glm::inverse(m_headpose); } @@ -516,30 +541,27 @@ void VRVolumeApp::render(const MinVR::VRGraphicsState& renderState) glClearDepth(1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - if (renderState.isInitialRenderCall()) + if (render_state.isInitialRenderCall()) { m_depthTextures.push_back(new DepthTexture); } - int window_w = renderState.index().getValue("WindowWidth"); - int window_h = renderState.index().getValue("WindowHeight"); - int framebuffer_w = renderState.index().getValue("FramebufferWidth"); - int framebuffer_h = renderState.index().getValue("FramebufferHeight"); - - //setup projection - m_projection_mtrx = glm::make_mat4(renderState.getProjectionMatrix()); - m_model_view = glm::make_mat4(renderState.getViewMatrix()); + // setup projection + m_projection_mtrx = glm::make_mat4(render_state.getProjectionMatrix()); + m_model_view = glm::make_mat4(render_state.getViewMatrix()); - //overwrite MV for 2D viewing + // overwrite MV for 2D viewing if (m_is2d) - m_model_view = m_trackball.getViewmatrix(); + m_model_view = m_trackball.get_view_matrix(); glMatrixMode(GL_PROJECTION); glLoadMatrixf(glm::value_ptr(m_projection_mtrx)); - //setup Modelview for volumes - for (int i = 0; i < m_volumes.size(); i++) { - for (int j = 0; j < m_volumes[i].size(); j++) { + // setup Modelview for volumes + for (int i = 0; i < m_volumes.size(); i++) + { + for (int j = 0; j < m_volumes[i].size(); j++) + { glm::mat4 tmp = m_model_view; tmp = tmp * m_object_pose; tmp = glm::scale(tmp, glm::vec3(m_ui_view->get_scale(), m_ui_view->get_scale(), m_ui_view->get_scale() * m_ui_view->get_z_scale())); @@ -549,39 +571,28 @@ void VRVolumeApp::render(const MinVR::VRGraphicsState& renderState) } } - //setup Modelview for meshes + // setup Modelview for meshes + glm::mat4 volume_mv; if (m_mesh_model) { int i = 0; - if (m_volumes.size() > m_models_volumeID[i]) { - glm::mat4 volume_mv = m_volumes[0][m_models_volumeID[i]]->get_volume_mv(); + if (m_volumes.size() > m_models_volumeID[i]) + { + volume_mv = m_volumes[0][m_models_volumeID[i]]->get_volume_mv(); volume_mv = glm::translate(volume_mv, glm::vec3(-0.5f, -0.5f, -0.5f * m_volumes[0][m_models_volumeID[i]]->get_volume_scale().x / (m_volumes[0][m_models_volumeID[i]]->get_volume_scale().z))); volume_mv = glm::scale(volume_mv, glm::vec3(m_volumes[0][m_models_volumeID[i]]->get_volume_scale().x, m_volumes[0][m_models_volumeID[i]]->get_volume_scale().y, m_volumes[0][m_models_volumeID[i]]->get_volume_scale().x)); m_mesh_model->setMVMatrix(volume_mv); m_models_MV[i] = volume_mv; - - /*Original transformations of the model - DO NOT REMOVE YET*/ - //mesh_model->setPosition(glm::vec3(-0.5f, -0.5f, - // -0.5f * m_volumes[m_models_volumeID[i]]->get_volume_scale().x / (m_volumes[m_models_volumeID[i]]->get_volume_scale().z))); - //mesh_model->setScale(glm::vec3(m_volumes[m_models_volumeID[i]]->get_volume_scale().x, m_volumes[m_models_volumeID[i]]->get_volume_scale().y, m_volumes[m_models_volumeID[i]]->get_volume_scale().x)); } } - /* SOriginal transformations of the volumes - DO NOT REMOVE YET */ - //for (int i = 0; i < m_models_displayLists.size(); i++) { - // if (m_volumes.size() > m_models_volumeID[i]) { - // m_models_MV[i] = m_volumes[m_models_volumeID[i]]->get_volume_mv(); - // m_models_MV[i] = glm::translate(m_models_MV[i], glm::vec3(-0.5f, -0.5f, -0.5f * m_volumes[m_models_volumeID[i]]->get_volume_scale().x / (m_volumes[m_models_volumeID[i]]->get_volume_scale().z))); - // m_models_MV[i] = glm::scale(m_models_MV[i], glm::vec3(m_volumes[m_models_volumeID[i]]->get_volume_scale().x, m_volumes[m_models_volumeID[i]]->get_volume_scale().y, m_volumes[m_models_volumeID[i]]->get_volume_scale().x)); - // //m_models_MV[i] = glm::scale(m_models_MV[i], glm::vec3(10,10,10)); - // } - //} - - if (m_clipping || m_ui_view->is_use_custom_clip_plane()) { + if (m_clipping || m_ui_view->is_use_custom_clip_plane()) + { glm::mat4 clipPlane = glm::inverse(m_controller_pose) * glm::inverse(m_model_view); - if (m_use_custom_clip_plane) { + if (m_use_custom_clip_plane) + { clipPlane = glm::eulerAngleYXZ(m_clip_ypr.x, m_clip_ypr.y, m_clip_ypr.z); clipPlane = glm::translate(clipPlane, m_clip_pos); clipPlane = clipPlane * glm::inverse(m_model_view); @@ -596,106 +607,79 @@ void VRVolumeApp::render(const MinVR::VRGraphicsState& renderState) ren->setClipping(false, nullptr); } - for (auto ren : m_renders) { + for (auto ren : m_renders) + { if (m_ui_view) { ren->setClipMinMax(m_ui_view->get_clip_min(), m_ui_view->get_clip_max()); } } - if (m_mesh_model) { m_simple_texture_shader.start(); - m_simple_texture_shader.setUniform("p", m_projection_mtrx); + m_simple_texture_shader.setUniform("projection_matrix", m_projection_mtrx); m_mesh_model->render(m_simple_texture_shader); m_simple_texture_shader.stop(); } - //render labels - render_labels(renderState); - - /*if (m_ui_view && !m_is2d) - { - - glm::mat4 viewMatrix = glm::make_mat4(renderState.getViewMatrix()); - m_ui_view->render_3D(viewMatrix); - }*/ - + // render labels + m_line_shader.start(); + m_line_shader.setUniform("projection_matrix", m_projection_mtrx); + m_line_shader.setUniform("model_view_matrix", volume_mv); + render_labels(volume_mv, render_state); + m_line_shader.stop(); m_depthTextures[m_rendercount]->copyDepthbuffer(); - (static_cast (m_renders[1]))->setDepthTexture(m_depthTextures[m_rendercount]); - - render_volume(renderState); - + (static_cast(m_renders[1]))->setDepthTexture(m_depthTextures[m_rendercount]); - render_ui(renderState); - - /*if (m_ui_view && m_is2d) + if (m_is2d) { - m_ui_view->render_2D(); - }*/ + m_ui_view->draw_transfer_function_legend(); + } - //drawTime - if (m_is2d && m_animated) { + // drawTime + if (m_is2d && m_animated) + { unsigned int active_volume = floor(m_frame); unsigned int active_volume2 = ceil(m_frame); - if (active_volume < m_volumes[0].size() && active_volume2 < m_volumes[0].size() && m_volumes[0][active_volume]->texture_initialized() && m_volumes[0][active_volume2]->texture_initialized()) { + if (active_volume < m_volumes[0].size() && active_volume2 < m_volumes[0].size() && m_volumes[0][active_volume]->texture_initialized() && m_volumes[0][active_volume2]->texture_initialized()) + { float alpha = m_frame - active_volume; time_t time = m_volumes[0][active_volume]->getTime() * (1 - alpha) + m_volumes[0][active_volume2]->getTime() * alpha; - FontHandler::getInstance()->drawClock(time); + m_ui_view->set_volume_time_info(time); } } - glFlush(); + render_volume(render_state); - m_rendercount++; + render_ui(render_state); + glFlush(); + m_rendercount++; - if (m_movieAction) { + if (m_movieAction) + { #ifndef _MSC_VER glFinish(); #endif std::cerr << "Add Frame" << std::endl; m_movieAction->addFrame(); - if (m_frame > m_volumes[m_selectedVolume].size() - 1 - m_speed) { - std::cerr << "Save Movie" << std::endl; -#ifdef _MSC_VER - m_movieAction->save(m_moviename); -#endif - delete m_movieAction; - m_movieAction = nullptr; - m_show_menu = true; - } } - - } -void VRVolumeApp::render_labels(const MinVR::VRGraphicsState& renderState) +void VRVolumeApp::render_labels(glm::mat4 &volume_mv, const MinVR::VRGraphicsState &renderState) { - //render labels - m_labels.draw(m_models_MV, m_headpose, m_ui_view->get_z_scale()); - - if (m_is2d && !m_description.empty()) - FontHandler::getInstance()->renderMultiLineTextBox2D(m_description, 50, 950, 200, m_descriptionHeight); + // render labels + if (m_labels) + { + m_labels->drawLabels(volume_mv, m_projection_mtrx, m_headpose, m_ui_view->get_z_scale()); + } } -void VRVolumeApp::render_mesh(const MinVR::VRGraphicsState& renderState) +void VRVolumeApp::render_mesh(const MinVR::VRGraphicsState &renderState) { - /*Original render Mesh using Fixed pipeline - DO NOT REMOVE YET*/ - //Render meshes - /*for (int i = 0; i < m_models_displayLists.size(); i++) { - if (m_volumes.size() > m_models_volumeID[i]) { - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadMatrixf(glm::value_ptr(m_models_MV[i])); - glColor3f(1.0f, 1.0f, 1.0f); - glCallList(m_models_displayLists[i]); - glPopMatrix(); - } - }*/ if (m_mesh_model) { m_simple_texture_shader.start(); @@ -705,38 +689,34 @@ void VRVolumeApp::render_mesh(const MinVR::VRGraphicsState& renderState) } } -void VRVolumeApp::render_volume(const MinVR::VRGraphicsState& renderState) +void VRVolumeApp::render_volume(const MinVR::VRGraphicsState &renderState) { - //render volumes - // renderState->getProjectionMatrix(); - for (auto ren : m_renders) { + + for (auto ren : m_renders) + { ren->set_multiplier(m_ui_view->get_multiplier()); ren->set_threshold(m_ui_view->get_threshold()); ren->set_numSlices(m_ui_view->get_slices()); ren->useMultichannelColormap(m_use_multi_transfer); } - - for (int tfn = 0; tfn < m_ui_view->get_num_transfer_functions(); tfn++) { for (int vol = 0; vol < m_numVolumes; vol++) { m_animated ? animated_render(tfn, vol) : normal_render_volume(tfn, vol); - } } - - } void VRVolumeApp::normal_render_volume(int tfn, int vol) { if (m_ui_view && m_ui_view->is_transfer_function_enabled(tfn, vol)) { - std::vector > order; - for (int i = 0; i < m_volumes.size(); i++) { + std::vector> order; + for (int i = 0; i < m_volumes.size(); i++) + { glm::vec4 center = m_volumes[vol][i]->get_volume_mv() * glm::vec4(0, 0, 0, 1); float l = glm::length(center); order.push_back(std::make_pair(l, i)); @@ -745,7 +725,8 @@ void VRVolumeApp::normal_render_volume(int tfn, int vol) int renderMethod = m_ui_view->get_render_method(); bool useTranferFunction = m_ui_view->is_use_transfer_function_enabled(); - for (int i = order.size() - 1; i >= 0; i--) { + for (int i = order.size() - 1; i >= 0; i--) + { if (m_volumes[vol][order[i].second]->texture_initialized()) { if (m_ui_view->is_render_volume_enabled()) @@ -754,29 +735,35 @@ void VRVolumeApp::normal_render_volume(int tfn, int vol) GLint colorMap = m_ui_view->get_transfer_function_colormap(tfn); GLint colorMapMult = m_ui_view->get_multitransfer_function_colormap(tfn); m_renders[renderMethod]->render(m_volumes[vol][order[i].second], m_volumes[vol][order[i].second]->get_volume_mv(), m_projection_mtrx, m_volumes[vol][order[i].second]->get_volume_scale().x / m_volumes[vol][order[i].second]->get_volume_scale().z, - useTranferFunction ? (m_use_multi_transfer) ? colorMapMult : colorMap : -1, m_ui_view->get_render_channel()); + useTranferFunction ? (m_use_multi_transfer) ? colorMapMult : colorMap : -1, m_ui_view->get_render_channel()); } - } } } } - void VRVolumeApp::animated_render(int tfn, int vol) { unsigned int active_volume = floor(m_frame); unsigned int active_volume2 = ceil(m_frame); - int renderMethod = m_ui_view->get_render_method(); - bool useTranferFunction = m_ui_view->is_use_transfer_function_enabled(); - //bool useMultitransferFunction = m_ui_view->isUseMultiTransfer(); + int render_method = m_ui_view->get_render_method(); + bool use_tranferFunction = m_ui_view->is_use_transfer_function_enabled(); + size_t max_animation_length = 0; + float global_min = std::numeric_limits::max(); + float global_max = std::numeric_limits::min(); + bool dirty = false; if (m_ui_view && m_ui_view->is_transfer_function_enabled(tfn, vol)) { + dirty = true; + max_animation_length = std::max(max_animation_length, m_volumes[vol].size()); + global_min = std::min(global_min, m_volumes[vol][active_volume]->getMin()); + global_max = std::max(global_max, m_volumes[vol][active_volume]->getMax()); + if (active_volume < m_volumes[vol].size() && active_volume2 < m_volumes[vol].size() && m_volumes[vol][active_volume]->texture_initialized() && m_volumes[vol][active_volume2]->texture_initialized()) { - m_renders[renderMethod]->set_blending(true, m_frame - active_volume, m_volumes[vol][active_volume2]); + m_renders[render_method]->set_blending(true, m_frame - active_volume, m_volumes[vol][active_volume2]); if (m_ui_view->is_render_volume_enabled()) { @@ -784,7 +771,7 @@ void VRVolumeApp::animated_render(int tfn, int vol) GLint colorMap = m_ui_view->get_transfer_function_colormap(tfn); GLint colorMapMult = m_ui_view->get_multitransfer_function_colormap(tfn); GLint lut = -1; - if (useTranferFunction) + if (use_tranferFunction) { if (m_use_multi_transfer) { @@ -796,19 +783,22 @@ void VRVolumeApp::animated_render(int tfn, int vol) } } - - m_renders[renderMethod]->render(m_volumes[vol][active_volume], m_volumes[vol][active_volume]->get_volume_mv(), m_projection_mtrx, m_volumes[vol][active_volume]->get_volume_scale().x / m_volumes[vol][active_volume]->get_volume_scale().z, - lut, m_ui_view->get_render_channel()); + m_renders[render_method]->render(m_volumes[vol][active_volume], m_volumes[vol][active_volume]->get_volume_mv(), m_projection_mtrx, m_volumes[vol][active_volume]->get_volume_scale().x / m_volumes[vol][active_volume]->get_volume_scale().z, + lut, m_ui_view->get_render_channel()); } } } + m_ui_view->set_animation_length(max_animation_length); + if (dirty) + { + m_ui_view->set_transfer_function_min_max(global_min, global_max); + } } -void VRVolumeApp::render_ui(const MinVR::VRGraphicsState& renderState) +void VRVolumeApp::render_ui(const MinVR::VRGraphicsState &renderState) { - //render menu - glm::mat4 mvMatrix = glm::make_mat4(renderState.getViewMatrix()); + // render menu if (m_ui_view && m_window_properties) { @@ -817,9 +807,9 @@ void VRVolumeApp::render_ui(const MinVR::VRGraphicsState& renderState) m_window_properties->framebuffer_w = renderState.index().getValue("FramebufferWidth"); m_window_properties->framebuffer_h = renderState.index().getValue("FramebufferHeight"); - if (!m_is2d) { + glm::mat4 mvMatrix = glm::make_mat4(renderState.getViewMatrix()); m_ui_view->render_3D(mvMatrix, *m_window_properties); } else @@ -827,10 +817,8 @@ void VRVolumeApp::render_ui(const MinVR::VRGraphicsState& renderState) m_ui_view->render_2D(*m_window_properties); } } - } - void VRVolumeApp::update_frame_state() { glMatrixMode(GL_MODELVIEW); @@ -838,8 +826,11 @@ void VRVolumeApp::update_frame_state() glLightfv(GL_LIGHT0, GL_POSITION, m_light_pos); if (m_animated && !m_ui_view->is_stopped()) { - m_frame += m_speed; - if (m_frame > m_volumes[m_selectedVolume].size() - 1) m_frame = 0.0; + m_frame += (m_speed * m_volume_animation_scale_factor); + if (m_frame > m_volumes[m_selectedVolume].size() - 1) + { + m_frame = 0.0; + } } m_rendercount = 0; } @@ -853,12 +844,8 @@ void VRVolumeApp::update_3D_ui() m_ui_view->update_3D_ui_frame(); } } - } - - - void VRVolumeApp::update_2D_ui() { if (m_show_menu && m_ui_view) @@ -873,10 +860,10 @@ void VRVolumeApp::update_2D_ui() void VRVolumeApp::add_lodaded_textures() { bool allready = true; - for (auto& fut : m_futures) + for (auto &fut : m_futures) { - std::vector >* _ft = fut; - for (auto& f : *_ft) + std::vector> *_ft = fut; + for (auto &f : *_ft) { #ifdef _MSC_VER allready = allready & f._Is_ready(); @@ -884,50 +871,48 @@ void VRVolumeApp::add_lodaded_textures() allready = allready & (f.wait_for(std::chrono::seconds(0)) == std::future_status::ready); #endif } - } if (allready) { for (int i = 0; i < m_futures.size(); i++) { - std::vector >* _ft = m_futures[i]; + std::vector> *_ft = m_futures[i]; int counter = 0; - for (auto& value : *_ft) + for (auto &value : *_ft) { - Volume* vlm = value.get(); + Volume *vlm = value.get(); m_volumes[i].push_back(vlm); m_threads[i][counter]->join(); delete m_threads[i][counter]; delete m_promises[i][counter]; counter++; } - - } - m_threads.clear(); m_promises.clear(); m_futures.clear(); - // m_ui_view->compute_new_histogram(); } } void VRVolumeApp::clear_data() { - for (int i = 0; i < m_volumes.size(); i++) { - std::vector< Volume* > v = m_volumes[i]; + for (int i = 0; i < m_volumes.size(); i++) + { + std::vector v = m_volumes[i]; for (int j = 0; j < v.size(); j++) { delete v[i]; } - } m_volumes.clear(); m_description.clear(); - m_labels.clear(); + if (m_labels) + { + m_labels->clear(); + } m_models_filenames.clear(); m_models_displayLists.clear(); @@ -936,7 +921,6 @@ void VRVolumeApp::clear_data() m_models_MV.clear(); } - bool VRVolumeApp::data_is_multi_channel() { bool is_multi_channel = false; @@ -945,19 +929,21 @@ bool VRVolumeApp::data_is_multi_channel() int renderchannel = m_ui_view->get_render_channel(); for (int i = 0; i < m_volumes.size(); i++) { + // renderchannel[0] = "based on data" + // renderchannel[5] = "rgba" + // renderchannel[6] = "rgba with alpha as max rgb"; if (m_volumes.size() > 0 && m_volumes[i][0]->get_channels() > 1 && - (renderchannel == 0 || renderchannel == 5 || renderchannel == 6)) + (renderchannel == 0 || renderchannel == 5 || renderchannel == 6)) { is_multi_channel |= true; } } } - return is_multi_channel; } -void VRVolumeApp::get_min_max(const float frame, float& min, float& max) +void VRVolumeApp::get_min_max(const float frame, float &min, float &max) { unsigned int active_volume = floor(frame); unsigned int active_volume2 = ceil(frame); @@ -991,15 +977,13 @@ void VRVolumeApp::set_num_volumes(int nVolumes) m_numVolumes = nVolumes; } -void VRVolumeApp::mouse_pos_event(glm::vec2& mPos) +void VRVolumeApp::mouse_pos_event(glm::vec2 &mPos) { - m_trackball.mouse_move(mPos.x, mPos.y); + get_trackball_camera().mouse_move(mPos.x, mPos.y); if (m_ui_view) { m_ui_view->set_cursor_pos(mPos); } - - } void VRVolumeApp::update_ui_events(float value) @@ -1008,12 +992,11 @@ void VRVolumeApp::update_ui_events(float value) { m_ui_view->set_analog_value(value); } - } void VRVolumeApp::update_track_ball_event(float value) { - m_trackball.mouse_scroll(value); + get_trackball_camera().mouse_scroll(value); } void VRVolumeApp::button_events_ui_handle(int button, int state) @@ -1022,12 +1005,11 @@ void VRVolumeApp::button_events_ui_handle(int button, int state) { m_ui_view->set_button_click(button, state); } - } void VRVolumeApp::button_event_trackBall_handle(int button, int state) { - m_trackball.mouse_pressed(button, state); + get_trackball_camera().mouse_pressed(button, state); } void VRVolumeApp::enable_grab(bool grab) @@ -1063,7 +1045,7 @@ void VRVolumeApp::enable_render_volume() } } -void VRVolumeApp::update_UI_pose_controller(glm::mat4& newPose) +void VRVolumeApp::update_UI_pose_controller(glm::mat4 &newPose) { if (m_ui_view) { @@ -1071,13 +1053,12 @@ void VRVolumeApp::update_UI_pose_controller(glm::mat4& newPose) } } -void VRVolumeApp::update_head_pose(glm::mat4& newPose) +void VRVolumeApp::update_head_pose(glm::mat4 &newPose) { if (m_is2d) { m_headpose = newPose; } - } void VRVolumeApp::update_fps(float fps) @@ -1098,9 +1079,10 @@ void VRVolumeApp::update_dynamic_slices() } } -void VRVolumeApp::do_grab(glm::mat4& newPose) +void VRVolumeApp::do_grab(glm::mat4 &newPose) { - if (m_grab) { + if (m_grab) + { // Update the paintingToRoom transform based upon the new transform // of the left hand relative to the last frame. m_object_pose = newPose * glm::inverse(m_controller_pose) * m_object_pose; @@ -1108,3 +1090,49 @@ void VRVolumeApp::do_grab(glm::mat4& newPose) m_controller_pose = newPose; } +ArcBallCamera &VRVolumeApp::get_trackball_camera() +{ + return m_trackball; +} + +void VRVolumeApp::set_volume_animation_scale_factor(float scale) +{ + m_volume_animation_scale_factor = scale; +} + +Simulation &VRVolumeApp::get_simulation() +{ + return *m_simulation; +} + +void VRVolumeApp::set_clip_min(glm::vec3 clip_min) +{ + m_ui_view->set_clip_min(clip_min); +} + +void VRVolumeApp::set_clip_max(glm::vec3 clip_max) +{ + m_ui_view->set_clip_max(clip_max); +} + +std::string VRVolumeApp::get_movie_state_label() +{ + if (m_current_movie_state == STOP) + { + return "Write Movie"; + } + else + { + return "STOP RECORD"; + } +} + +MOVIESTATE VRVolumeApp::get_movie_state() +{ + return m_current_movie_state; +} + +void VRVolumeApp::set_app_mode(APPMODE mode) +{ + m_app_mode = mode; +} diff --git a/src/vrapp/VolumeVisualizationApp.cpp b/src/vrapp/VolumeVisualizationApp.cpp index 6b6a1e0..365c008 100644 --- a/src/vrapp/VolumeVisualizationApp.cpp +++ b/src/vrapp/VolumeVisualizationApp.cpp @@ -22,16 +22,14 @@ #include "UI/UIView.h" #include "loader/VRDataLoader.h" - #include #include #include "render/FontHandler.h" - -VolumeVisualizationApp::VolumeVisualizationApp(int argc, char** argv) : VRApp(argc, argv), m_vrVolumeApp(nullptr) +VolumeVisualizationApp::VolumeVisualizationApp(int argc, char **argv) : VRApp(argc, argv), m_vrVolumeApp(nullptr), m_num_frames(0) { int argc_int = this->getLeftoverArgc(); - char** argv_int = this->getLeftoverArgv(); + char **argv_int = this->getLeftoverArgv(); m_vrVolumeApp = new VRVolumeApp(); std::string current_Path = std::string(argv_int[0]); @@ -40,54 +38,52 @@ VolumeVisualizationApp::VolumeVisualizationApp(int argc, char** argv) : VRApp(ar m_vrVolumeApp->set_directory_path(parent_Path); FontHandler::setParentPath(parent_Path); - if (argc_int >= 2) { - for (int i = 1; i < argc_int; i++) { - + if (argc_int >= 2) + { + for (int i = 1; i < argc_int; i++) + { if (std::string(argv_int[i]) == std::string("use2DUI")) { - //m_is2d = true; m_vrVolumeApp->set_is_2D(true); } if (std::string(argv_int[i]) == std::string("useHolo")) { - //m_lookingGlass = true; - //m_speed = 0.5; m_vrVolumeApp->set_looking_glass(true); - } - else if (std::string(argv_int[i]) == std::string("convert")) { - //convert = true; + else if (std::string(argv_int[i]) == std::string("convert")) + { m_vrVolumeApp->set_convert(true); } else if (helper::ends_with_string(std::string(argv_int[i]), ".txt")) { std::string fileName = argv_int[i]; - VRDataLoader::get_instance()->load_txt_file(*m_vrVolumeApp, fileName); + VRDataLoader::load_txt_file(*m_vrVolumeApp, fileName); } - else if (helper::ends_with_string(std::string(argv_int[i]), ".nrrd")) { - - /* - NRRD LOADING - std::vector vals; - vals.push_back(std::string(argv_int[i])); - std::vector*> v; - std::promise* pm = new std::promise(); - - v.push_back(pm); - promises.push_back(v); - - std::vector>* fut = new std::vector>; - fut->push_back(pm->get_future()); - futures.push_back(fut); - - std::vector ths; - std::vector*> v2= promises.back(); - ths.emplace_back(new std::thread(&VolumeVisualizationApp::loadVolume, this, vals, v2.back())); - threads.push_back(ths);*/ + else if (helper::ends_with_string(std::string(argv_int[i]), ".nrrd")) + { + + // NRRD LOADING + std::vector + vals; + vals.push_back(std::string(argv_int[i])); + std::vector *> v; + std::promise *pm = new std::promise(); + + v.push_back(pm); + promises.push_back(v); + + std::vector> *fut = new std::vector>; + fut->push_back(pm->get_future()); + futures.push_back(fut); + + std::vector ths; + std::vector *> v2 = promises.back(); + ths.emplace_back(new std::thread(&VolumeVisualizationApp::loadVolume, this, vals, v2.back())); + threads.push_back(ths); std::string nrrdFileName(argv_int[i]); m_vrVolumeApp->load_nrrd_file(nrrdFileName); - //m_vrVolumeApp->initialize(); + m_vrVolumeApp->initialize(); } } } @@ -96,7 +92,6 @@ VolumeVisualizationApp::VolumeVisualizationApp(int argc, char** argv) : VRApp(ar m_light_pos[1] = 4.0; m_light_pos[2] = 0.0; m_light_pos[3] = 1.0; - } VolumeVisualizationApp::~VolumeVisualizationApp() @@ -105,8 +100,7 @@ VolumeVisualizationApp::~VolumeVisualizationApp() delete m_vrVolumeApp; } - -void VolumeVisualizationApp::onCursorMove(const VRCursorEvent& event) +void VolumeVisualizationApp::onCursorMove(const VRCursorEvent &event) { if (event.getName() == "Mouse_Move") { @@ -116,54 +110,54 @@ void VolumeVisualizationApp::onCursorMove(const VRCursorEvent& event) glm::vec2 pos2d(event.getPos()[0], event.getPos()[1]); m_vrVolumeApp->mouse_pos_event(pos2d); } - - } } -#define count_Packages +#define count_Packages #ifdef count_Packages int last_received = 0; #endif count_Packages -void VolumeVisualizationApp::onAnalogChange(const VRAnalogEvent& event) { - if (m_vrVolumeApp && m_vrVolumeApp->is_show_menu() && m_vrVolumeApp->is_ui_event()) { - if (event.getName() == "HTC_Controller_Right_TrackPad0_Y" || event.getName() == "HTC_Controller_1_TrackPad0_Y" - || (event.getName() == "Wand_Joystick_Y_Update" && !(event.getValue() > -0.1 && event.getValue() < 0.1))) - //m_menu_handler->setAnalogValue(event.getValue()); +void VolumeVisualizationApp::onAnalogChange(const VRAnalogEvent &event) +{ + if (m_vrVolumeApp && m_vrVolumeApp->is_show_menu() && m_vrVolumeApp->is_ui_event()) + { + if (event.getName() == "HTC_Controller_Right_TrackPad0_Y" || event.getName() == "HTC_Controller_1_TrackPad0_Y" || (event.getName() == "Wand_Joystick_Y_Update" && !(event.getValue() > -0.1 && event.getValue() < 0.1))) m_vrVolumeApp->update_ui_events(event.getValue()); - if (event.getName() == "MouseWheel_Spin") { - std::cerr << event.getValue() << std::endl; - //m_menu_handler->setAnalogValue(event.getValue() * 10); + if (event.getName() == "MouseWheel_Spin") + { m_vrVolumeApp->update_ui_events(event.getValue() * 10); } } - else { - if (event.getName() == "MouseWheel_Spin") { + else + { + if (event.getName() == "MouseWheel_Spin") + { if (m_vrVolumeApp) { m_vrVolumeApp->update_track_ball_event(event.getValue() * 0.01); } - } - } - if (event.getName() == "PhotonLoopFinished") { + if (event.getName() == "PhotonLoopFinished") + { m_vrVolumeApp->update_3D_ui(); m_vrVolumeApp->update_2D_ui(); - if (last_received + 1 != event.getValue()) { + if (last_received + 1 != event.getValue()) + { std::cerr << "Problem with package , received " << event.getValue() << " expected " << last_received + 1 << std::endl; } last_received = event.getValue(); } } - -void VolumeVisualizationApp::onButtonDown(const VRButtonEvent& event) { - if (m_vrVolumeApp && m_vrVolumeApp->is_ui_event()) { +void VolumeVisualizationApp::onButtonDown(const VRButtonEvent &event) +{ + if (m_vrVolumeApp && m_vrVolumeApp->is_ui_event()) + { if (event.getName() == "MouseBtnLeft_Down") { m_vrVolumeApp->button_events_ui_handle(0, 1); @@ -197,10 +191,10 @@ void VolumeVisualizationApp::onButtonDown(const VRButtonEvent& event) { { m_vrVolumeApp->button_event_trackBall_handle(2, 1); } - } - if (m_vrVolumeApp && m_vrVolumeApp->is_show_menu() && m_vrVolumeApp->is_ui_event()) { + if (m_vrVolumeApp && m_vrVolumeApp->is_show_menu() && m_vrVolumeApp->is_ui_event()) + { if (event.getName() == "HTC_Controller_Right_Axis1Button_Down" || event.getName() == "HTC_Controller_1_Axis1Button_Down" || event.getName() == "B10_Down") { m_vrVolumeApp->button_events_ui_handle(0, 1); @@ -209,52 +203,46 @@ void VolumeVisualizationApp::onButtonDown(const VRButtonEvent& event) { { m_vrVolumeApp->button_events_ui_handle(2, 1); } - //else if (event.getName() == "HTC_Controller_Right_AButton_Down" || event.getName() == "HTC_Controller_1_AButton_Down") else if (event.getName() == "HTC_Controller_Right_Axis0Button_Down" || event.getName() == "HTC_Controller_1_Axis0Button_Down" || event.getName() == "B08_Down") { m_vrVolumeApp->button_events_ui_handle(1, 1); } } - else { + else + { // This routine is called for all Button_Down events. Check event->getName() // to see exactly which button has been pressed down. - //std::cerr << "onButtonDown " << event.getName() << std::endl; + if (event.getName() == "KbdEsc_Down") { exit(0); } else if (event.getName() == "HTC_Controller_Right_Axis1Button_Down" || event.getName() == "HTC_Controller_1_Axis1Button_Down" || event.getName() == "B10_Down") { - //m_grab = true; - //std::cerr << "Grab ON" << std::endl; if (m_vrVolumeApp) { m_vrVolumeApp->enable_grab(true); } - } - //else if (event.getName() == "HTC_Controller_Right_AButton_Down" || event.getName() == "HTC_Controller_1_AButton_Down") else if (event.getName() == "HTC_Controller_Right_Axis0Button_Down" || event.getName() == "HTC_Controller_1_Axis0Button_Down" || event.getName() == "Wand_Right_Btn_Down") { - //m_clipping = true; + if (m_vrVolumeApp) { m_vrVolumeApp->enable_clipping(true); } - - //std::cerr << "Clipping ON" << std::endl; } else if (event.getName() == "HTC_Controller_Right_GripButton_Down" || event.getName() == "HTC_Controller_1_GripButton_Down" || event.getName() == "B08_Down") { - //m_show_menu = !m_show_menu; + if (m_vrVolumeApp) { m_vrVolumeApp->enable_ui_menu(); } - } } - if (!(m_vrVolumeApp && m_vrVolumeApp->is_show_menu() && m_vrVolumeApp->is_ui_event())) { + if (!(m_vrVolumeApp && m_vrVolumeApp->is_show_menu() && m_vrVolumeApp->is_ui_event())) + { if (event.getName() == "KbdW_Down") { m_vrVolumeApp->set_AWSD_keyBoard_event(W); @@ -279,14 +267,13 @@ void VolumeVisualizationApp::onButtonDown(const VRButtonEvent& event) { { m_vrVolumeApp->set_AWSD_keyBoard_event(E); } - - } } - -void VolumeVisualizationApp::onButtonUp(const VRButtonEvent& event) { - if (m_vrVolumeApp && m_vrVolumeApp->is_ui_event()) { +void VolumeVisualizationApp::onButtonUp(const VRButtonEvent &event) +{ + if (m_vrVolumeApp && m_vrVolumeApp->is_ui_event()) + { if (event.getName() == "MouseBtnMiddle_ScrollUp") { m_vrVolumeApp->update_ui_events(10); @@ -311,7 +298,6 @@ void VolumeVisualizationApp::onButtonUp(const VRButtonEvent& event) { { m_vrVolumeApp->button_event_trackBall_handle(2, 0); } - } if (event.getName() == "MouseBtnMiddle_ScrollDown") @@ -330,7 +316,6 @@ void VolumeVisualizationApp::onButtonUp(const VRButtonEvent& event) { m_vrVolumeApp->button_events_ui_handle(0, 0); m_vrVolumeApp->button_event_trackBall_handle(0, 0); } - } else if (event.getName() == "MouseBtnRight_Up") { @@ -340,9 +325,9 @@ void VolumeVisualizationApp::onButtonUp(const VRButtonEvent& event) { m_vrVolumeApp->button_events_ui_handle(1, 0); m_vrVolumeApp->button_event_trackBall_handle(1, 0); } - } - else if (event.getName() == "MouseBtnMiddle_Up") { + else if (event.getName() == "MouseBtnMiddle_Up") + { if (m_vrVolumeApp) { @@ -351,8 +336,8 @@ void VolumeVisualizationApp::onButtonUp(const VRButtonEvent& event) { } } - - if (m_vrVolumeApp && m_vrVolumeApp->is_show_menu()) { + if (m_vrVolumeApp && m_vrVolumeApp->is_show_menu()) + { if (event.getName() == "HTC_Controller_Right_Axis1Button_Up" || event.getName() == "HTC_Controller_1_Axis1Button_Up" || event.getName() == "B10_Up") { m_vrVolumeApp->button_events_ui_handle(0, 0); @@ -361,7 +346,6 @@ void VolumeVisualizationApp::onButtonUp(const VRButtonEvent& event) { { m_vrVolumeApp->button_events_ui_handle(2, 0); } - //else if (event.getName() == "HTC_Controller_Right_AButton_Down" || event.getName() == "HTC_Controller_1_AButton_Down") else if (event.getName() == "HTC_Controller_Right_Axis0Button_Up" || event.getName() == "HTC_Controller_1_Axis0Button_Up" || event.getName() == "B08_Up") { m_vrVolumeApp->button_events_ui_handle(1, 0); @@ -369,7 +353,6 @@ void VolumeVisualizationApp::onButtonUp(const VRButtonEvent& event) { } // This routine is called for all Button_Up events. Check event->getName() // to see exactly which button has been released. - //std::cerr << "onButtonUp " << event.getName() << std::endl; if (event.getName() == "HTC_Controller_Right_Axis1Button_Up" || event.getName() == "HTC_Controller_1_Axis1Button_Up" || event.getName() == "B10_Up") { @@ -377,9 +360,7 @@ void VolumeVisualizationApp::onButtonUp(const VRButtonEvent& event) { { m_vrVolumeApp->enable_grab(false); } - } - //else if (event.getName() == "HTC_Controller_Right_AButton_Up" || event.getName() == "HTC_Controller_1_AButton_Up") else if (event.getName() == "HTC_Controller_Right_Axis0Button_Up" || event.getName() == "HTC_Controller_1_Axis0Button_Up" || event.getName() == "Wand_Right_Btn_Up") { @@ -387,16 +368,15 @@ void VolumeVisualizationApp::onButtonUp(const VRButtonEvent& event) { { m_vrVolumeApp->enable_clipping(false); } - } - if (event.getName() == "KbdW_Up") { + if (event.getName() == "KbdW_Up") + { if (m_vrVolumeApp) { m_vrVolumeApp->unset_AWSD_keyBoard_event(W); } - } if (event.getName() == "KbdA_Up") { @@ -412,7 +392,8 @@ void VolumeVisualizationApp::onButtonUp(const VRButtonEvent& event) { m_vrVolumeApp->unset_AWSD_keyBoard_event(S); } } - if (event.getName() == "KbdD_Up") { + if (event.getName() == "KbdD_Up") + { if (m_vrVolumeApp) { m_vrVolumeApp->unset_AWSD_keyBoard_event(D); @@ -433,20 +414,17 @@ void VolumeVisualizationApp::onButtonUp(const VRButtonEvent& event) { } } - if (event.getName() == "KbdSpace_Up") { - //m_renderVolume = !m_renderVolume; + if (event.getName() == "KbdSpace_Up") + { if (m_vrVolumeApp) { m_vrVolumeApp->enable_render_volume(); } } - - - } - -void VolumeVisualizationApp::onTrackerMove(const VRTrackerEvent& event) { +void VolumeVisualizationApp::onTrackerMove(const VRTrackerEvent &event) +{ if (event.getName() == "HTC_Controller_Right_Move" || event.getName() == "HTC_Controller_1_Move" || event.getName() == "Wand0_Move") { @@ -456,54 +434,62 @@ void VolumeVisualizationApp::onTrackerMove(const VRTrackerEvent& event) { glm::mat4 new_pose = glm::make_mat4(event.getTransform()); m_vrVolumeApp->update_UI_pose_controller(new_pose); } - } - - // This routine is called for all Tracker_Move events. Check event->getName() - // to see exactly which tracker has moved, and then access the tracker's new - // 4x4 transformation matrix with event->getTransform(). - if (event.getName() == "HTC_Controller_Right_Move" || event.getName() == "HTC_Controller_1_Move" || event.getName() == "Wand0_Move") { + // to see exactly which tracker has moved, and then access the tracker's new + // 4x4 transformation matrix with event->getTransform(). + if (event.getName() == "HTC_Controller_Right_Move" || event.getName() == "HTC_Controller_1_Move" || event.getName() == "Wand0_Move") + { glm::mat4 new_pose = glm::make_mat4(event.getTransform()); if (m_vrVolumeApp) { m_vrVolumeApp->do_grab(new_pose); } - } - else if (event.getName() == "HTC_HMD_1_Move") { + else if (event.getName() == "HTC_HMD_1_Move") + { glm::mat4 headPose = glm::make_mat4(event.getTransform()); if (m_vrVolumeApp) { m_vrVolumeApp->update_head_pose(headPose); } - //m_headpose = glm::inverse(m_headpose); + m_light_pos[0] = headPose[3][0]; m_light_pos[1] = headPose[3][1]; m_light_pos[2] = headPose[3][2]; } } - - -void VolumeVisualizationApp::onGenericEvent(const VRDataIndex& index) +void VolumeVisualizationApp::onGenericEvent(const VRDataIndex &index) { - if (index.getName() == "WindowClose") { + if (index.getName() == "WindowClose") + { shutdown(); } + + if (index.getName() == "BufferSize") + { + const std::vector *v = index.getValue("WindowSize"); + const float *f = &(v->front()); + glViewport(0, 0, GLint(f[0]), GLint(f[1])); + } } -void VolumeVisualizationApp::onRenderGraphicsContext(const VRGraphicsState& renderState) { +void VolumeVisualizationApp::onRenderGraphicsContext(const VRGraphicsState &renderState) +{ // This routine is called once per graphics context at the start of the // rendering process. So, this is the place to initialize textures, // load models, or do other operations that you only want to do once per // frame when in stereo mode. + m_num_frames++; std::chrono::steady_clock::time_point nowTime = std::chrono::steady_clock::now(); - std::chrono::duration time_span = std::chrono::duration(nowTime - m_lastTime); - float fps = 1000.0f / std::chrono::duration_cast(time_span).count(); + std::chrono::duration delta_time = std::chrono::duration(nowTime - m_lastTime); + float delta_time_to_milliseconds = std::chrono::duration_cast(delta_time).count(); + float fps = 1000.0f / delta_time_to_milliseconds; + if (m_vrVolumeApp) { m_vrVolumeApp->update_fps(fps); @@ -511,18 +497,18 @@ void VolumeVisualizationApp::onRenderGraphicsContext(const VRGraphicsState& rend } m_lastTime = nowTime; - - - if (renderState.isInitialRenderCall()) { + if (renderState.isInitialRenderCall()) + { #ifndef __APPLE__ glewExperimental = GL_TRUE; GLenum err = glewInit(); - if (GLEW_OK != err) { + if (GLEW_OK != err) + { std::cout << "Error initializing GLEW." << std::endl; } -#endif -std::cout << "init vizapp " << std::endl; +#endif + std::cout << "init vizapp " << std::endl; if (m_vrVolumeApp) { m_vrVolumeApp->initialize(); @@ -542,36 +528,29 @@ std::cout << "init vizapp " << std::endl; glClearDepth(1.0f); glDepthFunc(GL_LEQUAL); glClearColor(0.0, 0.0, 0.0, 1); - std::cout << "init vizapp end" << std::endl; + std::cout << "init vizapp end" << std::endl; } - - - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - glLightfv(GL_LIGHT0, GL_POSITION, m_light_pos); - if (m_vrVolumeApp) { if (m_vrVolumeApp->pending_models_to_load()) { m_vrVolumeApp->load_mesh_model(); } - + m_vrVolumeApp->initialize_textures(); m_vrVolumeApp->update_3D_ui(); m_vrVolumeApp->update_trackBall_state(); - m_vrVolumeApp->update_animation(); - m_vrVolumeApp->set_render_count(0); - } + m_vrVolumeApp->update_animation(delta_time.count()); + last_Update_Time = nowTime; - // std::cout << "init vizapp loop" << std::endl; + m_vrVolumeApp->set_render_count(0); + } } - -void VolumeVisualizationApp::onRenderGraphicsScene(const VRGraphicsState& renderState) { +void VolumeVisualizationApp::onRenderGraphicsScene(const VRGraphicsState &renderState) +{ // This routine is called once per eye. This is the place to actually // draw the scene... @@ -579,5 +558,4 @@ void VolumeVisualizationApp::onRenderGraphicsScene(const VRGraphicsState& render { m_vrVolumeApp->render(renderState); } - } diff --git a/superbuild/CMakeLists.txt b/superbuild/CMakeLists.txt index 27f5c54..5e1f566 100644 --- a/superbuild/CMakeLists.txt +++ b/superbuild/CMakeLists.txt @@ -45,7 +45,7 @@ endif() message("CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE}") if(NOT DEBUG_SUFFIX AND CMAKE_BUILD_TYPE MATCHES "Debug") - set(DEBUG_SUFFIX "d") + set(CMAKE_DEBUG_SUFFIX "d") endif() message("DEBUG_SUFFIX ${DEBUG_SUFFIX}") @@ -107,6 +107,37 @@ else() message("====== MINVR IS NOT WIN 32") endif (WIN32) + +#Choreograph +# Configure external project +execute_process( + COMMAND ${CMAKE_COMMAND} + -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX} + -DINSTALL_DIR_ABSOLUTE=${INSTALL_DIR_ABSOLUTE} + -DDEFAULT_BUILD_COMMAND=${DEFAULT_BUILD_COMMAND} + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + ${CMAKE_SOURCE_DIR}/Choreograph + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/Choreograph + ) + + +#Build external project +execute_process( COMMAND ${CMAKE_COMMAND} + --build ${CMAKE_BINARY_DIR}/Choreograph + --config ${CMAKE_BUILD_TYPE} +) + + +find_package(Choreograph REQUIRED) +if(Choreograph_FOUND) + message(STATUS "Choreograph found") + message(STATUS "CHOREOGRAPH_INCLUDE_DIR ${CHOREOGRAPH_INCLUDE_DIR}") + message(STATUS "CHOREOGRAPH_LIBRARY ${CHOREOGRAPH_LIBRARY}") +else() + message(STATUS "Choreograph NOT found" ) +endif() + + #MinVR # Configure external project IF(NOT EXISTS ${CMAKE_SOURCE_DIR}/MinVR/MinVR) @@ -386,12 +417,13 @@ endif() find_package(OpenCV CONFIG REQUIRED) +set_target_properties(${OpenCV_LIBS} PROPERTIES MAP_IMPORTED_CONFIG_RELWITHDEBINFO RELEASE) if(OpenCV_FOUND) message(STATUS "OpenCV found ${_OpenCV_LIB_PATH}") message(STATUS "OpenCV found ${OpenCV_INSTALL_PATH}") if(WIN32) set(OPENCV_PATH ${_OpenCV_LIB_PATH} ) - set(OPENCV_SUFIX "454" ) + set(OPENCV_SUFIX "455" ) elseif(APPLE) set(OPENCV_PATH "${CMAKE_BINARY_DIR}/install_${CMAKE_SYSTEM_NAME}/lib") set(OPENCV_PREFIX "lib" ) @@ -399,10 +431,10 @@ if(OpenCV_FOUND) #set(OPENCV_SUFIX "4.5.3" ) endif() - file(COPY "${OPENCV_PATH}/${OPENCV_PREFIX}opencv_videoio${OPENCV_SUFIX}${DEBUG_SUFFIX}${CMAKE_SHARED_LIBRARY_SUFFIX}" DESTINATION "${INSTALL_DIR_ABSOLUTE}/bin" ) - file(COPY "${OPENCV_PATH}/${OPENCV_PREFIX}opencv_imgcodecs${OPENCV_SUFIX}${DEBUG_SUFFIX}${CMAKE_SHARED_LIBRARY_SUFFIX}" DESTINATION "${INSTALL_DIR_ABSOLUTE}/bin" ) - file(COPY "${OPENCV_PATH}/${OPENCV_PREFIX}opencv_imgproc${OPENCV_SUFIX}${DEBUG_SUFFIX}${CMAKE_SHARED_LIBRARY_SUFFIX}" DESTINATION "${INSTALL_DIR_ABSOLUTE}/bin" ) - file(COPY "${OPENCV_PATH}/${OPENCV_PREFIX}opencv_core${OPENCV_SUFIX}${DEBUG_SUFFIX}${CMAKE_SHARED_LIBRARY_SUFFIX}" DESTINATION "${INSTALL_DIR_ABSOLUTE}/bin" ) + file(COPY "${OPENCV_PATH}/${OPENCV_PREFIX}opencv_videoio${OPENCV_SUFIX}${CMAKE_DEBUG_SUFFIX}${CMAKE_SHARED_LIBRARY_SUFFIX}" DESTINATION "${INSTALL_DIR_ABSOLUTE}/bin" ) + file(COPY "${OPENCV_PATH}/${OPENCV_PREFIX}opencv_imgcodecs${OPENCV_SUFIX}${CMAKE_DEBUG_SUFFIX}${CMAKE_SHARED_LIBRARY_SUFFIX}" DESTINATION "${INSTALL_DIR_ABSOLUTE}/bin" ) + file(COPY "${OPENCV_PATH}/${OPENCV_PREFIX}opencv_imgproc${OPENCV_SUFIX}${CMAKE_DEBUG_SUFFIX}${CMAKE_SHARED_LIBRARY_SUFFIX}" DESTINATION "${INSTALL_DIR_ABSOLUTE}/bin" ) + file(COPY "${OPENCV_PATH}/${OPENCV_PREFIX}opencv_core${OPENCV_SUFIX}${CMAKE_DEBUG_SUFFIX}${CMAKE_SHARED_LIBRARY_SUFFIX}" DESTINATION "${INSTALL_DIR_ABSOLUTE}/bin" ) endif() @@ -531,15 +563,16 @@ endif() ${CMAKE_CURRENT_BINARY_DIR}/../libs/glm.cpp ${CMAKE_CURRENT_BINARY_DIR}/../src/render/FrameBufferObject.cpp ${CMAKE_CURRENT_BINARY_DIR}/../src/render/DepthTexture.cpp - ${CMAKE_CURRENT_BINARY_DIR}/../src/interaction/Labels.cpp + ${CMAKE_CURRENT_BINARY_DIR}/../src/interaction/LabelManager.cpp ${CMAKE_CURRENT_BINARY_DIR}/../src/render/FontHandler.cpp ${CMAKE_CURRENT_BINARY_DIR}/../libs/UIHelpers/transfer_function_widget.cpp ${CMAKE_CURRENT_BINARY_DIR}/../libs/UIHelpers/transfer_function_multichannel_widget.cpp ${CMAKE_CURRENT_BINARY_DIR}/../libs/UIHelpers/histogram.cpp ${CMAKE_CURRENT_BINARY_DIR}/../libs/UIHelpers/Vec2.cpp - ${CMAKE_CURRENT_BINARY_DIR}/../src/interaction/ArcBall.cpp + ${CMAKE_CURRENT_BINARY_DIR}/../src/interaction/ArcBallCamera.cpp ${CMAKE_CURRENT_BINARY_DIR}/../src/interaction/HelperFunctions.cpp ${CMAKE_CURRENT_BINARY_DIR}/../src/interaction/CreateMovieAction.cpp + ${CMAKE_CURRENT_BINARY_DIR}/../src/interaction/Simulation.cpp ${CMAKE_CURRENT_BINARY_DIR}/../src/loader/LoadDescriptionAction.cpp ${CMAKE_CURRENT_BINARY_DIR}/../src/loader/VRDataLoader.cpp ) @@ -550,6 +583,7 @@ set(header_files ${CMAKE_CURRENT_BINARY_DIR}/../include/loader/LoadDataAction.h ${CMAKE_CURRENT_BINARY_DIR}/../include/render/Shader.h ${CMAKE_CURRENT_BINARY_DIR}/../include/render/Volume.h + ${CMAKE_CURRENT_BINARY_DIR}/../include/render/VolumeRenderer.h ${CMAKE_CURRENT_BINARY_DIR}/../include/render/VolumeSliceRenderer.h ${CMAKE_CURRENT_BINARY_DIR}/../include/render/VolumeSliceShader.h ${CMAKE_CURRENT_BINARY_DIR}/../include/render/VolumeRaycastRenderer.h @@ -558,16 +592,18 @@ set(header_files ${CMAKE_CURRENT_BINARY_DIR}/../libs/glm.h ${CMAKE_CURRENT_BINARY_DIR}/../include/render/FrameBufferObject.h ${CMAKE_CURRENT_BINARY_DIR}/../include/render/DepthTexture.h - ${CMAKE_CURRENT_BINARY_DIR}/../include/interaction/Labels.h + ${CMAKE_CURRENT_BINARY_DIR}/../include/interaction/LabelManager.h ${CMAKE_CURRENT_BINARY_DIR}/../include/render/FontHandler.h ${CMAKE_CURRENT_BINARY_DIR}/../libs/UIHelpers/transfer_function_widget.h ${CMAKE_CURRENT_BINARY_DIR}/../libs/UIHelpers/transfer_function_multichannel_widget.h ${CMAKE_CURRENT_BINARY_DIR}/../libs/UIHelpers/embedded_colormaps.h ${CMAKE_CURRENT_BINARY_DIR}/../libs/UIHelpers/histogram.h ${CMAKE_CURRENT_BINARY_DIR}/../libs/UIHelpers/Vec2.h - ${CMAKE_CURRENT_BINARY_DIR}/../include/interaction/ArcBall.h + ${CMAKE_CURRENT_BINARY_DIR}/../include/interaction/ArcBallCamera.h ${CMAKE_CURRENT_BINARY_DIR}/../include/interaction/HelperFunctions.h ${CMAKE_CURRENT_BINARY_DIR}/../include/interaction/CreateMovieAction.h + ${CMAKE_CURRENT_BINARY_DIR}/../include/interaction/PointOfInterests.h + ${CMAKE_CURRENT_BINARY_DIR}/../include/interaction/Simulation.h ${CMAKE_CURRENT_BINARY_DIR}/../include/loader/LoadDescriptionAction.h ${CMAKE_CURRENT_BINARY_DIR}/../include/loader/VRDataLoader.h @@ -585,6 +621,7 @@ set(header_files ${CPPFS_INCLUDE_DIRS} ${Imgui_INCLUDE_DIR} ${IMGUIVR_INCLUDE_DIR} + ${CHOREOGRAPH_INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../libs/ ${CMAKE_CURRENT_SOURCE_DIR}/../include/ ${Model_INCLUDE_DIR} @@ -596,6 +633,7 @@ set(header_files set(LIBRARIES ${OPENGL_LIBRARY} + ${CHOREOGRAPH_LIBRARY} ${OpenCV_LIBS} ${GLM_LIBRARIES} ${GLEW_LIBRARY} @@ -637,10 +675,11 @@ add_executable(${PROJECT_NAME} ${source_files} ${header_files}) target_link_libraries(${PROJECT_NAME} ${LIBRARIES}) file(COPY "${CMAKE_SOURCE_DIR}/../shaders" DESTINATION "${INSTALL_DIR_ABSOLUTE}/bin") -file(COPY "${CMAKE_SOURCE_DIR}/../fonts/" DESTINATION "${INSTALL_DIR_ABSOLUTE}/bin") -file(COPY "${CMAKE_SOURCE_DIR}/../observers/" DESTINATION "${INSTALL_DIR_ABSOLUTE}/bin") +file(COPY "${CMAKE_SOURCE_DIR}/../fonts" DESTINATION "${INSTALL_DIR_ABSOLUTE}/bin") +file(COPY "${CMAKE_SOURCE_DIR}/../observers" DESTINATION "${INSTALL_DIR_ABSOLUTE}/bin") file(COPY "${CMAKE_SOURCE_DIR}/../colormaps" DESTINATION "${INSTALL_DIR_ABSOLUTE}/bin") - +message(STATUS "COPY RESOURCES FOLDER") +file(COPY "${CMAKE_SOURCE_DIR}/../Resources" DESTINATION "${INSTALL_DIR_ABSOLUTE}/bin") enable_testing() diff --git a/superbuild/Choreograph/CMakeLists.txt b/superbuild/Choreograph/CMakeLists.txt new file mode 100644 index 0000000..09ec15f --- /dev/null +++ b/superbuild/Choreograph/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required (VERSION 3.15) +project(Choreograph) +include(ExternalProject) +include(GNUInstallDirs) +include(${CMAKE_SOURCE_DIR}/../macros.cmake) + +message("${CMAKE_PROJECT_NAME} INSTALL_DIR_ABSOLUTE ${INSTALL_DIR_ABSOLUTE}") + +set(EXTERNAL_DIR_LOCATION ${CMAKE_BINARY_DIR}) +set(EXTERNAL_DIR_INSTALL_LOCATION ${CMAKE_BINARY_DIR}/../install/) + +build_choerograph_subproject( + NAME Choreograph + URL https://github.com/brown-ccv/Choreograph.git + BUILD_ARGS + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} +) diff --git a/superbuild/MinVR/CMakeLists.txt b/superbuild/MinVR/CMakeLists.txt index 62d3694..25a2dc7 100644 --- a/superbuild/MinVR/CMakeLists.txt +++ b/superbuild/MinVR/CMakeLists.txt @@ -5,15 +5,13 @@ include(GNUInstallDirs) include(${CMAKE_SOURCE_DIR}/../macros.cmake) message("${CMAKE_PROJECT_NAME} INSTALL_DIR_ABSOLUTE ${INSTALL_DIR_ABSOLUTE}") -message("MINVR CMAKELISTS MINVR_PATCH_PATH ${MINVR_PATCH_PATH}") set(EXTERNAL_DIR_LOCATION ${CMAKE_BINARY_DIR}) set(EXTERNAL_DIR_INSTALL_LOCATION ${CMAKE_BINARY_DIR}/../install/) build_minvr_subproject( NAME MinVR - URL "https://github.com/MinVR/MinVR.git" - PATCH ${MINVR_PATCH_PATH} + URL "https://github.com/brown-ccv/MinVR.git" BUILD_ARGS -DWITH_PLUGIN_OPENGL=ON -DWITH_PLUGIN_GLFW=ON diff --git a/superbuild/clean/clean.py b/superbuild/clean/clean.py index b28de99..f8d155f 100644 --- a/superbuild/clean/clean.py +++ b/superbuild/clean/clean.py @@ -18,7 +18,7 @@ def handleRemoveReadonly(func, path, exc): current_dir = pathlib.Path(__file__).parent.resolve() parent_dir = dirname(dirname(abspath(__file__))) print("working directory " + parent_dir) -folders_to_operate = ["CPPFSD","freetype","FTGL","glew","glfw","glm","MinVR","opencv","teem","vr-imgui","zlib"] +folders_to_operate = ["CPPFSD","freetype","FTGL","glew","glfw","glm","MinVR","opencv","teem","vr-imgui","zlib","Choreograph"] files_to_exclude = ["CMakeLists.txt","macros.cmake","minvr_patch_082021.patch"] folders_to_exclude = ["cmake","clean","scripts","bat2exe"] diff --git a/superbuild/cmake/FindChoreograph.cmake b/superbuild/cmake/FindChoreograph.cmake new file mode 100644 index 0000000..afbd964 --- /dev/null +++ b/superbuild/cmake/FindChoreograph.cmake @@ -0,0 +1,30 @@ +message("FINDChoreograph CMAKE") +message("CMAKE_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}") +message("CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE}") +set(LIBNAME Choreograph${CMAKE_DEBUG_SUFFIX}) + +find_path(CHOREOGRAPH_INCLUDE_DIR + NAMES + Choreograph.h + HINTS + ${CMAKE_INSTALL_PREFIX}/include/Choreograph +) + +message(STATUS "CHOREOGRAPH_INCLUDE_DIR ${CHOREOGRAPH_INCLUDE_DIR}") + + +find_library(CHOREOGRAPH_LIBRARY + NAMES + ${LIBNAME} + HINTS + ${CMAKE_INSTALL_PREFIX}/lib/ +) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Choreograph + DEFAULT_MSG + CHOREOGRAPH_INCLUDE_DIR + CHOREOGRAPH_LIBRARY +) + + diff --git a/superbuild/macros.cmake b/superbuild/macros.cmake index 1b8d9da..6db2972 100644 --- a/superbuild/macros.cmake +++ b/superbuild/macros.cmake @@ -33,7 +33,7 @@ macro(build_git_subproject) # Setup SUBPROJECT_* variables (containing paths) for this function setup_subproject_path_vars(${BUILD_SUBPROJECT_NAME}) - + # Build the actual subproject ExternalProject_Add(${SUBPROJECT_NAME} PREFIX ${SUBPROJECT_NAME} @@ -69,6 +69,55 @@ macro(build_git_subproject) append_cmake_prefix_path(${SUBPROJECT_INSTALL_PATH}) endmacro() + +macro(build_choerograph_subproject) + # See cmake_parse_arguments docs to see how args get parsed here: + # https://cmake.org/cmake/help/latest/command/cmake_parse_arguments.html + set(oneValueArgs NAME URL ) + set(multiValueArgs BUILD_ARGS DEPENDS_ON) + cmake_parse_arguments(BUILD_SUBPROJECT "" "${oneValueArgs}" + "${multiValueArgs}" ${ARGN}) + + # Setup SUBPROJECT_* variables (containing paths) for this function + setup_subproject_path_vars(${BUILD_SUBPROJECT_NAME}) + + # Build the actual subproject + ExternalProject_Add(${SUBPROJECT_NAME} + PREFIX ${SUBPROJECT_NAME} + DOWNLOAD_DIR ${SUBPROJECT_NAME} + STAMP_DIR ${SUBPROJECT_STAMP_PATH} + SOURCE_DIR ${SUBPROJECT_SOURCE_PATH} + BINARY_DIR ${SUBPROJECT_BUILD_PATH} + GIT_REPOSITORY ${BUILD_SUBPROJECT_URL} + GIT_TAG stable + LIST_SEPARATOR | # Use the alternate list separator + CMAKE_ARGS + -S ${CMAKE_CURRENT_SOURCE_DIR}/Choreograph/source/src + -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} + -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} + -DCMAKE_INSTALL_PREFIX:PATH=${SUBPROJECT_INSTALL_PATH} + -DCMAKE_INSTALL_INCLUDEDIR=${CMAKE_INSTALL_INCLUDEDIR} + -DCMAKE_INSTALL_LIBDIR=${CMAKE_INSTALL_LIBDIR} + -DCMAKE_INSTALL_DOCDIR=${CMAKE_INSTALL_DOCDIR} + -DCMAKE_INSTALL_BINDIR=${CMAKE_INSTALL_BINDIR} + -DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH} + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + ${BUILD_SUBPROJECT_BUILD_ARGS} + BUILD_COMMAND ${DEFAULT_BUILD_COMMAND} + BUILD_ALWAYS OFF + ) + + if(BUILD_SUBPROJECT_DEPENDS_ON) + ExternalProject_Add_StepDependencies(${SUBPROJECT_NAME} + configure ${BUILD_SUBPROJECT_DEPENDS_ON} + ) + endif() + + # Place installed component on CMAKE_PREFIX_PATH for downstream consumption + append_cmake_prefix_path(${SUBPROJECT_INSTALL_PATH}) +endmacro() + + macro(build_minvr_subproject) # See cmake_parse_arguments docs to see how args get parsed here: # https://cmake.org/cmake/help/latest/command/cmake_parse_arguments.html @@ -80,12 +129,11 @@ macro(build_minvr_subproject) # Setup SUBPROJECT_* variables (containing paths) for this function setup_subproject_path_vars(${BUILD_SUBPROJECT_NAME}) - message("BUILD_SUBPROJECT_PATCH ${BUILD_SUBPROJECT_PATCH}") + # Build the actual subproject ExternalProject_Add(${SUBPROJECT_NAME} PREFIX ${SUBPROJECT_NAME} DOWNLOAD_DIR ${SUBPROJECT_NAME} - PATCH_COMMAND git apply ${BUILD_SUBPROJECT_PATCH}/minvr_patch_09142021.patch STAMP_DIR ${SUBPROJECT_STAMP_PATH} SOURCE_DIR ${SUBPROJECT_SOURCE_PATH} BINARY_DIR ${SUBPROJECT_BUILD_PATH} @@ -327,7 +375,7 @@ macro(build_glm_subproject) SOURCE_DIR ${SUBPROJECT_SOURCE_PATH} BINARY_DIR ${SUBPROJECT_BUILD_PATH} GIT_REPOSITORY ${BUILD_SUBPROJECT_URL} - GIT_TAG ${BUILD_SUBPROJECT_TAG} + GIT_TAG ${BUILD_SUBPROJECT_TAG} LIST_SEPARATOR | # Use the alternate list separator CMAKE_ARGS